| use std::num::{NonZero, ParseIntError}; | |
| use rustc_ast::token; | |
| use rustc_ast::util::literal::LitError; | |
| use rustc_errors::codes::*; | |
| use rustc_errors::{ | |
| Diag, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed, Level, | |
| MultiSpan, StashKey, | |
| }; | |
| use rustc_feature::{GateIssue, find_feature_issue}; | |
| use rustc_macros::{Diagnostic, Subdiagnostic}; | |
| use rustc_span::{Span, Symbol, sym}; | |
| use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTuple}; | |
| use crate::Session; | |
| use crate::lint::builtin::UNSTABLE_SYNTAX_PRE_EXPANSION; | |
| use crate::parse::ParseSess; | |
| /// Construct a diagnostic for a language feature error due to the given `span`. | |
| /// The `feature`'s `Symbol` is the one you used in `unstable.rs` and `rustc_span::symbol`. | |
| #[track_caller] | |
| pub fn feature_err( | |
| sess: &Session, | |
| feature: Symbol, | |
| span: impl Into<MultiSpan>, | |
| explain: impl Into<DiagMessage>, | |
| ) -> Diag<'_> { | |
| feature_err_issue(sess, feature, span, GateIssue::Language, explain) | |
| } | |
| /// Construct a diagnostic for a feature gate error. | |
| /// | |
| /// This variant allows you to control whether it is a library or language feature. | |
| /// Almost always, you want to use this for a language feature. If so, prefer `feature_err`. | |
| #[track_caller] | |
| pub fn feature_err_issue( | |
| sess: &Session, | |
| feature: Symbol, | |
| span: impl Into<MultiSpan>, | |
| issue: GateIssue, | |
| explain: impl Into<DiagMessage>, | |
| ) -> Diag<'_> { | |
| let span = span.into(); | |
| // Cancel an earlier warning for this same error, if it exists. | |
| if let Some(span) = span.primary_span() | |
| && let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) | |
| { | |
| err.cancel() | |
| } | |
| let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); | |
| add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); | |
| err | |
| } | |
| /// Construct a future incompatibility diagnostic for a feature gate. | |
| /// | |
| /// This diagnostic is only a warning and *does not cause compilation to fail*. | |
| #[track_caller] | |
| pub fn feature_warn(sess: &Session, feature: Symbol, span: Span, explain: &'static str) { | |
| feature_warn_issue(sess, feature, span, GateIssue::Language, explain); | |
| } | |
| /// Construct a future incompatibility diagnostic for a feature gate. | |
| /// | |
| /// This diagnostic is only a warning and *does not cause compilation to fail*. | |
| /// | |
| /// This variant allows you to control whether it is a library or language feature. | |
| /// Almost always, you want to use this for a language feature. If so, prefer `feature_warn`. | |
| #[track_caller] | |
| pub fn feature_warn_issue( | |
| sess: &Session, | |
| feature: Symbol, | |
| span: Span, | |
| issue: GateIssue, | |
| explain: &'static str, | |
| ) { | |
| let mut err = sess.dcx().struct_span_warn(span, explain); | |
| add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); | |
| // Decorate this as a future-incompatibility lint as in rustc_middle::lint::lint_level | |
| let lint = UNSTABLE_SYNTAX_PRE_EXPANSION; | |
| let future_incompatible = lint.future_incompatible.as_ref().unwrap(); | |
| err.is_lint( | |
| lint.name_lower(), | |
| /* has_future_breakage */ false, | |
| /* rust_version */ None, | |
| ); | |
| err.warn(lint.desc); | |
| err.note(format!("for more information, see {}", future_incompatible.reason.reference())); | |
| // A later feature_err call can steal and cancel this warning. | |
| err.stash(span, StashKey::EarlySyntaxWarning); | |
| } | |
| /// Adds the diagnostics for a feature to an existing error. | |
| /// Must be a language feature! | |
| pub fn add_feature_diagnostics<G: EmissionGuarantee>( | |
| err: &mut Diag<'_, G>, | |
| sess: &Session, | |
| feature: Symbol, | |
| ) { | |
| add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false, None); | |
| } | |
| /// Adds the diagnostics for a feature to an existing error. | |
| /// | |
| /// This variant allows you to control whether it is a library or language feature. | |
| /// Almost always, you want to use this for a language feature. If so, prefer | |
| /// `add_feature_diagnostics`. | |
| pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>( | |
| err: &mut Diag<'_, G>, | |
| sess: &Session, | |
| feature: Symbol, | |
| issue: GateIssue, | |
| feature_from_cli: bool, | |
| inject_span: Option<Span>, | |
| ) { | |
| if let Some(n) = find_feature_issue(feature, issue) { | |
| err.subdiagnostic(FeatureDiagnosticForIssue { n }); | |
| } | |
| // #23973: do not suggest `#![feature(...)]` if we are in beta/stable | |
| if sess.unstable_features.is_nightly_build() { | |
| if feature_from_cli { | |
| err.subdiagnostic(CliFeatureDiagnosticHelp { feature }); | |
| } else if let Some(span) = inject_span { | |
| err.subdiagnostic(FeatureDiagnosticSuggestion { feature, span }); | |
| } else { | |
| err.subdiagnostic(FeatureDiagnosticHelp { feature }); | |
| } | |
| if feature == sym::rustc_attrs { | |
| // We're unlikely to stabilize something out of `rustc_attrs` | |
| // without at least renaming it, so pointing out how old | |
| // the compiler is will do little good. | |
| } else if sess.opts.unstable_opts.ui_testing { | |
| err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); | |
| } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { | |
| err.subdiagnostic(suggestion); | |
| } | |
| } | |
| } | |
| /// This is only used by unstable_feature_bound as it does not have issue number information for now. | |
| /// This is basically the same as `feature_err_issue` | |
| /// but without the feature issue note. If we can do a lookup for issue number from feature name, | |
| /// then we should directly use `feature_err_issue` for ambiguity error of | |
| /// `#[unstable_feature_bound]`. | |
| #[track_caller] | |
| pub fn feature_err_unstable_feature_bound( | |
| sess: &Session, | |
| feature: Symbol, | |
| span: impl Into<MultiSpan>, | |
| explain: impl Into<DiagMessage>, | |
| ) -> Diag<'_> { | |
| let span = span.into(); | |
| // Cancel an earlier warning for this same error, if it exists. | |
| if let Some(span) = span.primary_span() { | |
| if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) { | |
| err.cancel() | |
| } | |
| } | |
| let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); | |
| // #23973: do not suggest `#![feature(...)]` if we are in beta/stable | |
| if sess.unstable_features.is_nightly_build() { | |
| err.subdiagnostic(FeatureDiagnosticHelp { feature }); | |
| if feature == sym::rustc_attrs { | |
| // We're unlikely to stabilize something out of `rustc_attrs` | |
| // without at least renaming it, so pointing out how old | |
| // the compiler is will do little good. | |
| } else if sess.opts.unstable_opts.ui_testing { | |
| err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); | |
| } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { | |
| err.subdiagnostic(suggestion); | |
| } | |
| } | |
| err | |
| } | |
| #[derive(Diagnostic)] | |
| pub(crate) enum AppleDeploymentTarget { | |
| #[diag("failed to parse deployment target specified in {$env_var}: {$error}")] | |
| Invalid { env_var: &'static str, error: ParseIntError }, | |
| #[diag( | |
| "deployment target in {$env_var} was set to {$version}, but the minimum supported by `rustc` is {$os_min}" | |
| )] | |
| TooLow { env_var: &'static str, version: String, os_min: String }, | |
| } | |
| pub(crate) struct FeatureGateError { | |
| pub(crate) span: MultiSpan, | |
| pub(crate) explain: DiagMessage, | |
| } | |
| impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for FeatureGateError { | |
| #[track_caller] | |
| fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { | |
| Diag::new(dcx, level, self.explain).with_span(self.span).with_code(E0658) | |
| } | |
| } | |
| #[derive(Subdiagnostic)] | |
| #[note("see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information")] | |
| pub(crate) struct FeatureDiagnosticForIssue { | |
| pub(crate) n: NonZero<u32>, | |
| } | |
| #[derive(Subdiagnostic)] | |
| #[note("this compiler was built on {$date}; consider upgrading it if it is out of date")] | |
| pub(crate) struct SuggestUpgradeCompiler { | |
| date: &'static str, | |
| } | |
| impl SuggestUpgradeCompiler { | |
| pub(crate) fn ui_testing() -> Self { | |
| Self { date: "YYYY-MM-DD" } | |
| } | |
| pub(crate) fn new() -> Option<Self> { | |
| let date = option_env!("CFG_VER_DATE")?; | |
| Some(Self { date }) | |
| } | |
| } | |
| #[derive(Subdiagnostic)] | |
| #[help("add `#![feature({$feature})]` to the crate attributes to enable")] | |
| pub(crate) struct FeatureDiagnosticHelp { | |
| pub(crate) feature: Symbol, | |
| } | |
| #[derive(Subdiagnostic)] | |
| #[suggestion( | |
| "add `#![feature({$feature})]` to the crate attributes to enable", | |
| applicability = "maybe-incorrect", | |
| code = "#![feature({feature})]\n" | |
| )] | |
| pub(crate) struct FeatureDiagnosticSuggestion { | |
| pub feature: Symbol, | |
| #[primary_span] | |
| pub span: Span, | |
| } | |
| #[derive(Subdiagnostic)] | |
| #[help("add `-Zcrate-attr=\"feature({$feature})\"` to the command-line options to enable")] | |
| pub(crate) struct CliFeatureDiagnosticHelp { | |
| pub(crate) feature: Symbol, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag( | |
| "`-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine" | |
| )] | |
| pub(crate) struct NotCircumventFeature; | |
| #[derive(Diagnostic)] | |
| #[diag( | |
| "linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets" | |
| )] | |
| pub(crate) struct LinkerPluginToWindowsNotSupported; | |
| #[derive(Diagnostic)] | |
| #[diag("file `{$path}` passed to `-C profile-use` does not exist")] | |
| pub(crate) struct ProfileUseFileDoesNotExist<'a> { | |
| pub(crate) path: &'a std::path::Path, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("file `{$path}` passed to `-C profile-sample-use` does not exist")] | |
| pub(crate) struct ProfileSampleUseFileDoesNotExist<'a> { | |
| pub(crate) path: &'a std::path::Path, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`")] | |
| pub(crate) struct TargetRequiresUnwindTables; | |
| #[derive(Diagnostic)] | |
| #[diag("{$us} instrumentation is not supported for this target")] | |
| pub(crate) struct InstrumentationNotSupported { | |
| pub(crate) us: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("{$us} sanitizer is not supported for this target")] | |
| pub(crate) struct SanitizerNotSupported { | |
| pub(crate) us: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("{$us} sanitizers are not supported for this target")] | |
| pub(crate) struct SanitizersNotSupported { | |
| pub(crate) us: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`")] | |
| pub(crate) struct CannotMixAndMatchSanitizers { | |
| pub(crate) first: String, | |
| pub(crate) second: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag( | |
| "sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`" | |
| )] | |
| pub(crate) struct CannotEnableCrtStaticLinux; | |
| #[derive(Diagnostic)] | |
| #[diag( | |
| "pointer authentication requires dynamic linking. Statically linked libc is incompatible, disable it using `-C target-feature=-crt-static`" | |
| )] | |
| pub(crate) struct CannotEnableCrtStaticPointerAuth; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`")] | |
| pub(crate) struct SanitizerCfiRequiresLto; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`")] | |
| pub(crate) struct SanitizerCfiRequiresSingleCodegenUnit; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`")] | |
| pub(crate) struct SanitizerCfiCanonicalJumpTablesRequiresCfi; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`")] | |
| pub(crate) struct SanitizerCfiGeneralizePointersRequiresCfi; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`")] | |
| pub(crate) struct SanitizerCfiNormalizeIntegersRequiresCfi; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zsanitizer-kcfi-arity` requires `-Zsanitizer=kcfi`")] | |
| pub(crate) struct SanitizerKcfiArityRequiresKcfi; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Z sanitizer=kcfi` requires `-C panic=abort`")] | |
| pub(crate) struct SanitizerKcfiRequiresPanicAbort; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zsplit-lto-unit` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`")] | |
| pub(crate) struct SplitLtoUnitRequiresLto; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zvirtual-function-elimination` requires `-Clto`")] | |
| pub(crate) struct UnstableVirtualFunctionElimination; | |
| #[derive(Diagnostic)] | |
| #[diag("requested DWARF version {$dwarf_version} is not supported")] | |
| #[help("supported DWARF versions are 2, 3, 4 and 5")] | |
| pub(crate) struct UnsupportedDwarfVersion { | |
| pub(crate) dwarf_version: u32, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag( | |
| "`-Zembed-source=y` requires at least `-Z dwarf-version=5` but DWARF version is {$dwarf_version}" | |
| )] | |
| pub(crate) struct EmbedSourceInsufficientDwarfVersion { | |
| pub(crate) dwarf_version: u32, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zembed-source=y` requires debug information to be enabled")] | |
| pub(crate) struct EmbedSourceRequiresDebugInfo; | |
| #[derive(Diagnostic)] | |
| #[diag( | |
| "`-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored" | |
| )] | |
| pub(crate) struct StackProtectorNotSupportedForTarget<'a> { | |
| pub(crate) stack_protector: StackProtector, | |
| pub(crate) target_triple: &'a TargetTuple, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("function pointer type discrimination is not supported")] | |
| pub(crate) struct PointerAuthenticationTypeDiscriminationNotSupportedForTarget<'a> { | |
| pub(crate) target_triple: &'a TargetTuple, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag( | |
| "`-Z pointer-authentication` is not supported for target {$target_triple} and will be ignored" | |
| )] | |
| pub(crate) struct PointerAuthenticationNotSupportedForTarget<'a> { | |
| pub(crate) target_triple: &'a TargetTuple, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag( | |
| "`-Z small-data-threshold` is not supported for target {$target_triple} and will be ignored" | |
| )] | |
| pub(crate) struct SmallDataThresholdNotSupportedForTarget<'a> { | |
| pub(crate) target_triple: &'a TargetTuple, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zbranch-protection` is only supported on aarch64")] | |
| pub(crate) struct BranchProtectionRequiresAArch64; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Csplit-debuginfo={$debuginfo}` is unstable on this platform")] | |
| pub(crate) struct SplitDebugInfoUnstablePlatform { | |
| pub(crate) debuginfo: SplitDebuginfo, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("output file {$file} is not writeable -- check its permissions")] | |
| pub(crate) struct FileIsNotWriteable<'a> { | |
| pub(crate) file: &'a std::path::Path, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("failed to write `{$path}` due to error `{$err}`")] | |
| pub(crate) struct FileWriteFail<'a> { | |
| pub(crate) path: &'a std::path::Path, | |
| pub(crate) err: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("crate name must not be empty")] | |
| pub(crate) struct CrateNameEmpty { | |
| #[primary_span] | |
| pub(crate) span: Option<Span>, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("invalid character {$character} in crate name: `{$crate_name}`")] | |
| #[note("crate names may only contain alphanumeric characters or underscores")] | |
| pub(crate) struct InvalidCharacterInCrateName { | |
| #[primary_span] | |
| pub(crate) span: Option<Span>, | |
| pub(crate) character: char, | |
| pub(crate) crate_name: Symbol, | |
| #[subdiagnostic] | |
| pub(crate) suggestion: Option<InvalidCharacterInCrateNameSuggestion>, | |
| } | |
| #[derive(Subdiagnostic)] | |
| #[help("you might have meant to use `--crate-name={$suggested_name}`")] | |
| pub(crate) struct InvalidCharacterInCrateNameSuggestion { | |
| pub(crate) suggested_name: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("skipping const checks")] | |
| pub(crate) struct SkippingConstChecks { | |
| #[subdiagnostic] | |
| pub(crate) unleashed_features: Vec<UnleashedFeatureHelp>, | |
| } | |
| #[derive(Subdiagnostic)] | |
| pub(crate) enum UnleashedFeatureHelp { | |
| #[help("skipping check for `{$gate}` feature")] | |
| Named { | |
| #[primary_span] | |
| span: Span, | |
| gate: Symbol, | |
| }, | |
| #[help("skipping check that does not even have a feature gate")] | |
| Unnamed { | |
| #[primary_span] | |
| span: Span, | |
| }, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("suffixes on {$kind} literals are invalid")] | |
| struct InvalidLiteralSuffix<'a> { | |
| #[primary_span] | |
| #[label("invalid suffix `{$suffix}`")] | |
| span: Span, | |
| // FIXME(#100717) | |
| kind: &'a str, | |
| suffix: Symbol, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("invalid width `{$width}` for integer literal")] | |
| #[help("valid widths are 8, 16, 32, 64 and 128")] | |
| struct InvalidIntLiteralWidth { | |
| #[primary_span] | |
| span: Span, | |
| width: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("invalid base prefix for number literal")] | |
| #[note("base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase")] | |
| struct InvalidNumLiteralBasePrefix { | |
| #[primary_span] | |
| #[suggestion( | |
| "try making the prefix lowercase", | |
| applicability = "maybe-incorrect", | |
| code = "{fixed}" | |
| )] | |
| span: Span, | |
| fixed: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("invalid suffix `{$suffix}` for number literal")] | |
| #[help("the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)")] | |
| struct InvalidNumLiteralSuffix { | |
| #[primary_span] | |
| #[label("invalid suffix `{$suffix}`")] | |
| span: Span, | |
| suffix: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("invalid width `{$width}` for float literal")] | |
| #[help("valid widths are 32 and 64")] | |
| struct InvalidFloatLiteralWidth { | |
| #[primary_span] | |
| span: Span, | |
| width: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("invalid suffix `{$suffix}` for float literal")] | |
| #[help("valid suffixes are `f32` and `f64`")] | |
| struct InvalidFloatLiteralSuffix { | |
| #[primary_span] | |
| #[label("invalid suffix `{$suffix}`")] | |
| span: Span, | |
| suffix: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("integer literal is too large")] | |
| #[note("value exceeds limit of `{$limit}`")] | |
| struct IntLiteralTooLarge { | |
| #[primary_span] | |
| span: Span, | |
| limit: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("hexadecimal float literal is not supported")] | |
| struct HexadecimalFloatLiteralNotSupported { | |
| #[primary_span] | |
| #[label("not supported")] | |
| span: Span, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("octal float literal is not supported")] | |
| struct OctalFloatLiteralNotSupported { | |
| #[primary_span] | |
| #[label("not supported")] | |
| span: Span, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("binary float literal is not supported")] | |
| struct BinaryFloatLiteralNotSupported { | |
| #[primary_span] | |
| #[label("not supported")] | |
| span: Span, | |
| } | |
| pub fn report_lit_error( | |
| psess: &ParseSess, | |
| err: LitError, | |
| lit: token::Lit, | |
| span: Span, | |
| ) -> ErrorGuaranteed { | |
| create_lit_error(psess, err, lit, span).emit() | |
| } | |
| pub fn create_lit_error(psess: &ParseSess, err: LitError, lit: token::Lit, span: Span) -> Diag<'_> { | |
| // Checks if `s` looks like i32 or u1234 etc. | |
| fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { | |
| s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) | |
| } | |
| // Try to lowercase the prefix if the prefix and suffix are valid. | |
| fn fix_base_capitalisation(prefix: &str, suffix: &str) -> Option<String> { | |
| let mut chars = suffix.chars(); | |
| let base_char = chars.next().unwrap(); | |
| let base = match base_char { | |
| 'B' => 2, | |
| 'O' => 8, | |
| 'X' => 16, | |
| _ => return None, | |
| }; | |
| // check that the suffix contains only base-appropriate characters | |
| let valid = prefix == "0" | |
| && chars | |
| .filter(|c| *c != '_') | |
| .take_while(|c| *c != 'i' && *c != 'u') | |
| .all(|c| c.to_digit(base).is_some()); | |
| valid.then(|| format!("0{}{}", base_char.to_ascii_lowercase(), &suffix[1..])) | |
| } | |
| let dcx = psess.dcx(); | |
| match err { | |
| LitError::InvalidSuffix(suffix) => { | |
| dcx.create_err(InvalidLiteralSuffix { span, kind: lit.kind.descr(), suffix }) | |
| } | |
| LitError::InvalidIntSuffix(suffix) => { | |
| let suf = suffix.as_str(); | |
| if looks_like_width_suffix(&['i', 'u'], suf) { | |
| // If it looks like a width, try to be helpful. | |
| dcx.create_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }) | |
| } else if let Some(fixed) = fix_base_capitalisation(lit.symbol.as_str(), suf) { | |
| dcx.create_err(InvalidNumLiteralBasePrefix { span, fixed }) | |
| } else { | |
| dcx.create_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }) | |
| } | |
| } | |
| LitError::InvalidFloatSuffix(suffix) => { | |
| let suf = suffix.as_str(); | |
| if looks_like_width_suffix(&['f'], suf) { | |
| // If it looks like a width, try to be helpful. | |
| dcx.create_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }) | |
| } else { | |
| dcx.create_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() }) | |
| } | |
| } | |
| LitError::NonDecimalFloat(base) => match base { | |
| 16 => dcx.create_err(HexadecimalFloatLiteralNotSupported { span }), | |
| 8 => dcx.create_err(OctalFloatLiteralNotSupported { span }), | |
| 2 => dcx.create_err(BinaryFloatLiteralNotSupported { span }), | |
| _ => unreachable!(), | |
| }, | |
| LitError::IntTooLarge(base) => { | |
| let max = u128::MAX; | |
| let limit = match base { | |
| 2 => format!("{max:#b}"), | |
| 8 => format!("{max:#o}"), | |
| 16 => format!("{max:#x}"), | |
| _ => format!("{max}"), | |
| }; | |
| dcx.create_err(IntLiteralTooLarge { span, limit }) | |
| } | |
| } | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("linker flavor `{$flavor}` is incompatible with the current target")] | |
| #[note("compatible flavors are: {$compatible_list}")] | |
| pub(crate) struct IncompatibleLinkerFlavor { | |
| pub(crate) flavor: &'static str, | |
| pub(crate) compatible_list: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zfunction-return` (except `keep`) is only supported on x86 and x86_64")] | |
| pub(crate) struct FunctionReturnRequiresX86OrX8664; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zfunction-return=thunk-extern` is only supported on non-large code models")] | |
| pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zindirect-branch-cs-prefix` is only supported on x86 and x86_64")] | |
| pub(crate) struct IndirectBranchCsPrefixRequiresX86OrX8664; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zregparm={$regparm}` is unsupported (valid values 0-3)")] | |
| pub(crate) struct UnsupportedRegparm { | |
| pub(crate) regparm: u32, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zregparm=N` is only supported on x86")] | |
| pub(crate) struct UnsupportedRegparmArch; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zreg-struct-return` is only supported on x86")] | |
| pub(crate) struct UnsupportedRegStructReturnArch; | |
| #[derive(Diagnostic)] | |
| #[diag("failed to create profiler: {$err}")] | |
| pub(crate) struct FailedToCreateProfiler { | |
| pub(crate) err: String, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("unexpected `--cfg {$cfg}` flag")] | |
| #[note("config `{$cfg_name}` is only supposed to be controlled by `{$controlled_by}`")] | |
| #[note("manually setting a built-in cfg can and does create incoherent behaviors")] | |
| pub(crate) struct UnexpectedBuiltinCfg { | |
| pub(crate) cfg: String, | |
| pub(crate) cfg_name: Symbol, | |
| pub(crate) controlled_by: &'static str, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("ThinLTO is not supported by the codegen backend, using fat LTO instead")] | |
| pub(crate) struct ThinLtoNotSupportedByBackend; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Zpacked-stack` is only supported on s390x")] | |
| pub(crate) struct UnsupportedPackedStack; | |
| #[derive(Diagnostic)] | |
| #[diag("`-Ctarget-cpu=native` is not allowed for target `{$target_triple}`")] | |
| #[note("this target requires consistent `-Ctarget-cpu` values across all crates")] | |
| #[help( | |
| "specify the target CPU explicitly {$need_explicit_cpu -> | |
| [false] or leave it blank to use the default | |
| *[other] {\"\"} | |
| }" | |
| )] | |
| pub(crate) struct NativeTargetCpuNotAllowed<'a> { | |
| pub(crate) target_triple: &'a TargetTuple, | |
| pub(crate) need_explicit_cpu: bool, | |
| } | |
| #[derive(Diagnostic)] | |
| #[diag("cannot resolve relative path in non-file source `{$path}`")] | |
| pub(crate) struct ResolveRelativePath { | |
| #[primary_span] | |
| pub span: Span, | |
| pub path: String, | |
| } |