| author | bors <bors@rust-lang.org> 2025-04-20 02:08:02 UTC |
| committer | bors <bors@rust-lang.org> 2025-04-20 02:08:02 UTC |
| log | 49e5e4e3a5610c240a717cb99003a5d5d3356679 |
| tree | f7d71ca252f47aa55dedab1ee31180dea2334d98 |
| parent | 90fd16eb5be9255006c95e8af12a0d43854dc1a9 |
| parent | f0a0efdcdc326cf94d232b8f6f93c8e7ad2809c2 |
Rollup of 8 pull requests
Successful merges:
- #138934 (support config extensions)
- #139091 (Rewrite on_unimplemented format string parser.)
- #139753 (Make `#[naked]` an unsafe attribute)
- #139762 (Don't assemble non-env/bound candidates if projection is rigid)
- #139834 (Don't canonicalize crate paths)
- #139868 (Move `pal::env` to `std::sys::env_consts`)
- #139978 (Add citool command for generating a test dashboard)
- #139995 (Clean UI tests 4 of n)
r? `@ghost`
`@rustbot` modify labels: rollup139 files changed, 3027 insertions(+), 1790 deletions(-)
bootstrap.example.toml+8| ... | ... | @@ -19,6 +19,14 @@ |
| 19 | 19 | # Note that this has no default value (x.py uses the defaults in `bootstrap.example.toml`). |
| 20 | 20 | #profile = <none> |
| 21 | 21 | |
| 22 | # Inherits configuration values from different configuration files (a.k.a. config extensions). | |
| 23 | # Supports absolute paths, and uses the current directory (where the bootstrap was invoked) | |
| 24 | # as the base if the given path is not absolute. | |
| 25 | # | |
| 26 | # The overriding logic follows a right-to-left order. For example, in `include = ["a.toml", "b.toml"]`, | |
| 27 | # extension `b.toml` overrides `a.toml`. Also, parent extensions always overrides the inner ones. | |
| 28 | #include = [] | |
| 29 | ||
| 22 | 30 | # Keeps track of major changes made to this configuration. |
| 23 | 31 | # |
| 24 | 32 | # This value also represents ID of the PR that caused major changes. Meaning, |
compiler/rustc_builtin_macros/messages.ftl+2-2| ... | ... | @@ -247,9 +247,9 @@ builtin_macros_multiple_defaults = multiple declared defaults |
| 247 | 247 | .suggestion = make `{$ident}` default |
| 248 | 248 | |
| 249 | 249 | builtin_macros_naked_functions_testing_attribute = |
| 250 | cannot use `#[naked]` with testing attributes | |
| 250 | cannot use `#[unsafe(naked)]` with testing attributes | |
| 251 | 251 | .label = function marked with testing attribute here |
| 252 | .naked_attribute = `#[naked]` is incompatible with testing attributes | |
| 252 | .naked_attribute = `#[unsafe(naked)]` is incompatible with testing attributes | |
| 253 | 253 | |
| 254 | 254 | builtin_macros_no_default_variant = `#[derive(Default)]` on enum with no `#[default]` |
| 255 | 255 | .label = this enum needs a unit variant marked with `#[default]` |
compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs+2-4| ... | ... | @@ -387,11 +387,9 @@ global_asm! { |
| 387 | 387 | } |
| 388 | 388 | |
| 389 | 389 | #[cfg(all(not(jit), target_arch = "x86_64"))] |
| 390 | #[naked] | |
| 390 | #[unsafe(naked)] | |
| 391 | 391 | extern "C" fn naked_test() { |
| 392 | unsafe { | |
| 393 | naked_asm!("ret"); | |
| 394 | } | |
| 392 | naked_asm!("ret") | |
| 395 | 393 | } |
| 396 | 394 | |
| 397 | 395 | #[repr(C)] |
compiler/rustc_error_codes/src/error_codes/E0736.md+1-1| ... | ... | @@ -11,7 +11,7 @@ Erroneous code example: |
| 11 | 11 | |
| 12 | 12 | ```compile_fail,E0736 |
| 13 | 13 | #[inline] |
| 14 | #[naked] | |
| 14 | #[unsafe(naked)] | |
| 15 | 15 | fn foo() {} |
| 16 | 16 | ``` |
| 17 | 17 |
compiler/rustc_error_codes/src/error_codes/E0787.md+1-1| ... | ... | @@ -5,7 +5,7 @@ Erroneous code example: |
| 5 | 5 | ```compile_fail,E0787 |
| 6 | 6 | #![feature(naked_functions)] |
| 7 | 7 | |
| 8 | #[naked] | |
| 8 | #[unsafe(naked)] | |
| 9 | 9 | pub extern "C" fn f() -> u32 { |
| 10 | 10 | 42 |
| 11 | 11 | } |
compiler/rustc_feature/src/builtin_attrs.rs+1-1| ... | ... | @@ -517,7 +517,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ |
| 517 | 517 | |
| 518 | 518 | // Linking: |
| 519 | 519 | gated!( |
| 520 | naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, | |
| 520 | unsafe naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, | |
| 521 | 521 | naked_functions, experimental!(naked) |
| 522 | 522 | ), |
| 523 | 523 |
compiler/rustc_metadata/src/locator.rs+15-6| ... | ... | @@ -427,12 +427,21 @@ impl<'a> CrateLocator<'a> { |
| 427 | 427 | |
| 428 | 428 | let (rlibs, rmetas, dylibs) = |
| 429 | 429 | candidates.entry(hash.to_string()).or_default(); |
| 430 | let path = | |
| 431 | try_canonicalize(&spf.path).unwrap_or_else(|_| spf.path.to_path_buf()); | |
| 432 | if seen_paths.contains(&path) { | |
| 433 | continue; | |
| 434 | }; | |
| 435 | seen_paths.insert(path.clone()); | |
| 430 | { | |
| 431 | // As a perforamnce optimisation we canonicalize the path and skip | |
| 432 | // ones we've already seeen. This allows us to ignore crates | |
| 433 | // we know are exactual equal to ones we've already found. | |
| 434 | // Going to the same crate through different symlinks does not change the result. | |
| 435 | let path = try_canonicalize(&spf.path) | |
| 436 | .unwrap_or_else(|_| spf.path.to_path_buf()); | |
| 437 | if seen_paths.contains(&path) { | |
| 438 | continue; | |
| 439 | }; | |
| 440 | seen_paths.insert(path); | |
| 441 | } | |
| 442 | // Use the original path (potentially with unresolved symlinks), | |
| 443 | // filesystem code should not care, but this is nicer for diagnostics. | |
| 444 | let path = spf.path.to_path_buf(); | |
| 436 | 445 | match kind { |
| 437 | 446 | CrateFlavor::Rlib => rlibs.insert(path, search_path.kind), |
| 438 | 447 | CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind), |
compiler/rustc_mir_build/src/check_unsafety.rs+6-2| ... | ... | @@ -564,13 +564,17 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { |
| 564 | 564 | } |
| 565 | 565 | } |
| 566 | 566 | ExprKind::InlineAsm(box InlineAsmExpr { |
| 567 | asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm, | |
| 567 | asm_macro: asm_macro @ (AsmMacro::Asm | AsmMacro::NakedAsm), | |
| 568 | 568 | ref operands, |
| 569 | 569 | template: _, |
| 570 | 570 | options: _, |
| 571 | 571 | line_spans: _, |
| 572 | 572 | }) => { |
| 573 | self.requires_unsafe(expr.span, UseOfInlineAssembly); | |
| 573 | // The `naked` attribute and the `naked_asm!` block form one atomic unit of | |
| 574 | // unsafety, and `naked_asm!` does not itself need to be wrapped in an unsafe block. | |
| 575 | if let AsmMacro::Asm = asm_macro { | |
| 576 | self.requires_unsafe(expr.span, UseOfInlineAssembly); | |
| 577 | } | |
| 574 | 578 | |
| 575 | 579 | // For inline asm, do not use `walk_expr`, since we want to handle the label block |
| 576 | 580 | // specially. |
compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs+54-33| ... | ... | @@ -288,6 +288,21 @@ where |
| 288 | 288 | ) -> Vec<Candidate<I>>; |
| 289 | 289 | } |
| 290 | 290 | |
| 291 | /// Allows callers of `assemble_and_evaluate_candidates` to choose whether to limit | |
| 292 | /// candidate assembly to param-env and alias-bound candidates. | |
| 293 | /// | |
| 294 | /// On top of being a micro-optimization, as it avoids doing unnecessary work when | |
| 295 | /// a param-env trait bound candidate shadows impls for normalization, this is also | |
| 296 | /// required to prevent query cycles due to RPITIT inference. See the issue at: | |
| 297 | /// <https://github.com/rust-lang/trait-system-refactor-initiative/issues/173>. | |
| 298 | pub(super) enum AssembleCandidatesFrom { | |
| 299 | All, | |
| 300 | /// Only assemble candidates from the environment and alias bounds, ignoring | |
| 301 | /// user-written and built-in impls. We only expect `ParamEnv` and `AliasBound` | |
| 302 | /// candidates to be assembled. | |
| 303 | EnvAndBounds, | |
| 304 | } | |
| 305 | ||
| 291 | 306 | impl<D, I> EvalCtxt<'_, D> |
| 292 | 307 | where |
| 293 | 308 | D: SolverDelegate<Interner = I>, |
| ... | ... | @@ -296,6 +311,7 @@ where |
| 296 | 311 | pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>( |
| 297 | 312 | &mut self, |
| 298 | 313 | goal: Goal<I, G>, |
| 314 | assemble_from: AssembleCandidatesFrom, | |
| 299 | 315 | ) -> Vec<Candidate<I>> { |
| 300 | 316 | let Ok(normalized_self_ty) = |
| 301 | 317 | self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty()) |
| ... | ... | @@ -322,16 +338,18 @@ where |
| 322 | 338 | } |
| 323 | 339 | } |
| 324 | 340 | |
| 325 | self.assemble_impl_candidates(goal, &mut candidates); | |
| 326 | ||
| 327 | self.assemble_builtin_impl_candidates(goal, &mut candidates); | |
| 328 | ||
| 329 | 341 | self.assemble_alias_bound_candidates(goal, &mut candidates); |
| 330 | ||
| 331 | self.assemble_object_bound_candidates(goal, &mut candidates); | |
| 332 | ||
| 333 | 342 | self.assemble_param_env_candidates(goal, &mut candidates); |
| 334 | 343 | |
| 344 | match assemble_from { | |
| 345 | AssembleCandidatesFrom::All => { | |
| 346 | self.assemble_impl_candidates(goal, &mut candidates); | |
| 347 | self.assemble_builtin_impl_candidates(goal, &mut candidates); | |
| 348 | self.assemble_object_bound_candidates(goal, &mut candidates); | |
| 349 | } | |
| 350 | AssembleCandidatesFrom::EnvAndBounds => {} | |
| 351 | } | |
| 352 | ||
| 335 | 353 | candidates |
| 336 | 354 | } |
| 337 | 355 | |
| ... | ... | @@ -754,6 +772,9 @@ where |
| 754 | 772 | }) |
| 755 | 773 | } |
| 756 | 774 | |
| 775 | /// Assemble and merge candidates for goals which are related to an underlying trait | |
| 776 | /// goal. Right now, this is normalizes-to and host effect goals. | |
| 777 | /// | |
| 757 | 778 | /// We sadly can't simply take all possible candidates for normalization goals |
| 758 | 779 | /// and check whether they result in the same constraints. We want to make sure |
| 759 | 780 | /// that trying to normalize an alias doesn't result in constraints which aren't |
| ... | ... | @@ -782,47 +803,44 @@ where |
| 782 | 803 | /// |
| 783 | 804 | /// See trait-system-refactor-initiative#124 for more details. |
| 784 | 805 | #[instrument(level = "debug", skip(self, inject_normalize_to_rigid_candidate), ret)] |
| 785 | pub(super) fn merge_candidates( | |
| 806 | pub(super) fn assemble_and_merge_candidates<G: GoalKind<D>>( | |
| 786 | 807 | &mut self, |
| 787 | 808 | proven_via: Option<TraitGoalProvenVia>, |
| 788 | candidates: Vec<Candidate<I>>, | |
| 809 | goal: Goal<I, G>, | |
| 789 | 810 | inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, |
| 790 | 811 | ) -> QueryResult<I> { |
| 791 | 812 | let Some(proven_via) = proven_via else { |
| 792 | 813 | // We don't care about overflow. If proving the trait goal overflowed, then |
| 793 | 814 | // it's enough to report an overflow error for that, we don't also have to |
| 794 | 815 | // overflow during normalization. |
| 795 | return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Ambiguity)); | |
| 816 | // | |
| 817 | // We use `forced_ambiguity` here over `make_ambiguous_response_no_constraints` | |
| 818 | // because the former will also record a built-in candidate in the inspector. | |
| 819 | return self.forced_ambiguity(MaybeCause::Ambiguity).map(|cand| cand.result); | |
| 796 | 820 | }; |
| 797 | 821 | |
| 798 | 822 | match proven_via { |
| 799 | 823 | TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => { |
| 800 | let mut considered_candidates = Vec::new(); | |
| 801 | considered_candidates.extend( | |
| 802 | candidates | |
| 803 | .iter() | |
| 804 | .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) | |
| 805 | .map(|c| c.result), | |
| 806 | ); | |
| 807 | ||
| 808 | 824 | // Even when a trait bound has been proven using a where-bound, we |
| 809 | 825 | // still need to consider alias-bounds for normalization, see |
| 810 | // tests/ui/next-solver/alias-bound-shadowed-by-env.rs. | |
| 811 | // | |
| 826 | // `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`. | |
| 827 | let candidates_from_env_and_bounds: Vec<_> = self | |
| 828 | .assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds); | |
| 829 | ||
| 812 | 830 | // We still need to prefer where-bounds over alias-bounds however. |
| 813 | // See tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs. | |
| 814 | // | |
| 815 | // FIXME(const_trait_impl): should this behavior also be used by | |
| 816 | // constness checking. Doing so is *at least theoretically* breaking, | |
| 817 | // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754 | |
| 818 | if considered_candidates.is_empty() { | |
| 819 | considered_candidates.extend( | |
| 820 | candidates | |
| 821 | .iter() | |
| 822 | .filter(|c| matches!(c.source, CandidateSource::AliasBound)) | |
| 823 | .map(|c| c.result), | |
| 824 | ); | |
| 825 | } | |
| 831 | // See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`. | |
| 832 | let mut considered_candidates: Vec<_> = if candidates_from_env_and_bounds | |
| 833 | .iter() | |
| 834 | .any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) | |
| 835 | { | |
| 836 | candidates_from_env_and_bounds | |
| 837 | .into_iter() | |
| 838 | .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) | |
| 839 | .map(|c| c.result) | |
| 840 | .collect() | |
| 841 | } else { | |
| 842 | candidates_from_env_and_bounds.into_iter().map(|c| c.result).collect() | |
| 843 | }; | |
| 826 | 844 | |
| 827 | 845 | // If the trait goal has been proven by using the environment, we want to treat |
| 828 | 846 | // aliases as rigid if there are no applicable projection bounds in the environment. |
| ... | ... | @@ -839,6 +857,9 @@ where |
| 839 | 857 | } |
| 840 | 858 | } |
| 841 | 859 | TraitGoalProvenVia::Misc => { |
| 860 | let candidates = | |
| 861 | self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All); | |
| 862 | ||
| 842 | 863 | // Prefer "orphaned" param-env normalization predicates, which are used |
| 843 | 864 | // (for example, and ideally only) when proving item bounds for an impl. |
| 844 | 865 | let candidates_from_env: Vec<_> = candidates |
compiler/rustc_next_trait_solver/src/solve/effect_goals.rs+1-2| ... | ... | @@ -399,12 +399,11 @@ where |
| 399 | 399 | &mut self, |
| 400 | 400 | goal: Goal<I, ty::HostEffectPredicate<I>>, |
| 401 | 401 | ) -> QueryResult<I> { |
| 402 | let candidates = self.assemble_and_evaluate_candidates(goal); | |
| 403 | 402 | let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { |
| 404 | 403 | let trait_goal: Goal<I, ty::TraitPredicate<I>> = |
| 405 | 404 | goal.with(ecx.cx(), goal.predicate.trait_ref); |
| 406 | 405 | ecx.compute_trait_goal(trait_goal) |
| 407 | 406 | })?; |
| 408 | self.merge_candidates(proven_via, candidates, |_ecx| Err(NoSolution)) | |
| 407 | self.assemble_and_merge_candidates(proven_via, goal, |_ecx| Err(NoSolution)) | |
| 409 | 408 | } |
| 410 | 409 | } |
compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs+1-2| ... | ... | @@ -32,14 +32,13 @@ where |
| 32 | 32 | let cx = self.cx(); |
| 33 | 33 | match goal.predicate.alias.kind(cx) { |
| 34 | 34 | ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { |
| 35 | let candidates = self.assemble_and_evaluate_candidates(goal); | |
| 36 | 35 | let trait_ref = goal.predicate.alias.trait_ref(cx); |
| 37 | 36 | let (_, proven_via) = |
| 38 | 37 | self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { |
| 39 | 38 | let trait_goal: Goal<I, ty::TraitPredicate<I>> = goal.with(cx, trait_ref); |
| 40 | 39 | ecx.compute_trait_goal(trait_goal) |
| 41 | 40 | })?; |
| 42 | self.merge_candidates(proven_via, candidates, |ecx| { | |
| 41 | self.assemble_and_merge_candidates(proven_via, goal, |ecx| { | |
| 43 | 42 | ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| { |
| 44 | 43 | this.structurally_instantiate_normalizes_to_term( |
| 45 | 44 | goal, |
compiler/rustc_next_trait_solver/src/solve/trait_goals.rs+2-2| ... | ... | @@ -13,7 +13,7 @@ use tracing::{instrument, trace}; |
| 13 | 13 | |
| 14 | 14 | use crate::delegate::SolverDelegate; |
| 15 | 15 | use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; |
| 16 | use crate::solve::assembly::{self, Candidate}; | |
| 16 | use crate::solve::assembly::{self, AssembleCandidatesFrom, Candidate}; | |
| 17 | 17 | use crate::solve::inspect::ProbeKind; |
| 18 | 18 | use crate::solve::{ |
| 19 | 19 | BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, |
| ... | ... | @@ -1365,7 +1365,7 @@ where |
| 1365 | 1365 | &mut self, |
| 1366 | 1366 | goal: Goal<I, TraitPredicate<I>>, |
| 1367 | 1367 | ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> { |
| 1368 | let candidates = self.assemble_and_evaluate_candidates(goal); | |
| 1368 | let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All); | |
| 1369 | 1369 | self.merge_trait_candidates(goal, candidates) |
| 1370 | 1370 | } |
| 1371 | 1371 | } |
compiler/rustc_parse/src/validate_attr.rs-6| ... | ... | @@ -194,12 +194,6 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: |
| 194 | 194 | } |
| 195 | 195 | } |
| 196 | 196 | } else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { |
| 197 | // Allow (but don't require) `#[unsafe(naked)]` so that compiler-builtins can upgrade to it. | |
| 198 | // FIXME(#139797): remove this special case when compiler-builtins has upgraded. | |
| 199 | if attr.has_name(sym::naked) { | |
| 200 | return; | |
| 201 | } | |
| 202 | ||
| 203 | 197 | psess.dcx().emit_err(errors::InvalidAttrUnsafe { |
| 204 | 198 | span: unsafe_span, |
| 205 | 199 | name: attr_item.path.clone(), |
compiler/rustc_passes/messages.ftl+4-4| ... | ... | @@ -508,7 +508,7 @@ passes_must_use_no_effect = |
| 508 | 508 | `#[must_use]` has no effect when applied to {$article} {$target} |
| 509 | 509 | |
| 510 | 510 | passes_naked_asm_outside_naked_fn = |
| 511 | the `naked_asm!` macro can only be used in functions marked with `#[naked]` | |
| 511 | the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` | |
| 512 | 512 | |
| 513 | 513 | passes_naked_functions_asm_block = |
| 514 | 514 | naked functions must contain a single `naked_asm!` invocation |
| ... | ... | @@ -516,9 +516,9 @@ passes_naked_functions_asm_block = |
| 516 | 516 | .label_non_asm = not allowed in naked functions |
| 517 | 517 | |
| 518 | 518 | passes_naked_functions_incompatible_attribute = |
| 519 | attribute incompatible with `#[naked]` | |
| 520 | .label = the `{$attr}` attribute is incompatible with `#[naked]` | |
| 521 | .naked_attribute = function marked with `#[naked]` here | |
| 519 | attribute incompatible with `#[unsafe(naked)]` | |
| 520 | .label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]` | |
| 521 | .naked_attribute = function marked with `#[unsafe(naked)]` here | |
| 522 | 522 | |
| 523 | 523 | passes_naked_functions_must_naked_asm = |
| 524 | 524 | the `asm!` macro is not allowed in naked functions |
compiler/rustc_span/src/hygiene.rs+19| ... | ... | @@ -1232,6 +1232,25 @@ impl DesugaringKind { |
| 1232 | 1232 | DesugaringKind::PatTyRange => "pattern type", |
| 1233 | 1233 | } |
| 1234 | 1234 | } |
| 1235 | ||
| 1236 | /// For use with `rustc_unimplemented` to support conditions | |
| 1237 | /// like `from_desugaring = "QuestionMark"` | |
| 1238 | pub fn matches(&self, value: &str) -> bool { | |
| 1239 | match self { | |
| 1240 | DesugaringKind::CondTemporary => value == "CondTemporary", | |
| 1241 | DesugaringKind::Async => value == "Async", | |
| 1242 | DesugaringKind::Await => value == "Await", | |
| 1243 | DesugaringKind::QuestionMark => value == "QuestionMark", | |
| 1244 | DesugaringKind::TryBlock => value == "TryBlock", | |
| 1245 | DesugaringKind::YeetExpr => value == "YeetExpr", | |
| 1246 | DesugaringKind::OpaqueTy => value == "OpaqueTy", | |
| 1247 | DesugaringKind::ForLoop => value == "ForLoop", | |
| 1248 | DesugaringKind::WhileLoop => value == "WhileLoop", | |
| 1249 | DesugaringKind::BoundModifier => value == "BoundModifier", | |
| 1250 | DesugaringKind::Contract => value == "Contract", | |
| 1251 | DesugaringKind::PatTyRange => value == "PatTyRange", | |
| 1252 | } | |
| 1253 | } | |
| 1235 | 1254 | } |
| 1236 | 1255 | |
| 1237 | 1256 | #[derive(Default)] |
compiler/rustc_span/src/symbol.rs+1| ... | ... | @@ -372,6 +372,7 @@ symbols! { |
| 372 | 372 | SyncUnsafeCell, |
| 373 | 373 | T, |
| 374 | 374 | Target, |
| 375 | This, | |
| 375 | 376 | ToOwned, |
| 376 | 377 | ToString, |
| 377 | 378 | TokenStream, |
compiler/rustc_target/src/spec/base/linux_musl.rs+7-8| ... | ... | @@ -1,12 +1,11 @@ |
| 1 | 1 | use crate::spec::{LinkSelfContainedDefault, TargetOptions, base, crt_objects}; |
| 2 | 2 | |
| 3 | 3 | pub(crate) fn opts() -> TargetOptions { |
| 4 | let mut base = base::linux::opts(); | |
| 5 | ||
| 6 | base.env = "musl".into(); | |
| 7 | base.pre_link_objects_self_contained = crt_objects::pre_musl_self_contained(); | |
| 8 | base.post_link_objects_self_contained = crt_objects::post_musl_self_contained(); | |
| 9 | base.link_self_contained = LinkSelfContainedDefault::InferredForMusl; | |
| 10 | ||
| 11 | base | |
| 4 | TargetOptions { | |
| 5 | env: "musl".into(), | |
| 6 | pre_link_objects_self_contained: crt_objects::pre_musl_self_contained(), | |
| 7 | post_link_objects_self_contained: crt_objects::post_musl_self_contained(), | |
| 8 | link_self_contained: LinkSelfContainedDefault::InferredForMusl, | |
| 9 | ..base::linux::opts() | |
| 10 | } | |
| 12 | 11 | } |
compiler/rustc_target/src/spec/base/linux_ohos.rs+7-8| ... | ... | @@ -1,12 +1,11 @@ |
| 1 | 1 | use crate::spec::{TargetOptions, TlsModel, base}; |
| 2 | 2 | |
| 3 | 3 | pub(crate) fn opts() -> TargetOptions { |
| 4 | let mut base = base::linux::opts(); | |
| 5 | ||
| 6 | base.env = "ohos".into(); | |
| 7 | base.crt_static_default = false; | |
| 8 | base.tls_model = TlsModel::Emulated; | |
| 9 | base.has_thread_local = false; | |
| 10 | ||
| 11 | base | |
| 4 | TargetOptions { | |
| 5 | env: "ohos".into(), | |
| 6 | crt_static_default: false, | |
| 7 | tls_model: TlsModel::Emulated, | |
| 8 | has_thread_local: false, | |
| 9 | ..base::linux::opts() | |
| 10 | } | |
| 12 | 11 | } |
compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs+2| ... | ... | @@ -2,6 +2,8 @@ pub mod ambiguity; |
| 2 | 2 | pub mod call_kind; |
| 3 | 3 | mod fulfillment_errors; |
| 4 | 4 | pub mod on_unimplemented; |
| 5 | pub mod on_unimplemented_condition; | |
| 6 | pub mod on_unimplemented_format; | |
| 5 | 7 | mod overflow; |
| 6 | 8 | pub mod suggestions; |
| 7 | 9 |
compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs+253-368| ... | ... | @@ -1,44 +1,31 @@ |
| 1 | 1 | use std::iter; |
| 2 | 2 | use std::path::PathBuf; |
| 3 | 3 | |
| 4 | use rustc_ast::MetaItemInner; | |
| 5 | use rustc_data_structures::fx::FxHashMap; | |
| 4 | use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; | |
| 6 | 5 | use rustc_errors::codes::*; |
| 7 | 6 | use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; |
| 8 | 7 | use rustc_hir::def_id::{DefId, LocalDefId}; |
| 9 | 8 | use rustc_hir::{AttrArgs, Attribute}; |
| 10 | 9 | use rustc_macros::LintDiagnostic; |
| 11 | 10 | use rustc_middle::bug; |
| 12 | use rustc_middle::ty::print::PrintTraitRefExt as _; | |
| 13 | use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt}; | |
| 14 | use rustc_parse_format::{ParseMode, Parser, Piece, Position}; | |
| 11 | use rustc_middle::ty::print::PrintTraitRefExt; | |
| 12 | use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt}; | |
| 15 | 13 | use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; |
| 16 | use rustc_span::{Ident, Span, Symbol, kw, sym}; | |
| 14 | use rustc_span::{Span, Symbol, sym}; | |
| 17 | 15 | use tracing::{debug, info}; |
| 18 | 16 | use {rustc_attr_parsing as attr, rustc_hir as hir}; |
| 19 | 17 | |
| 20 | 18 | use super::{ObligationCauseCode, PredicateObligation}; |
| 21 | 19 | use crate::error_reporting::TypeErrCtxt; |
| 20 | use crate::error_reporting::traits::on_unimplemented_condition::{Condition, ConditionOptions}; | |
| 21 | use crate::error_reporting::traits::on_unimplemented_format::{ | |
| 22 | Ctx, FormatArgs, FormatString, FormatWarning, | |
| 23 | }; | |
| 22 | 24 | use crate::errors::{ |
| 23 | 25 | EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, |
| 24 | 26 | }; |
| 25 | 27 | use crate::infer::InferCtxtExt; |
| 26 | 28 | |
| 27 | /// The symbols which are always allowed in a format string | |
| 28 | static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ | |
| 29 | kw::SelfUpper, | |
| 30 | sym::ItemContext, | |
| 31 | sym::from_desugaring, | |
| 32 | sym::direct, | |
| 33 | sym::cause, | |
| 34 | sym::integral, | |
| 35 | sym::integer_, | |
| 36 | sym::float, | |
| 37 | sym::_Self, | |
| 38 | sym::crate_local, | |
| 39 | sym::Trait, | |
| 40 | ]; | |
| 41 | ||
| 42 | 29 | impl<'tcx> TypeErrCtxt<'_, 'tcx> { |
| 43 | 30 | fn impl_similar_to( |
| 44 | 31 | &self, |
| ... | ... | @@ -121,86 +108,78 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { |
| 121 | 108 | .unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args)); |
| 122 | 109 | let trait_pred = trait_pred.skip_binder(); |
| 123 | 110 | |
| 124 | let mut flags = vec![]; | |
| 111 | let mut self_types = vec![]; | |
| 112 | let mut generic_args: Vec<(Symbol, String)> = vec![]; | |
| 113 | let mut crate_local = false; | |
| 125 | 114 | // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs, |
| 126 | 115 | // but I guess we could synthesize one here. We don't see any errors that rely on |
| 127 | 116 | // that yet, though. |
| 128 | let enclosure = self.describe_enclosure(obligation.cause.body_id).map(|t| t.to_owned()); | |
| 129 | flags.push((sym::ItemContext, enclosure)); | |
| 117 | let item_context = self.describe_enclosure(obligation.cause.body_id).unwrap_or(""); | |
| 130 | 118 | |
| 131 | match obligation.cause.code() { | |
| 119 | let direct = match obligation.cause.code() { | |
| 132 | 120 | ObligationCauseCode::BuiltinDerived(..) |
| 133 | 121 | | ObligationCauseCode::ImplDerived(..) |
| 134 | | ObligationCauseCode::WellFormedDerived(..) => {} | |
| 122 | | ObligationCauseCode::WellFormedDerived(..) => false, | |
| 135 | 123 | _ => { |
| 136 | 124 | // this is a "direct", user-specified, rather than derived, |
| 137 | 125 | // obligation. |
| 138 | flags.push((sym::direct, None)); | |
| 126 | true | |
| 139 | 127 | } |
| 140 | } | |
| 141 | ||
| 142 | if let Some(k) = obligation.cause.span.desugaring_kind() { | |
| 143 | flags.push((sym::from_desugaring, None)); | |
| 144 | flags.push((sym::from_desugaring, Some(format!("{k:?}")))); | |
| 145 | } | |
| 128 | }; | |
| 146 | 129 | |
| 147 | if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { | |
| 148 | flags.push((sym::cause, Some("MainFunctionType".to_string()))); | |
| 149 | } | |
| 130 | let from_desugaring = obligation.cause.span.desugaring_kind(); | |
| 150 | 131 | |
| 151 | flags.push((sym::Trait, Some(trait_pred.trait_ref.print_trait_sugared().to_string()))); | |
| 132 | let cause = if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { | |
| 133 | Some("MainFunctionType".to_string()) | |
| 134 | } else { | |
| 135 | None | |
| 136 | }; | |
| 152 | 137 | |
| 153 | 138 | // Add all types without trimmed paths or visible paths, ensuring they end up with |
| 154 | 139 | // their "canonical" def path. |
| 155 | 140 | ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({ |
| 156 | 141 | let generics = self.tcx.generics_of(def_id); |
| 157 | 142 | let self_ty = trait_pred.self_ty(); |
| 158 | // This is also included through the generics list as `Self`, | |
| 159 | // but the parser won't allow you to use it | |
| 160 | flags.push((sym::_Self, Some(self_ty.to_string()))); | |
| 143 | self_types.push(self_ty.to_string()); | |
| 161 | 144 | if let Some(def) = self_ty.ty_adt_def() { |
| 162 | 145 | // We also want to be able to select self's original |
| 163 | 146 | // signature with no type arguments resolved |
| 164 | flags.push(( | |
| 165 | sym::_Self, | |
| 166 | Some(self.tcx.type_of(def.did()).instantiate_identity().to_string()), | |
| 167 | )); | |
| 147 | self_types.push(self.tcx.type_of(def.did()).instantiate_identity().to_string()); | |
| 168 | 148 | } |
| 169 | 149 | |
| 170 | for param in generics.own_params.iter() { | |
| 171 | let value = match param.kind { | |
| 150 | for GenericParamDef { name, kind, index, .. } in generics.own_params.iter() { | |
| 151 | let value = match kind { | |
| 172 | 152 | GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { |
| 173 | args[param.index as usize].to_string() | |
| 153 | args[*index as usize].to_string() | |
| 174 | 154 | } |
| 175 | 155 | GenericParamDefKind::Lifetime => continue, |
| 176 | 156 | }; |
| 177 | let name = param.name; | |
| 178 | flags.push((name, Some(value))); | |
| 157 | generic_args.push((*name, value)); | |
| 179 | 158 | |
| 180 | if let GenericParamDefKind::Type { .. } = param.kind { | |
| 181 | let param_ty = args[param.index as usize].expect_ty(); | |
| 159 | if let GenericParamDefKind::Type { .. } = kind { | |
| 160 | let param_ty = args[*index as usize].expect_ty(); | |
| 182 | 161 | if let Some(def) = param_ty.ty_adt_def() { |
| 183 | 162 | // We also want to be able to select the parameter's |
| 184 | 163 | // original signature with no type arguments resolved |
| 185 | flags.push(( | |
| 186 | name, | |
| 187 | Some(self.tcx.type_of(def.did()).instantiate_identity().to_string()), | |
| 164 | generic_args.push(( | |
| 165 | *name, | |
| 166 | self.tcx.type_of(def.did()).instantiate_identity().to_string(), | |
| 188 | 167 | )); |
| 189 | 168 | } |
| 190 | 169 | } |
| 191 | 170 | } |
| 192 | 171 | |
| 193 | 172 | if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) { |
| 194 | flags.push((sym::crate_local, None)); | |
| 173 | crate_local = true; | |
| 195 | 174 | } |
| 196 | 175 | |
| 197 | 176 | // Allow targeting all integers using `{integral}`, even if the exact type was resolved |
| 198 | 177 | if self_ty.is_integral() { |
| 199 | flags.push((sym::_Self, Some("{integral}".to_owned()))); | |
| 178 | self_types.push("{integral}".to_owned()); | |
| 200 | 179 | } |
| 201 | 180 | |
| 202 | 181 | if self_ty.is_array_slice() { |
| 203 | flags.push((sym::_Self, Some("&[]".to_owned()))); | |
| 182 | self_types.push("&[]".to_owned()); | |
| 204 | 183 | } |
| 205 | 184 | |
| 206 | 185 | if self_ty.is_fn() { |
| ... | ... | @@ -215,53 +194,51 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { |
| 215 | 194 | hir::Safety::Unsafe => "unsafe fn", |
| 216 | 195 | } |
| 217 | 196 | }; |
| 218 | flags.push((sym::_Self, Some(shortname.to_owned()))); | |
| 197 | self_types.push(shortname.to_owned()); | |
| 219 | 198 | } |
| 220 | 199 | |
| 221 | 200 | // Slices give us `[]`, `[{ty}]` |
| 222 | 201 | if let ty::Slice(aty) = self_ty.kind() { |
| 223 | flags.push((sym::_Self, Some("[]".to_string()))); | |
| 202 | self_types.push("[]".to_owned()); | |
| 224 | 203 | if let Some(def) = aty.ty_adt_def() { |
| 225 | 204 | // We also want to be able to select the slice's type's original |
| 226 | 205 | // signature with no type arguments resolved |
| 227 | flags.push(( | |
| 228 | sym::_Self, | |
| 229 | Some(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity())), | |
| 230 | )); | |
| 206 | self_types | |
| 207 | .push(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity())); | |
| 231 | 208 | } |
| 232 | 209 | if aty.is_integral() { |
| 233 | flags.push((sym::_Self, Some("[{integral}]".to_string()))); | |
| 210 | self_types.push("[{integral}]".to_string()); | |
| 234 | 211 | } |
| 235 | 212 | } |
| 236 | 213 | |
| 237 | 214 | // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]` |
| 238 | 215 | if let ty::Array(aty, len) = self_ty.kind() { |
| 239 | flags.push((sym::_Self, Some("[]".to_string()))); | |
| 216 | self_types.push("[]".to_string()); | |
| 240 | 217 | let len = len.try_to_target_usize(self.tcx); |
| 241 | flags.push((sym::_Self, Some(format!("[{aty}; _]")))); | |
| 218 | self_types.push(format!("[{aty}; _]")); | |
| 242 | 219 | if let Some(n) = len { |
| 243 | flags.push((sym::_Self, Some(format!("[{aty}; {n}]")))); | |
| 220 | self_types.push(format!("[{aty}; {n}]")); | |
| 244 | 221 | } |
| 245 | 222 | if let Some(def) = aty.ty_adt_def() { |
| 246 | 223 | // We also want to be able to select the array's type's original |
| 247 | 224 | // signature with no type arguments resolved |
| 248 | 225 | let def_ty = self.tcx.type_of(def.did()).instantiate_identity(); |
| 249 | flags.push((sym::_Self, Some(format!("[{def_ty}; _]")))); | |
| 226 | self_types.push(format!("[{def_ty}; _]")); | |
| 250 | 227 | if let Some(n) = len { |
| 251 | flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]")))); | |
| 228 | self_types.push(format!("[{def_ty}; {n}]")); | |
| 252 | 229 | } |
| 253 | 230 | } |
| 254 | 231 | if aty.is_integral() { |
| 255 | flags.push((sym::_Self, Some("[{integral}; _]".to_string()))); | |
| 232 | self_types.push("[{integral}; _]".to_string()); | |
| 256 | 233 | if let Some(n) = len { |
| 257 | flags.push((sym::_Self, Some(format!("[{{integral}}; {n}]")))); | |
| 234 | self_types.push(format!("[{{integral}}; {n}]")); | |
| 258 | 235 | } |
| 259 | 236 | } |
| 260 | 237 | } |
| 261 | 238 | if let ty::Dynamic(traits, _, _) = self_ty.kind() { |
| 262 | 239 | for t in traits.iter() { |
| 263 | 240 | if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() { |
| 264 | flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) | |
| 241 | self_types.push(self.tcx.def_path_str(trait_ref.def_id)); | |
| 265 | 242 | } |
| 266 | 243 | } |
| 267 | 244 | } |
| ... | ... | @@ -271,31 +248,76 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { |
| 271 | 248 | && let ty::Slice(sty) = ref_ty.kind() |
| 272 | 249 | && sty.is_integral() |
| 273 | 250 | { |
| 274 | flags.push((sym::_Self, Some("&[{integral}]".to_owned()))); | |
| 251 | self_types.push("&[{integral}]".to_owned()); | |
| 275 | 252 | } |
| 276 | 253 | })); |
| 277 | 254 | |
| 255 | let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id); | |
| 256 | let trait_sugared = trait_pred.trait_ref.print_trait_sugared(); | |
| 257 | ||
| 258 | let condition_options = ConditionOptions { | |
| 259 | self_types, | |
| 260 | from_desugaring, | |
| 261 | cause, | |
| 262 | crate_local, | |
| 263 | direct, | |
| 264 | generic_args, | |
| 265 | }; | |
| 266 | ||
| 267 | // Unlike the generic_args earlier, | |
| 268 | // this one is *not* collected under `with_no_trimmed_paths!` | |
| 269 | // for printing the type to the user | |
| 270 | // | |
| 271 | // This includes `Self`, as it is the first parameter in `own_params`. | |
| 272 | let generic_args = self | |
| 273 | .tcx | |
| 274 | .generics_of(trait_pred.trait_ref.def_id) | |
| 275 | .own_params | |
| 276 | .iter() | |
| 277 | .filter_map(|param| { | |
| 278 | let value = match param.kind { | |
| 279 | GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { | |
| 280 | if let Some(ty) = trait_pred.trait_ref.args[param.index as usize].as_type() | |
| 281 | { | |
| 282 | self.tcx.short_string(ty, long_ty_file) | |
| 283 | } else { | |
| 284 | trait_pred.trait_ref.args[param.index as usize].to_string() | |
| 285 | } | |
| 286 | } | |
| 287 | GenericParamDefKind::Lifetime => return None, | |
| 288 | }; | |
| 289 | let name = param.name; | |
| 290 | Some((name, value)) | |
| 291 | }) | |
| 292 | .collect(); | |
| 293 | ||
| 294 | let format_args = FormatArgs { this, trait_sugared, generic_args, item_context }; | |
| 295 | ||
| 278 | 296 | if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) { |
| 279 | command.evaluate(self.tcx, trait_pred.trait_ref, &flags, long_ty_file) | |
| 297 | command.evaluate(self.tcx, trait_pred.trait_ref, &condition_options, &format_args) | |
| 280 | 298 | } else { |
| 281 | 299 | OnUnimplementedNote::default() |
| 282 | 300 | } |
| 283 | 301 | } |
| 284 | 302 | } |
| 285 | 303 | |
| 304 | /// Represents a format string in a on_unimplemented attribute, | |
| 305 | /// like the "content" in `#[diagnostic::on_unimplemented(message = "content")]` | |
| 286 | 306 | #[derive(Clone, Debug)] |
| 287 | 307 | pub struct OnUnimplementedFormatString { |
| 288 | symbol: Symbol, | |
| 289 | span: Span, | |
| 290 | is_diagnostic_namespace_variant: bool, | |
| 308 | /// Symbol of the format string, i.e. `"content"` | |
| 309 | pub symbol: Symbol, | |
| 310 | ///The span of the format string, i.e. `"content"` | |
| 311 | pub span: Span, | |
| 312 | pub is_diagnostic_namespace_variant: bool, | |
| 291 | 313 | } |
| 292 | 314 | |
| 293 | 315 | #[derive(Debug)] |
| 294 | 316 | pub struct OnUnimplementedDirective { |
| 295 | pub condition: Option<MetaItemInner>, | |
| 317 | pub condition: Option<Condition>, | |
| 296 | 318 | pub subcommands: Vec<OnUnimplementedDirective>, |
| 297 | pub message: Option<OnUnimplementedFormatString>, | |
| 298 | pub label: Option<OnUnimplementedFormatString>, | |
| 319 | pub message: Option<(Span, OnUnimplementedFormatString)>, | |
| 320 | pub label: Option<(Span, OnUnimplementedFormatString)>, | |
| 299 | 321 | pub notes: Vec<OnUnimplementedFormatString>, |
| 300 | 322 | pub parent_label: Option<OnUnimplementedFormatString>, |
| 301 | 323 | pub append_const_msg: Option<AppendConstMessage>, |
| ... | ... | @@ -329,7 +351,7 @@ pub struct MalformedOnUnimplementedAttrLint { |
| 329 | 351 | } |
| 330 | 352 | |
| 331 | 353 | impl MalformedOnUnimplementedAttrLint { |
| 332 | fn new(span: Span) -> Self { | |
| 354 | pub fn new(span: Span) -> Self { | |
| 333 | 355 | Self { span } |
| 334 | 356 | } |
| 335 | 357 | } |
| ... | ... | @@ -350,7 +372,7 @@ pub struct IgnoredDiagnosticOption { |
| 350 | 372 | } |
| 351 | 373 | |
| 352 | 374 | impl IgnoredDiagnosticOption { |
| 353 | fn maybe_emit_warning<'tcx>( | |
| 375 | pub fn maybe_emit_warning<'tcx>( | |
| 354 | 376 | tcx: TyCtxt<'tcx>, |
| 355 | 377 | item_def_id: DefId, |
| 356 | 378 | new: Option<Span>, |
| ... | ... | @@ -370,29 +392,11 @@ impl IgnoredDiagnosticOption { |
| 370 | 392 | } |
| 371 | 393 | } |
| 372 | 394 | |
| 373 | #[derive(LintDiagnostic)] | |
| 374 | #[diag(trait_selection_unknown_format_parameter_for_on_unimplemented_attr)] | |
| 375 | #[help] | |
| 376 | pub struct UnknownFormatParameterForOnUnimplementedAttr { | |
| 377 | argument_name: Symbol, | |
| 378 | trait_name: Ident, | |
| 379 | } | |
| 380 | ||
| 381 | #[derive(LintDiagnostic)] | |
| 382 | #[diag(trait_selection_disallowed_positional_argument)] | |
| 383 | #[help] | |
| 384 | pub struct DisallowedPositionalArgument; | |
| 385 | ||
| 386 | #[derive(LintDiagnostic)] | |
| 387 | #[diag(trait_selection_invalid_format_specifier)] | |
| 388 | #[help] | |
| 389 | pub struct InvalidFormatSpecifier; | |
| 390 | ||
| 391 | 395 | #[derive(LintDiagnostic)] |
| 392 | 396 | #[diag(trait_selection_wrapped_parser_error)] |
| 393 | 397 | pub struct WrappedParserError { |
| 394 | description: String, | |
| 395 | label: String, | |
| 398 | pub description: String, | |
| 399 | pub label: String, | |
| 396 | 400 | } |
| 397 | 401 | |
| 398 | 402 | impl<'tcx> OnUnimplementedDirective { |
| ... | ... | @@ -407,12 +411,12 @@ impl<'tcx> OnUnimplementedDirective { |
| 407 | 411 | let mut errored = None; |
| 408 | 412 | let mut item_iter = items.iter(); |
| 409 | 413 | |
| 410 | let parse_value = |value_str, value_span| { | |
| 414 | let parse_value = |value_str, span| { | |
| 411 | 415 | OnUnimplementedFormatString::try_parse( |
| 412 | 416 | tcx, |
| 413 | 417 | item_def_id, |
| 414 | 418 | value_str, |
| 415 | value_span, | |
| 419 | span, | |
| 416 | 420 | is_diagnostic_namespace_variant, |
| 417 | 421 | ) |
| 418 | 422 | .map(Some) |
| ... | ... | @@ -434,7 +438,7 @@ impl<'tcx> OnUnimplementedDirective { |
| 434 | 438 | } |
| 435 | 439 | true |
| 436 | 440 | }); |
| 437 | Some(cond.clone()) | |
| 441 | Some(Condition { inner: cond.clone() }) | |
| 438 | 442 | }; |
| 439 | 443 | |
| 440 | 444 | let mut message = None; |
| ... | ... | @@ -444,24 +448,36 @@ impl<'tcx> OnUnimplementedDirective { |
| 444 | 448 | let mut subcommands = vec![]; |
| 445 | 449 | let mut append_const_msg = None; |
| 446 | 450 | |
| 451 | let get_value_and_span = |item: &_, key| { | |
| 452 | if let MetaItemInner::MetaItem(MetaItem { | |
| 453 | path, | |
| 454 | kind: MetaItemKind::NameValue(MetaItemLit { span, kind: LitKind::Str(s, _), .. }), | |
| 455 | .. | |
| 456 | }) = item | |
| 457 | && *path == key | |
| 458 | { | |
| 459 | Some((*s, *span)) | |
| 460 | } else { | |
| 461 | None | |
| 462 | } | |
| 463 | }; | |
| 464 | ||
| 447 | 465 | for item in item_iter { |
| 448 | if item.has_name(sym::message) && message.is_none() { | |
| 449 | if let Some(message_) = item.value_str() { | |
| 450 | message = parse_value(message_, item.span())?; | |
| 451 | continue; | |
| 452 | } | |
| 453 | } else if item.has_name(sym::label) && label.is_none() { | |
| 454 | if let Some(label_) = item.value_str() { | |
| 455 | label = parse_value(label_, item.span())?; | |
| 466 | if let Some((message_, span)) = get_value_and_span(item, sym::message) | |
| 467 | && message.is_none() | |
| 468 | { | |
| 469 | message = parse_value(message_, span)?.map(|l| (item.span(), l)); | |
| 470 | continue; | |
| 471 | } else if let Some((label_, span)) = get_value_and_span(item, sym::label) | |
| 472 | && label.is_none() | |
| 473 | { | |
| 474 | label = parse_value(label_, span)?.map(|l| (item.span(), l)); | |
| 475 | continue; | |
| 476 | } else if let Some((note_, span)) = get_value_and_span(item, sym::note) { | |
| 477 | if let Some(note) = parse_value(note_, span)? { | |
| 478 | notes.push(note); | |
| 456 | 479 | continue; |
| 457 | 480 | } |
| 458 | } else if item.has_name(sym::note) { | |
| 459 | if let Some(note_) = item.value_str() { | |
| 460 | if let Some(note) = parse_value(note_, item.span())? { | |
| 461 | notes.push(note); | |
| 462 | continue; | |
| 463 | } | |
| 464 | } | |
| 465 | 481 | } else if item.has_name(sym::parent_label) |
| 466 | 482 | && parent_label.is_none() |
| 467 | 483 | && !is_diagnostic_namespace_variant |
| ... | ... | @@ -539,6 +555,13 @@ impl<'tcx> OnUnimplementedDirective { |
| 539 | 555 | } |
| 540 | 556 | |
| 541 | 557 | pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> { |
| 558 | if !tcx.is_trait(item_def_id) { | |
| 559 | // It could be a trait_alias (`trait MyTrait = SomeOtherTrait`) | |
| 560 | // or an implementation (`impl MyTrait for Foo {}`) | |
| 561 | // | |
| 562 | // We don't support those. | |
| 563 | return Ok(None); | |
| 564 | } | |
| 542 | 565 | if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) { |
| 543 | 566 | return Self::parse_attribute(attr, false, tcx, item_def_id); |
| 544 | 567 | } else { |
| ... | ... | @@ -554,15 +577,15 @@ impl<'tcx> OnUnimplementedDirective { |
| 554 | 577 | IgnoredDiagnosticOption::maybe_emit_warning( |
| 555 | 578 | tcx, |
| 556 | 579 | item_def_id, |
| 557 | directive.message.as_ref().map(|f| f.span), | |
| 558 | aggr.message.as_ref().map(|f| f.span), | |
| 580 | directive.message.as_ref().map(|f| f.0), | |
| 581 | aggr.message.as_ref().map(|f| f.0), | |
| 559 | 582 | "message", |
| 560 | 583 | ); |
| 561 | 584 | IgnoredDiagnosticOption::maybe_emit_warning( |
| 562 | 585 | tcx, |
| 563 | 586 | item_def_id, |
| 564 | directive.label.as_ref().map(|f| f.span), | |
| 565 | aggr.label.as_ref().map(|f| f.span), | |
| 587 | directive.label.as_ref().map(|f| f.0), | |
| 588 | aggr.label.as_ref().map(|f| f.0), | |
| 566 | 589 | "label", |
| 567 | 590 | ); |
| 568 | 591 | IgnoredDiagnosticOption::maybe_emit_warning( |
| ... | ... | @@ -636,13 +659,16 @@ impl<'tcx> OnUnimplementedDirective { |
| 636 | 659 | condition: None, |
| 637 | 660 | message: None, |
| 638 | 661 | subcommands: vec![], |
| 639 | label: Some(OnUnimplementedFormatString::try_parse( | |
| 640 | tcx, | |
| 641 | item_def_id, | |
| 642 | value, | |
| 662 | label: Some(( | |
| 643 | 663 | attr.span(), |
| 644 | is_diagnostic_namespace_variant, | |
| 645 | )?), | |
| 664 | OnUnimplementedFormatString::try_parse( | |
| 665 | tcx, | |
| 666 | item_def_id, | |
| 667 | value, | |
| 668 | attr.value_span().unwrap_or(attr.span()), | |
| 669 | is_diagnostic_namespace_variant, | |
| 670 | )?, | |
| 671 | )), | |
| 646 | 672 | notes: Vec::new(), |
| 647 | 673 | parent_label: None, |
| 648 | 674 | append_const_msg: None, |
| ... | ... | @@ -702,43 +728,23 @@ impl<'tcx> OnUnimplementedDirective { |
| 702 | 728 | &self, |
| 703 | 729 | tcx: TyCtxt<'tcx>, |
| 704 | 730 | trait_ref: ty::TraitRef<'tcx>, |
| 705 | options: &[(Symbol, Option<String>)], | |
| 706 | long_ty_file: &mut Option<PathBuf>, | |
| 731 | condition_options: &ConditionOptions, | |
| 732 | args: &FormatArgs<'tcx>, | |
| 707 | 733 | ) -> OnUnimplementedNote { |
| 708 | 734 | let mut message = None; |
| 709 | 735 | let mut label = None; |
| 710 | 736 | let mut notes = Vec::new(); |
| 711 | 737 | let mut parent_label = None; |
| 712 | 738 | let mut append_const_msg = None; |
| 713 | info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); | |
| 714 | ||
| 715 | let options_map: FxHashMap<Symbol, String> = | |
| 716 | options.iter().filter_map(|(k, v)| v.clone().map(|v| (*k, v))).collect(); | |
| 739 | info!( | |
| 740 | "evaluate({:?}, trait_ref={:?}, options={:?}, args ={:?})", | |
| 741 | self, trait_ref, condition_options, args | |
| 742 | ); | |
| 717 | 743 | |
| 718 | 744 | for command in self.subcommands.iter().chain(Some(self)).rev() { |
| 719 | 745 | debug!(?command); |
| 720 | 746 | if let Some(ref condition) = command.condition |
| 721 | && !attr::eval_condition(condition, &tcx.sess, Some(tcx.features()), &mut |cfg| { | |
| 722 | let value = cfg.value.map(|v| { | |
| 723 | // `with_no_visible_paths` is also used when generating the options, | |
| 724 | // so we need to match it here. | |
| 725 | ty::print::with_no_visible_paths!( | |
| 726 | OnUnimplementedFormatString { | |
| 727 | symbol: v, | |
| 728 | span: cfg.span, | |
| 729 | is_diagnostic_namespace_variant: false | |
| 730 | } | |
| 731 | .format( | |
| 732 | tcx, | |
| 733 | trait_ref, | |
| 734 | &options_map, | |
| 735 | long_ty_file | |
| 736 | ) | |
| 737 | ) | |
| 738 | }); | |
| 739 | ||
| 740 | options.contains(&(cfg.name, value)) | |
| 741 | }) | |
| 747 | && !condition.matches_predicate(tcx, condition_options) | |
| 742 | 748 | { |
| 743 | 749 | debug!("evaluate: skipping {:?} due to condition", command); |
| 744 | 750 | continue; |
| ... | ... | @@ -762,14 +768,10 @@ impl<'tcx> OnUnimplementedDirective { |
| 762 | 768 | } |
| 763 | 769 | |
| 764 | 770 | OnUnimplementedNote { |
| 765 | label: label.map(|l| l.format(tcx, trait_ref, &options_map, long_ty_file)), | |
| 766 | message: message.map(|m| m.format(tcx, trait_ref, &options_map, long_ty_file)), | |
| 767 | notes: notes | |
| 768 | .into_iter() | |
| 769 | .map(|n| n.format(tcx, trait_ref, &options_map, long_ty_file)) | |
| 770 | .collect(), | |
| 771 | parent_label: parent_label | |
| 772 | .map(|e_s| e_s.format(tcx, trait_ref, &options_map, long_ty_file)), | |
| 771 | label: label.map(|l| l.1.format(tcx, trait_ref, args)), | |
| 772 | message: message.map(|m| m.1.format(tcx, trait_ref, args)), | |
| 773 | notes: notes.into_iter().map(|n| n.format(tcx, trait_ref, args)).collect(), | |
| 774 | parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, args)), | |
| 773 | 775 | append_const_msg, |
| 774 | 776 | } |
| 775 | 777 | } |
| ... | ... | @@ -780,142 +782,95 @@ impl<'tcx> OnUnimplementedFormatString { |
| 780 | 782 | tcx: TyCtxt<'tcx>, |
| 781 | 783 | item_def_id: DefId, |
| 782 | 784 | from: Symbol, |
| 783 | value_span: Span, | |
| 785 | span: Span, | |
| 784 | 786 | is_diagnostic_namespace_variant: bool, |
| 785 | 787 | ) -> Result<Self, ErrorGuaranteed> { |
| 786 | let result = OnUnimplementedFormatString { | |
| 787 | symbol: from, | |
| 788 | span: value_span, | |
| 789 | is_diagnostic_namespace_variant, | |
| 790 | }; | |
| 788 | let result = | |
| 789 | OnUnimplementedFormatString { symbol: from, span, is_diagnostic_namespace_variant }; | |
| 791 | 790 | result.verify(tcx, item_def_id)?; |
| 792 | 791 | Ok(result) |
| 793 | 792 | } |
| 794 | 793 | |
| 795 | fn verify(&self, tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<(), ErrorGuaranteed> { | |
| 796 | let trait_def_id = if tcx.is_trait(item_def_id) { | |
| 797 | item_def_id | |
| 794 | fn verify(&self, tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> Result<(), ErrorGuaranteed> { | |
| 795 | if !tcx.is_trait(trait_def_id) { | |
| 796 | return Ok(()); | |
| 797 | }; | |
| 798 | ||
| 799 | let ctx = if self.is_diagnostic_namespace_variant { | |
| 800 | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id } | |
| 798 | 801 | } else { |
| 799 | tcx.trait_id_of_impl(item_def_id) | |
| 800 | .expect("expected `on_unimplemented` to correspond to a trait") | |
| 802 | Ctx::RustcOnUnimplemented { tcx, trait_def_id } | |
| 801 | 803 | }; |
| 802 | let trait_name = tcx.item_ident(trait_def_id); | |
| 803 | let generics = tcx.generics_of(item_def_id); | |
| 804 | let s = self.symbol.as_str(); | |
| 805 | let mut parser = Parser::new(s, None, None, false, ParseMode::Format); | |
| 804 | ||
| 806 | 805 | let mut result = Ok(()); |
| 807 | for token in &mut parser { | |
| 808 | match token { | |
| 809 | Piece::Lit(_) => (), // Normal string, no need to check it | |
| 810 | Piece::NextArgument(a) => { | |
| 811 | let format_spec = a.format; | |
| 812 | if self.is_diagnostic_namespace_variant | |
| 813 | && (format_spec.ty_span.is_some() | |
| 814 | || format_spec.width_span.is_some() | |
| 815 | || format_spec.precision_span.is_some() | |
| 816 | || format_spec.fill_span.is_some()) | |
| 817 | { | |
| 818 | if let Some(item_def_id) = item_def_id.as_local() { | |
| 819 | tcx.emit_node_span_lint( | |
| 820 | UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, | |
| 821 | tcx.local_def_id_to_hir_id(item_def_id), | |
| 822 | self.span, | |
| 823 | InvalidFormatSpecifier, | |
| 824 | ); | |
| 825 | } | |
| 806 | ||
| 807 | match FormatString::parse(self.symbol, self.span, &ctx) { | |
| 808 | // Warnings about format specifiers, deprecated parameters, wrong parameters etc. | |
| 809 | // In other words we'd like to let the author know, but we can still try to format the string later | |
| 810 | Ok(FormatString { warnings, .. }) => { | |
| 811 | if self.is_diagnostic_namespace_variant { | |
| 812 | for w in warnings { | |
| 813 | w.emit_warning(tcx, trait_def_id) | |
| 826 | 814 | } |
| 827 | match a.position { | |
| 828 | Position::ArgumentNamed(s) => { | |
| 829 | match Symbol::intern(s) { | |
| 830 | // `{ThisTraitsName}` is allowed | |
| 831 | s if s == trait_name.name | |
| 832 | && !self.is_diagnostic_namespace_variant => | |
| 833 | { | |
| 834 | () | |
| 835 | } | |
| 836 | s if ALLOWED_FORMAT_SYMBOLS.contains(&s) | |
| 837 | && !self.is_diagnostic_namespace_variant => | |
| 838 | { | |
| 839 | () | |
| 840 | } | |
| 841 | // So is `{A}` if A is a type parameter | |
| 842 | s if generics.own_params.iter().any(|param| param.name == s) => (), | |
| 843 | s => { | |
| 844 | if self.is_diagnostic_namespace_variant { | |
| 845 | if let Some(item_def_id) = item_def_id.as_local() { | |
| 846 | tcx.emit_node_span_lint( | |
| 847 | UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, | |
| 848 | tcx.local_def_id_to_hir_id(item_def_id), | |
| 849 | self.span, | |
| 850 | UnknownFormatParameterForOnUnimplementedAttr { | |
| 851 | argument_name: s, | |
| 852 | trait_name, | |
| 853 | }, | |
| 854 | ); | |
| 855 | } | |
| 856 | } else { | |
| 857 | result = Err(struct_span_code_err!( | |
| 858 | tcx.dcx(), | |
| 859 | self.span, | |
| 860 | E0230, | |
| 861 | "there is no parameter `{}` on {}", | |
| 862 | s, | |
| 863 | if trait_def_id == item_def_id { | |
| 864 | format!("trait `{trait_name}`") | |
| 865 | } else { | |
| 866 | "impl".to_string() | |
| 867 | } | |
| 868 | ) | |
| 869 | .emit()); | |
| 870 | } | |
| 871 | } | |
| 815 | } else { | |
| 816 | for w in warnings { | |
| 817 | match w { | |
| 818 | FormatWarning::UnknownParam { argument_name, span } => { | |
| 819 | let reported = struct_span_code_err!( | |
| 820 | tcx.dcx(), | |
| 821 | span, | |
| 822 | E0230, | |
| 823 | "cannot find parameter {} on this trait", | |
| 824 | argument_name, | |
| 825 | ) | |
| 826 | .emit(); | |
| 827 | result = Err(reported); | |
| 872 | 828 | } |
| 873 | } | |
| 874 | // `{:1}` and `{}` are not to be used | |
| 875 | Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => { | |
| 876 | if self.is_diagnostic_namespace_variant { | |
| 877 | if let Some(item_def_id) = item_def_id.as_local() { | |
| 878 | tcx.emit_node_span_lint( | |
| 879 | UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, | |
| 880 | tcx.local_def_id_to_hir_id(item_def_id), | |
| 881 | self.span, | |
| 882 | DisallowedPositionalArgument, | |
| 883 | ); | |
| 884 | } | |
| 885 | } else { | |
| 829 | FormatWarning::PositionalArgument { span, .. } => { | |
| 886 | 830 | let reported = struct_span_code_err!( |
| 887 | 831 | tcx.dcx(), |
| 888 | self.span, | |
| 832 | span, | |
| 889 | 833 | E0231, |
| 890 | "only named generic parameters are allowed" | |
| 834 | "positional format arguments are not allowed here" | |
| 891 | 835 | ) |
| 892 | 836 | .emit(); |
| 893 | 837 | result = Err(reported); |
| 894 | 838 | } |
| 839 | FormatWarning::InvalidSpecifier { .. } | |
| 840 | | FormatWarning::FutureIncompat { .. } => {} | |
| 895 | 841 | } |
| 896 | 842 | } |
| 897 | 843 | } |
| 898 | 844 | } |
| 899 | } | |
| 900 | // we cannot return errors from processing the format string as hard error here | |
| 901 | // as the diagnostic namespace guarantees that malformed input cannot cause an error | |
| 902 | // | |
| 903 | // if we encounter any error while processing we nevertheless want to show it as warning | |
| 904 | // so that users are aware that something is not correct | |
| 905 | for e in parser.errors { | |
| 906 | if self.is_diagnostic_namespace_variant { | |
| 907 | if let Some(item_def_id) = item_def_id.as_local() { | |
| 908 | tcx.emit_node_span_lint( | |
| 909 | UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, | |
| 910 | tcx.local_def_id_to_hir_id(item_def_id), | |
| 911 | self.span, | |
| 912 | WrappedParserError { description: e.description, label: e.label }, | |
| 913 | ); | |
| 845 | // Errors from the underlying `rustc_parse_format::Parser` | |
| 846 | Err(errors) => { | |
| 847 | // we cannot return errors from processing the format string as hard error here | |
| 848 | // as the diagnostic namespace guarantees that malformed input cannot cause an error | |
| 849 | // | |
| 850 | // if we encounter any error while processing we nevertheless want to show it as warning | |
| 851 | // so that users are aware that something is not correct | |
| 852 | for e in errors { | |
| 853 | if self.is_diagnostic_namespace_variant { | |
| 854 | if let Some(trait_def_id) = trait_def_id.as_local() { | |
| 855 | tcx.emit_node_span_lint( | |
| 856 | UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, | |
| 857 | tcx.local_def_id_to_hir_id(trait_def_id), | |
| 858 | self.span, | |
| 859 | WrappedParserError { description: e.description, label: e.label }, | |
| 860 | ); | |
| 861 | } | |
| 862 | } else { | |
| 863 | let reported = struct_span_code_err!( | |
| 864 | tcx.dcx(), | |
| 865 | self.span, | |
| 866 | E0231, | |
| 867 | "{}", | |
| 868 | e.description, | |
| 869 | ) | |
| 870 | .emit(); | |
| 871 | result = Err(reported); | |
| 872 | } | |
| 914 | 873 | } |
| 915 | } else { | |
| 916 | let reported = | |
| 917 | struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,).emit(); | |
| 918 | result = Err(reported); | |
| 919 | 874 | } |
| 920 | 875 | } |
| 921 | 876 | |
| ... | ... | @@ -926,98 +881,28 @@ impl<'tcx> OnUnimplementedFormatString { |
| 926 | 881 | &self, |
| 927 | 882 | tcx: TyCtxt<'tcx>, |
| 928 | 883 | trait_ref: ty::TraitRef<'tcx>, |
| 929 | options: &FxHashMap<Symbol, String>, | |
| 930 | long_ty_file: &mut Option<PathBuf>, | |
| 884 | args: &FormatArgs<'tcx>, | |
| 931 | 885 | ) -> String { |
| 932 | let name = tcx.item_name(trait_ref.def_id); | |
| 933 | let trait_str = tcx.def_path_str(trait_ref.def_id); | |
| 934 | let generics = tcx.generics_of(trait_ref.def_id); | |
| 935 | let generic_map = generics | |
| 936 | .own_params | |
| 937 | .iter() | |
| 938 | .filter_map(|param| { | |
| 939 | let value = match param.kind { | |
| 940 | GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { | |
| 941 | if let Some(ty) = trait_ref.args[param.index as usize].as_type() { | |
| 942 | tcx.short_string(ty, long_ty_file) | |
| 943 | } else { | |
| 944 | trait_ref.args[param.index as usize].to_string() | |
| 945 | } | |
| 946 | } | |
| 947 | GenericParamDefKind::Lifetime => return None, | |
| 948 | }; | |
| 949 | let name = param.name; | |
| 950 | Some((name, value)) | |
| 951 | }) | |
| 952 | .collect::<FxHashMap<Symbol, String>>(); | |
| 953 | let empty_string = String::new(); | |
| 954 | ||
| 955 | let s = self.symbol.as_str(); | |
| 956 | let mut parser = Parser::new(s, None, None, false, ParseMode::Format); | |
| 957 | let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string); | |
| 958 | let constructed_message = (&mut parser) | |
| 959 | .map(|p| match p { | |
| 960 | Piece::Lit(s) => s.to_owned(), | |
| 961 | Piece::NextArgument(a) => match a.position { | |
| 962 | Position::ArgumentNamed(arg) => { | |
| 963 | let s = Symbol::intern(arg); | |
| 964 | match generic_map.get(&s) { | |
| 965 | Some(val) => val.to_string(), | |
| 966 | None if self.is_diagnostic_namespace_variant => { | |
| 967 | format!("{{{arg}}}") | |
| 968 | } | |
| 969 | None if s == name => trait_str.clone(), | |
| 970 | None => { | |
| 971 | if let Some(val) = options.get(&s) { | |
| 972 | val.clone() | |
| 973 | } else if s == sym::from_desugaring { | |
| 974 | // don't break messages using these two arguments incorrectly | |
| 975 | String::new() | |
| 976 | } else if s == sym::ItemContext | |
| 977 | && !self.is_diagnostic_namespace_variant | |
| 978 | { | |
| 979 | item_context.clone() | |
| 980 | } else if s == sym::integral { | |
| 981 | String::from("{integral}") | |
| 982 | } else if s == sym::integer_ { | |
| 983 | String::from("{integer}") | |
| 984 | } else if s == sym::float { | |
| 985 | String::from("{float}") | |
| 986 | } else { | |
| 987 | bug!( | |
| 988 | "broken on_unimplemented {:?} for {:?}: \ | |
| 989 | no argument matching {:?}", | |
| 990 | self.symbol, | |
| 991 | trait_ref, | |
| 992 | s | |
| 993 | ) | |
| 994 | } | |
| 995 | } | |
| 996 | } | |
| 997 | } | |
| 998 | Position::ArgumentImplicitlyIs(_) if self.is_diagnostic_namespace_variant => { | |
| 999 | String::from("{}") | |
| 1000 | } | |
| 1001 | Position::ArgumentIs(idx) if self.is_diagnostic_namespace_variant => { | |
| 1002 | format!("{{{idx}}}") | |
| 1003 | } | |
| 1004 | _ => bug!("broken on_unimplemented {:?} - bad format arg", self.symbol), | |
| 1005 | }, | |
| 1006 | }) | |
| 1007 | .collect(); | |
| 1008 | // we cannot return errors from processing the format string as hard error here | |
| 1009 | // as the diagnostic namespace guarantees that malformed input cannot cause an error | |
| 1010 | // | |
| 1011 | // if we encounter any error while processing the format string | |
| 1012 | // we don't want to show the potentially half assembled formatted string, | |
| 1013 | // therefore we fall back to just showing the input string in this case | |
| 1014 | // | |
| 1015 | // The actual parser errors are emitted earlier | |
| 1016 | // as lint warnings in OnUnimplementedFormatString::verify | |
| 1017 | if self.is_diagnostic_namespace_variant && !parser.errors.is_empty() { | |
| 1018 | String::from(s) | |
| 886 | let trait_def_id = trait_ref.def_id; | |
| 887 | let ctx = if self.is_diagnostic_namespace_variant { | |
| 888 | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id } | |
| 889 | } else { | |
| 890 | Ctx::RustcOnUnimplemented { tcx, trait_def_id } | |
| 891 | }; | |
| 892 | ||
| 893 | if let Ok(s) = FormatString::parse(self.symbol, self.span, &ctx) { | |
| 894 | s.format(args) | |
| 1019 | 895 | } else { |
| 1020 | constructed_message | |
| 896 | // we cannot return errors from processing the format string as hard error here | |
| 897 | // as the diagnostic namespace guarantees that malformed input cannot cause an error | |
| 898 | // | |
| 899 | // if we encounter any error while processing the format string | |
| 900 | // we don't want to show the potentially half assembled formatted string, | |
| 901 | // therefore we fall back to just showing the input string in this case | |
| 902 | // | |
| 903 | // The actual parser errors are emitted earlier | |
| 904 | // as lint warnings in OnUnimplementedFormatString::verify | |
| 905 | self.symbol.as_str().into() | |
| 1021 | 906 | } |
| 1022 | 907 | } |
| 1023 | 908 | } |
compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs created+120| ... | ... | @@ -0,0 +1,120 @@ |
| 1 | use rustc_ast::MetaItemInner; | |
| 2 | use rustc_attr_parsing as attr; | |
| 3 | use rustc_middle::ty::{self, TyCtxt}; | |
| 4 | use rustc_parse_format::{ParseMode, Parser, Piece, Position}; | |
| 5 | use rustc_span::{DesugaringKind, Span, Symbol, kw, sym}; | |
| 6 | ||
| 7 | /// A predicate in an attribute using on, all, any, | |
| 8 | /// similar to a cfg predicate. | |
| 9 | #[derive(Debug)] | |
| 10 | pub struct Condition { | |
| 11 | pub inner: MetaItemInner, | |
| 12 | } | |
| 13 | ||
| 14 | impl Condition { | |
| 15 | pub fn span(&self) -> Span { | |
| 16 | self.inner.span() | |
| 17 | } | |
| 18 | ||
| 19 | pub fn matches_predicate<'tcx>(&self, tcx: TyCtxt<'tcx>, options: &ConditionOptions) -> bool { | |
| 20 | attr::eval_condition(&self.inner, tcx.sess, Some(tcx.features()), &mut |cfg| { | |
| 21 | let value = cfg.value.map(|v| { | |
| 22 | // `with_no_visible_paths` is also used when generating the options, | |
| 23 | // so we need to match it here. | |
| 24 | ty::print::with_no_visible_paths!({ | |
| 25 | Parser::new(v.as_str(), None, None, false, ParseMode::Format) | |
| 26 | .map(|p| match p { | |
| 27 | Piece::Lit(s) => s.to_owned(), | |
| 28 | Piece::NextArgument(a) => match a.position { | |
| 29 | Position::ArgumentNamed(arg) => { | |
| 30 | let s = Symbol::intern(arg); | |
| 31 | match options.generic_args.iter().find(|(k, _)| *k == s) { | |
| 32 | Some((_, val)) => val.to_string(), | |
| 33 | None => format!("{{{arg}}}"), | |
| 34 | } | |
| 35 | } | |
| 36 | Position::ArgumentImplicitlyIs(_) => String::from("{}"), | |
| 37 | Position::ArgumentIs(idx) => format!("{{{idx}}}"), | |
| 38 | }, | |
| 39 | }) | |
| 40 | .collect() | |
| 41 | }) | |
| 42 | }); | |
| 43 | ||
| 44 | options.contains(cfg.name, &value) | |
| 45 | }) | |
| 46 | } | |
| 47 | } | |
| 48 | ||
| 49 | /// Used with `Condition::matches_predicate` to test whether the condition applies | |
| 50 | /// | |
| 51 | /// For example, given a | |
| 52 | /// ```rust,ignore (just an example) | |
| 53 | /// #[rustc_on_unimplemented( | |
| 54 | /// on(all(from_desugaring = "QuestionMark"), | |
| 55 | /// message = "the `?` operator can only be used in {ItemContext} \ | |
| 56 | /// that returns `Result` or `Option` \ | |
| 57 | /// (or another type that implements `{FromResidual}`)", | |
| 58 | /// label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", | |
| 59 | /// parent_label = "this function should return `Result` or `Option` to accept `?`" | |
| 60 | /// ), | |
| 61 | /// )] | |
| 62 | /// pub trait FromResidual<R = <Self as Try>::Residual> { | |
| 63 | /// ... | |
| 64 | /// } | |
| 65 | /// | |
| 66 | /// async fn an_async_function() -> u32 { | |
| 67 | /// let x: Option<u32> = None; | |
| 68 | /// x?; //~ ERROR the `?` operator | |
| 69 | /// 22 | |
| 70 | /// } | |
| 71 | /// ``` | |
| 72 | /// it will look like this: | |
| 73 | /// | |
| 74 | /// ```rust,ignore (just an example) | |
| 75 | /// ConditionOptions { | |
| 76 | /// self_types: ["u32", "{integral}"], | |
| 77 | /// from_desugaring: Some("QuestionMark"), | |
| 78 | /// cause: None, | |
| 79 | /// crate_local: false, | |
| 80 | /// direct: true, | |
| 81 | /// generic_args: [("Self","u32"), | |
| 82 | /// ("R", "core::option::Option<core::convert::Infallible>"), | |
| 83 | /// ("R", "core::option::Option<T>" ), | |
| 84 | /// ], | |
| 85 | /// } | |
| 86 | /// ``` | |
| 87 | #[derive(Debug)] | |
| 88 | pub struct ConditionOptions { | |
| 89 | /// All the self types that may apply. | |
| 90 | /// for example | |
| 91 | pub self_types: Vec<String>, | |
| 92 | // The kind of compiler desugaring. | |
| 93 | pub from_desugaring: Option<DesugaringKind>, | |
| 94 | /// Match on a variant of [rustc_infer::traits::ObligationCauseCode] | |
| 95 | pub cause: Option<String>, | |
| 96 | pub crate_local: bool, | |
| 97 | /// Is the obligation "directly" user-specified, rather than derived? | |
| 98 | pub direct: bool, | |
| 99 | // A list of the generic arguments and their reified types | |
| 100 | pub generic_args: Vec<(Symbol, String)>, | |
| 101 | } | |
| 102 | ||
| 103 | impl ConditionOptions { | |
| 104 | pub fn contains(&self, key: Symbol, value: &Option<String>) -> bool { | |
| 105 | match (key, value) { | |
| 106 | (sym::_Self | kw::SelfUpper, Some(value)) => self.self_types.contains(&value), | |
| 107 | // from_desugaring as a flag | |
| 108 | (sym::from_desugaring, None) => self.from_desugaring.is_some(), | |
| 109 | // from_desugaring as key == value | |
| 110 | (sym::from_desugaring, Some(v)) if let Some(ds) = self.from_desugaring => ds.matches(v), | |
| 111 | (sym::cause, Some(value)) => self.cause.as_deref() == Some(value), | |
| 112 | (sym::crate_local, None) => self.crate_local, | |
| 113 | (sym::direct, None) => self.direct, | |
| 114 | (other, Some(value)) => { | |
| 115 | self.generic_args.iter().any(|(k, v)| *k == other && v == value) | |
| 116 | } | |
| 117 | _ => false, | |
| 118 | } | |
| 119 | } | |
| 120 | } |
compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs created+414| ... | ... | @@ -0,0 +1,414 @@ |
| 1 | use std::fmt; | |
| 2 | ||
| 3 | use errors::*; | |
| 4 | use rustc_middle::ty::TyCtxt; | |
| 5 | use rustc_middle::ty::print::TraitRefPrintSugared; | |
| 6 | use rustc_parse_format::{ | |
| 7 | Alignment, Argument, Count, FormatSpec, InnerSpan, ParseError, ParseMode, Parser, | |
| 8 | Piece as RpfPiece, Position, | |
| 9 | }; | |
| 10 | use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; | |
| 11 | use rustc_span::def_id::DefId; | |
| 12 | use rustc_span::{BytePos, Pos, Span, Symbol, kw, sym}; | |
| 13 | ||
| 14 | /// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces", | |
| 15 | /// either as string pieces or dynamic arguments. | |
| 16 | #[derive(Debug)] | |
| 17 | pub struct FormatString { | |
| 18 | #[allow(dead_code, reason = "Debug impl")] | |
| 19 | input: Symbol, | |
| 20 | span: Span, | |
| 21 | pieces: Vec<Piece>, | |
| 22 | /// The formatting string was parsed succesfully but with warnings | |
| 23 | pub warnings: Vec<FormatWarning>, | |
| 24 | } | |
| 25 | ||
| 26 | #[derive(Debug)] | |
| 27 | enum Piece { | |
| 28 | Lit(String), | |
| 29 | Arg(FormatArg), | |
| 30 | } | |
| 31 | ||
| 32 | #[derive(Debug)] | |
| 33 | enum FormatArg { | |
| 34 | // A generic parameter, like `{T}` if we're on the `From<T>` trait. | |
| 35 | GenericParam { | |
| 36 | generic_param: Symbol, | |
| 37 | }, | |
| 38 | // `{Self}` | |
| 39 | SelfUpper, | |
| 40 | /// `{This}` or `{TraitName}` | |
| 41 | This, | |
| 42 | /// The sugared form of the trait | |
| 43 | Trait, | |
| 44 | /// what we're in, like a function, method, closure etc. | |
| 45 | ItemContext, | |
| 46 | /// What the user typed, if it doesn't match anything we can use. | |
| 47 | AsIs(String), | |
| 48 | } | |
| 49 | ||
| 50 | pub enum Ctx<'tcx> { | |
| 51 | // `#[rustc_on_unimplemented]` | |
| 52 | RustcOnUnimplemented { tcx: TyCtxt<'tcx>, trait_def_id: DefId }, | |
| 53 | // `#[diagnostic::...]` | |
| 54 | DiagnosticOnUnimplemented { tcx: TyCtxt<'tcx>, trait_def_id: DefId }, | |
| 55 | } | |
| 56 | ||
| 57 | #[derive(Debug)] | |
| 58 | pub enum FormatWarning { | |
| 59 | UnknownParam { argument_name: Symbol, span: Span }, | |
| 60 | PositionalArgument { span: Span, help: String }, | |
| 61 | InvalidSpecifier { name: String, span: Span }, | |
| 62 | FutureIncompat { span: Span, help: String }, | |
| 63 | } | |
| 64 | ||
| 65 | impl FormatWarning { | |
| 66 | pub fn emit_warning<'tcx>(&self, tcx: TyCtxt<'tcx>, item_def_id: DefId) { | |
| 67 | match *self { | |
| 68 | FormatWarning::UnknownParam { argument_name, span } => { | |
| 69 | let this = tcx.item_ident(item_def_id); | |
| 70 | if let Some(item_def_id) = item_def_id.as_local() { | |
| 71 | tcx.emit_node_span_lint( | |
| 72 | UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, | |
| 73 | tcx.local_def_id_to_hir_id(item_def_id), | |
| 74 | span, | |
| 75 | UnknownFormatParameterForOnUnimplementedAttr { | |
| 76 | argument_name, | |
| 77 | trait_name: this, | |
| 78 | }, | |
| 79 | ); | |
| 80 | } | |
| 81 | } | |
| 82 | FormatWarning::PositionalArgument { span, .. } => { | |
| 83 | if let Some(item_def_id) = item_def_id.as_local() { | |
| 84 | tcx.emit_node_span_lint( | |
| 85 | UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, | |
| 86 | tcx.local_def_id_to_hir_id(item_def_id), | |
| 87 | span, | |
| 88 | DisallowedPositionalArgument, | |
| 89 | ); | |
| 90 | } | |
| 91 | } | |
| 92 | FormatWarning::InvalidSpecifier { span, .. } => { | |
| 93 | if let Some(item_def_id) = item_def_id.as_local() { | |
| 94 | tcx.emit_node_span_lint( | |
| 95 | UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, | |
| 96 | tcx.local_def_id_to_hir_id(item_def_id), | |
| 97 | span, | |
| 98 | InvalidFormatSpecifier, | |
| 99 | ); | |
| 100 | } | |
| 101 | } | |
| 102 | FormatWarning::FutureIncompat { .. } => { | |
| 103 | // We've never deprecated anything in diagnostic namespace format strings | |
| 104 | // but if we do we will emit a warning here | |
| 105 | ||
| 106 | // FIXME(mejrs) in a couple releases, start emitting warnings for | |
| 107 | // #[rustc_on_unimplemented] deprecated args | |
| 108 | } | |
| 109 | } | |
| 110 | } | |
| 111 | } | |
| 112 | ||
| 113 | /// Arguments to fill a [FormatString] with. | |
| 114 | /// | |
| 115 | /// For example, given a | |
| 116 | /// ```rust,ignore (just an example) | |
| 117 | /// | |
| 118 | /// #[rustc_on_unimplemented( | |
| 119 | /// on(all(from_desugaring = "QuestionMark"), | |
| 120 | /// message = "the `?` operator can only be used in {ItemContext} \ | |
| 121 | /// that returns `Result` or `Option` \ | |
| 122 | /// (or another type that implements `{FromResidual}`)", | |
| 123 | /// label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", | |
| 124 | /// parent_label = "this function should return `Result` or `Option` to accept `?`" | |
| 125 | /// ), | |
| 126 | /// )] | |
| 127 | /// pub trait FromResidual<R = <Self as Try>::Residual> { | |
| 128 | /// ... | |
| 129 | /// } | |
| 130 | /// | |
| 131 | /// async fn an_async_function() -> u32 { | |
| 132 | /// let x: Option<u32> = None; | |
| 133 | /// x?; //~ ERROR the `?` operator | |
| 134 | /// 22 | |
| 135 | /// } | |
| 136 | /// ``` | |
| 137 | /// it will look like this: | |
| 138 | /// | |
| 139 | /// ```rust,ignore (just an example) | |
| 140 | /// FormatArgs { | |
| 141 | /// this: "FromResidual", | |
| 142 | /// trait_sugared: "FromResidual<Option<Infallible>>", | |
| 143 | /// item_context: "an async function", | |
| 144 | /// generic_args: [("Self", "u32"), ("R", "Option<Infallible>")], | |
| 145 | /// } | |
| 146 | /// ``` | |
| 147 | #[derive(Debug)] | |
| 148 | pub struct FormatArgs<'tcx> { | |
| 149 | pub this: String, | |
| 150 | pub trait_sugared: TraitRefPrintSugared<'tcx>, | |
| 151 | pub item_context: &'static str, | |
| 152 | pub generic_args: Vec<(Symbol, String)>, | |
| 153 | } | |
| 154 | ||
| 155 | impl FormatString { | |
| 156 | pub fn span(&self) -> Span { | |
| 157 | self.span | |
| 158 | } | |
| 159 | ||
| 160 | pub fn parse<'tcx>( | |
| 161 | input: Symbol, | |
| 162 | span: Span, | |
| 163 | ctx: &Ctx<'tcx>, | |
| 164 | ) -> Result<Self, Vec<ParseError>> { | |
| 165 | let s = input.as_str(); | |
| 166 | let mut parser = Parser::new(s, None, None, false, ParseMode::Format); | |
| 167 | let mut pieces = Vec::new(); | |
| 168 | let mut warnings = Vec::new(); | |
| 169 | ||
| 170 | for piece in &mut parser { | |
| 171 | match piece { | |
| 172 | RpfPiece::Lit(lit) => { | |
| 173 | pieces.push(Piece::Lit(lit.into())); | |
| 174 | } | |
| 175 | RpfPiece::NextArgument(arg) => { | |
| 176 | warn_on_format_spec(arg.format, &mut warnings, span); | |
| 177 | let arg = parse_arg(&arg, ctx, &mut warnings, span); | |
| 178 | pieces.push(Piece::Arg(arg)); | |
| 179 | } | |
| 180 | } | |
| 181 | } | |
| 182 | ||
| 183 | if parser.errors.is_empty() { | |
| 184 | Ok(FormatString { input, pieces, span, warnings }) | |
| 185 | } else { | |
| 186 | Err(parser.errors) | |
| 187 | } | |
| 188 | } | |
| 189 | ||
| 190 | pub fn format(&self, args: &FormatArgs<'_>) -> String { | |
| 191 | let mut ret = String::new(); | |
| 192 | for piece in &self.pieces { | |
| 193 | match piece { | |
| 194 | Piece::Lit(s) | Piece::Arg(FormatArg::AsIs(s)) => ret.push_str(&s), | |
| 195 | ||
| 196 | // `A` if we have `trait Trait<A> {}` and `note = "i'm the actual type of {A}"` | |
| 197 | Piece::Arg(FormatArg::GenericParam { generic_param }) => { | |
| 198 | // Should always be some but we can't raise errors here | |
| 199 | let value = match args.generic_args.iter().find(|(p, _)| p == generic_param) { | |
| 200 | Some((_, val)) => val.to_string(), | |
| 201 | None => generic_param.to_string(), | |
| 202 | }; | |
| 203 | ret.push_str(&value); | |
| 204 | } | |
| 205 | // `{Self}` | |
| 206 | Piece::Arg(FormatArg::SelfUpper) => { | |
| 207 | let slf = match args.generic_args.iter().find(|(p, _)| *p == kw::SelfUpper) { | |
| 208 | Some((_, val)) => val.to_string(), | |
| 209 | None => "Self".to_string(), | |
| 210 | }; | |
| 211 | ret.push_str(&slf); | |
| 212 | } | |
| 213 | ||
| 214 | // It's only `rustc_onunimplemented` from here | |
| 215 | Piece::Arg(FormatArg::This) => ret.push_str(&args.this), | |
| 216 | Piece::Arg(FormatArg::Trait) => { | |
| 217 | let _ = fmt::write(&mut ret, format_args!("{}", &args.trait_sugared)); | |
| 218 | } | |
| 219 | Piece::Arg(FormatArg::ItemContext) => ret.push_str(args.item_context), | |
| 220 | } | |
| 221 | } | |
| 222 | ret | |
| 223 | } | |
| 224 | } | |
| 225 | ||
| 226 | fn parse_arg<'tcx>( | |
| 227 | arg: &Argument<'_>, | |
| 228 | ctx: &Ctx<'tcx>, | |
| 229 | warnings: &mut Vec<FormatWarning>, | |
| 230 | input_span: Span, | |
| 231 | ) -> FormatArg { | |
| 232 | let (Ctx::RustcOnUnimplemented { tcx, trait_def_id } | |
| 233 | | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx; | |
| 234 | let trait_name = tcx.item_ident(*trait_def_id); | |
| 235 | let generics = tcx.generics_of(trait_def_id); | |
| 236 | let span = slice_span(input_span, arg.position_span); | |
| 237 | ||
| 238 | match arg.position { | |
| 239 | // Something like "hello {name}" | |
| 240 | Position::ArgumentNamed(name) => match (ctx, Symbol::intern(name)) { | |
| 241 | // accepted, but deprecated | |
| 242 | (Ctx::RustcOnUnimplemented { .. }, sym::_Self) => { | |
| 243 | warnings | |
| 244 | .push(FormatWarning::FutureIncompat { span, help: String::from("use {Self}") }); | |
| 245 | FormatArg::SelfUpper | |
| 246 | } | |
| 247 | ( | |
| 248 | Ctx::RustcOnUnimplemented { .. }, | |
| 249 | sym::from_desugaring | |
| 250 | | sym::crate_local | |
| 251 | | sym::direct | |
| 252 | | sym::cause | |
| 253 | | sym::float | |
| 254 | | sym::integer_ | |
| 255 | | sym::integral, | |
| 256 | ) => { | |
| 257 | warnings.push(FormatWarning::FutureIncompat { | |
| 258 | span, | |
| 259 | help: String::from("don't use this in a format string"), | |
| 260 | }); | |
| 261 | FormatArg::AsIs(String::new()) | |
| 262 | } | |
| 263 | ||
| 264 | // Only `#[rustc_on_unimplemented]` can use these | |
| 265 | (Ctx::RustcOnUnimplemented { .. }, sym::ItemContext) => FormatArg::ItemContext, | |
| 266 | (Ctx::RustcOnUnimplemented { .. }, sym::This) => FormatArg::This, | |
| 267 | (Ctx::RustcOnUnimplemented { .. }, sym::Trait) => FormatArg::Trait, | |
| 268 | // `{ThisTraitsName}`. Some attrs in std use this, but I'd like to change it to the more general `{This}` | |
| 269 | // because that'll be simpler to parse and extend in the future | |
| 270 | (Ctx::RustcOnUnimplemented { .. }, name) if name == trait_name.name => { | |
| 271 | warnings | |
| 272 | .push(FormatWarning::FutureIncompat { span, help: String::from("use {This}") }); | |
| 273 | FormatArg::This | |
| 274 | } | |
| 275 | ||
| 276 | // Any attribute can use these | |
| 277 | ( | |
| 278 | Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. }, | |
| 279 | kw::SelfUpper, | |
| 280 | ) => FormatArg::SelfUpper, | |
| 281 | ( | |
| 282 | Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. }, | |
| 283 | generic_param, | |
| 284 | ) if generics.own_params.iter().any(|param| param.name == generic_param) => { | |
| 285 | FormatArg::GenericParam { generic_param } | |
| 286 | } | |
| 287 | ||
| 288 | (_, argument_name) => { | |
| 289 | warnings.push(FormatWarning::UnknownParam { argument_name, span }); | |
| 290 | FormatArg::AsIs(format!("{{{}}}", argument_name.as_str())) | |
| 291 | } | |
| 292 | }, | |
| 293 | ||
| 294 | // `{:1}` and `{}` are ignored | |
| 295 | Position::ArgumentIs(idx) => { | |
| 296 | warnings.push(FormatWarning::PositionalArgument { | |
| 297 | span, | |
| 298 | help: format!("use `{{{idx}}}` to print a number in braces"), | |
| 299 | }); | |
| 300 | FormatArg::AsIs(format!("{{{idx}}}")) | |
| 301 | } | |
| 302 | Position::ArgumentImplicitlyIs(_) => { | |
| 303 | warnings.push(FormatWarning::PositionalArgument { | |
| 304 | span, | |
| 305 | help: String::from("use `{{}}` to print empty braces"), | |
| 306 | }); | |
| 307 | FormatArg::AsIs(String::from("{}")) | |
| 308 | } | |
| 309 | } | |
| 310 | } | |
| 311 | ||
| 312 | /// `#[rustc_on_unimplemented]` and `#[diagnostic::...]` don't actually do anything | |
| 313 | /// with specifiers, so emit a warning if they are used. | |
| 314 | fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec<FormatWarning>, input_span: Span) { | |
| 315 | if !matches!( | |
| 316 | spec, | |
| 317 | FormatSpec { | |
| 318 | fill: None, | |
| 319 | fill_span: None, | |
| 320 | align: Alignment::AlignUnknown, | |
| 321 | sign: None, | |
| 322 | alternate: false, | |
| 323 | zero_pad: false, | |
| 324 | debug_hex: None, | |
| 325 | precision: Count::CountImplied, | |
| 326 | precision_span: None, | |
| 327 | width: Count::CountImplied, | |
| 328 | width_span: None, | |
| 329 | ty: _, | |
| 330 | ty_span: _, | |
| 331 | }, | |
| 332 | ) { | |
| 333 | let span = spec.ty_span.map(|inner| slice_span(input_span, inner)).unwrap_or(input_span); | |
| 334 | warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() }) | |
| 335 | } | |
| 336 | } | |
| 337 | ||
| 338 | /// Helper function because `Span` and `rustc_parse_format::InnerSpan` don't know about each other | |
| 339 | fn slice_span(input: Span, inner: InnerSpan) -> Span { | |
| 340 | let InnerSpan { start, end } = inner; | |
| 341 | let span = input.data(); | |
| 342 | ||
| 343 | Span::new( | |
| 344 | span.lo + BytePos::from_usize(start), | |
| 345 | span.lo + BytePos::from_usize(end), | |
| 346 | span.ctxt, | |
| 347 | span.parent, | |
| 348 | ) | |
| 349 | } | |
| 350 | ||
| 351 | pub mod errors { | |
| 352 | use rustc_macros::LintDiagnostic; | |
| 353 | use rustc_span::Ident; | |
| 354 | ||
| 355 | use super::*; | |
| 356 | ||
| 357 | #[derive(LintDiagnostic)] | |
| 358 | #[diag(trait_selection_unknown_format_parameter_for_on_unimplemented_attr)] | |
| 359 | #[help] | |
| 360 | pub struct UnknownFormatParameterForOnUnimplementedAttr { | |
| 361 | pub argument_name: Symbol, | |
| 362 | pub trait_name: Ident, | |
| 363 | } | |
| 364 | ||
| 365 | #[derive(LintDiagnostic)] | |
| 366 | #[diag(trait_selection_disallowed_positional_argument)] | |
| 367 | #[help] | |
| 368 | pub struct DisallowedPositionalArgument; | |
| 369 | ||
| 370 | #[derive(LintDiagnostic)] | |
| 371 | #[diag(trait_selection_invalid_format_specifier)] | |
| 372 | #[help] | |
| 373 | pub struct InvalidFormatSpecifier; | |
| 374 | ||
| 375 | #[derive(LintDiagnostic)] | |
| 376 | #[diag(trait_selection_missing_options_for_on_unimplemented_attr)] | |
| 377 | #[help] | |
| 378 | pub struct MissingOptionsForOnUnimplementedAttr; | |
| 379 | ||
| 380 | #[derive(LintDiagnostic)] | |
| 381 | #[diag(trait_selection_ignored_diagnostic_option)] | |
| 382 | pub struct IgnoredDiagnosticOption { | |
| 383 | pub option_name: &'static str, | |
| 384 | #[label] | |
| 385 | pub span: Span, | |
| 386 | #[label(trait_selection_other_label)] | |
| 387 | pub prev_span: Span, | |
| 388 | } | |
| 389 | ||
| 390 | impl IgnoredDiagnosticOption { | |
| 391 | pub fn maybe_emit_warning<'tcx>( | |
| 392 | tcx: TyCtxt<'tcx>, | |
| 393 | item_def_id: DefId, | |
| 394 | new: Option<Span>, | |
| 395 | old: Option<Span>, | |
| 396 | option_name: &'static str, | |
| 397 | ) { | |
| 398 | if let (Some(new_item), Some(old_item)) = (new, old) { | |
| 399 | if let Some(item_def_id) = item_def_id.as_local() { | |
| 400 | tcx.emit_node_span_lint( | |
| 401 | UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, | |
| 402 | tcx.local_def_id_to_hir_id(item_def_id), | |
| 403 | new_item, | |
| 404 | IgnoredDiagnosticOption { | |
| 405 | span: new_item, | |
| 406 | prev_span: old_item, | |
| 407 | option_name, | |
| 408 | }, | |
| 409 | ); | |
| 410 | } | |
| 411 | } | |
| 412 | } | |
| 413 | } | |
| 414 | } |
library/std/src/env.rs+1-1| ... | ... | @@ -950,7 +950,7 @@ impl fmt::Debug for ArgsOs { |
| 950 | 950 | /// Constants associated with the current target |
| 951 | 951 | #[stable(feature = "env", since = "1.0.0")] |
| 952 | 952 | pub mod consts { |
| 953 | use crate::sys::env::os; | |
| 953 | use crate::sys::env_consts::os; | |
| 954 | 954 | |
| 955 | 955 | /// A string describing the architecture of the CPU that is currently in use. |
| 956 | 956 | /// An example value may be: `"x86"`, `"arm"` or `"riscv64"`. |
library/std/src/sys/env_consts.rs created+404| ... | ... | @@ -0,0 +1,404 @@ |
| 1 | //! Constants associated with each target. | |
| 2 | ||
| 3 | // Replaces the #[else] gate with #[cfg(not(any(…)))] of all the other gates. | |
| 4 | // This ensures that they must be mutually exclusive and do not have precedence | |
| 5 | // like cfg_if!. | |
| 6 | macro cfg_unordered( | |
| 7 | $(#[cfg($cfg:meta)] $os:item)* | |
| 8 | #[else] $fallback:item | |
| 9 | ) { | |
| 10 | $(#[cfg($cfg)] $os)* | |
| 11 | #[cfg(not(any($($cfg),*)))] $fallback | |
| 12 | } | |
| 13 | ||
| 14 | // Keep entries sorted alphabetically and mutually exclusive. | |
| 15 | ||
| 16 | cfg_unordered! { | |
| 17 | ||
| 18 | #[cfg(target_os = "aix")] | |
| 19 | pub mod os { | |
| 20 | pub const FAMILY: &str = "unix"; | |
| 21 | pub const OS: &str = "aix"; | |
| 22 | pub const DLL_PREFIX: &str = "lib"; | |
| 23 | pub const DLL_SUFFIX: &str = ".a"; | |
| 24 | pub const DLL_EXTENSION: &str = "a"; | |
| 25 | pub const EXE_SUFFIX: &str = ""; | |
| 26 | pub const EXE_EXTENSION: &str = ""; | |
| 27 | } | |
| 28 | ||
| 29 | #[cfg(target_os = "android")] | |
| 30 | pub mod os { | |
| 31 | pub const FAMILY: &str = "unix"; | |
| 32 | pub const OS: &str = "android"; | |
| 33 | pub const DLL_PREFIX: &str = "lib"; | |
| 34 | pub const DLL_SUFFIX: &str = ".so"; | |
| 35 | pub const DLL_EXTENSION: &str = "so"; | |
| 36 | pub const EXE_SUFFIX: &str = ""; | |
| 37 | pub const EXE_EXTENSION: &str = ""; | |
| 38 | } | |
| 39 | ||
| 40 | #[cfg(target_os = "cygwin")] | |
| 41 | pub mod os { | |
| 42 | pub const FAMILY: &str = "unix"; | |
| 43 | pub const OS: &str = "cygwin"; | |
| 44 | pub const DLL_PREFIX: &str = ""; | |
| 45 | pub const DLL_SUFFIX: &str = ".dll"; | |
| 46 | pub const DLL_EXTENSION: &str = "dll"; | |
| 47 | pub const EXE_SUFFIX: &str = ".exe"; | |
| 48 | pub const EXE_EXTENSION: &str = "exe"; | |
| 49 | } | |
| 50 | ||
| 51 | #[cfg(target_os = "dragonfly")] | |
| 52 | pub mod os { | |
| 53 | pub const FAMILY: &str = "unix"; | |
| 54 | pub const OS: &str = "dragonfly"; | |
| 55 | pub const DLL_PREFIX: &str = "lib"; | |
| 56 | pub const DLL_SUFFIX: &str = ".so"; | |
| 57 | pub const DLL_EXTENSION: &str = "so"; | |
| 58 | pub const EXE_SUFFIX: &str = ""; | |
| 59 | pub const EXE_EXTENSION: &str = ""; | |
| 60 | } | |
| 61 | ||
| 62 | #[cfg(target_os = "emscripten")] | |
| 63 | pub mod os { | |
| 64 | pub const FAMILY: &str = "unix"; | |
| 65 | pub const OS: &str = "emscripten"; | |
| 66 | pub const DLL_PREFIX: &str = "lib"; | |
| 67 | pub const DLL_SUFFIX: &str = ".so"; | |
| 68 | pub const DLL_EXTENSION: &str = "so"; | |
| 69 | pub const EXE_SUFFIX: &str = ".js"; | |
| 70 | pub const EXE_EXTENSION: &str = "js"; | |
| 71 | } | |
| 72 | ||
| 73 | #[cfg(target_os = "espidf")] | |
| 74 | pub mod os { | |
| 75 | pub const FAMILY: &str = "unix"; | |
| 76 | pub const OS: &str = "espidf"; | |
| 77 | pub const DLL_PREFIX: &str = "lib"; | |
| 78 | pub const DLL_SUFFIX: &str = ".so"; | |
| 79 | pub const DLL_EXTENSION: &str = "so"; | |
| 80 | pub const EXE_SUFFIX: &str = ""; | |
| 81 | pub const EXE_EXTENSION: &str = ""; | |
| 82 | } | |
| 83 | ||
| 84 | #[cfg(target_os = "freebsd")] | |
| 85 | pub mod os { | |
| 86 | pub const FAMILY: &str = "unix"; | |
| 87 | pub const OS: &str = "freebsd"; | |
| 88 | pub const DLL_PREFIX: &str = "lib"; | |
| 89 | pub const DLL_SUFFIX: &str = ".so"; | |
| 90 | pub const DLL_EXTENSION: &str = "so"; | |
| 91 | pub const EXE_SUFFIX: &str = ""; | |
| 92 | pub const EXE_EXTENSION: &str = ""; | |
| 93 | } | |
| 94 | ||
| 95 | #[cfg(target_os = "fuchsia")] | |
| 96 | pub mod os { | |
| 97 | pub const FAMILY: &str = "unix"; | |
| 98 | pub const OS: &str = "fuchsia"; | |
| 99 | pub const DLL_PREFIX: &str = "lib"; | |
| 100 | pub const DLL_SUFFIX: &str = ".so"; | |
| 101 | pub const DLL_EXTENSION: &str = "so"; | |
| 102 | pub const EXE_SUFFIX: &str = ""; | |
| 103 | pub const EXE_EXTENSION: &str = ""; | |
| 104 | } | |
| 105 | ||
| 106 | #[cfg(target_os = "haiku")] | |
| 107 | pub mod os { | |
| 108 | pub const FAMILY: &str = "unix"; | |
| 109 | pub const OS: &str = "haiku"; | |
| 110 | pub const DLL_PREFIX: &str = "lib"; | |
| 111 | pub const DLL_SUFFIX: &str = ".so"; | |
| 112 | pub const DLL_EXTENSION: &str = "so"; | |
| 113 | pub const EXE_SUFFIX: &str = ""; | |
| 114 | pub const EXE_EXTENSION: &str = ""; | |
| 115 | } | |
| 116 | ||
| 117 | #[cfg(target_os = "hermit")] | |
| 118 | pub mod os { | |
| 119 | pub const FAMILY: &str = ""; | |
| 120 | pub const OS: &str = "hermit"; | |
| 121 | pub const DLL_PREFIX: &str = ""; | |
| 122 | pub const DLL_SUFFIX: &str = ""; | |
| 123 | pub const DLL_EXTENSION: &str = ""; | |
| 124 | pub const EXE_SUFFIX: &str = ""; | |
| 125 | pub const EXE_EXTENSION: &str = ""; | |
| 126 | } | |
| 127 | ||
| 128 | #[cfg(target_os = "horizon")] | |
| 129 | pub mod os { | |
| 130 | pub const FAMILY: &str = "unix"; | |
| 131 | pub const OS: &str = "horizon"; | |
| 132 | pub const DLL_PREFIX: &str = "lib"; | |
| 133 | pub const DLL_SUFFIX: &str = ".so"; | |
| 134 | pub const DLL_EXTENSION: &str = "so"; | |
| 135 | pub const EXE_SUFFIX: &str = ".elf"; | |
| 136 | pub const EXE_EXTENSION: &str = "elf"; | |
| 137 | } | |
| 138 | ||
| 139 | #[cfg(target_os = "hurd")] | |
| 140 | pub mod os { | |
| 141 | pub const FAMILY: &str = "unix"; | |
| 142 | pub const OS: &str = "hurd"; | |
| 143 | pub const DLL_PREFIX: &str = "lib"; | |
| 144 | pub const DLL_SUFFIX: &str = ".so"; | |
| 145 | pub const DLL_EXTENSION: &str = "so"; | |
| 146 | pub const EXE_SUFFIX: &str = ""; | |
| 147 | pub const EXE_EXTENSION: &str = ""; | |
| 148 | } | |
| 149 | ||
| 150 | #[cfg(target_os = "illumos")] | |
| 151 | pub mod os { | |
| 152 | pub const FAMILY: &str = "unix"; | |
| 153 | pub const OS: &str = "illumos"; | |
| 154 | pub const DLL_PREFIX: &str = "lib"; | |
| 155 | pub const DLL_SUFFIX: &str = ".so"; | |
| 156 | pub const DLL_EXTENSION: &str = "so"; | |
| 157 | pub const EXE_SUFFIX: &str = ""; | |
| 158 | pub const EXE_EXTENSION: &str = ""; | |
| 159 | } | |
| 160 | ||
| 161 | #[cfg(target_os = "ios")] | |
| 162 | pub mod os { | |
| 163 | pub const FAMILY: &str = "unix"; | |
| 164 | pub const OS: &str = "ios"; | |
| 165 | pub const DLL_PREFIX: &str = "lib"; | |
| 166 | pub const DLL_SUFFIX: &str = ".dylib"; | |
| 167 | pub const DLL_EXTENSION: &str = "dylib"; | |
| 168 | pub const EXE_SUFFIX: &str = ""; | |
| 169 | pub const EXE_EXTENSION: &str = ""; | |
| 170 | } | |
| 171 | ||
| 172 | #[cfg(target_os = "l4re")] | |
| 173 | pub mod os { | |
| 174 | pub const FAMILY: &str = "unix"; | |
| 175 | pub const OS: &str = "l4re"; | |
| 176 | pub const DLL_PREFIX: &str = "lib"; | |
| 177 | pub const DLL_SUFFIX: &str = ".so"; | |
| 178 | pub const DLL_EXTENSION: &str = "so"; | |
| 179 | pub const EXE_SUFFIX: &str = ""; | |
| 180 | pub const EXE_EXTENSION: &str = ""; | |
| 181 | } | |
| 182 | ||
| 183 | #[cfg(target_os = "linux")] | |
| 184 | pub mod os { | |
| 185 | pub const FAMILY: &str = "unix"; | |
| 186 | pub const OS: &str = "linux"; | |
| 187 | pub const DLL_PREFIX: &str = "lib"; | |
| 188 | pub const DLL_SUFFIX: &str = ".so"; | |
| 189 | pub const DLL_EXTENSION: &str = "so"; | |
| 190 | pub const EXE_SUFFIX: &str = ""; | |
| 191 | pub const EXE_EXTENSION: &str = ""; | |
| 192 | } | |
| 193 | ||
| 194 | #[cfg(target_os = "macos")] | |
| 195 | pub mod os { | |
| 196 | pub const FAMILY: &str = "unix"; | |
| 197 | pub const OS: &str = "macos"; | |
| 198 | pub const DLL_PREFIX: &str = "lib"; | |
| 199 | pub const DLL_SUFFIX: &str = ".dylib"; | |
| 200 | pub const DLL_EXTENSION: &str = "dylib"; | |
| 201 | pub const EXE_SUFFIX: &str = ""; | |
| 202 | pub const EXE_EXTENSION: &str = ""; | |
| 203 | } | |
| 204 | ||
| 205 | #[cfg(target_os = "netbsd")] | |
| 206 | pub mod os { | |
| 207 | pub const FAMILY: &str = "unix"; | |
| 208 | pub const OS: &str = "netbsd"; | |
| 209 | pub const DLL_PREFIX: &str = "lib"; | |
| 210 | pub const DLL_SUFFIX: &str = ".so"; | |
| 211 | pub const DLL_EXTENSION: &str = "so"; | |
| 212 | pub const EXE_SUFFIX: &str = ""; | |
| 213 | pub const EXE_EXTENSION: &str = ""; | |
| 214 | } | |
| 215 | ||
| 216 | #[cfg(target_os = "nto")] | |
| 217 | pub mod os { | |
| 218 | pub const FAMILY: &str = "unix"; | |
| 219 | pub const OS: &str = "nto"; | |
| 220 | pub const DLL_PREFIX: &str = "lib"; | |
| 221 | pub const DLL_SUFFIX: &str = ".so"; | |
| 222 | pub const DLL_EXTENSION: &str = "so"; | |
| 223 | pub const EXE_SUFFIX: &str = ""; | |
| 224 | pub const EXE_EXTENSION: &str = ""; | |
| 225 | } | |
| 226 | ||
| 227 | #[cfg(target_os = "nuttx")] | |
| 228 | pub mod os { | |
| 229 | pub const FAMILY: &str = "unix"; | |
| 230 | pub const OS: &str = "nuttx"; | |
| 231 | pub const DLL_PREFIX: &str = "lib"; | |
| 232 | pub const DLL_SUFFIX: &str = ".so"; | |
| 233 | pub const DLL_EXTENSION: &str = "so"; | |
| 234 | pub const EXE_SUFFIX: &str = ""; | |
| 235 | pub const EXE_EXTENSION: &str = ""; | |
| 236 | } | |
| 237 | ||
| 238 | #[cfg(target_os = "openbsd")] | |
| 239 | pub mod os { | |
| 240 | pub const FAMILY: &str = "unix"; | |
| 241 | pub const OS: &str = "openbsd"; | |
| 242 | pub const DLL_PREFIX: &str = "lib"; | |
| 243 | pub const DLL_SUFFIX: &str = ".so"; | |
| 244 | pub const DLL_EXTENSION: &str = "so"; | |
| 245 | pub const EXE_SUFFIX: &str = ""; | |
| 246 | pub const EXE_EXTENSION: &str = ""; | |
| 247 | } | |
| 248 | ||
| 249 | #[cfg(target_os = "redox")] | |
| 250 | pub mod os { | |
| 251 | pub const FAMILY: &str = "unix"; | |
| 252 | pub const OS: &str = "redox"; | |
| 253 | pub const DLL_PREFIX: &str = "lib"; | |
| 254 | pub const DLL_SUFFIX: &str = ".so"; | |
| 255 | pub const DLL_EXTENSION: &str = "so"; | |
| 256 | pub const EXE_SUFFIX: &str = ""; | |
| 257 | pub const EXE_EXTENSION: &str = ""; | |
| 258 | } | |
| 259 | ||
| 260 | #[cfg(target_os = "rtems")] | |
| 261 | pub mod os { | |
| 262 | pub const FAMILY: &str = "unix"; | |
| 263 | pub const OS: &str = "rtems"; | |
| 264 | pub const DLL_PREFIX: &str = "lib"; | |
| 265 | pub const DLL_SUFFIX: &str = ".so"; | |
| 266 | pub const DLL_EXTENSION: &str = "so"; | |
| 267 | pub const EXE_SUFFIX: &str = ""; | |
| 268 | pub const EXE_EXTENSION: &str = ""; | |
| 269 | } | |
| 270 | ||
| 271 | #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] | |
| 272 | pub mod os { | |
| 273 | pub const FAMILY: &str = ""; | |
| 274 | pub const OS: &str = ""; | |
| 275 | pub const DLL_PREFIX: &str = ""; | |
| 276 | pub const DLL_SUFFIX: &str = ".sgxs"; | |
| 277 | pub const DLL_EXTENSION: &str = "sgxs"; | |
| 278 | pub const EXE_SUFFIX: &str = ".sgxs"; | |
| 279 | pub const EXE_EXTENSION: &str = "sgxs"; | |
| 280 | } | |
| 281 | ||
| 282 | #[cfg(target_os = "solaris")] | |
| 283 | pub mod os { | |
| 284 | pub const FAMILY: &str = "unix"; | |
| 285 | pub const OS: &str = "solaris"; | |
| 286 | pub const DLL_PREFIX: &str = "lib"; | |
| 287 | pub const DLL_SUFFIX: &str = ".so"; | |
| 288 | pub const DLL_EXTENSION: &str = "so"; | |
| 289 | pub const EXE_SUFFIX: &str = ""; | |
| 290 | pub const EXE_EXTENSION: &str = ""; | |
| 291 | } | |
| 292 | ||
| 293 | #[cfg(target_os = "solid_asp3")] | |
| 294 | pub mod os { | |
| 295 | pub const FAMILY: &str = "itron"; | |
| 296 | pub const OS: &str = "solid"; | |
| 297 | pub const DLL_PREFIX: &str = ""; | |
| 298 | pub const DLL_SUFFIX: &str = ".so"; | |
| 299 | pub const DLL_EXTENSION: &str = "so"; | |
| 300 | pub const EXE_SUFFIX: &str = ""; | |
| 301 | pub const EXE_EXTENSION: &str = ""; | |
| 302 | } | |
| 303 | ||
| 304 | #[cfg(target_os = "tvos")] | |
| 305 | pub mod os { | |
| 306 | pub const FAMILY: &str = "unix"; | |
| 307 | pub const OS: &str = "tvos"; | |
| 308 | pub const DLL_PREFIX: &str = "lib"; | |
| 309 | pub const DLL_SUFFIX: &str = ".dylib"; | |
| 310 | pub const DLL_EXTENSION: &str = "dylib"; | |
| 311 | pub const EXE_SUFFIX: &str = ""; | |
| 312 | pub const EXE_EXTENSION: &str = ""; | |
| 313 | } | |
| 314 | ||
| 315 | #[cfg(target_os = "uefi")] | |
| 316 | pub mod os { | |
| 317 | pub const FAMILY: &str = ""; | |
| 318 | pub const OS: &str = "uefi"; | |
| 319 | pub const DLL_PREFIX: &str = ""; | |
| 320 | pub const DLL_SUFFIX: &str = ""; | |
| 321 | pub const DLL_EXTENSION: &str = ""; | |
| 322 | pub const EXE_SUFFIX: &str = ".efi"; | |
| 323 | pub const EXE_EXTENSION: &str = "efi"; | |
| 324 | } | |
| 325 | ||
| 326 | #[cfg(target_os = "visionos")] | |
| 327 | pub mod os { | |
| 328 | pub const FAMILY: &str = "unix"; | |
| 329 | pub const OS: &str = "visionos"; | |
| 330 | pub const DLL_PREFIX: &str = "lib"; | |
| 331 | pub const DLL_SUFFIX: &str = ".dylib"; | |
| 332 | pub const DLL_EXTENSION: &str = "dylib"; | |
| 333 | pub const EXE_SUFFIX: &str = ""; | |
| 334 | pub const EXE_EXTENSION: &str = ""; | |
| 335 | } | |
| 336 | ||
| 337 | #[cfg(target_os = "vita")] | |
| 338 | pub mod os { | |
| 339 | pub const FAMILY: &str = "unix"; | |
| 340 | pub const OS: &str = "vita"; | |
| 341 | pub const DLL_PREFIX: &str = "lib"; | |
| 342 | pub const DLL_SUFFIX: &str = ".so"; | |
| 343 | pub const DLL_EXTENSION: &str = "so"; | |
| 344 | pub const EXE_SUFFIX: &str = ".elf"; | |
| 345 | pub const EXE_EXTENSION: &str = "elf"; | |
| 346 | } | |
| 347 | ||
| 348 | #[cfg(target_os = "vxworks")] | |
| 349 | pub mod os { | |
| 350 | pub const FAMILY: &str = "unix"; | |
| 351 | pub const OS: &str = "vxworks"; | |
| 352 | pub const DLL_PREFIX: &str = "lib"; | |
| 353 | pub const DLL_SUFFIX: &str = ".so"; | |
| 354 | pub const DLL_EXTENSION: &str = "so"; | |
| 355 | pub const EXE_SUFFIX: &str = ""; | |
| 356 | pub const EXE_EXTENSION: &str = ""; | |
| 357 | } | |
| 358 | ||
| 359 | #[cfg(all(target_family = "wasm", not(any(target_os = "emscripten", target_os = "linux"))))] | |
| 360 | pub mod os { | |
| 361 | pub const FAMILY: &str = ""; | |
| 362 | pub const OS: &str = ""; | |
| 363 | pub const DLL_PREFIX: &str = ""; | |
| 364 | pub const DLL_SUFFIX: &str = ".wasm"; | |
| 365 | pub const DLL_EXTENSION: &str = "wasm"; | |
| 366 | pub const EXE_SUFFIX: &str = ".wasm"; | |
| 367 | pub const EXE_EXTENSION: &str = "wasm"; | |
| 368 | } | |
| 369 | ||
| 370 | #[cfg(target_os = "watchos")] | |
| 371 | pub mod os { | |
| 372 | pub const FAMILY: &str = "unix"; | |
| 373 | pub const OS: &str = "watchos"; | |
| 374 | pub const DLL_PREFIX: &str = "lib"; | |
| 375 | pub const DLL_SUFFIX: &str = ".dylib"; | |
| 376 | pub const DLL_EXTENSION: &str = "dylib"; | |
| 377 | pub const EXE_SUFFIX: &str = ""; | |
| 378 | pub const EXE_EXTENSION: &str = ""; | |
| 379 | } | |
| 380 | ||
| 381 | #[cfg(target_os = "windows")] | |
| 382 | pub mod os { | |
| 383 | pub const FAMILY: &str = "windows"; | |
| 384 | pub const OS: &str = "windows"; | |
| 385 | pub const DLL_PREFIX: &str = ""; | |
| 386 | pub const DLL_SUFFIX: &str = ".dll"; | |
| 387 | pub const DLL_EXTENSION: &str = "dll"; | |
| 388 | pub const EXE_SUFFIX: &str = ".exe"; | |
| 389 | pub const EXE_EXTENSION: &str = "exe"; | |
| 390 | } | |
| 391 | ||
| 392 | // The fallback when none of the other gates match. | |
| 393 | #[else] | |
| 394 | pub mod os { | |
| 395 | pub const FAMILY: &str = ""; | |
| 396 | pub const OS: &str = ""; | |
| 397 | pub const DLL_PREFIX: &str = ""; | |
| 398 | pub const DLL_SUFFIX: &str = ""; | |
| 399 | pub const DLL_EXTENSION: &str = ""; | |
| 400 | pub const EXE_SUFFIX: &str = ""; | |
| 401 | pub const EXE_EXTENSION: &str = ""; | |
| 402 | } | |
| 403 | ||
| 404 | } |
library/std/src/sys/mod.rs+1| ... | ... | @@ -12,6 +12,7 @@ pub mod anonymous_pipe; |
| 12 | 12 | pub mod args; |
| 13 | 13 | pub mod backtrace; |
| 14 | 14 | pub mod cmath; |
| 15 | pub mod env_consts; | |
| 15 | 16 | pub mod exit_guard; |
| 16 | 17 | pub mod fd; |
| 17 | 18 | pub mod fs; |
library/std/src/sys/pal/hermit/env.rs deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | pub mod os { | |
| 2 | pub const FAMILY: &str = ""; | |
| 3 | pub const OS: &str = "hermit"; | |
| 4 | pub const DLL_PREFIX: &str = ""; | |
| 5 | pub const DLL_SUFFIX: &str = ""; | |
| 6 | pub const DLL_EXTENSION: &str = ""; | |
| 7 | pub const EXE_SUFFIX: &str = ""; | |
| 8 | pub const EXE_EXTENSION: &str = ""; | |
| 9 | } |
library/std/src/sys/pal/hermit/mod.rs-1| ... | ... | @@ -18,7 +18,6 @@ |
| 18 | 18 | |
| 19 | 19 | use crate::os::raw::c_char; |
| 20 | 20 | |
| 21 | pub mod env; | |
| 22 | 21 | pub mod futex; |
| 23 | 22 | pub mod os; |
| 24 | 23 | #[path = "../unsupported/pipe.rs"] |
library/std/src/sys/pal/sgx/env.rs deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | pub mod os { | |
| 2 | pub const FAMILY: &str = ""; | |
| 3 | pub const OS: &str = ""; | |
| 4 | pub const DLL_PREFIX: &str = ""; | |
| 5 | pub const DLL_SUFFIX: &str = ".sgxs"; | |
| 6 | pub const DLL_EXTENSION: &str = "sgxs"; | |
| 7 | pub const EXE_SUFFIX: &str = ".sgxs"; | |
| 8 | pub const EXE_EXTENSION: &str = "sgxs"; | |
| 9 | } |
library/std/src/sys/pal/sgx/mod.rs-1| ... | ... | @@ -9,7 +9,6 @@ use crate::io::ErrorKind; |
| 9 | 9 | use crate::sync::atomic::{AtomicBool, Ordering}; |
| 10 | 10 | |
| 11 | 11 | pub mod abi; |
| 12 | pub mod env; | |
| 13 | 12 | mod libunwind_integration; |
| 14 | 13 | pub mod os; |
| 15 | 14 | #[path = "../unsupported/pipe.rs"] |
library/std/src/sys/pal/solid/env.rs deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | pub mod os { | |
| 2 | pub const FAMILY: &str = "itron"; | |
| 3 | pub const OS: &str = "solid"; | |
| 4 | pub const DLL_PREFIX: &str = ""; | |
| 5 | pub const DLL_SUFFIX: &str = ".so"; | |
| 6 | pub const DLL_EXTENSION: &str = "so"; | |
| 7 | pub const EXE_SUFFIX: &str = ""; | |
| 8 | pub const EXE_EXTENSION: &str = ""; | |
| 9 | } |
library/std/src/sys/pal/solid/mod.rs-1| ... | ... | @@ -16,7 +16,6 @@ pub mod itron { |
| 16 | 16 | use super::unsupported; |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | pub mod env; | |
| 20 | 19 | // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as |
| 21 | 20 | // `crate::sys::error` |
| 22 | 21 | pub(crate) mod error; |
library/std/src/sys/pal/teeos/mod.rs-3| ... | ... | @@ -6,9 +6,6 @@ |
| 6 | 6 | #![allow(unused_variables)] |
| 7 | 7 | #![allow(dead_code)] |
| 8 | 8 | |
| 9 | #[path = "../unsupported/env.rs"] | |
| 10 | pub mod env; | |
| 11 | //pub mod fd; | |
| 12 | 9 | pub mod os; |
| 13 | 10 | #[path = "../unsupported/pipe.rs"] |
| 14 | 11 | pub mod pipe; |
library/std/src/sys/pal/trusty/mod.rs-2| ... | ... | @@ -3,8 +3,6 @@ |
| 3 | 3 | #[path = "../unsupported/common.rs"] |
| 4 | 4 | #[deny(unsafe_op_in_unsafe_fn)] |
| 5 | 5 | mod common; |
| 6 | #[path = "../unsupported/env.rs"] | |
| 7 | pub mod env; | |
| 8 | 6 | #[path = "../unsupported/os.rs"] |
| 9 | 7 | pub mod os; |
| 10 | 8 | #[path = "../unsupported/pipe.rs"] |
library/std/src/sys/pal/uefi/env.rs deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | pub mod os { | |
| 2 | pub const FAMILY: &str = ""; | |
| 3 | pub const OS: &str = "uefi"; | |
| 4 | pub const DLL_PREFIX: &str = ""; | |
| 5 | pub const DLL_SUFFIX: &str = ""; | |
| 6 | pub const DLL_EXTENSION: &str = ""; | |
| 7 | pub const EXE_SUFFIX: &str = ".efi"; | |
| 8 | pub const EXE_EXTENSION: &str = "efi"; | |
| 9 | } |
library/std/src/sys/pal/uefi/mod.rs-1| ... | ... | @@ -13,7 +13,6 @@ |
| 13 | 13 | //! [`OsString`]: crate::ffi::OsString |
| 14 | 14 | #![forbid(unsafe_op_in_unsafe_fn)] |
| 15 | 15 | |
| 16 | pub mod env; | |
| 17 | 16 | pub mod helpers; |
| 18 | 17 | pub mod os; |
| 19 | 18 | #[path = "../unsupported/pipe.rs"] |
library/std/src/sys/pal/unix/env.rs deleted-307| ... | ... | @@ -1,307 +0,0 @@ |
| 1 | #[cfg(target_os = "linux")] | |
| 2 | pub mod os { | |
| 3 | pub const FAMILY: &str = "unix"; | |
| 4 | pub const OS: &str = "linux"; | |
| 5 | pub const DLL_PREFIX: &str = "lib"; | |
| 6 | pub const DLL_SUFFIX: &str = ".so"; | |
| 7 | pub const DLL_EXTENSION: &str = "so"; | |
| 8 | pub const EXE_SUFFIX: &str = ""; | |
| 9 | pub const EXE_EXTENSION: &str = ""; | |
| 10 | } | |
| 11 | ||
| 12 | #[cfg(target_os = "macos")] | |
| 13 | pub mod os { | |
| 14 | pub const FAMILY: &str = "unix"; | |
| 15 | pub const OS: &str = "macos"; | |
| 16 | pub const DLL_PREFIX: &str = "lib"; | |
| 17 | pub const DLL_SUFFIX: &str = ".dylib"; | |
| 18 | pub const DLL_EXTENSION: &str = "dylib"; | |
| 19 | pub const EXE_SUFFIX: &str = ""; | |
| 20 | pub const EXE_EXTENSION: &str = ""; | |
| 21 | } | |
| 22 | ||
| 23 | #[cfg(target_os = "ios")] | |
| 24 | pub mod os { | |
| 25 | pub const FAMILY: &str = "unix"; | |
| 26 | pub const OS: &str = "ios"; | |
| 27 | pub const DLL_PREFIX: &str = "lib"; | |
| 28 | pub const DLL_SUFFIX: &str = ".dylib"; | |
| 29 | pub const DLL_EXTENSION: &str = "dylib"; | |
| 30 | pub const EXE_SUFFIX: &str = ""; | |
| 31 | pub const EXE_EXTENSION: &str = ""; | |
| 32 | } | |
| 33 | ||
| 34 | #[cfg(target_os = "tvos")] | |
| 35 | pub mod os { | |
| 36 | pub const FAMILY: &str = "unix"; | |
| 37 | pub const OS: &str = "tvos"; | |
| 38 | pub const DLL_PREFIX: &str = "lib"; | |
| 39 | pub const DLL_SUFFIX: &str = ".dylib"; | |
| 40 | pub const DLL_EXTENSION: &str = "dylib"; | |
| 41 | pub const EXE_SUFFIX: &str = ""; | |
| 42 | pub const EXE_EXTENSION: &str = ""; | |
| 43 | } | |
| 44 | ||
| 45 | #[cfg(target_os = "watchos")] | |
| 46 | pub mod os { | |
| 47 | pub const FAMILY: &str = "unix"; | |
| 48 | pub const OS: &str = "watchos"; | |
| 49 | pub const DLL_PREFIX: &str = "lib"; | |
| 50 | pub const DLL_SUFFIX: &str = ".dylib"; | |
| 51 | pub const DLL_EXTENSION: &str = "dylib"; | |
| 52 | pub const EXE_SUFFIX: &str = ""; | |
| 53 | pub const EXE_EXTENSION: &str = ""; | |
| 54 | } | |
| 55 | ||
| 56 | #[cfg(target_os = "visionos")] | |
| 57 | pub mod os { | |
| 58 | pub const FAMILY: &str = "unix"; | |
| 59 | pub const OS: &str = "visionos"; | |
| 60 | pub const DLL_PREFIX: &str = "lib"; | |
| 61 | pub const DLL_SUFFIX: &str = ".dylib"; | |
| 62 | pub const DLL_EXTENSION: &str = "dylib"; | |
| 63 | pub const EXE_SUFFIX: &str = ""; | |
| 64 | pub const EXE_EXTENSION: &str = ""; | |
| 65 | } | |
| 66 | ||
| 67 | #[cfg(target_os = "freebsd")] | |
| 68 | pub mod os { | |
| 69 | pub const FAMILY: &str = "unix"; | |
| 70 | pub const OS: &str = "freebsd"; | |
| 71 | pub const DLL_PREFIX: &str = "lib"; | |
| 72 | pub const DLL_SUFFIX: &str = ".so"; | |
| 73 | pub const DLL_EXTENSION: &str = "so"; | |
| 74 | pub const EXE_SUFFIX: &str = ""; | |
| 75 | pub const EXE_EXTENSION: &str = ""; | |
| 76 | } | |
| 77 | ||
| 78 | #[cfg(target_os = "dragonfly")] | |
| 79 | pub mod os { | |
| 80 | pub const FAMILY: &str = "unix"; | |
| 81 | pub const OS: &str = "dragonfly"; | |
| 82 | pub const DLL_PREFIX: &str = "lib"; | |
| 83 | pub const DLL_SUFFIX: &str = ".so"; | |
| 84 | pub const DLL_EXTENSION: &str = "so"; | |
| 85 | pub const EXE_SUFFIX: &str = ""; | |
| 86 | pub const EXE_EXTENSION: &str = ""; | |
| 87 | } | |
| 88 | ||
| 89 | #[cfg(target_os = "netbsd")] | |
| 90 | pub mod os { | |
| 91 | pub const FAMILY: &str = "unix"; | |
| 92 | pub const OS: &str = "netbsd"; | |
| 93 | pub const DLL_PREFIX: &str = "lib"; | |
| 94 | pub const DLL_SUFFIX: &str = ".so"; | |
| 95 | pub const DLL_EXTENSION: &str = "so"; | |
| 96 | pub const EXE_SUFFIX: &str = ""; | |
| 97 | pub const EXE_EXTENSION: &str = ""; | |
| 98 | } | |
| 99 | ||
| 100 | #[cfg(target_os = "openbsd")] | |
| 101 | pub mod os { | |
| 102 | pub const FAMILY: &str = "unix"; | |
| 103 | pub const OS: &str = "openbsd"; | |
| 104 | pub const DLL_PREFIX: &str = "lib"; | |
| 105 | pub const DLL_SUFFIX: &str = ".so"; | |
| 106 | pub const DLL_EXTENSION: &str = "so"; | |
| 107 | pub const EXE_SUFFIX: &str = ""; | |
| 108 | pub const EXE_EXTENSION: &str = ""; | |
| 109 | } | |
| 110 | ||
| 111 | #[cfg(target_os = "cygwin")] | |
| 112 | pub mod os { | |
| 113 | pub const FAMILY: &str = "unix"; | |
| 114 | pub const OS: &str = "cygwin"; | |
| 115 | pub const DLL_PREFIX: &str = ""; | |
| 116 | pub const DLL_SUFFIX: &str = ".dll"; | |
| 117 | pub const DLL_EXTENSION: &str = "dll"; | |
| 118 | pub const EXE_SUFFIX: &str = ".exe"; | |
| 119 | pub const EXE_EXTENSION: &str = "exe"; | |
| 120 | } | |
| 121 | ||
| 122 | #[cfg(target_os = "android")] | |
| 123 | pub mod os { | |
| 124 | pub const FAMILY: &str = "unix"; | |
| 125 | pub const OS: &str = "android"; | |
| 126 | pub const DLL_PREFIX: &str = "lib"; | |
| 127 | pub const DLL_SUFFIX: &str = ".so"; | |
| 128 | pub const DLL_EXTENSION: &str = "so"; | |
| 129 | pub const EXE_SUFFIX: &str = ""; | |
| 130 | pub const EXE_EXTENSION: &str = ""; | |
| 131 | } | |
| 132 | ||
| 133 | #[cfg(target_os = "solaris")] | |
| 134 | pub mod os { | |
| 135 | pub const FAMILY: &str = "unix"; | |
| 136 | pub const OS: &str = "solaris"; | |
| 137 | pub const DLL_PREFIX: &str = "lib"; | |
| 138 | pub const DLL_SUFFIX: &str = ".so"; | |
| 139 | pub const DLL_EXTENSION: &str = "so"; | |
| 140 | pub const EXE_SUFFIX: &str = ""; | |
| 141 | pub const EXE_EXTENSION: &str = ""; | |
| 142 | } | |
| 143 | ||
| 144 | #[cfg(target_os = "illumos")] | |
| 145 | pub mod os { | |
| 146 | pub const FAMILY: &str = "unix"; | |
| 147 | pub const OS: &str = "illumos"; | |
| 148 | pub const DLL_PREFIX: &str = "lib"; | |
| 149 | pub const DLL_SUFFIX: &str = ".so"; | |
| 150 | pub const DLL_EXTENSION: &str = "so"; | |
| 151 | pub const EXE_SUFFIX: &str = ""; | |
| 152 | pub const EXE_EXTENSION: &str = ""; | |
| 153 | } | |
| 154 | ||
| 155 | #[cfg(target_os = "haiku")] | |
| 156 | pub mod os { | |
| 157 | pub const FAMILY: &str = "unix"; | |
| 158 | pub const OS: &str = "haiku"; | |
| 159 | pub const DLL_PREFIX: &str = "lib"; | |
| 160 | pub const DLL_SUFFIX: &str = ".so"; | |
| 161 | pub const DLL_EXTENSION: &str = "so"; | |
| 162 | pub const EXE_SUFFIX: &str = ""; | |
| 163 | pub const EXE_EXTENSION: &str = ""; | |
| 164 | } | |
| 165 | ||
| 166 | #[cfg(target_os = "horizon")] | |
| 167 | pub mod os { | |
| 168 | pub const FAMILY: &str = "unix"; | |
| 169 | pub const OS: &str = "horizon"; | |
| 170 | pub const DLL_PREFIX: &str = "lib"; | |
| 171 | pub const DLL_SUFFIX: &str = ".so"; | |
| 172 | pub const DLL_EXTENSION: &str = "so"; | |
| 173 | pub const EXE_SUFFIX: &str = ".elf"; | |
| 174 | pub const EXE_EXTENSION: &str = "elf"; | |
| 175 | } | |
| 176 | ||
| 177 | #[cfg(target_os = "hurd")] | |
| 178 | pub mod os { | |
| 179 | pub const FAMILY: &str = "unix"; | |
| 180 | pub const OS: &str = "hurd"; | |
| 181 | pub const DLL_PREFIX: &str = "lib"; | |
| 182 | pub const DLL_SUFFIX: &str = ".so"; | |
| 183 | pub const DLL_EXTENSION: &str = "so"; | |
| 184 | pub const EXE_SUFFIX: &str = ""; | |
| 185 | pub const EXE_EXTENSION: &str = ""; | |
| 186 | } | |
| 187 | ||
| 188 | #[cfg(target_os = "vita")] | |
| 189 | pub mod os { | |
| 190 | pub const FAMILY: &str = "unix"; | |
| 191 | pub const OS: &str = "vita"; | |
| 192 | pub const DLL_PREFIX: &str = "lib"; | |
| 193 | pub const DLL_SUFFIX: &str = ".so"; | |
| 194 | pub const DLL_EXTENSION: &str = "so"; | |
| 195 | pub const EXE_SUFFIX: &str = ".elf"; | |
| 196 | pub const EXE_EXTENSION: &str = "elf"; | |
| 197 | } | |
| 198 | ||
| 199 | #[cfg(all(target_os = "emscripten", target_arch = "wasm32"))] | |
| 200 | pub mod os { | |
| 201 | pub const FAMILY: &str = "unix"; | |
| 202 | pub const OS: &str = "emscripten"; | |
| 203 | pub const DLL_PREFIX: &str = "lib"; | |
| 204 | pub const DLL_SUFFIX: &str = ".so"; | |
| 205 | pub const DLL_EXTENSION: &str = "so"; | |
| 206 | pub const EXE_SUFFIX: &str = ".js"; | |
| 207 | pub const EXE_EXTENSION: &str = "js"; | |
| 208 | } | |
| 209 | ||
| 210 | #[cfg(target_os = "fuchsia")] | |
| 211 | pub mod os { | |
| 212 | pub const FAMILY: &str = "unix"; | |
| 213 | pub const OS: &str = "fuchsia"; | |
| 214 | pub const DLL_PREFIX: &str = "lib"; | |
| 215 | pub const DLL_SUFFIX: &str = ".so"; | |
| 216 | pub const DLL_EXTENSION: &str = "so"; | |
| 217 | pub const EXE_SUFFIX: &str = ""; | |
| 218 | pub const EXE_EXTENSION: &str = ""; | |
| 219 | } | |
| 220 | ||
| 221 | #[cfg(target_os = "l4re")] | |
| 222 | pub mod os { | |
| 223 | pub const FAMILY: &str = "unix"; | |
| 224 | pub const OS: &str = "l4re"; | |
| 225 | pub const DLL_PREFIX: &str = "lib"; | |
| 226 | pub const DLL_SUFFIX: &str = ".so"; | |
| 227 | pub const DLL_EXTENSION: &str = "so"; | |
| 228 | pub const EXE_SUFFIX: &str = ""; | |
| 229 | pub const EXE_EXTENSION: &str = ""; | |
| 230 | } | |
| 231 | ||
| 232 | #[cfg(target_os = "nto")] | |
| 233 | pub mod os { | |
| 234 | pub const FAMILY: &str = "unix"; | |
| 235 | pub const OS: &str = "nto"; | |
| 236 | pub const DLL_PREFIX: &str = "lib"; | |
| 237 | pub const DLL_SUFFIX: &str = ".so"; | |
| 238 | pub const DLL_EXTENSION: &str = "so"; | |
| 239 | pub const EXE_SUFFIX: &str = ""; | |
| 240 | pub const EXE_EXTENSION: &str = ""; | |
| 241 | } | |
| 242 | ||
| 243 | #[cfg(target_os = "redox")] | |
| 244 | pub mod os { | |
| 245 | pub const FAMILY: &str = "unix"; | |
| 246 | pub const OS: &str = "redox"; | |
| 247 | pub const DLL_PREFIX: &str = "lib"; | |
| 248 | pub const DLL_SUFFIX: &str = ".so"; | |
| 249 | pub const DLL_EXTENSION: &str = "so"; | |
| 250 | pub const EXE_SUFFIX: &str = ""; | |
| 251 | pub const EXE_EXTENSION: &str = ""; | |
| 252 | } | |
| 253 | ||
| 254 | #[cfg(target_os = "rtems")] | |
| 255 | pub mod os { | |
| 256 | pub const FAMILY: &str = "unix"; | |
| 257 | pub const OS: &str = "rtems"; | |
| 258 | pub const DLL_PREFIX: &str = "lib"; | |
| 259 | pub const DLL_SUFFIX: &str = ".so"; | |
| 260 | pub const DLL_EXTENSION: &str = "so"; | |
| 261 | pub const EXE_SUFFIX: &str = ""; | |
| 262 | pub const EXE_EXTENSION: &str = ""; | |
| 263 | } | |
| 264 | ||
| 265 | #[cfg(target_os = "vxworks")] | |
| 266 | pub mod os { | |
| 267 | pub const FAMILY: &str = "unix"; | |
| 268 | pub const OS: &str = "vxworks"; | |
| 269 | pub const DLL_PREFIX: &str = "lib"; | |
| 270 | pub const DLL_SUFFIX: &str = ".so"; | |
| 271 | pub const DLL_EXTENSION: &str = "so"; | |
| 272 | pub const EXE_SUFFIX: &str = ""; | |
| 273 | pub const EXE_EXTENSION: &str = ""; | |
| 274 | } | |
| 275 | ||
| 276 | #[cfg(target_os = "espidf")] | |
| 277 | pub mod os { | |
| 278 | pub const FAMILY: &str = "unix"; | |
| 279 | pub const OS: &str = "espidf"; | |
| 280 | pub const DLL_PREFIX: &str = "lib"; | |
| 281 | pub const DLL_SUFFIX: &str = ".so"; | |
| 282 | pub const DLL_EXTENSION: &str = "so"; | |
| 283 | pub const EXE_SUFFIX: &str = ""; | |
| 284 | pub const EXE_EXTENSION: &str = ""; | |
| 285 | } | |
| 286 | ||
| 287 | #[cfg(target_os = "aix")] | |
| 288 | pub mod os { | |
| 289 | pub const FAMILY: &str = "unix"; | |
| 290 | pub const OS: &str = "aix"; | |
| 291 | pub const DLL_PREFIX: &str = "lib"; | |
| 292 | pub const DLL_SUFFIX: &str = ".a"; | |
| 293 | pub const DLL_EXTENSION: &str = "a"; | |
| 294 | pub const EXE_SUFFIX: &str = ""; | |
| 295 | pub const EXE_EXTENSION: &str = ""; | |
| 296 | } | |
| 297 | ||
| 298 | #[cfg(target_os = "nuttx")] | |
| 299 | pub mod os { | |
| 300 | pub const FAMILY: &str = "unix"; | |
| 301 | pub const OS: &str = "nuttx"; | |
| 302 | pub const DLL_PREFIX: &str = "lib"; | |
| 303 | pub const DLL_SUFFIX: &str = ".so"; | |
| 304 | pub const DLL_EXTENSION: &str = "so"; | |
| 305 | pub const EXE_SUFFIX: &str = ""; | |
| 306 | pub const EXE_EXTENSION: &str = ""; | |
| 307 | } |
library/std/src/sys/pal/unix/mod.rs-1| ... | ... | @@ -6,7 +6,6 @@ use crate::io::ErrorKind; |
| 6 | 6 | #[macro_use] |
| 7 | 7 | pub mod weak; |
| 8 | 8 | |
| 9 | pub mod env; | |
| 10 | 9 | #[cfg(target_os = "fuchsia")] |
| 11 | 10 | pub mod fuchsia; |
| 12 | 11 | pub mod futex; |
library/std/src/sys/pal/unsupported/env.rs deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | pub mod os { | |
| 2 | pub const FAMILY: &str = ""; | |
| 3 | pub const OS: &str = ""; | |
| 4 | pub const DLL_PREFIX: &str = ""; | |
| 5 | pub const DLL_SUFFIX: &str = ""; | |
| 6 | pub const DLL_EXTENSION: &str = ""; | |
| 7 | pub const EXE_SUFFIX: &str = ""; | |
| 8 | pub const EXE_EXTENSION: &str = ""; | |
| 9 | } |
library/std/src/sys/pal/unsupported/mod.rs-1| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | 1 | #![deny(unsafe_op_in_unsafe_fn)] |
| 2 | 2 | |
| 3 | pub mod env; | |
| 4 | 3 | pub mod os; |
| 5 | 4 | pub mod pipe; |
| 6 | 5 | pub mod thread; |
library/std/src/sys/pal/wasi/env.rs deleted-11| ... | ... | @@ -1,11 +0,0 @@ |
| 1 | #![forbid(unsafe_op_in_unsafe_fn)] | |
| 2 | ||
| 3 | pub mod os { | |
| 4 | pub const FAMILY: &str = ""; | |
| 5 | pub const OS: &str = ""; | |
| 6 | pub const DLL_PREFIX: &str = ""; | |
| 7 | pub const DLL_SUFFIX: &str = ".wasm"; | |
| 8 | pub const DLL_EXTENSION: &str = "wasm"; | |
| 9 | pub const EXE_SUFFIX: &str = ".wasm"; | |
| 10 | pub const EXE_EXTENSION: &str = "wasm"; | |
| 11 | } |
library/std/src/sys/pal/wasi/mod.rs-1| ... | ... | @@ -13,7 +13,6 @@ |
| 13 | 13 | //! compiling for wasm. That way it's a compile time error for something that's |
| 14 | 14 | //! guaranteed to be a runtime error! |
| 15 | 15 | |
| 16 | pub mod env; | |
| 17 | 16 | #[allow(unused)] |
| 18 | 17 | #[path = "../wasm/atomics/futex.rs"] |
| 19 | 18 | pub mod futex; |
library/std/src/sys/pal/wasip2/mod.rs-2| ... | ... | @@ -6,8 +6,6 @@ |
| 6 | 6 | //! To begin with, this target mirrors the wasi target 1 to 1, but over |
| 7 | 7 | //! time this will change significantly. |
| 8 | 8 | |
| 9 | #[path = "../wasi/env.rs"] | |
| 10 | pub mod env; | |
| 11 | 9 | #[allow(unused)] |
| 12 | 10 | #[path = "../wasm/atomics/futex.rs"] |
| 13 | 11 | pub mod futex; |
library/std/src/sys/pal/wasm/env.rs deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | pub mod os { | |
| 2 | pub const FAMILY: &str = ""; | |
| 3 | pub const OS: &str = ""; | |
| 4 | pub const DLL_PREFIX: &str = ""; | |
| 5 | pub const DLL_SUFFIX: &str = ".wasm"; | |
| 6 | pub const DLL_EXTENSION: &str = "wasm"; | |
| 7 | pub const EXE_SUFFIX: &str = ".wasm"; | |
| 8 | pub const EXE_EXTENSION: &str = "wasm"; | |
| 9 | } |
library/std/src/sys/pal/wasm/mod.rs-1| ... | ... | @@ -16,7 +16,6 @@ |
| 16 | 16 | |
| 17 | 17 | #![deny(unsafe_op_in_unsafe_fn)] |
| 18 | 18 | |
| 19 | pub mod env; | |
| 20 | 19 | #[path = "../unsupported/os.rs"] |
| 21 | 20 | pub mod os; |
| 22 | 21 | #[path = "../unsupported/pipe.rs"] |
library/std/src/sys/pal/windows/env.rs deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | pub mod os { | |
| 2 | pub const FAMILY: &str = "windows"; | |
| 3 | pub const OS: &str = "windows"; | |
| 4 | pub const DLL_PREFIX: &str = ""; | |
| 5 | pub const DLL_SUFFIX: &str = ".dll"; | |
| 6 | pub const DLL_EXTENSION: &str = "dll"; | |
| 7 | pub const EXE_SUFFIX: &str = ".exe"; | |
| 8 | pub const EXE_EXTENSION: &str = "exe"; | |
| 9 | } |
library/std/src/sys/pal/windows/mod.rs-1| ... | ... | @@ -15,7 +15,6 @@ pub mod compat; |
| 15 | 15 | pub mod api; |
| 16 | 16 | |
| 17 | 17 | pub mod c; |
| 18 | pub mod env; | |
| 19 | 18 | #[cfg(not(target_vendor = "win7"))] |
| 20 | 19 | pub mod futex; |
| 21 | 20 | pub mod handle; |
library/std/src/sys/pal/xous/mod.rs-2| ... | ... | @@ -1,7 +1,5 @@ |
| 1 | 1 | #![forbid(unsafe_op_in_unsafe_fn)] |
| 2 | 2 | |
| 3 | #[path = "../unsupported/env.rs"] | |
| 4 | pub mod env; | |
| 5 | 3 | pub mod os; |
| 6 | 4 | #[path = "../unsupported/pipe.rs"] |
| 7 | 5 | pub mod pipe; |
library/std/src/sys/pal/zkvm/mod.rs-1| ... | ... | @@ -11,7 +11,6 @@ |
| 11 | 11 | pub const WORD_SIZE: usize = size_of::<u32>(); |
| 12 | 12 | |
| 13 | 13 | pub mod abi; |
| 14 | pub mod env; | |
| 15 | 14 | pub mod os; |
| 16 | 15 | #[path = "../unsupported/pipe.rs"] |
| 17 | 16 | pub mod pipe; |
src/bootstrap/src/core/config/config.rs+115-18| ... | ... | @@ -6,6 +6,7 @@ |
| 6 | 6 | use std::cell::{Cell, RefCell}; |
| 7 | 7 | use std::collections::{BTreeSet, HashMap, HashSet}; |
| 8 | 8 | use std::fmt::{self, Display}; |
| 9 | use std::hash::Hash; | |
| 9 | 10 | use std::io::IsTerminal; |
| 10 | 11 | use std::path::{Path, PathBuf, absolute}; |
| 11 | 12 | use std::process::Command; |
| ... | ... | @@ -701,6 +702,7 @@ pub(crate) struct TomlConfig { |
| 701 | 702 | target: Option<HashMap<String, TomlTarget>>, |
| 702 | 703 | dist: Option<Dist>, |
| 703 | 704 | profile: Option<String>, |
| 705 | include: Option<Vec<PathBuf>>, | |
| 704 | 706 | } |
| 705 | 707 | |
| 706 | 708 | /// This enum is used for deserializing change IDs from TOML, allowing both numeric values and the string `"ignore"`. |
| ... | ... | @@ -747,27 +749,35 @@ enum ReplaceOpt { |
| 747 | 749 | } |
| 748 | 750 | |
| 749 | 751 | trait Merge { |
| 750 | fn merge(&mut self, other: Self, replace: ReplaceOpt); | |
| 752 | fn merge( | |
| 753 | &mut self, | |
| 754 | parent_config_path: Option<PathBuf>, | |
| 755 | included_extensions: &mut HashSet<PathBuf>, | |
| 756 | other: Self, | |
| 757 | replace: ReplaceOpt, | |
| 758 | ); | |
| 751 | 759 | } |
| 752 | 760 | |
| 753 | 761 | impl Merge for TomlConfig { |
| 754 | 762 | fn merge( |
| 755 | 763 | &mut self, |
| 756 | TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id }: Self, | |
| 764 | parent_config_path: Option<PathBuf>, | |
| 765 | included_extensions: &mut HashSet<PathBuf>, | |
| 766 | TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self, | |
| 757 | 767 | replace: ReplaceOpt, |
| 758 | 768 | ) { |
| 759 | 769 | fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) { |
| 760 | 770 | if let Some(new) = y { |
| 761 | 771 | if let Some(original) = x { |
| 762 | original.merge(new, replace); | |
| 772 | original.merge(None, &mut Default::default(), new, replace); | |
| 763 | 773 | } else { |
| 764 | 774 | *x = Some(new); |
| 765 | 775 | } |
| 766 | 776 | } |
| 767 | 777 | } |
| 768 | 778 | |
| 769 | self.change_id.inner.merge(change_id.inner, replace); | |
| 770 | self.profile.merge(profile, replace); | |
| 779 | self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace); | |
| 780 | self.profile.merge(None, &mut Default::default(), profile, replace); | |
| 771 | 781 | |
| 772 | 782 | do_merge(&mut self.build, build, replace); |
| 773 | 783 | do_merge(&mut self.install, install, replace); |
| ... | ... | @@ -782,13 +792,50 @@ impl Merge for TomlConfig { |
| 782 | 792 | (Some(original_target), Some(new_target)) => { |
| 783 | 793 | for (triple, new) in new_target { |
| 784 | 794 | if let Some(original) = original_target.get_mut(&triple) { |
| 785 | original.merge(new, replace); | |
| 795 | original.merge(None, &mut Default::default(), new, replace); | |
| 786 | 796 | } else { |
| 787 | 797 | original_target.insert(triple, new); |
| 788 | 798 | } |
| 789 | 799 | } |
| 790 | 800 | } |
| 791 | 801 | } |
| 802 | ||
| 803 | let parent_dir = parent_config_path | |
| 804 | .as_ref() | |
| 805 | .and_then(|p| p.parent().map(ToOwned::to_owned)) | |
| 806 | .unwrap_or_default(); | |
| 807 | ||
| 808 | // `include` handled later since we ignore duplicates using `ReplaceOpt::IgnoreDuplicate` to | |
| 809 | // keep the upper-level configuration to take precedence. | |
| 810 | for include_path in include.clone().unwrap_or_default().iter().rev() { | |
| 811 | let include_path = parent_dir.join(include_path); | |
| 812 | let include_path = include_path.canonicalize().unwrap_or_else(|e| { | |
| 813 | eprintln!("ERROR: Failed to canonicalize '{}' path: {e}", include_path.display()); | |
| 814 | exit!(2); | |
| 815 | }); | |
| 816 | ||
| 817 | let included_toml = Config::get_toml_inner(&include_path).unwrap_or_else(|e| { | |
| 818 | eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display()); | |
| 819 | exit!(2); | |
| 820 | }); | |
| 821 | ||
| 822 | assert!( | |
| 823 | included_extensions.insert(include_path.clone()), | |
| 824 | "Cyclic inclusion detected: '{}' is being included again before its previous inclusion was fully processed.", | |
| 825 | include_path.display() | |
| 826 | ); | |
| 827 | ||
| 828 | self.merge( | |
| 829 | Some(include_path.clone()), | |
| 830 | included_extensions, | |
| 831 | included_toml, | |
| 832 | // Ensures that parent configuration always takes precedence | |
| 833 | // over child configurations. | |
| 834 | ReplaceOpt::IgnoreDuplicate, | |
| 835 | ); | |
| 836 | ||
| 837 | included_extensions.remove(&include_path); | |
| 838 | } | |
| 792 | 839 | } |
| 793 | 840 | } |
| 794 | 841 | |
| ... | ... | @@ -803,7 +850,13 @@ macro_rules! define_config { |
| 803 | 850 | } |
| 804 | 851 | |
| 805 | 852 | impl Merge for $name { |
| 806 | fn merge(&mut self, other: Self, replace: ReplaceOpt) { | |
| 853 | fn merge( | |
| 854 | &mut self, | |
| 855 | _parent_config_path: Option<PathBuf>, | |
| 856 | _included_extensions: &mut HashSet<PathBuf>, | |
| 857 | other: Self, | |
| 858 | replace: ReplaceOpt | |
| 859 | ) { | |
| 807 | 860 | $( |
| 808 | 861 | match replace { |
| 809 | 862 | ReplaceOpt::IgnoreDuplicate => { |
| ... | ... | @@ -903,7 +956,13 @@ macro_rules! define_config { |
| 903 | 956 | } |
| 904 | 957 | |
| 905 | 958 | impl<T> Merge for Option<T> { |
| 906 | fn merge(&mut self, other: Self, replace: ReplaceOpt) { | |
| 959 | fn merge( | |
| 960 | &mut self, | |
| 961 | _parent_config_path: Option<PathBuf>, | |
| 962 | _included_extensions: &mut HashSet<PathBuf>, | |
| 963 | other: Self, | |
| 964 | replace: ReplaceOpt, | |
| 965 | ) { | |
| 907 | 966 | match replace { |
| 908 | 967 | ReplaceOpt::IgnoreDuplicate => { |
| 909 | 968 | if self.is_none() { |
| ... | ... | @@ -1363,13 +1422,15 @@ impl Config { |
| 1363 | 1422 | Self::get_toml(&builder_config_path) |
| 1364 | 1423 | } |
| 1365 | 1424 | |
| 1366 | #[cfg(test)] | |
| 1367 | pub(crate) fn get_toml(_: &Path) -> Result<TomlConfig, toml::de::Error> { | |
| 1368 | Ok(TomlConfig::default()) | |
| 1425 | pub(crate) fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> { | |
| 1426 | #[cfg(test)] | |
| 1427 | return Ok(TomlConfig::default()); | |
| 1428 | ||
| 1429 | #[cfg(not(test))] | |
| 1430 | Self::get_toml_inner(file) | |
| 1369 | 1431 | } |
| 1370 | 1432 | |
| 1371 | #[cfg(not(test))] | |
| 1372 | pub(crate) fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> { | |
| 1433 | fn get_toml_inner(file: &Path) -> Result<TomlConfig, toml::de::Error> { | |
| 1373 | 1434 | let contents = |
| 1374 | 1435 | t!(fs::read_to_string(file), format!("config file {} not found", file.display())); |
| 1375 | 1436 | // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of |
| ... | ... | @@ -1548,7 +1609,8 @@ impl Config { |
| 1548 | 1609 | // but not if `bootstrap.toml` hasn't been created. |
| 1549 | 1610 | let mut toml = if !using_default_path || toml_path.exists() { |
| 1550 | 1611 | config.config = Some(if cfg!(not(test)) { |
| 1551 | toml_path.canonicalize().unwrap() | |
| 1612 | toml_path = toml_path.canonicalize().unwrap(); | |
| 1613 | toml_path.clone() | |
| 1552 | 1614 | } else { |
| 1553 | 1615 | toml_path.clone() |
| 1554 | 1616 | }); |
| ... | ... | @@ -1576,6 +1638,26 @@ impl Config { |
| 1576 | 1638 | toml.profile = Some("dist".into()); |
| 1577 | 1639 | } |
| 1578 | 1640 | |
| 1641 | // Reverse the list to ensure the last added config extension remains the most dominant. | |
| 1642 | // For example, given ["a.toml", "b.toml"], "b.toml" should take precedence over "a.toml". | |
| 1643 | // | |
| 1644 | // This must be handled before applying the `profile` since `include`s should always take | |
| 1645 | // precedence over `profile`s. | |
| 1646 | for include_path in toml.include.clone().unwrap_or_default().iter().rev() { | |
| 1647 | let include_path = toml_path.parent().unwrap().join(include_path); | |
| 1648 | ||
| 1649 | let included_toml = get_toml(&include_path).unwrap_or_else(|e| { | |
| 1650 | eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display()); | |
| 1651 | exit!(2); | |
| 1652 | }); | |
| 1653 | toml.merge( | |
| 1654 | Some(include_path), | |
| 1655 | &mut Default::default(), | |
| 1656 | included_toml, | |
| 1657 | ReplaceOpt::IgnoreDuplicate, | |
| 1658 | ); | |
| 1659 | } | |
| 1660 | ||
| 1579 | 1661 | if let Some(include) = &toml.profile { |
| 1580 | 1662 | // Allows creating alias for profile names, allowing |
| 1581 | 1663 | // profiles to be renamed while maintaining back compatibility |
| ... | ... | @@ -1597,7 +1679,12 @@ impl Config { |
| 1597 | 1679 | ); |
| 1598 | 1680 | exit!(2); |
| 1599 | 1681 | }); |
| 1600 | toml.merge(included_toml, ReplaceOpt::IgnoreDuplicate); | |
| 1682 | toml.merge( | |
| 1683 | Some(include_path), | |
| 1684 | &mut Default::default(), | |
| 1685 | included_toml, | |
| 1686 | ReplaceOpt::IgnoreDuplicate, | |
| 1687 | ); | |
| 1601 | 1688 | } |
| 1602 | 1689 | |
| 1603 | 1690 | let mut override_toml = TomlConfig::default(); |
| ... | ... | @@ -1608,7 +1695,12 @@ impl Config { |
| 1608 | 1695 | |
| 1609 | 1696 | let mut err = match get_table(option) { |
| 1610 | 1697 | Ok(v) => { |
| 1611 | override_toml.merge(v, ReplaceOpt::ErrorOnDuplicate); | |
| 1698 | override_toml.merge( | |
| 1699 | None, | |
| 1700 | &mut Default::default(), | |
| 1701 | v, | |
| 1702 | ReplaceOpt::ErrorOnDuplicate, | |
| 1703 | ); | |
| 1612 | 1704 | continue; |
| 1613 | 1705 | } |
| 1614 | 1706 | Err(e) => e, |
| ... | ... | @@ -1619,7 +1711,12 @@ impl Config { |
| 1619 | 1711 | if !value.contains('"') { |
| 1620 | 1712 | match get_table(&format!(r#"{key}="{value}""#)) { |
| 1621 | 1713 | Ok(v) => { |
| 1622 | override_toml.merge(v, ReplaceOpt::ErrorOnDuplicate); | |
| 1714 | override_toml.merge( | |
| 1715 | None, | |
| 1716 | &mut Default::default(), | |
| 1717 | v, | |
| 1718 | ReplaceOpt::ErrorOnDuplicate, | |
| 1719 | ); | |
| 1623 | 1720 | continue; |
| 1624 | 1721 | } |
| 1625 | 1722 | Err(e) => err = e, |
| ... | ... | @@ -1629,7 +1726,7 @@ impl Config { |
| 1629 | 1726 | eprintln!("failed to parse override `{option}`: `{err}"); |
| 1630 | 1727 | exit!(2) |
| 1631 | 1728 | } |
| 1632 | toml.merge(override_toml, ReplaceOpt::Override); | |
| 1729 | toml.merge(None, &mut Default::default(), override_toml, ReplaceOpt::Override); | |
| 1633 | 1730 | |
| 1634 | 1731 | config.change_id = toml.change_id.inner; |
| 1635 | 1732 |
src/bootstrap/src/core/config/tests.rs+209-2| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | use std::collections::BTreeSet; |
| 2 | use std::env; | |
| 3 | 2 | use std::fs::{File, remove_file}; |
| 4 | 3 | use std::io::Write; |
| 5 | use std::path::Path; | |
| 4 | use std::path::{Path, PathBuf}; | |
| 5 | use std::{env, fs}; | |
| 6 | 6 | |
| 7 | 7 | use build_helper::ci::CiEnv; |
| 8 | 8 | use clap::CommandFactory; |
| ... | ... | @@ -23,6 +23,27 @@ pub(crate) fn parse(config: &str) -> Config { |
| 23 | 23 | ) |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> { | |
| 27 | let contents = std::fs::read_to_string(file).unwrap(); | |
| 28 | toml::from_str(&contents).and_then(|table: toml::Value| TomlConfig::deserialize(table)) | |
| 29 | } | |
| 30 | ||
| 31 | /// Helps with debugging by using consistent test-specific directories instead of | |
| 32 | /// random temporary directories. | |
| 33 | fn prepare_test_specific_dir() -> PathBuf { | |
| 34 | let current = std::thread::current(); | |
| 35 | // Replace "::" with "_" to make it safe for directory names on Windows systems | |
| 36 | let test_path = current.name().unwrap().replace("::", "_"); | |
| 37 | ||
| 38 | let testdir = parse("").tempdir().join(test_path); | |
| 39 | ||
| 40 | // clean up any old test files | |
| 41 | let _ = fs::remove_dir_all(&testdir); | |
| 42 | let _ = fs::create_dir_all(&testdir); | |
| 43 | ||
| 44 | testdir | |
| 45 | } | |
| 46 | ||
| 26 | 47 | #[test] |
| 27 | 48 | fn download_ci_llvm() { |
| 28 | 49 | let config = parse("llvm.download-ci-llvm = false"); |
| ... | ... | @@ -539,3 +560,189 @@ fn test_ci_flag() { |
| 539 | 560 | let config = Config::parse_inner(Flags::parse(&["check".into()]), |&_| toml::from_str("")); |
| 540 | 561 | assert_eq!(config.is_running_on_ci, CiEnv::is_ci()); |
| 541 | 562 | } |
| 563 | ||
| 564 | #[test] | |
| 565 | fn test_precedence_of_includes() { | |
| 566 | let testdir = prepare_test_specific_dir(); | |
| 567 | ||
| 568 | let root_config = testdir.join("config.toml"); | |
| 569 | let root_config_content = br#" | |
| 570 | include = ["./extension.toml"] | |
| 571 | ||
| 572 | [llvm] | |
| 573 | link-jobs = 2 | |
| 574 | "#; | |
| 575 | File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); | |
| 576 | ||
| 577 | let extension = testdir.join("extension.toml"); | |
| 578 | let extension_content = br#" | |
| 579 | change-id=543 | |
| 580 | include = ["./extension2.toml"] | |
| 581 | "#; | |
| 582 | File::create(extension).unwrap().write_all(extension_content).unwrap(); | |
| 583 | ||
| 584 | let extension = testdir.join("extension2.toml"); | |
| 585 | let extension_content = br#" | |
| 586 | change-id=742 | |
| 587 | ||
| 588 | [llvm] | |
| 589 | link-jobs = 10 | |
| 590 | ||
| 591 | [build] | |
| 592 | description = "Some creative description" | |
| 593 | "#; | |
| 594 | File::create(extension).unwrap().write_all(extension_content).unwrap(); | |
| 595 | ||
| 596 | let config = Config::parse_inner( | |
| 597 | Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), | |
| 598 | get_toml, | |
| 599 | ); | |
| 600 | ||
| 601 | assert_eq!(config.change_id.unwrap(), ChangeId::Id(543)); | |
| 602 | assert_eq!(config.llvm_link_jobs.unwrap(), 2); | |
| 603 | assert_eq!(config.description.unwrap(), "Some creative description"); | |
| 604 | } | |
| 605 | ||
| 606 | #[test] | |
| 607 | #[should_panic(expected = "Cyclic inclusion detected")] | |
| 608 | fn test_cyclic_include_direct() { | |
| 609 | let testdir = prepare_test_specific_dir(); | |
| 610 | ||
| 611 | let root_config = testdir.join("config.toml"); | |
| 612 | let root_config_content = br#" | |
| 613 | include = ["./extension.toml"] | |
| 614 | "#; | |
| 615 | File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); | |
| 616 | ||
| 617 | let extension = testdir.join("extension.toml"); | |
| 618 | let extension_content = br#" | |
| 619 | include = ["./config.toml"] | |
| 620 | "#; | |
| 621 | File::create(extension).unwrap().write_all(extension_content).unwrap(); | |
| 622 | ||
| 623 | let config = Config::parse_inner( | |
| 624 | Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), | |
| 625 | get_toml, | |
| 626 | ); | |
| 627 | } | |
| 628 | ||
| 629 | #[test] | |
| 630 | #[should_panic(expected = "Cyclic inclusion detected")] | |
| 631 | fn test_cyclic_include_indirect() { | |
| 632 | let testdir = prepare_test_specific_dir(); | |
| 633 | ||
| 634 | let root_config = testdir.join("config.toml"); | |
| 635 | let root_config_content = br#" | |
| 636 | include = ["./extension.toml"] | |
| 637 | "#; | |
| 638 | File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); | |
| 639 | ||
| 640 | let extension = testdir.join("extension.toml"); | |
| 641 | let extension_content = br#" | |
| 642 | include = ["./extension2.toml"] | |
| 643 | "#; | |
| 644 | File::create(extension).unwrap().write_all(extension_content).unwrap(); | |
| 645 | ||
| 646 | let extension = testdir.join("extension2.toml"); | |
| 647 | let extension_content = br#" | |
| 648 | include = ["./extension3.toml"] | |
| 649 | "#; | |
| 650 | File::create(extension).unwrap().write_all(extension_content).unwrap(); | |
| 651 | ||
| 652 | let extension = testdir.join("extension3.toml"); | |
| 653 | let extension_content = br#" | |
| 654 | include = ["./extension.toml"] | |
| 655 | "#; | |
| 656 | File::create(extension).unwrap().write_all(extension_content).unwrap(); | |
| 657 | ||
| 658 | let config = Config::parse_inner( | |
| 659 | Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), | |
| 660 | get_toml, | |
| 661 | ); | |
| 662 | } | |
| 663 | ||
| 664 | #[test] | |
| 665 | fn test_include_absolute_paths() { | |
| 666 | let testdir = prepare_test_specific_dir(); | |
| 667 | ||
| 668 | let extension = testdir.join("extension.toml"); | |
| 669 | File::create(&extension).unwrap().write_all(&[]).unwrap(); | |
| 670 | ||
| 671 | let root_config = testdir.join("config.toml"); | |
| 672 | let extension_absolute_path = | |
| 673 | extension.canonicalize().unwrap().to_str().unwrap().replace('\\', r"\\"); | |
| 674 | let root_config_content = format!(r#"include = ["{}"]"#, extension_absolute_path); | |
| 675 | File::create(&root_config).unwrap().write_all(root_config_content.as_bytes()).unwrap(); | |
| 676 | ||
| 677 | let config = Config::parse_inner( | |
| 678 | Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), | |
| 679 | get_toml, | |
| 680 | ); | |
| 681 | } | |
| 682 | ||
| 683 | #[test] | |
| 684 | fn test_include_relative_paths() { | |
| 685 | let testdir = prepare_test_specific_dir(); | |
| 686 | ||
| 687 | let _ = fs::create_dir_all(&testdir.join("subdir/another_subdir")); | |
| 688 | ||
| 689 | let root_config = testdir.join("config.toml"); | |
| 690 | let root_config_content = br#" | |
| 691 | include = ["./subdir/extension.toml"] | |
| 692 | "#; | |
| 693 | File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); | |
| 694 | ||
| 695 | let extension = testdir.join("subdir/extension.toml"); | |
| 696 | let extension_content = br#" | |
| 697 | include = ["../extension2.toml"] | |
| 698 | "#; | |
| 699 | File::create(extension).unwrap().write_all(extension_content).unwrap(); | |
| 700 | ||
| 701 | let extension = testdir.join("extension2.toml"); | |
| 702 | let extension_content = br#" | |
| 703 | include = ["./subdir/another_subdir/extension3.toml"] | |
| 704 | "#; | |
| 705 | File::create(extension).unwrap().write_all(extension_content).unwrap(); | |
| 706 | ||
| 707 | let extension = testdir.join("subdir/another_subdir/extension3.toml"); | |
| 708 | let extension_content = br#" | |
| 709 | include = ["../../extension4.toml"] | |
| 710 | "#; | |
| 711 | File::create(extension).unwrap().write_all(extension_content).unwrap(); | |
| 712 | ||
| 713 | let extension = testdir.join("extension4.toml"); | |
| 714 | File::create(extension).unwrap().write_all(&[]).unwrap(); | |
| 715 | ||
| 716 | let config = Config::parse_inner( | |
| 717 | Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), | |
| 718 | get_toml, | |
| 719 | ); | |
| 720 | } | |
| 721 | ||
| 722 | #[test] | |
| 723 | fn test_include_precedence_over_profile() { | |
| 724 | let testdir = prepare_test_specific_dir(); | |
| 725 | ||
| 726 | let root_config = testdir.join("config.toml"); | |
| 727 | let root_config_content = br#" | |
| 728 | profile = "dist" | |
| 729 | include = ["./extension.toml"] | |
| 730 | "#; | |
| 731 | File::create(&root_config).unwrap().write_all(root_config_content).unwrap(); | |
| 732 | ||
| 733 | let extension = testdir.join("extension.toml"); | |
| 734 | let extension_content = br#" | |
| 735 | [rust] | |
| 736 | channel = "dev" | |
| 737 | "#; | |
| 738 | File::create(extension).unwrap().write_all(extension_content).unwrap(); | |
| 739 | ||
| 740 | let config = Config::parse_inner( | |
| 741 | Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]), | |
| 742 | get_toml, | |
| 743 | ); | |
| 744 | ||
| 745 | // "dist" profile would normally set the channel to "auto-detect", but includes should | |
| 746 | // override profile settings, so we expect this to be "dev" here. | |
| 747 | assert_eq!(config.channel, "dev"); | |
| 748 | } |
src/bootstrap/src/utils/change_tracker.rs+5| ... | ... | @@ -396,4 +396,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ |
| 396 | 396 | severity: ChangeSeverity::Info, |
| 397 | 397 | summary: "Added a new option `build.compiletest-use-stage0-libtest` to force `compiletest` to use the stage 0 libtest.", |
| 398 | 398 | }, |
| 399 | ChangeInfo { | |
| 400 | change_id: 138934, | |
| 401 | severity: ChangeSeverity::Info, | |
| 402 | summary: "Added new option `include` to create config extensions.", | |
| 403 | }, | |
| 399 | 404 | ]; |
src/ci/citool/Cargo.lock+67| ... | ... | @@ -64,12 +64,63 @@ version = "1.0.95" |
| 64 | 64 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 65 | 65 | checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" |
| 66 | 66 | |
| 67 | [[package]] | |
| 68 | name = "askama" | |
| 69 | version = "0.13.1" | |
| 70 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 71 | checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7" | |
| 72 | dependencies = [ | |
| 73 | "askama_derive", | |
| 74 | "itoa", | |
| 75 | "percent-encoding", | |
| 76 | "serde", | |
| 77 | "serde_json", | |
| 78 | ] | |
| 79 | ||
| 80 | [[package]] | |
| 81 | name = "askama_derive" | |
| 82 | version = "0.13.1" | |
| 83 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 84 | checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac" | |
| 85 | dependencies = [ | |
| 86 | "askama_parser", | |
| 87 | "basic-toml", | |
| 88 | "memchr", | |
| 89 | "proc-macro2", | |
| 90 | "quote", | |
| 91 | "rustc-hash", | |
| 92 | "serde", | |
| 93 | "serde_derive", | |
| 94 | "syn", | |
| 95 | ] | |
| 96 | ||
| 97 | [[package]] | |
| 98 | name = "askama_parser" | |
| 99 | version = "0.13.0" | |
| 100 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 101 | checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f" | |
| 102 | dependencies = [ | |
| 103 | "memchr", | |
| 104 | "serde", | |
| 105 | "serde_derive", | |
| 106 | "winnow", | |
| 107 | ] | |
| 108 | ||
| 67 | 109 | [[package]] |
| 68 | 110 | name = "base64" |
| 69 | 111 | version = "0.22.1" |
| 70 | 112 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 71 | 113 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" |
| 72 | 114 | |
| 115 | [[package]] | |
| 116 | name = "basic-toml" | |
| 117 | version = "0.1.10" | |
| 118 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 119 | checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" | |
| 120 | dependencies = [ | |
| 121 | "serde", | |
| 122 | ] | |
| 123 | ||
| 73 | 124 | [[package]] |
| 74 | 125 | name = "build_helper" |
| 75 | 126 | version = "0.1.0" |
| ... | ... | @@ -104,6 +155,7 @@ name = "citool" |
| 104 | 155 | version = "0.1.0" |
| 105 | 156 | dependencies = [ |
| 106 | 157 | "anyhow", |
| 158 | "askama", | |
| 107 | 159 | "build_helper", |
| 108 | 160 | "clap", |
| 109 | 161 | "csv", |
| ... | ... | @@ -646,6 +698,12 @@ dependencies = [ |
| 646 | 698 | "windows-sys 0.52.0", |
| 647 | 699 | ] |
| 648 | 700 | |
| 701 | [[package]] | |
| 702 | name = "rustc-hash" | |
| 703 | version = "2.1.1" | |
| 704 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 705 | checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" | |
| 706 | ||
| 649 | 707 | [[package]] |
| 650 | 708 | name = "rustls" |
| 651 | 709 | version = "0.23.23" |
| ... | ... | @@ -1026,6 +1084,15 @@ version = "0.52.6" |
| 1026 | 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 1027 | 1085 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" |
| 1028 | 1086 | |
| 1087 | [[package]] | |
| 1088 | name = "winnow" | |
| 1089 | version = "0.7.6" | |
| 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1091 | checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" | |
| 1092 | dependencies = [ | |
| 1093 | "memchr", | |
| 1094 | ] | |
| 1095 | ||
| 1029 | 1096 | [[package]] |
| 1030 | 1097 | name = "write16" |
| 1031 | 1098 | version = "1.0.0" |
src/ci/citool/Cargo.toml+1| ... | ... | @@ -5,6 +5,7 @@ edition = "2021" |
| 5 | 5 | |
| 6 | 6 | [dependencies] |
| 7 | 7 | anyhow = "1" |
| 8 | askama = "0.13" | |
| 8 | 9 | clap = { version = "4.5", features = ["derive"] } |
| 9 | 10 | csv = "1" |
| 10 | 11 | diff = "0.1" |
src/ci/citool/src/analysis.rs+6-7| ... | ... | @@ -8,9 +8,9 @@ use build_helper::metrics::{ |
| 8 | 8 | }; |
| 9 | 9 | |
| 10 | 10 | use crate::github::JobInfoResolver; |
| 11 | use crate::metrics; | |
| 12 | 11 | use crate::metrics::{JobMetrics, JobName, get_test_suites}; |
| 13 | 12 | use crate::utils::{output_details, pluralize}; |
| 13 | use crate::{metrics, utils}; | |
| 14 | 14 | |
| 15 | 15 | /// Outputs durations of individual bootstrap steps from the gathered bootstrap invocations, |
| 16 | 16 | /// and also a table with summarized information about executed tests. |
| ... | ... | @@ -394,18 +394,17 @@ fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData { |
| 394 | 394 | // Poor man's detection of doctests based on the "(line XYZ)" suffix |
| 395 | 395 | let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. }) |
| 396 | 396 | && test.name.contains("(line"); |
| 397 | let test_entry = Test { name: generate_test_name(&test.name), stage, is_doctest }; | |
| 397 | let test_entry = Test { | |
| 398 | name: utils::normalize_path_delimiters(&test.name).to_string(), | |
| 399 | stage, | |
| 400 | is_doctest, | |
| 401 | }; | |
| 398 | 402 | tests.insert(test_entry, test.outcome.clone()); |
| 399 | 403 | } |
| 400 | 404 | } |
| 401 | 405 | TestSuiteData { tests } |
| 402 | 406 | } |
| 403 | 407 | |
| 404 | /// Normalizes Windows-style path delimiters to Unix-style paths. | |
| 405 | fn generate_test_name(name: &str) -> String { | |
| 406 | name.replace('\\', "/") | |
| 407 | } | |
| 408 | ||
| 409 | 408 | /// Prints test changes in Markdown format to stdout. |
| 410 | 409 | fn report_test_diffs( |
| 411 | 410 | diff: AggregatedTestDiffs, |
src/ci/citool/src/main.rs+31-3| ... | ... | @@ -4,6 +4,7 @@ mod datadog; |
| 4 | 4 | mod github; |
| 5 | 5 | mod jobs; |
| 6 | 6 | mod metrics; |
| 7 | mod test_dashboard; | |
| 7 | 8 | mod utils; |
| 8 | 9 | |
| 9 | 10 | use std::collections::{BTreeMap, HashMap}; |
| ... | ... | @@ -22,7 +23,8 @@ use crate::datadog::upload_datadog_metric; |
| 22 | 23 | use crate::github::JobInfoResolver; |
| 23 | 24 | use crate::jobs::RunType; |
| 24 | 25 | use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics}; |
| 25 | use crate::utils::load_env_var; | |
| 26 | use crate::test_dashboard::generate_test_dashboard; | |
| 27 | use crate::utils::{load_env_var, output_details}; | |
| 26 | 28 | |
| 27 | 29 | const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/.."); |
| 28 | 30 | const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker"); |
| ... | ... | @@ -180,12 +182,26 @@ fn postprocess_metrics( |
| 180 | 182 | } |
| 181 | 183 | |
| 182 | 184 | fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow::Result<()> { |
| 183 | let metrics = download_auto_job_metrics(&db, &parent, &current)?; | |
| 185 | let metrics = download_auto_job_metrics(&db, Some(&parent), &current)?; | |
| 184 | 186 | |
| 185 | 187 | println!("\nComparing {parent} (parent) -> {current} (this PR)\n"); |
| 186 | 188 | |
| 187 | 189 | let mut job_info_resolver = JobInfoResolver::new(); |
| 188 | 190 | output_test_diffs(&metrics, &mut job_info_resolver); |
| 191 | ||
| 192 | output_details("Test dashboard", || { | |
| 193 | println!( | |
| 194 | r#"\nRun | |
| 195 | ||
| 196 | ```bash | |
| 197 | cargo run --manifest-path src/ci/citool/Cargo.toml -- \ | |
| 198 | test-dashboard {current} --output-dir test-dashboard | |
| 199 | ``` | |
| 200 | And then open `test-dashboard/index.html` in your browser to see an overview of all executed tests. | |
| 201 | "# | |
| 202 | ); | |
| 203 | }); | |
| 204 | ||
| 189 | 205 | output_largest_duration_changes(&metrics, &mut job_info_resolver); |
| 190 | 206 | |
| 191 | 207 | Ok(()) |
| ... | ... | @@ -234,6 +250,14 @@ enum Args { |
| 234 | 250 | /// Current commit that will be compared to `parent`. |
| 235 | 251 | current: String, |
| 236 | 252 | }, |
| 253 | /// Generate a directory containing a HTML dashboard of test results from a CI run. | |
| 254 | TestDashboard { | |
| 255 | /// Commit SHA that was tested on CI to analyze. | |
| 256 | current: String, | |
| 257 | /// Output path for the HTML directory. | |
| 258 | #[clap(long)] | |
| 259 | output_dir: PathBuf, | |
| 260 | }, | |
| 237 | 261 | } |
| 238 | 262 | |
| 239 | 263 | #[derive(clap::ValueEnum, Clone)] |
| ... | ... | @@ -275,7 +299,11 @@ fn main() -> anyhow::Result<()> { |
| 275 | 299 | postprocess_metrics(metrics_path, parent, job_name)?; |
| 276 | 300 | } |
| 277 | 301 | Args::PostMergeReport { current, parent } => { |
| 278 | post_merge_report(load_db(default_jobs_file)?, current, parent)?; | |
| 302 | post_merge_report(load_db(&default_jobs_file)?, current, parent)?; | |
| 303 | } | |
| 304 | Args::TestDashboard { current, output_dir } => { | |
| 305 | let db = load_db(&default_jobs_file)?; | |
| 306 | generate_test_dashboard(db, &current, &output_dir)?; | |
| 279 | 307 | } |
| 280 | 308 | } |
| 281 | 309 |
src/ci/citool/src/metrics.rs+12-11| ... | ... | @@ -46,24 +46,25 @@ pub struct JobMetrics { |
| 46 | 46 | /// `parent` and `current` should be commit SHAs. |
| 47 | 47 | pub fn download_auto_job_metrics( |
| 48 | 48 | job_db: &JobDatabase, |
| 49 | parent: &str, | |
| 49 | parent: Option<&str>, | |
| 50 | 50 | current: &str, |
| 51 | 51 | ) -> anyhow::Result<HashMap<JobName, JobMetrics>> { |
| 52 | 52 | let mut jobs = HashMap::default(); |
| 53 | 53 | |
| 54 | 54 | for job in &job_db.auto_jobs { |
| 55 | 55 | eprintln!("Downloading metrics of job {}", job.name); |
| 56 | let metrics_parent = match download_job_metrics(&job.name, parent) { | |
| 57 | Ok(metrics) => Some(metrics), | |
| 58 | Err(error) => { | |
| 59 | eprintln!( | |
| 60 | r#"Did not find metrics for job `{}` at `{parent}`: {error:?}. | |
| 56 | let metrics_parent = | |
| 57 | parent.and_then(|parent| match download_job_metrics(&job.name, parent) { | |
| 58 | Ok(metrics) => Some(metrics), | |
| 59 | Err(error) => { | |
| 60 | eprintln!( | |
| 61 | r#"Did not find metrics for job `{}` at `{parent}`: {error:?}. | |
| 61 | 62 | Maybe it was newly added?"#, |
| 62 | job.name | |
| 63 | ); | |
| 64 | None | |
| 65 | } | |
| 66 | }; | |
| 63 | job.name | |
| 64 | ); | |
| 65 | None | |
| 66 | } | |
| 67 | }); | |
| 67 | 68 | let metrics_current = download_job_metrics(&job.name, current)?; |
| 68 | 69 | jobs.insert( |
| 69 | 70 | job.name.clone(), |
src/ci/citool/src/test_dashboard.rs created+216| ... | ... | @@ -0,0 +1,216 @@ |
| 1 | use std::collections::{BTreeMap, HashMap}; | |
| 2 | use std::fs::File; | |
| 3 | use std::io::BufWriter; | |
| 4 | use std::path::{Path, PathBuf}; | |
| 5 | ||
| 6 | use askama::Template; | |
| 7 | use build_helper::metrics::{TestOutcome, TestSuiteMetadata}; | |
| 8 | ||
| 9 | use crate::jobs::JobDatabase; | |
| 10 | use crate::metrics::{JobMetrics, JobName, download_auto_job_metrics, get_test_suites}; | |
| 11 | use crate::utils::normalize_path_delimiters; | |
| 12 | ||
| 13 | /// Generate a set of HTML files into a directory that contain a dashboard of test results. | |
| 14 | pub fn generate_test_dashboard( | |
| 15 | db: JobDatabase, | |
| 16 | current: &str, | |
| 17 | output_dir: &Path, | |
| 18 | ) -> anyhow::Result<()> { | |
| 19 | let metrics = download_auto_job_metrics(&db, None, current)?; | |
| 20 | let suites = gather_test_suites(&metrics); | |
| 21 | ||
| 22 | std::fs::create_dir_all(output_dir)?; | |
| 23 | ||
| 24 | let test_count = suites.test_count(); | |
| 25 | write_page(output_dir, "index.html", &TestSuitesPage { suites, test_count })?; | |
| 26 | ||
| 27 | Ok(()) | |
| 28 | } | |
| 29 | ||
| 30 | fn write_page<T: Template>(dir: &Path, name: &str, template: &T) -> anyhow::Result<()> { | |
| 31 | let mut file = BufWriter::new(File::create(dir.join(name))?); | |
| 32 | Template::write_into(template, &mut file)?; | |
| 33 | Ok(()) | |
| 34 | } | |
| 35 | ||
| 36 | fn gather_test_suites(job_metrics: &HashMap<JobName, JobMetrics>) -> TestSuites { | |
| 37 | struct CoarseTestSuite<'a> { | |
| 38 | tests: BTreeMap<String, Test<'a>>, | |
| 39 | } | |
| 40 | ||
| 41 | let mut suites: HashMap<String, CoarseTestSuite> = HashMap::new(); | |
| 42 | ||
| 43 | // First, gather tests from all jobs, stages and targets, and aggregate them per suite | |
| 44 | // Only work with compiletest suites. | |
| 45 | for (job, metrics) in job_metrics { | |
| 46 | let test_suites = get_test_suites(&metrics.current); | |
| 47 | for suite in test_suites { | |
| 48 | let (suite_name, stage, target) = match &suite.metadata { | |
| 49 | TestSuiteMetadata::CargoPackage { .. } => { | |
| 50 | continue; | |
| 51 | } | |
| 52 | TestSuiteMetadata::Compiletest { suite, stage, target, .. } => { | |
| 53 | (suite.clone(), *stage, target) | |
| 54 | } | |
| 55 | }; | |
| 56 | let suite_entry = suites | |
| 57 | .entry(suite_name.clone()) | |
| 58 | .or_insert_with(|| CoarseTestSuite { tests: Default::default() }); | |
| 59 | let test_metadata = TestMetadata { job, stage, target }; | |
| 60 | ||
| 61 | for test in &suite.tests { | |
| 62 | let test_name = normalize_test_name(&test.name, &suite_name); | |
| 63 | let (test_name, variant_name) = match test_name.rsplit_once('#') { | |
| 64 | Some((name, variant)) => (name.to_string(), variant.to_string()), | |
| 65 | None => (test_name, "".to_string()), | |
| 66 | }; | |
| 67 | let test_entry = suite_entry | |
| 68 | .tests | |
| 69 | .entry(test_name.clone()) | |
| 70 | .or_insert_with(|| Test { revisions: Default::default() }); | |
| 71 | let variant_entry = test_entry | |
| 72 | .revisions | |
| 73 | .entry(variant_name) | |
| 74 | .or_insert_with(|| TestResults { passed: vec![], ignored: vec![] }); | |
| 75 | ||
| 76 | match test.outcome { | |
| 77 | TestOutcome::Passed => { | |
| 78 | variant_entry.passed.push(test_metadata); | |
| 79 | } | |
| 80 | TestOutcome::Ignored { ignore_reason: _ } => { | |
| 81 | variant_entry.ignored.push(test_metadata); | |
| 82 | } | |
| 83 | TestOutcome::Failed => { | |
| 84 | eprintln!("Warning: failed test {test_name}"); | |
| 85 | } | |
| 86 | } | |
| 87 | } | |
| 88 | } | |
| 89 | } | |
| 90 | ||
| 91 | // Then, split the suites per directory | |
| 92 | let mut suites = suites.into_iter().collect::<Vec<_>>(); | |
| 93 | suites.sort_by(|a, b| a.0.cmp(&b.0)); | |
| 94 | ||
| 95 | let suites = suites | |
| 96 | .into_iter() | |
| 97 | .map(|(suite_name, suite)| TestSuite { group: build_test_group(&suite_name, suite.tests) }) | |
| 98 | .collect(); | |
| 99 | ||
| 100 | TestSuites { suites } | |
| 101 | } | |
| 102 | ||
| 103 | /// Recursively expand a test group based on filesystem hierarchy. | |
| 104 | fn build_test_group<'a>(name: &str, tests: BTreeMap<String, Test<'a>>) -> TestGroup<'a> { | |
| 105 | let mut root_tests = vec![]; | |
| 106 | let mut subdirs: BTreeMap<String, BTreeMap<String, Test<'a>>> = Default::default(); | |
| 107 | ||
| 108 | // Split tests into root tests and tests located in subdirectories | |
| 109 | for (name, test) in tests { | |
| 110 | let mut components = Path::new(&name).components().peekable(); | |
| 111 | let subdir = components.next().unwrap(); | |
| 112 | ||
| 113 | if components.peek().is_none() { | |
| 114 | // This is a root test | |
| 115 | root_tests.push((name, test)); | |
| 116 | } else { | |
| 117 | // This is a test in a nested directory | |
| 118 | let subdir_tests = | |
| 119 | subdirs.entry(subdir.as_os_str().to_str().unwrap().to_string()).or_default(); | |
| 120 | let test_name = | |
| 121 | components.into_iter().collect::<PathBuf>().to_str().unwrap().to_string(); | |
| 122 | subdir_tests.insert(test_name, test); | |
| 123 | } | |
| 124 | } | |
| 125 | let dirs = subdirs | |
| 126 | .into_iter() | |
| 127 | .map(|(name, tests)| { | |
| 128 | let group = build_test_group(&name, tests); | |
| 129 | (name, group) | |
| 130 | }) | |
| 131 | .collect(); | |
| 132 | ||
| 133 | TestGroup { name: name.to_string(), root_tests, groups: dirs } | |
| 134 | } | |
| 135 | ||
| 136 | /// Compiletest tests start with `[suite] tests/[suite]/a/b/c...`. | |
| 137 | /// Remove the `[suite] tests/[suite]/` prefix so that we can find the filesystem path. | |
| 138 | /// Also normalizes path delimiters. | |
| 139 | fn normalize_test_name(name: &str, suite_name: &str) -> String { | |
| 140 | let name = normalize_path_delimiters(name); | |
| 141 | let name = name.as_ref(); | |
| 142 | let name = name.strip_prefix(&format!("[{suite_name}]")).unwrap_or(name).trim(); | |
| 143 | let name = name.strip_prefix("tests/").unwrap_or(name); | |
| 144 | let name = name.strip_prefix(suite_name).unwrap_or(name); | |
| 145 | name.trim_start_matches("/").to_string() | |
| 146 | } | |
| 147 | ||
| 148 | struct TestSuites<'a> { | |
| 149 | suites: Vec<TestSuite<'a>>, | |
| 150 | } | |
| 151 | ||
| 152 | impl<'a> TestSuites<'a> { | |
| 153 | fn test_count(&self) -> u64 { | |
| 154 | self.suites.iter().map(|suite| suite.group.test_count()).sum::<u64>() | |
| 155 | } | |
| 156 | } | |
| 157 | ||
| 158 | struct TestSuite<'a> { | |
| 159 | group: TestGroup<'a>, | |
| 160 | } | |
| 161 | ||
| 162 | struct TestResults<'a> { | |
| 163 | passed: Vec<TestMetadata<'a>>, | |
| 164 | ignored: Vec<TestMetadata<'a>>, | |
| 165 | } | |
| 166 | ||
| 167 | struct Test<'a> { | |
| 168 | revisions: BTreeMap<String, TestResults<'a>>, | |
| 169 | } | |
| 170 | ||
| 171 | impl<'a> Test<'a> { | |
| 172 | /// If this is a test without revisions, it will have a single entry in `revisions` with | |
| 173 | /// an empty string as the revision name. | |
| 174 | fn single_test(&self) -> Option<&TestResults<'a>> { | |
| 175 | if self.revisions.len() == 1 { | |
| 176 | self.revisions.iter().next().take_if(|e| e.0.is_empty()).map(|e| e.1) | |
| 177 | } else { | |
| 178 | None | |
| 179 | } | |
| 180 | } | |
| 181 | } | |
| 182 | ||
| 183 | #[derive(Clone, Copy)] | |
| 184 | #[allow(dead_code)] | |
| 185 | struct TestMetadata<'a> { | |
| 186 | job: &'a str, | |
| 187 | stage: u32, | |
| 188 | target: &'a str, | |
| 189 | } | |
| 190 | ||
| 191 | // We have to use a template for the TestGroup instead of a macro, because | |
| 192 | // macros cannot be recursive in askama at the moment. | |
| 193 | #[derive(Template)] | |
| 194 | #[template(path = "test_group.askama")] | |
| 195 | /// Represents a group of tests | |
| 196 | struct TestGroup<'a> { | |
| 197 | name: String, | |
| 198 | /// Tests located directly in this directory | |
| 199 | root_tests: Vec<(String, Test<'a>)>, | |
| 200 | /// Nested directories with additional tests | |
| 201 | groups: Vec<(String, TestGroup<'a>)>, | |
| 202 | } | |
| 203 | ||
| 204 | impl<'a> TestGroup<'a> { | |
| 205 | fn test_count(&self) -> u64 { | |
| 206 | let root = self.root_tests.len() as u64; | |
| 207 | self.groups.iter().map(|(_, group)| group.test_count()).sum::<u64>() + root | |
| 208 | } | |
| 209 | } | |
| 210 | ||
| 211 | #[derive(Template)] | |
| 212 | #[template(path = "test_suites.askama")] | |
| 213 | struct TestSuitesPage<'a> { | |
| 214 | suites: TestSuites<'a>, | |
| 215 | test_count: u64, | |
| 216 | } |
src/ci/citool/src/utils.rs+6| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | use std::borrow::Cow; | |
| 1 | 2 | use std::path::Path; |
| 2 | 3 | |
| 3 | 4 | use anyhow::Context; |
| ... | ... | @@ -28,3 +29,8 @@ where |
| 28 | 29 | func(); |
| 29 | 30 | println!("</details>\n"); |
| 30 | 31 | } |
| 32 | ||
| 33 | /// Normalizes Windows-style path delimiters to Unix-style paths. | |
| 34 | pub fn normalize_path_delimiters(name: &str) -> Cow<str> { | |
| 35 | if name.contains("\\") { name.replace('\\', "/").into() } else { name.into() } | |
| 36 | } |
src/ci/citool/templates/layout.askama created+22| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | <html> | |
| 2 | <head> | |
| 3 | <meta charset="UTF-8"> | |
| 4 | <title>Rust CI Test Dashboard</title> | |
| 5 | <style> | |
| 6 | body { | |
| 7 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; | |
| 8 | line-height: 1.6; | |
| 9 | max-width: 1500px; | |
| 10 | margin: 0 auto; | |
| 11 | padding: 20px; | |
| 12 | background: #F5F5F5; | |
| 13 | } | |
| 14 | {% block styles %}{% endblock %} | |
| 15 | </style> | |
| 16 | </head> | |
| 17 | ||
| 18 | <body> | |
| 19 | {% block content %}{% endblock %} | |
| 20 | {% block scripts %}{% endblock %} | |
| 21 | </body> | |
| 22 | </html> |
src/ci/citool/templates/test_group.askama created+42| ... | ... | @@ -0,0 +1,42 @@ |
| 1 | {% macro test_result(r) -%} | |
| 2 | passed: {{ r.passed.len() }}, ignored: {{ r.ignored.len() }} | |
| 3 | {%- endmacro %} | |
| 4 | ||
| 5 | <li> | |
| 6 | <details> | |
| 7 | <summary>{{ name }} ({{ test_count() }} test{{ test_count() | pluralize }}{% if !root_tests.is_empty() && root_tests.len() as u64 != test_count() -%} | |
| 8 | , {{ root_tests.len() }} root test{{ root_tests.len() | pluralize }} | |
| 9 | {%- endif %}{% if !groups.is_empty() -%} | |
| 10 | , {{ groups.len() }} subdir{{ groups.len() | pluralize }} | |
| 11 | {%- endif %}) | |
| 12 | </summary> | |
| 13 | ||
| 14 | {% if !groups.is_empty() %} | |
| 15 | <ul> | |
| 16 | {% for (dir_name, subgroup) in groups %} | |
| 17 | {{ subgroup|safe }} | |
| 18 | {% endfor %} | |
| 19 | </ul> | |
| 20 | {% endif %} | |
| 21 | ||
| 22 | {% if !root_tests.is_empty() %} | |
| 23 | <ul> | |
| 24 | {% for (name, test) in root_tests %} | |
| 25 | <li> | |
| 26 | {% if let Some(result) = test.single_test() %} | |
| 27 | <b>{{ name }}</b> ({% call test_result(result) %}) | |
| 28 | {% else %} | |
| 29 | <b>{{ name }}</b> ({{ test.revisions.len() }} revision{{ test.revisions.len() | pluralize }}) | |
| 30 | <ul> | |
| 31 | {% for (revision, result) in test.revisions %} | |
| 32 | <li>#<i>{{ revision }}</i> ({% call test_result(result) %})</li> | |
| 33 | {% endfor %} | |
| 34 | </ul> | |
| 35 | {% endif %} | |
| 36 | </li> | |
| 37 | {% endfor %} | |
| 38 | </ul> | |
| 39 | {% endif %} | |
| 40 | ||
| 41 | </details> | |
| 42 | </li> |
src/ci/citool/templates/test_suites.askama created+108| ... | ... | @@ -0,0 +1,108 @@ |
| 1 | {% extends "layout.askama" %} | |
| 2 | ||
| 3 | {% block content %} | |
| 4 | <h1>Rust CI test dashboard</h1> | |
| 5 | <div> | |
| 6 | Here's how to interpret the "passed" and "ignored" counts: | |
| 7 | the count includes all combinations of "stage" x "target" x "CI job where the test was executed or ignored". | |
| 8 | </div> | |
| 9 | <div class="test-suites"> | |
| 10 | <div class="summary"> | |
| 11 | <div> | |
| 12 | <div class="test-count">Total tests: {{ test_count }}</div> | |
| 13 | <div> | |
| 14 | To find tests that haven't been executed anywhere, click on "Open all" and search for "passed: 0". | |
| 15 | </div> | |
| 16 | </div> | |
| 17 | <div> | |
| 18 | <button onclick="openAll()">Open all</button> | |
| 19 | <button onclick="closeAll()">Close all</button> | |
| 20 | </div> | |
| 21 | </div> | |
| 22 | ||
| 23 | <ul> | |
| 24 | {% for suite in suites.suites %} | |
| 25 | {{ suite.group|safe }} | |
| 26 | {% endfor %} | |
| 27 | </ul> | |
| 28 | </div> | |
| 29 | {% endblock %} | |
| 30 | ||
| 31 | {% block styles %} | |
| 32 | h1 { | |
| 33 | text-align: center; | |
| 34 | color: #333333; | |
| 35 | margin-bottom: 30px; | |
| 36 | } | |
| 37 | ||
| 38 | .summary { | |
| 39 | display: flex; | |
| 40 | justify-content: space-between; | |
| 41 | } | |
| 42 | ||
| 43 | .test-count { | |
| 44 | font-size: 1.2em; | |
| 45 | } | |
| 46 | ||
| 47 | .test-suites { | |
| 48 | background: white; | |
| 49 | border-radius: 8px; | |
| 50 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |
| 51 | padding: 20px; | |
| 52 | } | |
| 53 | ||
| 54 | ul { | |
| 55 | padding-left: 0; | |
| 56 | } | |
| 57 | ||
| 58 | li { | |
| 59 | list-style: none; | |
| 60 | padding-left: 20px; | |
| 61 | } | |
| 62 | summary { | |
| 63 | margin-bottom: 5px; | |
| 64 | padding: 6px; | |
| 65 | background-color: #F4F4F4; | |
| 66 | border: 1px solid #ddd; | |
| 67 | border-radius: 4px; | |
| 68 | cursor: pointer; | |
| 69 | } | |
| 70 | summary:hover { | |
| 71 | background-color: #CFCFCF; | |
| 72 | } | |
| 73 | ||
| 74 | /* Style the disclosure triangles */ | |
| 75 | details > summary { | |
| 76 | list-style: none; | |
| 77 | position: relative; | |
| 78 | } | |
| 79 | ||
| 80 | details > summary::before { | |
| 81 | content: "â–¶"; | |
| 82 | position: absolute; | |
| 83 | left: -15px; | |
| 84 | transform: rotate(0); | |
| 85 | transition: transform 0.2s; | |
| 86 | } | |
| 87 | ||
| 88 | details[open] > summary::before { | |
| 89 | transform: rotate(90deg); | |
| 90 | } | |
| 91 | {% endblock %} | |
| 92 | ||
| 93 | {% block scripts %} | |
| 94 | <script type="text/javascript"> | |
| 95 | function openAll() { | |
| 96 | const details = document.getElementsByTagName("details"); | |
| 97 | for (const elem of details) { | |
| 98 | elem.open = true; | |
| 99 | } | |
| 100 | } | |
| 101 | function closeAll() { | |
| 102 | const details = document.getElementsByTagName("details"); | |
| 103 | for (const elem of details) { | |
| 104 | elem.open = false; | |
| 105 | } | |
| 106 | } | |
| 107 | </script> | |
| 108 | {% endblock %} |
src/doc/rustc-dev-guide/src/building/suggested.md+37| ... | ... | @@ -20,6 +20,43 @@ your `.git/hooks` folder as `pre-push` (without the `.sh` extension!). |
| 20 | 20 | |
| 21 | 21 | You can also install the hook as a step of running `./x setup`! |
| 22 | 22 | |
| 23 | ## Config extensions | |
| 24 | ||
| 25 | When working on different tasks, you might need to switch between different bootstrap configurations. | |
| 26 | Sometimes you may want to keep an old configuration for future use. But saving raw config values in | |
| 27 | random files and manually copying and pasting them can quickly become messy, especially if you have a | |
| 28 | long history of different configurations. | |
| 29 | ||
| 30 | To simplify managing multiple configurations, you can create config extensions. | |
| 31 | ||
| 32 | For example, you can create a simple config file named `cross.toml`: | |
| 33 | ||
| 34 | ```toml | |
| 35 | [build] | |
| 36 | build = "x86_64-unknown-linux-gnu" | |
| 37 | host = ["i686-unknown-linux-gnu"] | |
| 38 | target = ["i686-unknown-linux-gnu"] | |
| 39 | ||
| 40 | ||
| 41 | [llvm] | |
| 42 | download-ci-llvm = false | |
| 43 | ||
| 44 | [target.x86_64-unknown-linux-gnu] | |
| 45 | llvm-config = "/path/to/llvm-19/bin/llvm-config" | |
| 46 | ``` | |
| 47 | ||
| 48 | Then, include this in your `bootstrap.toml`: | |
| 49 | ||
| 50 | ```toml | |
| 51 | include = ["cross.toml"] | |
| 52 | ``` | |
| 53 | ||
| 54 | You can also include extensions within extensions recursively. | |
| 55 | ||
| 56 | **Note:** In the `include` field, the overriding logic follows a right-to-left order. For example, | |
| 57 | in `include = ["a.toml", "b.toml"]`, extension `b.toml` overrides `a.toml`. Also, parent extensions | |
| 58 | always overrides the inner ones. | |
| 59 | ||
| 23 | 60 | ## Configuring `rust-analyzer` for `rustc` |
| 24 | 61 | |
| 25 | 62 | ### Project-local rust-analyzer setup |
src/doc/unstable-book/src/compiler-flags/sanitizer.md+17-20| ... | ... | @@ -247,34 +247,31 @@ See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details. |
| 247 | 247 | ```rust,ignore (making doc tests pass cross-platform is hard) |
| 248 | 248 | #![feature(naked_functions)] |
| 249 | 249 | |
| 250 | use std::arch::asm; | |
| 250 | use std::arch::naked_asm; | |
| 251 | 251 | use std::mem; |
| 252 | 252 | |
| 253 | 253 | fn add_one(x: i32) -> i32 { |
| 254 | 254 | x + 1 |
| 255 | 255 | } |
| 256 | 256 | |
| 257 | #[naked] | |
| 257 | #[unsafe(naked)] | |
| 258 | 258 | pub extern "C" fn add_two(x: i32) { |
| 259 | 259 | // x + 2 preceded by a landing pad/nop block |
| 260 | unsafe { | |
| 261 | asm!( | |
| 262 | " | |
| 263 | nop | |
| 264 | nop | |
| 265 | nop | |
| 266 | nop | |
| 267 | nop | |
| 268 | nop | |
| 269 | nop | |
| 270 | nop | |
| 271 | nop | |
| 272 | lea eax, [rdi+2] | |
| 273 | ret | |
| 274 | ", | |
| 275 | options(noreturn) | |
| 276 | ); | |
| 277 | } | |
| 260 | naked_asm!( | |
| 261 | " | |
| 262 | nop | |
| 263 | nop | |
| 264 | nop | |
| 265 | nop | |
| 266 | nop | |
| 267 | nop | |
| 268 | nop | |
| 269 | nop | |
| 270 | nop | |
| 271 | lea eax, [rdi+2] | |
| 272 | ret | |
| 273 | " | |
| 274 | ); | |
| 278 | 275 | } |
| 279 | 276 | |
| 280 | 277 | fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { |
src/tools/tidy/src/issues.txt-6| ... | ... | @@ -1397,7 +1397,6 @@ ui/issues/auxiliary/issue-13620-1.rs |
| 1397 | 1397 | ui/issues/auxiliary/issue-13620-2.rs |
| 1398 | 1398 | ui/issues/auxiliary/issue-14344-1.rs |
| 1399 | 1399 | ui/issues/auxiliary/issue-14344-2.rs |
| 1400 | ui/issues/auxiliary/issue-14421.rs | |
| 1401 | 1400 | ui/issues/auxiliary/issue-14422.rs |
| 1402 | 1401 | ui/issues/auxiliary/issue-15562.rs |
| 1403 | 1402 | ui/issues/auxiliary/issue-16643.rs |
| ... | ... | @@ -1564,7 +1563,6 @@ ui/issues/issue-14366.rs |
| 1564 | 1563 | ui/issues/issue-14382.rs |
| 1565 | 1564 | ui/issues/issue-14393.rs |
| 1566 | 1565 | ui/issues/issue-14399.rs |
| 1567 | ui/issues/issue-14421.rs | |
| 1568 | 1566 | ui/issues/issue-14422.rs |
| 1569 | 1567 | ui/issues/issue-14541.rs |
| 1570 | 1568 | ui/issues/issue-14721.rs |
| ... | ... | @@ -1629,7 +1627,6 @@ ui/issues/issue-16774.rs |
| 1629 | 1627 | ui/issues/issue-16783.rs |
| 1630 | 1628 | ui/issues/issue-16819.rs |
| 1631 | 1629 | ui/issues/issue-16922-rpass.rs |
| 1632 | ui/issues/issue-16939.rs | |
| 1633 | 1630 | ui/issues/issue-16966.rs |
| 1634 | 1631 | ui/issues/issue-16994.rs |
| 1635 | 1632 | ui/issues/issue-17001.rs |
| ... | ... | @@ -1867,7 +1864,6 @@ ui/issues/issue-23550.rs |
| 1867 | 1864 | ui/issues/issue-23589.rs |
| 1868 | 1865 | ui/issues/issue-23699.rs |
| 1869 | 1866 | ui/issues/issue-2380-b.rs |
| 1870 | ui/issues/issue-23808.rs | |
| 1871 | 1867 | ui/issues/issue-2383.rs |
| 1872 | 1868 | ui/issues/issue-23891.rs |
| 1873 | 1869 | ui/issues/issue-23898.rs |
| ... | ... | @@ -2607,7 +2603,6 @@ ui/issues/issue-9249.rs |
| 2607 | 2603 | ui/issues/issue-9259.rs |
| 2608 | 2604 | ui/issues/issue-92741.rs |
| 2609 | 2605 | ui/issues/issue-9446.rs |
| 2610 | ui/issues/issue-9719.rs | |
| 2611 | 2606 | ui/issues/issue-9725.rs |
| 2612 | 2607 | ui/issues/issue-9737.rs |
| 2613 | 2608 | ui/issues/issue-9814.rs |
| ... | ... | @@ -3138,7 +3133,6 @@ ui/nll/user-annotations/issue-55241.rs |
| 3138 | 3133 | ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs |
| 3139 | 3134 | ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs |
| 3140 | 3135 | ui/numbers-arithmetic/issue-8460.rs |
| 3141 | ui/on-unimplemented/issue-104140.rs | |
| 3142 | 3136 | ui/or-patterns/issue-64879-trailing-before-guard.rs |
| 3143 | 3137 | ui/or-patterns/issue-67514-irrefutable-param.rs |
| 3144 | 3138 | ui/or-patterns/issue-68785-irrefutable-param-with-at.rs |
src/tools/tidy/src/ui_tests.rs+1-1| ... | ... | @@ -17,7 +17,7 @@ use ignore::Walk; |
| 17 | 17 | const ENTRY_LIMIT: u32 = 901; |
| 18 | 18 | // FIXME: The following limits should be reduced eventually. |
| 19 | 19 | |
| 20 | const ISSUES_ENTRY_LIMIT: u32 = 1631; | |
| 20 | const ISSUES_ENTRY_LIMIT: u32 = 1626; | |
| 21 | 21 | |
| 22 | 22 | const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ |
| 23 | 23 | "rs", // test source files |
tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs+2-2| ... | ... | @@ -13,8 +13,8 @@ use std::arch::naked_asm; |
| 13 | 13 | // LLVM implements this via making sure of that, even for functions with the naked attribute. |
| 14 | 14 | // So, we must emit an appropriate instruction instead! |
| 15 | 15 | #[no_mangle] |
| 16 | #[naked] | |
| 17 | pub unsafe extern "C" fn _hlt() -> ! { | |
| 16 | #[unsafe(naked)] | |
| 17 | pub extern "C" fn _hlt() -> ! { | |
| 18 | 18 | // CHECK-NOT: hint #34 |
| 19 | 19 | // CHECK: hlt #0x1 |
| 20 | 20 | naked_asm!("hlt #1") |
tests/assembly/naked-functions/aix.rs+2-2| ... | ... | @@ -29,7 +29,7 @@ use minicore::*; |
| 29 | 29 | // CHECK-LABEL: blr: |
| 30 | 30 | // CHECK: blr |
| 31 | 31 | #[no_mangle] |
| 32 | #[naked] | |
| 33 | unsafe extern "C" fn blr() { | |
| 32 | #[unsafe(naked)] | |
| 33 | extern "C" fn blr() { | |
| 34 | 34 | naked_asm!("blr") |
| 35 | 35 | } |
tests/assembly/naked-functions/wasm32.rs+30-30| ... | ... | @@ -22,8 +22,8 @@ use minicore::*; |
| 22 | 22 | // CHECK-NOT: .size |
| 23 | 23 | // CHECK: end_function |
| 24 | 24 | #[no_mangle] |
| 25 | #[naked] | |
| 26 | unsafe extern "C" fn nop() { | |
| 25 | #[unsafe(naked)] | |
| 26 | extern "C" fn nop() { | |
| 27 | 27 | naked_asm!("nop") |
| 28 | 28 | } |
| 29 | 29 | |
| ... | ... | @@ -34,11 +34,11 @@ unsafe extern "C" fn nop() { |
| 34 | 34 | // CHECK-NOT: .size |
| 35 | 35 | // CHECK: end_function |
| 36 | 36 | #[no_mangle] |
| 37 | #[naked] | |
| 37 | #[unsafe(naked)] | |
| 38 | 38 | #[linkage = "weak"] |
| 39 | 39 | // wasm functions cannot be aligned, so this has no effect |
| 40 | 40 | #[repr(align(32))] |
| 41 | unsafe extern "C" fn weak_aligned_nop() { | |
| 41 | extern "C" fn weak_aligned_nop() { | |
| 42 | 42 | naked_asm!("nop") |
| 43 | 43 | } |
| 44 | 44 | |
| ... | ... | @@ -51,48 +51,48 @@ unsafe extern "C" fn weak_aligned_nop() { |
| 51 | 51 | // |
| 52 | 52 | // CHECK-NEXT: end_function |
| 53 | 53 | #[no_mangle] |
| 54 | #[naked] | |
| 55 | unsafe extern "C" fn fn_i8_i8(num: i8) -> i8 { | |
| 54 | #[unsafe(naked)] | |
| 55 | extern "C" fn fn_i8_i8(num: i8) -> i8 { | |
| 56 | 56 | naked_asm!("local.get 0", "local.get 0", "i32.mul") |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | 59 | // CHECK-LABEL: fn_i8_i8_i8: |
| 60 | 60 | // CHECK: .functype fn_i8_i8_i8 (i32, i32) -> (i32) |
| 61 | 61 | #[no_mangle] |
| 62 | #[naked] | |
| 63 | unsafe extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 { | |
| 62 | #[unsafe(naked)] | |
| 63 | extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 { | |
| 64 | 64 | naked_asm!("local.get 1", "local.get 0", "i32.mul") |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | 67 | // CHECK-LABEL: fn_unit_i8: |
| 68 | 68 | // CHECK: .functype fn_unit_i8 () -> (i32) |
| 69 | 69 | #[no_mangle] |
| 70 | #[naked] | |
| 71 | unsafe extern "C" fn fn_unit_i8() -> i8 { | |
| 70 | #[unsafe(naked)] | |
| 71 | extern "C" fn fn_unit_i8() -> i8 { | |
| 72 | 72 | naked_asm!("i32.const 42") |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | 75 | // CHECK-LABEL: fn_i8_unit: |
| 76 | 76 | // CHECK: .functype fn_i8_unit (i32) -> () |
| 77 | 77 | #[no_mangle] |
| 78 | #[naked] | |
| 79 | unsafe extern "C" fn fn_i8_unit(_: i8) { | |
| 78 | #[unsafe(naked)] | |
| 79 | extern "C" fn fn_i8_unit(_: i8) { | |
| 80 | 80 | naked_asm!("nop") |
| 81 | 81 | } |
| 82 | 82 | |
| 83 | 83 | // CHECK-LABEL: fn_i32_i32: |
| 84 | 84 | // CHECK: .functype fn_i32_i32 (i32) -> (i32) |
| 85 | 85 | #[no_mangle] |
| 86 | #[naked] | |
| 87 | unsafe extern "C" fn fn_i32_i32(num: i32) -> i32 { | |
| 86 | #[unsafe(naked)] | |
| 87 | extern "C" fn fn_i32_i32(num: i32) -> i32 { | |
| 88 | 88 | naked_asm!("local.get 0", "local.get 0", "i32.mul") |
| 89 | 89 | } |
| 90 | 90 | |
| 91 | 91 | // CHECK-LABEL: fn_i64_i64: |
| 92 | 92 | // CHECK: .functype fn_i64_i64 (i64) -> (i64) |
| 93 | 93 | #[no_mangle] |
| 94 | #[naked] | |
| 95 | unsafe extern "C" fn fn_i64_i64(num: i64) -> i64 { | |
| 94 | #[unsafe(naked)] | |
| 95 | extern "C" fn fn_i64_i64(num: i64) -> i64 { | |
| 96 | 96 | naked_asm!("local.get 0", "local.get 0", "i64.mul") |
| 97 | 97 | } |
| 98 | 98 | |
| ... | ... | @@ -101,8 +101,8 @@ unsafe extern "C" fn fn_i64_i64(num: i64) -> i64 { |
| 101 | 101 | // wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> () |
| 102 | 102 | #[allow(improper_ctypes_definitions)] |
| 103 | 103 | #[no_mangle] |
| 104 | #[naked] | |
| 105 | unsafe extern "C" fn fn_i128_i128(num: i128) -> i128 { | |
| 104 | #[unsafe(naked)] | |
| 105 | extern "C" fn fn_i128_i128(num: i128) -> i128 { | |
| 106 | 106 | naked_asm!( |
| 107 | 107 | "local.get 0", |
| 108 | 108 | "local.get 2", |
| ... | ... | @@ -117,8 +117,8 @@ unsafe extern "C" fn fn_i128_i128(num: i128) -> i128 { |
| 117 | 117 | // wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> () |
| 118 | 118 | // wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> () |
| 119 | 119 | #[no_mangle] |
| 120 | #[naked] | |
| 121 | unsafe extern "C" fn fn_f128_f128(num: f128) -> f128 { | |
| 120 | #[unsafe(naked)] | |
| 121 | extern "C" fn fn_f128_f128(num: f128) -> f128 { | |
| 122 | 122 | naked_asm!( |
| 123 | 123 | "local.get 0", |
| 124 | 124 | "local.get 2", |
| ... | ... | @@ -139,8 +139,8 @@ struct Compound { |
| 139 | 139 | // wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> () |
| 140 | 140 | // wasm64-unknown: .functype fn_compound_compound (i64, i64) -> () |
| 141 | 141 | #[no_mangle] |
| 142 | #[naked] | |
| 143 | unsafe extern "C" fn fn_compound_compound(_: Compound) -> Compound { | |
| 142 | #[unsafe(naked)] | |
| 143 | extern "C" fn fn_compound_compound(_: Compound) -> Compound { | |
| 144 | 144 | // this is the wasm32-wasip1 assembly |
| 145 | 145 | naked_asm!( |
| 146 | 146 | "local.get 0", |
| ... | ... | @@ -160,8 +160,8 @@ struct WrapperI32(i32); |
| 160 | 160 | // CHECK-LABEL: fn_wrapperi32_wrapperi32: |
| 161 | 161 | // CHECK: .functype fn_wrapperi32_wrapperi32 (i32) -> (i32) |
| 162 | 162 | #[no_mangle] |
| 163 | #[naked] | |
| 164 | unsafe extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 { | |
| 163 | #[unsafe(naked)] | |
| 164 | extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 { | |
| 165 | 165 | naked_asm!("local.get 0") |
| 166 | 166 | } |
| 167 | 167 | |
| ... | ... | @@ -171,8 +171,8 @@ struct WrapperI64(i64); |
| 171 | 171 | // CHECK-LABEL: fn_wrapperi64_wrapperi64: |
| 172 | 172 | // CHECK: .functype fn_wrapperi64_wrapperi64 (i64) -> (i64) |
| 173 | 173 | #[no_mangle] |
| 174 | #[naked] | |
| 175 | unsafe extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 { | |
| 174 | #[unsafe(naked)] | |
| 175 | extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 { | |
| 176 | 176 | naked_asm!("local.get 0") |
| 177 | 177 | } |
| 178 | 178 | |
| ... | ... | @@ -182,8 +182,8 @@ struct WrapperF32(f32); |
| 182 | 182 | // CHECK-LABEL: fn_wrapperf32_wrapperf32: |
| 183 | 183 | // CHECK: .functype fn_wrapperf32_wrapperf32 (f32) -> (f32) |
| 184 | 184 | #[no_mangle] |
| 185 | #[naked] | |
| 186 | unsafe extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 { | |
| 185 | #[unsafe(naked)] | |
| 186 | extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 { | |
| 187 | 187 | naked_asm!("local.get 0") |
| 188 | 188 | } |
| 189 | 189 | |
| ... | ... | @@ -193,7 +193,7 @@ struct WrapperF64(f64); |
| 193 | 193 | // CHECK-LABEL: fn_wrapperf64_wrapperf64: |
| 194 | 194 | // CHECK: .functype fn_wrapperf64_wrapperf64 (f64) -> (f64) |
| 195 | 195 | #[no_mangle] |
| 196 | #[naked] | |
| 197 | unsafe extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 { | |
| 196 | #[unsafe(naked)] | |
| 197 | extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 { | |
| 198 | 198 | naked_asm!("local.get 0") |
| 199 | 199 | } |
tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs+2-2| ... | ... | @@ -13,8 +13,8 @@ use std::arch::naked_asm; |
| 13 | 13 | // works by using an instruction for each possible landing site, |
| 14 | 14 | // and LLVM implements this via making sure of that. |
| 15 | 15 | #[no_mangle] |
| 16 | #[naked] | |
| 17 | pub unsafe extern "sysv64" fn will_halt() -> ! { | |
| 16 | #[unsafe(naked)] | |
| 17 | pub extern "sysv64" fn will_halt() -> ! { | |
| 18 | 18 | // CHECK-NOT: endbr{{32|64}} |
| 19 | 19 | // CHECK: hlt |
| 20 | 20 | naked_asm!("hlt") |
tests/codegen/cffi/c-variadic-naked.rs+2-4| ... | ... | @@ -8,11 +8,9 @@ |
| 8 | 8 | #![feature(naked_functions)] |
| 9 | 9 | #![no_std] |
| 10 | 10 | |
| 11 | #[naked] | |
| 11 | #[unsafe(naked)] | |
| 12 | 12 | pub unsafe extern "C" fn c_variadic(_: usize, _: ...) { |
| 13 | 13 | // CHECK-NOT: va_start |
| 14 | 14 | // CHECK-NOT: alloca |
| 15 | core::arch::naked_asm! { | |
| 16 | "ret", | |
| 17 | } | |
| 15 | core::arch::naked_asm!("ret") | |
| 18 | 16 | } |
tests/codegen/naked-asan.rs+2-2| ... | ... | @@ -13,10 +13,10 @@ pub fn caller() { |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | // CHECK: declare x86_intrcc void @page_fault_handler(ptr {{.*}}, i64{{.*}}){{.*}}#[[ATTRS:[0-9]+]] |
| 16 | #[naked] | |
| 16 | #[unsafe(naked)] | |
| 17 | 17 | #[no_mangle] |
| 18 | 18 | pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) { |
| 19 | unsafe { core::arch::naked_asm!("ud2") }; | |
| 19 | core::arch::naked_asm!("ud2") | |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | // CHECK: #[[ATTRS]] = |
tests/codegen/naked-fn/aligned.rs+3-3| ... | ... | @@ -10,8 +10,8 @@ use std::arch::naked_asm; |
| 10 | 10 | // CHECK-LABEL: naked_empty: |
| 11 | 11 | #[repr(align(16))] |
| 12 | 12 | #[no_mangle] |
| 13 | #[naked] | |
| 14 | pub unsafe extern "C" fn naked_empty() { | |
| 13 | #[unsafe(naked)] | |
| 14 | pub extern "C" fn naked_empty() { | |
| 15 | 15 | // CHECK: ret |
| 16 | naked_asm!("ret"); | |
| 16 | naked_asm!("ret") | |
| 17 | 17 | } |
tests/codegen/naked-fn/generics.rs+21-25| ... | ... | @@ -28,21 +28,19 @@ fn test(x: u64) { |
| 28 | 28 | // CHECK: add rax, 1 |
| 29 | 29 | // CHECK: add rax, 42 |
| 30 | 30 | |
| 31 | #[naked] | |
| 31 | #[unsafe(naked)] | |
| 32 | 32 | pub extern "C" fn using_const_generics<const N: u64>(x: u64) -> u64 { |
| 33 | 33 | const M: u64 = 42; |
| 34 | 34 | |
| 35 | unsafe { | |
| 36 | naked_asm!( | |
| 37 | "xor rax, rax", | |
| 38 | "add rax, rdi", | |
| 39 | "add rax, {}", | |
| 40 | "add rax, {}", | |
| 41 | "ret", | |
| 42 | const N, | |
| 43 | const M, | |
| 44 | ) | |
| 45 | } | |
| 35 | naked_asm!( | |
| 36 | "xor rax, rax", | |
| 37 | "add rax, rdi", | |
| 38 | "add rax, {}", | |
| 39 | "add rax, {}", | |
| 40 | "ret", | |
| 41 | const N, | |
| 42 | const M, | |
| 43 | ) | |
| 46 | 44 | } |
| 47 | 45 | |
| 48 | 46 | trait Invert { |
| ... | ... | @@ -60,16 +58,14 @@ impl Invert for i64 { |
| 60 | 58 | // CHECK: call |
| 61 | 59 | // CHECK: ret |
| 62 | 60 | |
| 63 | #[naked] | |
| 61 | #[unsafe(naked)] | |
| 64 | 62 | #[no_mangle] |
| 65 | 63 | pub extern "C" fn generic_function<T: Invert>(x: i64) -> i64 { |
| 66 | unsafe { | |
| 67 | naked_asm!( | |
| 68 | "call {}", | |
| 69 | "ret", | |
| 70 | sym <T as Invert>::invert, | |
| 71 | ) | |
| 72 | } | |
| 64 | naked_asm!( | |
| 65 | "call {}", | |
| 66 | "ret", | |
| 67 | sym <T as Invert>::invert, | |
| 68 | ) | |
| 73 | 69 | } |
| 74 | 70 | |
| 75 | 71 | #[derive(Copy, Clone)] |
| ... | ... | @@ -81,10 +77,10 @@ struct Foo(u64); |
| 81 | 77 | // CHECK: mov rax, rdi |
| 82 | 78 | |
| 83 | 79 | impl Foo { |
| 84 | #[naked] | |
| 80 | #[unsafe(naked)] | |
| 85 | 81 | #[no_mangle] |
| 86 | 82 | extern "C" fn method(self) -> u64 { |
| 87 | unsafe { naked_asm!("mov rax, rdi", "ret") } | |
| 83 | naked_asm!("mov rax, rdi", "ret") | |
| 88 | 84 | } |
| 89 | 85 | } |
| 90 | 86 | |
| ... | ... | @@ -97,10 +93,10 @@ trait Bar { |
| 97 | 93 | } |
| 98 | 94 | |
| 99 | 95 | impl Bar for Foo { |
| 100 | #[naked] | |
| 96 | #[unsafe(naked)] | |
| 101 | 97 | #[no_mangle] |
| 102 | 98 | extern "C" fn trait_method(self) -> u64 { |
| 103 | unsafe { naked_asm!("mov rax, rdi", "ret") } | |
| 99 | naked_asm!("mov rax, rdi", "ret") | |
| 104 | 100 | } |
| 105 | 101 | } |
| 106 | 102 | |
| ... | ... | @@ -109,7 +105,7 @@ impl Bar for Foo { |
| 109 | 105 | // CHECK: lea rax, [rdi + rsi] |
| 110 | 106 | |
| 111 | 107 | // this previously ICE'd, see https://github.com/rust-lang/rust/issues/124375 |
| 112 | #[naked] | |
| 108 | #[unsafe(naked)] | |
| 113 | 109 | #[no_mangle] |
| 114 | 110 | pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { |
| 115 | 111 | naked_asm!("lea rax, [rdi + rsi]", "ret"); |
tests/codegen/naked-fn/instruction-set.rs+6-6| ... | ... | @@ -20,8 +20,8 @@ use minicore::*; |
| 20 | 20 | // arm-mode: .arm |
| 21 | 21 | // thumb-mode: .thumb |
| 22 | 22 | #[no_mangle] |
| 23 | #[naked] | |
| 24 | unsafe extern "C" fn test_unspecified() { | |
| 23 | #[unsafe(naked)] | |
| 24 | extern "C" fn test_unspecified() { | |
| 25 | 25 | naked_asm!("bx lr"); |
| 26 | 26 | } |
| 27 | 27 | |
| ... | ... | @@ -33,9 +33,9 @@ unsafe extern "C" fn test_unspecified() { |
| 33 | 33 | // arm-mode: .arm |
| 34 | 34 | // thumb-mode: .thumb |
| 35 | 35 | #[no_mangle] |
| 36 | #[naked] | |
| 36 | #[unsafe(naked)] | |
| 37 | 37 | #[instruction_set(arm::t32)] |
| 38 | unsafe extern "C" fn test_thumb() { | |
| 38 | extern "C" fn test_thumb() { | |
| 39 | 39 | naked_asm!("bx lr"); |
| 40 | 40 | } |
| 41 | 41 | |
| ... | ... | @@ -46,8 +46,8 @@ unsafe extern "C" fn test_thumb() { |
| 46 | 46 | // arm-mode: .arm |
| 47 | 47 | // thumb-mode: .thumb |
| 48 | 48 | #[no_mangle] |
| 49 | #[naked] | |
| 49 | #[unsafe(naked)] | |
| 50 | 50 | #[instruction_set(arm::a32)] |
| 51 | unsafe extern "C" fn test_arm() { | |
| 51 | extern "C" fn test_arm() { | |
| 52 | 52 | naked_asm!("bx lr"); |
| 53 | 53 | } |
tests/codegen/naked-fn/min-function-alignment.rs+8-8| ... | ... | @@ -9,24 +9,24 @@ |
| 9 | 9 | // |
| 10 | 10 | // CHECK: .balign 16 |
| 11 | 11 | #[no_mangle] |
| 12 | #[naked] | |
| 13 | pub unsafe extern "C" fn naked_no_explicit_align() { | |
| 12 | #[unsafe(naked)] | |
| 13 | pub extern "C" fn naked_no_explicit_align() { | |
| 14 | 14 | core::arch::naked_asm!("ret") |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | // CHECK: .balign 16 |
| 18 | 18 | #[no_mangle] |
| 19 | 19 | #[repr(align(8))] |
| 20 | #[naked] | |
| 21 | pub unsafe extern "C" fn naked_lower_align() { | |
| 20 | #[unsafe(naked)] | |
| 21 | pub extern "C" fn naked_lower_align() { | |
| 22 | 22 | core::arch::naked_asm!("ret") |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | 25 | // CHECK: .balign 32 |
| 26 | 26 | #[no_mangle] |
| 27 | 27 | #[repr(align(32))] |
| 28 | #[naked] | |
| 29 | pub unsafe extern "C" fn naked_higher_align() { | |
| 28 | #[unsafe(naked)] | |
| 29 | pub extern "C" fn naked_higher_align() { | |
| 30 | 30 | core::arch::naked_asm!("ret") |
| 31 | 31 | } |
| 32 | 32 | |
| ... | ... | @@ -38,7 +38,7 @@ pub unsafe extern "C" fn naked_higher_align() { |
| 38 | 38 | // CHECK: .balign 16 |
| 39 | 39 | #[no_mangle] |
| 40 | 40 | #[cold] |
| 41 | #[naked] | |
| 42 | pub unsafe extern "C" fn no_explicit_align_cold() { | |
| 41 | #[unsafe(naked)] | |
| 42 | pub extern "C" fn no_explicit_align_cold() { | |
| 43 | 43 | core::arch::naked_asm!("ret") |
| 44 | 44 | } |
tests/codegen/naked-fn/naked-functions.rs+8-8| ... | ... | @@ -60,8 +60,8 @@ use minicore::*; |
| 60 | 60 | // linux,win: .att_syntax |
| 61 | 61 | |
| 62 | 62 | #[no_mangle] |
| 63 | #[naked] | |
| 64 | pub unsafe extern "C" fn naked_empty() { | |
| 63 | #[unsafe(naked)] | |
| 64 | pub extern "C" fn naked_empty() { | |
| 65 | 65 | #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))] |
| 66 | 66 | naked_asm!("ret"); |
| 67 | 67 | |
| ... | ... | @@ -114,8 +114,8 @@ pub unsafe extern "C" fn naked_empty() { |
| 114 | 114 | // linux,win: .att_syntax |
| 115 | 115 | |
| 116 | 116 | #[no_mangle] |
| 117 | #[naked] | |
| 118 | pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { | |
| 117 | #[unsafe(naked)] | |
| 118 | pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { | |
| 119 | 119 | #[cfg(any(target_os = "windows", target_os = "linux"))] |
| 120 | 120 | { |
| 121 | 121 | naked_asm!("lea rax, [rdi + rsi]", "ret") |
| ... | ... | @@ -138,9 +138,9 @@ pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize |
| 138 | 138 | // thumb: .pushsection .text.some_different_name,\22ax\22, %progbits |
| 139 | 139 | // CHECK-LABEL: test_link_section: |
| 140 | 140 | #[no_mangle] |
| 141 | #[naked] | |
| 141 | #[unsafe(naked)] | |
| 142 | 142 | #[link_section = ".text.some_different_name"] |
| 143 | pub unsafe extern "C" fn test_link_section() { | |
| 143 | pub extern "C" fn test_link_section() { | |
| 144 | 144 | #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))] |
| 145 | 145 | naked_asm!("ret"); |
| 146 | 146 | |
| ... | ... | @@ -159,7 +159,7 @@ pub unsafe extern "C" fn test_link_section() { |
| 159 | 159 | // win_i686-LABEL: @fastcall_cc@4: |
| 160 | 160 | #[cfg(target_os = "windows")] |
| 161 | 161 | #[no_mangle] |
| 162 | #[naked] | |
| 163 | pub unsafe extern "fastcall" fn fastcall_cc(x: i32) -> i32 { | |
| 162 | #[unsafe(naked)] | |
| 163 | pub extern "fastcall" fn fastcall_cc(x: i32) -> i32 { | |
| 164 | 164 | naked_asm!("ret"); |
| 165 | 165 | } |
tests/crashes/130627.rs deleted-20| ... | ... | @@ -1,20 +0,0 @@ |
| 1 | //@ known-bug: #130627 | |
| 2 | ||
| 3 | #![feature(trait_alias)] | |
| 4 | ||
| 5 | trait Test {} | |
| 6 | ||
| 7 | #[diagnostic::on_unimplemented( | |
| 8 | message="message", | |
| 9 | label="label", | |
| 10 | note="note" | |
| 11 | )] | |
| 12 | trait Alias = Test; | |
| 13 | ||
| 14 | // Use trait alias as bound on type parameter. | |
| 15 | fn foo<T: Alias>(v: &T) { | |
| 16 | } | |
| 17 | ||
| 18 | pub fn main() { | |
| 19 | foo(&1); | |
| 20 | } |
tests/run-make/crate-loading-multiple-candidates/crateresolve1-1.rs created+6| ... | ... | @@ -0,0 +1,6 @@ |
| 1 | #![crate_name = "crateresolve1"] | |
| 2 | #![crate_type = "lib"] | |
| 3 | ||
| 4 | pub fn f() -> isize { | |
| 5 | 10 | |
| 6 | } |
tests/run-make/crate-loading-multiple-candidates/crateresolve1-2.rs created+6| ... | ... | @@ -0,0 +1,6 @@ |
| 1 | #![crate_name = "crateresolve1"] | |
| 2 | #![crate_type = "lib"] | |
| 3 | ||
| 4 | pub fn f() -> isize { | |
| 5 | 20 | |
| 6 | } |
tests/run-make/crate-loading-multiple-candidates/multiple-candidates.rs created+3| ... | ... | @@ -0,0 +1,3 @@ |
| 1 | extern crate crateresolve1; | |
| 2 | ||
| 3 | fn main() {} |
tests/run-make/crate-loading-multiple-candidates/multiple-candidates.stderr created+12| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | error[E0464]: multiple candidates for `rlib` dependency `crateresolve1` found | |
| 2 | --> multiple-candidates.rs:1:1 | |
| 3 | | | |
| 4 | LL | extern crate crateresolve1; | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = note: candidate #1: ./mylibs/libcrateresolve1-1.rlib | |
| 8 | = note: candidate #2: ./mylibs/libcrateresolve1-2.rlib | |
| 9 | ||
| 10 | error: aborting due to 1 previous error | |
| 11 | ||
| 12 | For more information about this error, try `rustc --explain E0464`. |
tests/run-make/crate-loading-multiple-candidates/rmake.rs created+34| ... | ... | @@ -0,0 +1,34 @@ |
| 1 | //@ needs-symlink | |
| 2 | //@ ignore-cross-compile | |
| 3 | ||
| 4 | // Tests that the multiple candidate dependencies diagnostic prints relative | |
| 5 | // paths if a relative library path was passed in. | |
| 6 | ||
| 7 | use run_make_support::{bare_rustc, diff, rfs, rustc}; | |
| 8 | ||
| 9 | fn main() { | |
| 10 | // Check that relative paths are preserved in the diagnostic | |
| 11 | rfs::create_dir("mylibs"); | |
| 12 | rustc().input("crateresolve1-1.rs").out_dir("mylibs").extra_filename("-1").run(); | |
| 13 | rustc().input("crateresolve1-2.rs").out_dir("mylibs").extra_filename("-2").run(); | |
| 14 | check("./mylibs"); | |
| 15 | ||
| 16 | // Check that symlinks aren't followed when printing the diagnostic | |
| 17 | rfs::rename("mylibs", "original"); | |
| 18 | rfs::symlink_dir("original", "mylibs"); | |
| 19 | check("./mylibs"); | |
| 20 | } | |
| 21 | ||
| 22 | fn check(library_path: &str) { | |
| 23 | let out = rustc() | |
| 24 | .input("multiple-candidates.rs") | |
| 25 | .library_search_path(library_path) | |
| 26 | .ui_testing() | |
| 27 | .run_fail() | |
| 28 | .stderr_utf8(); | |
| 29 | diff() | |
| 30 | .expected_file("multiple-candidates.stderr") | |
| 31 | .normalize(r"\\", "/") | |
| 32 | .actual_text("(rustc)", &out) | |
| 33 | .run(); | |
| 34 | } |
tests/run-make/naked-symbol-visibility/a_rust_dylib.rs+10-10| ... | ... | @@ -26,9 +26,9 @@ extern "C" fn private_vanilla() -> u32 { |
| 26 | 26 | 42 |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | #[naked] | |
| 29 | #[unsafe(naked)] | |
| 30 | 30 | extern "C" fn private_naked() -> u32 { |
| 31 | unsafe { naked_asm!("mov rax, 42", "ret") } | |
| 31 | naked_asm!("mov rax, 42", "ret") | |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | 34 | #[no_mangle] |
| ... | ... | @@ -36,19 +36,19 @@ pub extern "C" fn public_vanilla() -> u32 { |
| 36 | 36 | 42 |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | #[naked] | |
| 39 | #[unsafe(naked)] | |
| 40 | 40 | #[no_mangle] |
| 41 | 41 | pub extern "C" fn public_naked_nongeneric() -> u32 { |
| 42 | unsafe { naked_asm!("mov rax, 42", "ret") } | |
| 42 | naked_asm!("mov rax, 42", "ret") | |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 { |
| 46 | 46 | T::COUNT |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | #[naked] | |
| 49 | #[unsafe(naked)] | |
| 50 | 50 | pub extern "C" fn public_naked_generic<T: TraitWithConst>() -> u32 { |
| 51 | unsafe { naked_asm!("mov rax, {}", "ret", const T::COUNT) } | |
| 51 | naked_asm!("mov rax, {}", "ret", const T::COUNT) | |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | 54 | #[linkage = "external"] |
| ... | ... | @@ -56,10 +56,10 @@ extern "C" fn vanilla_external_linkage() -> u32 { |
| 56 | 56 | 42 |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | #[naked] | |
| 59 | #[unsafe(naked)] | |
| 60 | 60 | #[linkage = "external"] |
| 61 | 61 | extern "C" fn naked_external_linkage() -> u32 { |
| 62 | unsafe { naked_asm!("mov rax, 42", "ret") } | |
| 62 | naked_asm!("mov rax, 42", "ret") | |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | 65 | #[cfg(not(windows))] |
| ... | ... | @@ -68,11 +68,11 @@ extern "C" fn vanilla_weak_linkage() -> u32 { |
| 68 | 68 | 42 |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | #[naked] | |
| 71 | #[unsafe(naked)] | |
| 72 | 72 | #[cfg(not(windows))] |
| 73 | 73 | #[linkage = "weak"] |
| 74 | 74 | extern "C" fn naked_weak_linkage() -> u32 { |
| 75 | unsafe { naked_asm!("mov rax, 42", "ret") } | |
| 75 | naked_asm!("mov rax, 42", "ret") | |
| 76 | 76 | } |
| 77 | 77 | |
| 78 | 78 | // functions that are declared in an `extern "C"` block are currently not exported |
tests/ui/argument-suggestions/exotic-calls.rs+10| ... | ... | @@ -1,8 +1,18 @@ |
| 1 | //! Checks variations of E0057, which is the incorrect number of agruments passed into a closure | |
| 2 | ||
| 3 | //@ check-fail | |
| 4 | ||
| 1 | 5 | fn foo<T: Fn()>(t: T) { |
| 2 | 6 | t(1i32); |
| 3 | 7 | //~^ ERROR function takes 0 arguments but 1 argument was supplied |
| 4 | 8 | } |
| 5 | 9 | |
| 10 | /// Regression test for <https://github.com/rust-lang/rust/issues/16939> | |
| 11 | fn foo2<T: Fn()>(f: T) { | |
| 12 | |t| f(t); | |
| 13 | //~^ ERROR function takes 0 arguments but 1 argument was supplied | |
| 14 | } | |
| 15 | ||
| 6 | 16 | fn bar(t: impl Fn()) { |
| 7 | 17 | t(1i32); |
| 8 | 18 | //~^ ERROR function takes 0 arguments but 1 argument was supplied |
tests/ui/argument-suggestions/exotic-calls.stderr+26-9| ... | ... | @@ -1,11 +1,11 @@ |
| 1 | 1 | error[E0057]: this function takes 0 arguments but 1 argument was supplied |
| 2 | --> $DIR/exotic-calls.rs:2:5 | |
| 2 | --> $DIR/exotic-calls.rs:6:5 | |
| 3 | 3 | | |
| 4 | 4 | LL | t(1i32); |
| 5 | 5 | | ^ ---- unexpected argument of type `i32` |
| 6 | 6 | | |
| 7 | 7 | note: callable defined here |
| 8 | --> $DIR/exotic-calls.rs:1:11 | |
| 8 | --> $DIR/exotic-calls.rs:5:11 | |
| 9 | 9 | | |
| 10 | 10 | LL | fn foo<T: Fn()>(t: T) { |
| 11 | 11 | | ^^^^ |
| ... | ... | @@ -16,13 +16,30 @@ LL + t(); |
| 16 | 16 | | |
| 17 | 17 | |
| 18 | 18 | error[E0057]: this function takes 0 arguments but 1 argument was supplied |
| 19 | --> $DIR/exotic-calls.rs:7:5 | |
| 19 | --> $DIR/exotic-calls.rs:12:9 | |
| 20 | | | |
| 21 | LL | |t| f(t); | |
| 22 | | ^ - unexpected argument | |
| 23 | | | |
| 24 | note: callable defined here | |
| 25 | --> $DIR/exotic-calls.rs:11:12 | |
| 26 | | | |
| 27 | LL | fn foo2<T: Fn()>(f: T) { | |
| 28 | | ^^^^ | |
| 29 | help: remove the extra argument | |
| 30 | | | |
| 31 | LL - |t| f(t); | |
| 32 | LL + |t| f(); | |
| 33 | | | |
| 34 | ||
| 35 | error[E0057]: this function takes 0 arguments but 1 argument was supplied | |
| 36 | --> $DIR/exotic-calls.rs:17:5 | |
| 20 | 37 | | |
| 21 | 38 | LL | t(1i32); |
| 22 | 39 | | ^ ---- unexpected argument of type `i32` |
| 23 | 40 | | |
| 24 | 41 | note: type parameter defined here |
| 25 | --> $DIR/exotic-calls.rs:6:11 | |
| 42 | --> $DIR/exotic-calls.rs:16:11 | |
| 26 | 43 | | |
| 27 | 44 | LL | fn bar(t: impl Fn()) { |
| 28 | 45 | | ^^^^^^^^^ |
| ... | ... | @@ -33,13 +50,13 @@ LL + t(); |
| 33 | 50 | | |
| 34 | 51 | |
| 35 | 52 | error[E0057]: this function takes 0 arguments but 1 argument was supplied |
| 36 | --> $DIR/exotic-calls.rs:16:5 | |
| 53 | --> $DIR/exotic-calls.rs:26:5 | |
| 37 | 54 | | |
| 38 | 55 | LL | baz()(1i32) |
| 39 | 56 | | ^^^^^ ---- unexpected argument of type `i32` |
| 40 | 57 | | |
| 41 | 58 | note: opaque type defined here |
| 42 | --> $DIR/exotic-calls.rs:11:13 | |
| 59 | --> $DIR/exotic-calls.rs:21:13 | |
| 43 | 60 | | |
| 44 | 61 | LL | fn baz() -> impl Fn() { |
| 45 | 62 | | ^^^^^^^^^ |
| ... | ... | @@ -50,13 +67,13 @@ LL + baz()() |
| 50 | 67 | | |
| 51 | 68 | |
| 52 | 69 | error[E0057]: this function takes 0 arguments but 1 argument was supplied |
| 53 | --> $DIR/exotic-calls.rs:22:5 | |
| 70 | --> $DIR/exotic-calls.rs:32:5 | |
| 54 | 71 | | |
| 55 | 72 | LL | x(1i32); |
| 56 | 73 | | ^ ---- unexpected argument of type `i32` |
| 57 | 74 | | |
| 58 | 75 | note: closure defined here |
| 59 | --> $DIR/exotic-calls.rs:21:13 | |
| 76 | --> $DIR/exotic-calls.rs:31:13 | |
| 60 | 77 | | |
| 61 | 78 | LL | let x = || {}; |
| 62 | 79 | | ^^ |
| ... | ... | @@ -66,6 +83,6 @@ LL - x(1i32); |
| 66 | 83 | LL + x(); |
| 67 | 84 | | |
| 68 | 85 | |
| 69 | error: aborting due to 4 previous errors | |
| 86 | error: aborting due to 5 previous errors | |
| 70 | 87 | |
| 71 | 88 | For more information about this error, try `rustc --explain E0057`. |
tests/ui/asm/naked-asm-outside-naked-fn.rs+8-8| ... | ... | @@ -12,24 +12,24 @@ fn main() { |
| 12 | 12 | test1(); |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | #[naked] | |
| 15 | #[unsafe(naked)] | |
| 16 | 16 | extern "C" fn test1() { |
| 17 | unsafe { naked_asm!("") } | |
| 17 | naked_asm!("") | |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | extern "C" fn test2() { |
| 21 | unsafe { naked_asm!("") } | |
| 22 | //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]` | |
| 21 | naked_asm!("") | |
| 22 | //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` | |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | 25 | extern "C" fn test3() { |
| 26 | unsafe { (|| naked_asm!(""))() } | |
| 27 | //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]` | |
| 26 | (|| naked_asm!(""))() | |
| 27 | //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` | |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | 30 | fn test4() { |
| 31 | 31 | async move { |
| 32 | unsafe { naked_asm!("") } ; | |
| 33 | //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]` | |
| 32 | naked_asm!(""); | |
| 33 | //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` | |
| 34 | 34 | }; |
| 35 | 35 | } |
tests/ui/asm/naked-asm-outside-naked-fn.stderr+12-12| ... | ... | @@ -1,20 +1,20 @@ |
| 1 | error: the `naked_asm!` macro can only be used in functions marked with `#[naked]` | |
| 2 | --> $DIR/naked-asm-outside-naked-fn.rs:21:14 | |
| 1 | error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` | |
| 2 | --> $DIR/naked-asm-outside-naked-fn.rs:21:5 | |
| 3 | 3 | | |
| 4 | LL | unsafe { naked_asm!("") } | |
| 5 | | ^^^^^^^^^^^^^^ | |
| 4 | LL | naked_asm!("") | |
| 5 | | ^^^^^^^^^^^^^^ | |
| 6 | 6 | |
| 7 | error: the `naked_asm!` macro can only be used in functions marked with `#[naked]` | |
| 8 | --> $DIR/naked-asm-outside-naked-fn.rs:26:18 | |
| 7 | error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` | |
| 8 | --> $DIR/naked-asm-outside-naked-fn.rs:26:9 | |
| 9 | 9 | | |
| 10 | LL | unsafe { (|| naked_asm!(""))() } | |
| 11 | | ^^^^^^^^^^^^^^ | |
| 10 | LL | (|| naked_asm!(""))() | |
| 11 | | ^^^^^^^^^^^^^^ | |
| 12 | 12 | |
| 13 | error: the `naked_asm!` macro can only be used in functions marked with `#[naked]` | |
| 14 | --> $DIR/naked-asm-outside-naked-fn.rs:32:19 | |
| 13 | error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` | |
| 14 | --> $DIR/naked-asm-outside-naked-fn.rs:32:9 | |
| 15 | 15 | | |
| 16 | LL | unsafe { naked_asm!("") } ; | |
| 17 | | ^^^^^^^^^^^^^^ | |
| 16 | LL | naked_asm!(""); | |
| 17 | | ^^^^^^^^^^^^^^ | |
| 18 | 18 | |
| 19 | 19 | error: aborting due to 3 previous errors |
| 20 | 20 |
tests/ui/asm/naked-functions-ffi.rs+2-4| ... | ... | @@ -5,11 +5,9 @@ |
| 5 | 5 | |
| 6 | 6 | use std::arch::naked_asm; |
| 7 | 7 | |
| 8 | #[naked] | |
| 8 | #[unsafe(naked)] | |
| 9 | 9 | pub extern "C" fn naked(p: char) -> u128 { |
| 10 | 10 | //~^ WARN uses type `char` |
| 11 | 11 | //~| WARN uses type `u128` |
| 12 | unsafe { | |
| 13 | naked_asm!(""); | |
| 14 | } | |
| 12 | naked_asm!("") | |
| 15 | 13 | } |
tests/ui/asm/naked-functions-inline.rs+10-10| ... | ... | @@ -4,35 +4,35 @@ |
| 4 | 4 | |
| 5 | 5 | use std::arch::naked_asm; |
| 6 | 6 | |
| 7 | #[naked] | |
| 8 | pub unsafe extern "C" fn inline_none() { | |
| 7 | #[unsafe(naked)] | |
| 8 | pub extern "C" fn inline_none() { | |
| 9 | 9 | naked_asm!(""); |
| 10 | 10 | } |
| 11 | 11 | |
| 12 | #[naked] | |
| 12 | #[unsafe(naked)] | |
| 13 | 13 | #[inline] |
| 14 | 14 | //~^ ERROR [E0736] |
| 15 | pub unsafe extern "C" fn inline_hint() { | |
| 15 | pub extern "C" fn inline_hint() { | |
| 16 | 16 | naked_asm!(""); |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | #[naked] | |
| 19 | #[unsafe(naked)] | |
| 20 | 20 | #[inline(always)] |
| 21 | 21 | //~^ ERROR [E0736] |
| 22 | pub unsafe extern "C" fn inline_always() { | |
| 22 | pub extern "C" fn inline_always() { | |
| 23 | 23 | naked_asm!(""); |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | #[naked] | |
| 26 | #[unsafe(naked)] | |
| 27 | 27 | #[inline(never)] |
| 28 | 28 | //~^ ERROR [E0736] |
| 29 | pub unsafe extern "C" fn inline_never() { | |
| 29 | pub extern "C" fn inline_never() { | |
| 30 | 30 | naked_asm!(""); |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | #[naked] | |
| 33 | #[unsafe(naked)] | |
| 34 | 34 | #[cfg_attr(all(), inline(never))] |
| 35 | 35 | //~^ ERROR [E0736] |
| 36 | pub unsafe extern "C" fn conditional_inline_never() { | |
| 36 | pub extern "C" fn conditional_inline_never() { | |
| 37 | 37 | naked_asm!(""); |
| 38 | 38 | } |
tests/ui/asm/naked-functions-inline.stderr+16-16| ... | ... | @@ -1,34 +1,34 @@ |
| 1 | error[E0736]: attribute incompatible with `#[naked]` | |
| 1 | error[E0736]: attribute incompatible with `#[unsafe(naked)]` | |
| 2 | 2 | --> $DIR/naked-functions-inline.rs:13:1 |
| 3 | 3 | | |
| 4 | LL | #[naked] | |
| 5 | | -------- function marked with `#[naked]` here | |
| 4 | LL | #[unsafe(naked)] | |
| 5 | | ---------------- function marked with `#[unsafe(naked)]` here | |
| 6 | 6 | LL | #[inline] |
| 7 | | ^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` | |
| 7 | | ^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` | |
| 8 | 8 | |
| 9 | error[E0736]: attribute incompatible with `#[naked]` | |
| 9 | error[E0736]: attribute incompatible with `#[unsafe(naked)]` | |
| 10 | 10 | --> $DIR/naked-functions-inline.rs:20:1 |
| 11 | 11 | | |
| 12 | LL | #[naked] | |
| 13 | | -------- function marked with `#[naked]` here | |
| 12 | LL | #[unsafe(naked)] | |
| 13 | | ---------------- function marked with `#[unsafe(naked)]` here | |
| 14 | 14 | LL | #[inline(always)] |
| 15 | | ^^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` | |
| 15 | | ^^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` | |
| 16 | 16 | |
| 17 | error[E0736]: attribute incompatible with `#[naked]` | |
| 17 | error[E0736]: attribute incompatible with `#[unsafe(naked)]` | |
| 18 | 18 | --> $DIR/naked-functions-inline.rs:27:1 |
| 19 | 19 | | |
| 20 | LL | #[naked] | |
| 21 | | -------- function marked with `#[naked]` here | |
| 20 | LL | #[unsafe(naked)] | |
| 21 | | ---------------- function marked with `#[unsafe(naked)]` here | |
| 22 | 22 | LL | #[inline(never)] |
| 23 | | ^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` | |
| 23 | | ^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` | |
| 24 | 24 | |
| 25 | error[E0736]: attribute incompatible with `#[naked]` | |
| 25 | error[E0736]: attribute incompatible with `#[unsafe(naked)]` | |
| 26 | 26 | --> $DIR/naked-functions-inline.rs:34:19 |
| 27 | 27 | | |
| 28 | LL | #[naked] | |
| 29 | | -------- function marked with `#[naked]` here | |
| 28 | LL | #[unsafe(naked)] | |
| 29 | | ---------------- function marked with `#[unsafe(naked)]` here | |
| 30 | 30 | LL | #[cfg_attr(all(), inline(never))] |
| 31 | | ^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` | |
| 31 | | ^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` | |
| 32 | 32 | |
| 33 | 33 | error: aborting due to 4 previous errors |
| 34 | 34 |
tests/ui/asm/naked-functions-instruction-set.rs+4-4| ... | ... | @@ -12,15 +12,15 @@ extern crate minicore; |
| 12 | 12 | use minicore::*; |
| 13 | 13 | |
| 14 | 14 | #[no_mangle] |
| 15 | #[naked] | |
| 15 | #[unsafe(naked)] | |
| 16 | 16 | #[instruction_set(arm::t32)] |
| 17 | unsafe extern "C" fn test_thumb() { | |
| 17 | extern "C" fn test_thumb() { | |
| 18 | 18 | naked_asm!("bx lr"); |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | #[no_mangle] |
| 22 | #[naked] | |
| 22 | #[unsafe(naked)] | |
| 23 | 23 | #[instruction_set(arm::a32)] |
| 24 | unsafe extern "C" fn test_arm() { | |
| 24 | extern "C" fn test_arm() { | |
| 25 | 25 | naked_asm!("bx lr"); |
| 26 | 26 | } |
tests/ui/asm/naked-functions-rustic-abi.rs+6-6| ... | ... | @@ -11,17 +11,17 @@ |
| 11 | 11 | |
| 12 | 12 | use std::arch::{asm, naked_asm}; |
| 13 | 13 | |
| 14 | #[naked] | |
| 15 | pub unsafe fn rust_implicit() { | |
| 14 | #[unsafe(naked)] | |
| 15 | pub fn rust_implicit() { | |
| 16 | 16 | naked_asm!("ret"); |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | #[naked] | |
| 20 | pub unsafe extern "Rust" fn rust_explicit() { | |
| 19 | #[unsafe(naked)] | |
| 20 | pub extern "Rust" fn rust_explicit() { | |
| 21 | 21 | naked_asm!("ret"); |
| 22 | 22 | } |
| 23 | 23 | |
| 24 | #[naked] | |
| 25 | pub unsafe extern "rust-cold" fn rust_cold() { | |
| 24 | #[unsafe(naked)] | |
| 25 | pub extern "rust-cold" fn rust_cold() { | |
| 26 | 26 | naked_asm!("ret"); |
| 27 | 27 | } |
tests/ui/asm/naked-functions-target-feature.rs+6-6| ... | ... | @@ -8,14 +8,14 @@ use std::arch::{asm, naked_asm}; |
| 8 | 8 | |
| 9 | 9 | #[cfg(target_arch = "x86_64")] |
| 10 | 10 | #[target_feature(enable = "sse2")] |
| 11 | #[naked] | |
| 12 | pub unsafe extern "C" fn compatible_target_feature() { | |
| 13 | naked_asm!(""); | |
| 11 | #[unsafe(naked)] | |
| 12 | pub extern "C" fn compatible_target_feature() { | |
| 13 | naked_asm!("ret"); | |
| 14 | 14 | } |
| 15 | 15 | |
| 16 | 16 | #[cfg(target_arch = "aarch64")] |
| 17 | 17 | #[target_feature(enable = "neon")] |
| 18 | #[naked] | |
| 19 | pub unsafe extern "C" fn compatible_target_feature() { | |
| 20 | naked_asm!(""); | |
| 18 | #[unsafe(naked)] | |
| 19 | pub extern "C" fn compatible_target_feature() { | |
| 20 | naked_asm!("ret"); | |
| 21 | 21 | } |
tests/ui/asm/naked-functions-testattrs.rs+8-8| ... | ... | @@ -8,31 +8,31 @@ |
| 8 | 8 | use std::arch::naked_asm; |
| 9 | 9 | |
| 10 | 10 | #[test] |
| 11 | #[naked] | |
| 11 | #[unsafe(naked)] | |
| 12 | 12 | //~^ ERROR [E0736] |
| 13 | 13 | extern "C" fn test_naked() { |
| 14 | unsafe { naked_asm!("") }; | |
| 14 | naked_asm!("") | |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | #[should_panic] |
| 18 | 18 | #[test] |
| 19 | #[naked] | |
| 19 | #[unsafe(naked)] | |
| 20 | 20 | //~^ ERROR [E0736] |
| 21 | 21 | extern "C" fn test_naked_should_panic() { |
| 22 | unsafe { naked_asm!("") }; | |
| 22 | naked_asm!("") | |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | 25 | #[ignore] |
| 26 | 26 | #[test] |
| 27 | #[naked] | |
| 27 | #[unsafe(naked)] | |
| 28 | 28 | //~^ ERROR [E0736] |
| 29 | 29 | extern "C" fn test_naked_ignore() { |
| 30 | unsafe { naked_asm!("") }; | |
| 30 | naked_asm!("") | |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | 33 | #[bench] |
| 34 | #[naked] | |
| 34 | #[unsafe(naked)] | |
| 35 | 35 | //~^ ERROR [E0736] |
| 36 | 36 | extern "C" fn bench_naked() { |
| 37 | unsafe { naked_asm!("") }; | |
| 37 | naked_asm!("") | |
| 38 | 38 | } |
tests/ui/asm/naked-functions-testattrs.stderr+12-12| ... | ... | @@ -1,34 +1,34 @@ |
| 1 | error[E0736]: cannot use `#[naked]` with testing attributes | |
| 1 | error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes | |
| 2 | 2 | --> $DIR/naked-functions-testattrs.rs:11:1 |
| 3 | 3 | | |
| 4 | 4 | LL | #[test] |
| 5 | 5 | | ------- function marked with testing attribute here |
| 6 | LL | #[naked] | |
| 7 | | ^^^^^^^^ `#[naked]` is incompatible with testing attributes | |
| 6 | LL | #[unsafe(naked)] | |
| 7 | | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes | |
| 8 | 8 | |
| 9 | error[E0736]: cannot use `#[naked]` with testing attributes | |
| 9 | error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes | |
| 10 | 10 | --> $DIR/naked-functions-testattrs.rs:19:1 |
| 11 | 11 | | |
| 12 | 12 | LL | #[test] |
| 13 | 13 | | ------- function marked with testing attribute here |
| 14 | LL | #[naked] | |
| 15 | | ^^^^^^^^ `#[naked]` is incompatible with testing attributes | |
| 14 | LL | #[unsafe(naked)] | |
| 15 | | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes | |
| 16 | 16 | |
| 17 | error[E0736]: cannot use `#[naked]` with testing attributes | |
| 17 | error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes | |
| 18 | 18 | --> $DIR/naked-functions-testattrs.rs:27:1 |
| 19 | 19 | | |
| 20 | 20 | LL | #[test] |
| 21 | 21 | | ------- function marked with testing attribute here |
| 22 | LL | #[naked] | |
| 23 | | ^^^^^^^^ `#[naked]` is incompatible with testing attributes | |
| 22 | LL | #[unsafe(naked)] | |
| 23 | | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes | |
| 24 | 24 | |
| 25 | error[E0736]: cannot use `#[naked]` with testing attributes | |
| 25 | error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes | |
| 26 | 26 | --> $DIR/naked-functions-testattrs.rs:34:1 |
| 27 | 27 | | |
| 28 | 28 | LL | #[bench] |
| 29 | 29 | | -------- function marked with testing attribute here |
| 30 | LL | #[naked] | |
| 31 | | ^^^^^^^^ `#[naked]` is incompatible with testing attributes | |
| 30 | LL | #[unsafe(naked)] | |
| 31 | | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes | |
| 32 | 32 | |
| 33 | 33 | error: aborting due to 4 previous errors |
| 34 | 34 |
tests/ui/asm/naked-functions-unused.rs+10-20| ... | ... | @@ -64,44 +64,34 @@ pub mod normal { |
| 64 | 64 | pub mod naked { |
| 65 | 65 | use std::arch::naked_asm; |
| 66 | 66 | |
| 67 | #[naked] | |
| 67 | #[unsafe(naked)] | |
| 68 | 68 | pub extern "C" fn function(a: usize, b: usize) -> usize { |
| 69 | unsafe { | |
| 70 | naked_asm!(""); | |
| 71 | } | |
| 69 | naked_asm!("") | |
| 72 | 70 | } |
| 73 | 71 | |
| 74 | 72 | pub struct Naked; |
| 75 | 73 | |
| 76 | 74 | impl Naked { |
| 77 | #[naked] | |
| 75 | #[unsafe(naked)] | |
| 78 | 76 | pub extern "C" fn associated(a: usize, b: usize) -> usize { |
| 79 | unsafe { | |
| 80 | naked_asm!(""); | |
| 81 | } | |
| 77 | naked_asm!("") | |
| 82 | 78 | } |
| 83 | 79 | |
| 84 | #[naked] | |
| 80 | #[unsafe(naked)] | |
| 85 | 81 | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { |
| 86 | unsafe { | |
| 87 | naked_asm!(""); | |
| 88 | } | |
| 82 | naked_asm!("") | |
| 89 | 83 | } |
| 90 | 84 | } |
| 91 | 85 | |
| 92 | 86 | impl super::Trait for Naked { |
| 93 | #[naked] | |
| 87 | #[unsafe(naked)] | |
| 94 | 88 | extern "C" fn trait_associated(a: usize, b: usize) -> usize { |
| 95 | unsafe { | |
| 96 | naked_asm!(""); | |
| 97 | } | |
| 89 | naked_asm!("") | |
| 98 | 90 | } |
| 99 | 91 | |
| 100 | #[naked] | |
| 92 | #[unsafe(naked)] | |
| 101 | 93 | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { |
| 102 | unsafe { | |
| 103 | naked_asm!(""); | |
| 104 | } | |
| 94 | naked_asm!("") | |
| 105 | 95 | } |
| 106 | 96 | } |
| 107 | 97 | } |
tests/ui/asm/naked-functions.rs+28-34| ... | ... | @@ -9,8 +9,8 @@ |
| 9 | 9 | use std::arch::{asm, naked_asm}; |
| 10 | 10 | |
| 11 | 11 | #[unsafe(naked)] |
| 12 | pub unsafe extern "C" fn inline_asm_macro() { | |
| 13 | asm!("", options(raw)); | |
| 12 | pub extern "C" fn inline_asm_macro() { | |
| 13 | unsafe { asm!("", options(raw)) }; | |
| 14 | 14 | //~^ERROR the `asm!` macro is not allowed in naked functions |
| 15 | 15 | } |
| 16 | 16 | |
| ... | ... | @@ -21,7 +21,7 @@ pub struct P { |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | #[unsafe(naked)] |
| 24 | pub unsafe extern "C" fn patterns( | |
| 24 | pub extern "C" fn patterns( | |
| 25 | 25 | mut a: u32, |
| 26 | 26 | //~^ ERROR patterns not allowed in naked function parameters |
| 27 | 27 | &b: &i32, |
| ... | ... | @@ -35,7 +35,7 @@ pub unsafe extern "C" fn patterns( |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | 37 | #[unsafe(naked)] |
| 38 | pub unsafe extern "C" fn inc(a: u32) -> u32 { | |
| 38 | pub extern "C" fn inc(a: u32) -> u32 { | |
| 39 | 39 | //~^ ERROR naked functions must contain a single `naked_asm!` invocation |
| 40 | 40 | a + 1 |
| 41 | 41 | //~^ ERROR referencing function parameters is not allowed in naked functions |
| ... | ... | @@ -43,19 +43,19 @@ pub unsafe extern "C" fn inc(a: u32) -> u32 { |
| 43 | 43 | |
| 44 | 44 | #[unsafe(naked)] |
| 45 | 45 | #[allow(asm_sub_register)] |
| 46 | pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { | |
| 46 | pub extern "C" fn inc_asm(a: u32) -> u32 { | |
| 47 | 47 | naked_asm!("/* {0} */", in(reg) a) |
| 48 | 48 | //~^ ERROR the `in` operand cannot be used with `naked_asm!` |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | #[unsafe(naked)] |
| 52 | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { | |
| 52 | pub extern "C" fn inc_closure(a: u32) -> u32 { | |
| 53 | 53 | //~^ ERROR naked functions must contain a single `naked_asm!` invocation |
| 54 | 54 | (|| a + 1)() |
| 55 | 55 | } |
| 56 | 56 | |
| 57 | 57 | #[unsafe(naked)] |
| 58 | pub unsafe extern "C" fn unsupported_operands() { | |
| 58 | pub extern "C" fn unsupported_operands() { | |
| 59 | 59 | //~^ ERROR naked functions must contain a single `naked_asm!` invocation |
| 60 | 60 | let mut a = 0usize; |
| 61 | 61 | let mut b = 0usize; |
| ... | ... | @@ -84,11 +84,10 @@ pub extern "C" fn missing_assembly() { |
| 84 | 84 | #[unsafe(naked)] |
| 85 | 85 | pub extern "C" fn too_many_asm_blocks() { |
| 86 | 86 | //~^ ERROR naked functions must contain a single `naked_asm!` invocation |
| 87 | unsafe { | |
| 88 | naked_asm!("", options(noreturn)); | |
| 89 | //~^ ERROR the `noreturn` option cannot be used with `naked_asm!` | |
| 90 | naked_asm!(""); | |
| 91 | } | |
| 87 | ||
| 88 | naked_asm!("", options(noreturn)); | |
| 89 | //~^ ERROR the `noreturn` option cannot be used with `naked_asm!` | |
| 90 | naked_asm!(""); | |
| 92 | 91 | } |
| 93 | 92 | |
| 94 | 93 | pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { |
| ... | ... | @@ -124,49 +123,44 @@ unsafe extern "C" fn invalid_may_unwind() { |
| 124 | 123 | |
| 125 | 124 | #[unsafe(naked)] |
| 126 | 125 | pub extern "C" fn valid_a<T>() -> T { |
| 127 | unsafe { | |
| 128 | naked_asm!(""); | |
| 129 | } | |
| 126 | naked_asm!(""); | |
| 130 | 127 | } |
| 131 | 128 | |
| 132 | 129 | #[unsafe(naked)] |
| 133 | 130 | pub extern "C" fn valid_b() { |
| 134 | unsafe { | |
| 131 | { | |
| 135 | 132 | { |
| 136 | { | |
| 137 | naked_asm!(""); | |
| 138 | }; | |
| 133 | naked_asm!(""); | |
| 139 | 134 | }; |
| 140 | } | |
| 135 | }; | |
| 141 | 136 | } |
| 142 | 137 | |
| 143 | 138 | #[unsafe(naked)] |
| 144 | pub unsafe extern "C" fn valid_c() { | |
| 139 | pub extern "C" fn valid_c() { | |
| 145 | 140 | naked_asm!(""); |
| 146 | 141 | } |
| 147 | 142 | |
| 148 | 143 | #[cfg(target_arch = "x86_64")] |
| 149 | 144 | #[unsafe(naked)] |
| 150 | pub unsafe extern "C" fn valid_att_syntax() { | |
| 145 | pub extern "C" fn valid_att_syntax() { | |
| 151 | 146 | naked_asm!("", options(att_syntax)); |
| 152 | 147 | } |
| 153 | 148 | |
| 154 | 149 | #[unsafe(naked)] |
| 155 | #[unsafe(naked)] | |
| 156 | pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { | |
| 150 | pub extern "C" fn allow_compile_error(a: u32) -> u32 { | |
| 157 | 151 | compile_error!("this is a user specified error") |
| 158 | 152 | //~^ ERROR this is a user specified error |
| 159 | 153 | } |
| 160 | 154 | |
| 161 | 155 | #[unsafe(naked)] |
| 162 | pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { | |
| 156 | pub extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { | |
| 163 | 157 | compile_error!("this is a user specified error"); |
| 164 | 158 | //~^ ERROR this is a user specified error |
| 165 | 159 | naked_asm!("") |
| 166 | 160 | } |
| 167 | 161 | |
| 168 | 162 | #[unsafe(naked)] |
| 169 | pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { | |
| 163 | pub extern "C" fn invalid_asm_syntax(a: u32) -> u32 { | |
| 170 | 164 | naked_asm!(invalid_syntax) |
| 171 | 165 | //~^ ERROR asm template must be a string literal |
| 172 | 166 | } |
| ... | ... | @@ -174,7 +168,7 @@ pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { |
| 174 | 168 | #[cfg(target_arch = "x86_64")] |
| 175 | 169 | #[cfg_attr(target_pointer_width = "64", no_mangle)] |
| 176 | 170 | #[unsafe(naked)] |
| 177 | pub unsafe extern "C" fn compatible_cfg_attributes() { | |
| 171 | pub extern "C" fn compatible_cfg_attributes() { | |
| 178 | 172 | naked_asm!("", options(att_syntax)); |
| 179 | 173 | } |
| 180 | 174 | |
| ... | ... | @@ -183,20 +177,20 @@ pub unsafe extern "C" fn compatible_cfg_attributes() { |
| 183 | 177 | #[deny(dead_code)] |
| 184 | 178 | #[forbid(dead_code)] |
| 185 | 179 | #[unsafe(naked)] |
| 186 | pub unsafe extern "C" fn compatible_diagnostic_attributes() { | |
| 180 | pub extern "C" fn compatible_diagnostic_attributes() { | |
| 187 | 181 | naked_asm!("", options(raw)); |
| 188 | 182 | } |
| 189 | 183 | |
| 190 | 184 | #[deprecated = "test"] |
| 191 | 185 | #[unsafe(naked)] |
| 192 | pub unsafe extern "C" fn compatible_deprecated_attributes() { | |
| 186 | pub extern "C" fn compatible_deprecated_attributes() { | |
| 193 | 187 | naked_asm!("", options(raw)); |
| 194 | 188 | } |
| 195 | 189 | |
| 196 | 190 | #[cfg(target_arch = "x86_64")] |
| 197 | 191 | #[must_use] |
| 198 | 192 | #[unsafe(naked)] |
| 199 | pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { | |
| 193 | pub extern "C" fn compatible_must_use_attributes() -> u64 { | |
| 200 | 194 | naked_asm!( |
| 201 | 195 | " |
| 202 | 196 | mov rax, 42 |
| ... | ... | @@ -208,13 +202,13 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { |
| 208 | 202 | #[export_name = "exported_function_name"] |
| 209 | 203 | #[link_section = ".custom_section"] |
| 210 | 204 | #[unsafe(naked)] |
| 211 | pub unsafe extern "C" fn compatible_ffi_attributes_1() { | |
| 205 | pub extern "C" fn compatible_ffi_attributes_1() { | |
| 212 | 206 | naked_asm!("", options(raw)); |
| 213 | 207 | } |
| 214 | 208 | |
| 215 | 209 | #[cold] |
| 216 | 210 | #[unsafe(naked)] |
| 217 | pub unsafe extern "C" fn compatible_codegen_attributes() { | |
| 211 | pub extern "C" fn compatible_codegen_attributes() { | |
| 218 | 212 | naked_asm!("", options(raw)); |
| 219 | 213 | } |
| 220 | 214 | |
| ... | ... | @@ -223,12 +217,12 @@ pub unsafe extern "C" fn compatible_codegen_attributes() { |
| 223 | 217 | // a normal comment |
| 224 | 218 | #[doc(alias = "ADocAlias")] |
| 225 | 219 | #[unsafe(naked)] |
| 226 | pub unsafe extern "C" fn compatible_doc_attributes() { | |
| 220 | pub extern "C" fn compatible_doc_attributes() { | |
| 227 | 221 | naked_asm!("", options(raw)); |
| 228 | 222 | } |
| 229 | 223 | |
| 230 | 224 | #[linkage = "external"] |
| 231 | 225 | #[unsafe(naked)] |
| 232 | pub unsafe extern "C" fn compatible_linkage() { | |
| 226 | pub extern "C" fn compatible_linkage() { | |
| 233 | 227 | naked_asm!("", options(raw)); |
| 234 | 228 | } |
tests/ui/asm/naked-functions.stderr+25-25| ... | ... | @@ -11,70 +11,70 @@ LL | in(reg) a, |
| 11 | 11 | | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it |
| 12 | 12 | |
| 13 | 13 | error: the `noreturn` option cannot be used with `naked_asm!` |
| 14 | --> $DIR/naked-functions.rs:88:32 | |
| 14 | --> $DIR/naked-functions.rs:88:28 | |
| 15 | 15 | | |
| 16 | LL | naked_asm!("", options(noreturn)); | |
| 17 | | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly | |
| 16 | LL | naked_asm!("", options(noreturn)); | |
| 17 | | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly | |
| 18 | 18 | |
| 19 | 19 | error: the `nomem` option cannot be used with `naked_asm!` |
| 20 | --> $DIR/naked-functions.rs:106:28 | |
| 20 | --> $DIR/naked-functions.rs:105:28 | |
| 21 | 21 | | |
| 22 | 22 | LL | naked_asm!("", options(nomem, preserves_flags)); |
| 23 | 23 | | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly |
| 24 | 24 | |
| 25 | 25 | error: the `preserves_flags` option cannot be used with `naked_asm!` |
| 26 | --> $DIR/naked-functions.rs:106:35 | |
| 26 | --> $DIR/naked-functions.rs:105:35 | |
| 27 | 27 | | |
| 28 | 28 | LL | naked_asm!("", options(nomem, preserves_flags)); |
| 29 | 29 | | ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly |
| 30 | 30 | |
| 31 | 31 | error: the `readonly` option cannot be used with `naked_asm!` |
| 32 | --> $DIR/naked-functions.rs:113:28 | |
| 32 | --> $DIR/naked-functions.rs:112:28 | |
| 33 | 33 | | |
| 34 | 34 | LL | naked_asm!("", options(readonly, nostack), options(pure)); |
| 35 | 35 | | ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly |
| 36 | 36 | |
| 37 | 37 | error: the `nostack` option cannot be used with `naked_asm!` |
| 38 | --> $DIR/naked-functions.rs:113:38 | |
| 38 | --> $DIR/naked-functions.rs:112:38 | |
| 39 | 39 | | |
| 40 | 40 | LL | naked_asm!("", options(readonly, nostack), options(pure)); |
| 41 | 41 | | ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly |
| 42 | 42 | |
| 43 | 43 | error: the `pure` option cannot be used with `naked_asm!` |
| 44 | --> $DIR/naked-functions.rs:113:56 | |
| 44 | --> $DIR/naked-functions.rs:112:56 | |
| 45 | 45 | | |
| 46 | 46 | LL | naked_asm!("", options(readonly, nostack), options(pure)); |
| 47 | 47 | | ^^^^ the `pure` option is not meaningful for global-scoped inline assembly |
| 48 | 48 | |
| 49 | 49 | error: the `may_unwind` option cannot be used with `naked_asm!` |
| 50 | --> $DIR/naked-functions.rs:121:28 | |
| 50 | --> $DIR/naked-functions.rs:120:28 | |
| 51 | 51 | | |
| 52 | 52 | LL | naked_asm!("", options(may_unwind)); |
| 53 | 53 | | ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly |
| 54 | 54 | |
| 55 | 55 | error: this is a user specified error |
| 56 | --> $DIR/naked-functions.rs:157:5 | |
| 56 | --> $DIR/naked-functions.rs:151:5 | |
| 57 | 57 | | |
| 58 | 58 | LL | compile_error!("this is a user specified error") |
| 59 | 59 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 60 | 60 | |
| 61 | 61 | error: this is a user specified error |
| 62 | --> $DIR/naked-functions.rs:163:5 | |
| 62 | --> $DIR/naked-functions.rs:157:5 | |
| 63 | 63 | | |
| 64 | 64 | LL | compile_error!("this is a user specified error"); |
| 65 | 65 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 66 | 66 | |
| 67 | 67 | error: asm template must be a string literal |
| 68 | --> $DIR/naked-functions.rs:170:16 | |
| 68 | --> $DIR/naked-functions.rs:164:16 | |
| 69 | 69 | | |
| 70 | 70 | LL | naked_asm!(invalid_syntax) |
| 71 | 71 | | ^^^^^^^^^^^^^^ |
| 72 | 72 | |
| 73 | 73 | error[E0787]: the `asm!` macro is not allowed in naked functions |
| 74 | --> $DIR/naked-functions.rs:13:5 | |
| 74 | --> $DIR/naked-functions.rs:13:14 | |
| 75 | 75 | | |
| 76 | LL | asm!("", options(raw)); | |
| 77 | | ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead | |
| 76 | LL | unsafe { asm!("", options(raw)) }; | |
| 77 | | ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead | |
| 78 | 78 | |
| 79 | 79 | error: patterns not allowed in naked function parameters |
| 80 | 80 | --> $DIR/naked-functions.rs:25:5 |
| ... | ... | @@ -111,8 +111,8 @@ LL | a + 1 |
| 111 | 111 | error[E0787]: naked functions must contain a single `naked_asm!` invocation |
| 112 | 112 | --> $DIR/naked-functions.rs:38:1 |
| 113 | 113 | | |
| 114 | LL | pub unsafe extern "C" fn inc(a: u32) -> u32 { | |
| 115 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 114 | LL | pub extern "C" fn inc(a: u32) -> u32 { | |
| 115 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 116 | 116 | LL | |
| 117 | 117 | LL | a + 1 |
| 118 | 118 | | ----- not allowed in naked functions |
| ... | ... | @@ -120,8 +120,8 @@ LL | a + 1 |
| 120 | 120 | error[E0787]: naked functions must contain a single `naked_asm!` invocation |
| 121 | 121 | --> $DIR/naked-functions.rs:52:1 |
| 122 | 122 | | |
| 123 | LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { | |
| 124 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 123 | LL | pub extern "C" fn inc_closure(a: u32) -> u32 { | |
| 124 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 125 | 125 | LL | |
| 126 | 126 | LL | (|| a + 1)() |
| 127 | 127 | | ------------ not allowed in naked functions |
| ... | ... | @@ -129,8 +129,8 @@ LL | (|| a + 1)() |
| 129 | 129 | error[E0787]: naked functions must contain a single `naked_asm!` invocation |
| 130 | 130 | --> $DIR/naked-functions.rs:58:1 |
| 131 | 131 | | |
| 132 | LL | pub unsafe extern "C" fn unsupported_operands() { | |
| 133 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 132 | LL | pub extern "C" fn unsupported_operands() { | |
| 133 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 134 | 134 | LL | |
| 135 | 135 | LL | let mut a = 0usize; |
| 136 | 136 | | ------------------- not allowed in naked functions |
| ... | ... | @@ -155,11 +155,11 @@ error[E0787]: naked functions must contain a single `naked_asm!` invocation |
| 155 | 155 | LL | pub extern "C" fn too_many_asm_blocks() { |
| 156 | 156 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 157 | 157 | ... |
| 158 | LL | naked_asm!(""); | |
| 159 | | -------------- multiple `naked_asm!` invocations are not allowed in naked functions | |
| 158 | LL | naked_asm!(""); | |
| 159 | | -------------- multiple `naked_asm!` invocations are not allowed in naked functions | |
| 160 | 160 | |
| 161 | 161 | error: referencing function parameters is not allowed in naked functions |
| 162 | --> $DIR/naked-functions.rs:98:11 | |
| 162 | --> $DIR/naked-functions.rs:97:11 | |
| 163 | 163 | | |
| 164 | 164 | LL | *&y |
| 165 | 165 | | ^ |
| ... | ... | @@ -167,7 +167,7 @@ LL | *&y |
| 167 | 167 | = help: follow the calling convention in asm block to use parameters |
| 168 | 168 | |
| 169 | 169 | error[E0787]: naked functions must contain a single `naked_asm!` invocation |
| 170 | --> $DIR/naked-functions.rs:96:5 | |
| 170 | --> $DIR/naked-functions.rs:95:5 | |
| 171 | 171 | | |
| 172 | 172 | LL | pub extern "C" fn inner(y: usize) -> usize { |
| 173 | 173 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
tests/ui/asm/naked-invalid-attr.rs+14-14| ... | ... | @@ -1,17 +1,17 @@ |
| 1 | // Checks that #[naked] attribute can be placed on function definitions only. | |
| 1 | // Checks that #[unsafe(naked)] attribute can be placed on function definitions only. | |
| 2 | 2 | // |
| 3 | 3 | //@ needs-asm-support |
| 4 | 4 | #![feature(naked_functions)] |
| 5 | #![naked] //~ ERROR should be applied to a function definition | |
| 5 | #![unsafe(naked)] //~ ERROR should be applied to a function definition | |
| 6 | 6 | |
| 7 | 7 | use std::arch::naked_asm; |
| 8 | 8 | |
| 9 | 9 | extern "C" { |
| 10 | #[naked] //~ ERROR should be applied to a function definition | |
| 10 | #[unsafe(naked)] //~ ERROR should be applied to a function definition | |
| 11 | 11 | fn f(); |
| 12 | 12 | } |
| 13 | 13 | |
| 14 | #[naked] //~ ERROR should be applied to a function definition | |
| 14 | #[unsafe(naked)] //~ ERROR should be applied to a function definition | |
| 15 | 15 | #[repr(C)] |
| 16 | 16 | struct S { |
| 17 | 17 | a: u32, |
| ... | ... | @@ -19,35 +19,35 @@ struct S { |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | trait Invoke { |
| 22 | #[naked] //~ ERROR should be applied to a function definition | |
| 22 | #[unsafe(naked)] //~ ERROR should be applied to a function definition | |
| 23 | 23 | extern "C" fn invoke(&self); |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | 26 | impl Invoke for S { |
| 27 | #[naked] | |
| 27 | #[unsafe(naked)] | |
| 28 | 28 | extern "C" fn invoke(&self) { |
| 29 | unsafe { naked_asm!("") } | |
| 29 | naked_asm!("") | |
| 30 | 30 | } |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | #[naked] | |
| 33 | #[unsafe(naked)] | |
| 34 | 34 | extern "C" fn ok() { |
| 35 | unsafe { naked_asm!("") } | |
| 35 | naked_asm!("") | |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | 38 | impl S { |
| 39 | #[naked] | |
| 39 | #[unsafe(naked)] | |
| 40 | 40 | extern "C" fn g() { |
| 41 | unsafe { naked_asm!("") } | |
| 41 | naked_asm!("") | |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | #[naked] | |
| 44 | #[unsafe(naked)] | |
| 45 | 45 | extern "C" fn h(&self) { |
| 46 | unsafe { naked_asm!("") } | |
| 46 | naked_asm!("") | |
| 47 | 47 | } |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | 50 | fn main() { |
| 51 | #[naked] //~ ERROR should be applied to a function definition | |
| 51 | #[unsafe(naked)] //~ ERROR should be applied to a function definition | |
| 52 | 52 | || {}; |
| 53 | 53 | } |
tests/ui/asm/naked-invalid-attr.stderr+10-10| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | error: attribute should be applied to a function definition |
| 2 | 2 | --> $DIR/naked-invalid-attr.rs:14:1 |
| 3 | 3 | | |
| 4 | LL | #[naked] | |
| 5 | | ^^^^^^^^ | |
| 4 | LL | #[unsafe(naked)] | |
| 5 | | ^^^^^^^^^^^^^^^^ | |
| 6 | 6 | LL | #[repr(C)] |
| 7 | 7 | LL | / struct S { |
| 8 | 8 | LL | | a: u32, |
| ... | ... | @@ -13,32 +13,32 @@ LL | | } |
| 13 | 13 | error: attribute should be applied to a function definition |
| 14 | 14 | --> $DIR/naked-invalid-attr.rs:51:5 |
| 15 | 15 | | |
| 16 | LL | #[naked] | |
| 17 | | ^^^^^^^^ | |
| 16 | LL | #[unsafe(naked)] | |
| 17 | | ^^^^^^^^^^^^^^^^ | |
| 18 | 18 | LL | || {}; |
| 19 | 19 | | ----- not a function definition |
| 20 | 20 | |
| 21 | 21 | error: attribute should be applied to a function definition |
| 22 | 22 | --> $DIR/naked-invalid-attr.rs:22:5 |
| 23 | 23 | | |
| 24 | LL | #[naked] | |
| 25 | | ^^^^^^^^ | |
| 24 | LL | #[unsafe(naked)] | |
| 25 | | ^^^^^^^^^^^^^^^^ | |
| 26 | 26 | LL | extern "C" fn invoke(&self); |
| 27 | 27 | | ---------------------------- not a function definition |
| 28 | 28 | |
| 29 | 29 | error: attribute should be applied to a function definition |
| 30 | 30 | --> $DIR/naked-invalid-attr.rs:10:5 |
| 31 | 31 | | |
| 32 | LL | #[naked] | |
| 33 | | ^^^^^^^^ | |
| 32 | LL | #[unsafe(naked)] | |
| 33 | | ^^^^^^^^^^^^^^^^ | |
| 34 | 34 | LL | fn f(); |
| 35 | 35 | | ------- not a function definition |
| 36 | 36 | |
| 37 | 37 | error: attribute should be applied to a function definition |
| 38 | 38 | --> $DIR/naked-invalid-attr.rs:5:1 |
| 39 | 39 | | |
| 40 | LL | #![naked] | |
| 41 | | ^^^^^^^^^ cannot be applied to crates | |
| 40 | LL | #![unsafe(naked)] | |
| 41 | | ^^^^^^^^^^^^^^^^^ cannot be applied to crates | |
| 42 | 42 | |
| 43 | 43 | error: aborting due to 5 previous errors |
| 44 | 44 |
tests/ui/asm/naked-with-invalid-repr-attr.rs+10-10| ... | ... | @@ -6,43 +6,43 @@ use std::arch::naked_asm; |
| 6 | 6 | |
| 7 | 7 | #[repr(C)] |
| 8 | 8 | //~^ ERROR attribute should be applied to a struct, enum, or union [E0517] |
| 9 | #[naked] | |
| 9 | #[unsafe(naked)] | |
| 10 | 10 | extern "C" fn example1() { |
| 11 | 11 | //~^ NOTE not a struct, enum, or union |
| 12 | unsafe { naked_asm!("") } | |
| 12 | naked_asm!("") | |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | #[repr(transparent)] |
| 16 | 16 | //~^ ERROR attribute should be applied to a struct, enum, or union [E0517] |
| 17 | #[naked] | |
| 17 | #[unsafe(naked)] | |
| 18 | 18 | extern "C" fn example2() { |
| 19 | 19 | //~^ NOTE not a struct, enum, or union |
| 20 | unsafe { naked_asm!("") } | |
| 20 | naked_asm!("") | |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | #[repr(align(16), C)] |
| 24 | 24 | //~^ ERROR attribute should be applied to a struct, enum, or union [E0517] |
| 25 | #[naked] | |
| 25 | #[unsafe(naked)] | |
| 26 | 26 | extern "C" fn example3() { |
| 27 | 27 | //~^ NOTE not a struct, enum, or union |
| 28 | unsafe { naked_asm!("") } | |
| 28 | naked_asm!("") | |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | 31 | // note: two errors because of packed and C |
| 32 | 32 | #[repr(C, packed)] |
| 33 | 33 | //~^ ERROR attribute should be applied to a struct or union [E0517] |
| 34 | 34 | //~| ERROR attribute should be applied to a struct, enum, or union [E0517] |
| 35 | #[naked] | |
| 35 | #[unsafe(naked)] | |
| 36 | 36 | extern "C" fn example4() { |
| 37 | 37 | //~^ NOTE not a struct, enum, or union |
| 38 | 38 | //~| NOTE not a struct or union |
| 39 | unsafe { naked_asm!("") } | |
| 39 | naked_asm!("") | |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | 42 | #[repr(u8)] |
| 43 | 43 | //~^ ERROR attribute should be applied to an enum [E0517] |
| 44 | #[naked] | |
| 44 | #[unsafe(naked)] | |
| 45 | 45 | extern "C" fn example5() { |
| 46 | 46 | //~^ NOTE not an enum |
| 47 | unsafe { naked_asm!("") } | |
| 47 | naked_asm!("") | |
| 48 | 48 | } |
tests/ui/asm/naked-with-invalid-repr-attr.stderr+6-6| ... | ... | @@ -6,7 +6,7 @@ LL | #[repr(C)] |
| 6 | 6 | ... |
| 7 | 7 | LL | / extern "C" fn example1() { |
| 8 | 8 | LL | | |
| 9 | LL | | unsafe { naked_asm!("") } | |
| 9 | LL | | naked_asm!("") | |
| 10 | 10 | LL | | } |
| 11 | 11 | | |_- not a struct, enum, or union |
| 12 | 12 | |
| ... | ... | @@ -18,7 +18,7 @@ LL | #[repr(transparent)] |
| 18 | 18 | ... |
| 19 | 19 | LL | / extern "C" fn example2() { |
| 20 | 20 | LL | | |
| 21 | LL | | unsafe { naked_asm!("") } | |
| 21 | LL | | naked_asm!("") | |
| 22 | 22 | LL | | } |
| 23 | 23 | | |_- not a struct, enum, or union |
| 24 | 24 | |
| ... | ... | @@ -30,7 +30,7 @@ LL | #[repr(align(16), C)] |
| 30 | 30 | ... |
| 31 | 31 | LL | / extern "C" fn example3() { |
| 32 | 32 | LL | | |
| 33 | LL | | unsafe { naked_asm!("") } | |
| 33 | LL | | naked_asm!("") | |
| 34 | 34 | LL | | } |
| 35 | 35 | | |_- not a struct, enum, or union |
| 36 | 36 | |
| ... | ... | @@ -43,7 +43,7 @@ LL | #[repr(C, packed)] |
| 43 | 43 | LL | / extern "C" fn example4() { |
| 44 | 44 | LL | | |
| 45 | 45 | LL | | |
| 46 | LL | | unsafe { naked_asm!("") } | |
| 46 | LL | | naked_asm!("") | |
| 47 | 47 | LL | | } |
| 48 | 48 | | |_- not a struct, enum, or union |
| 49 | 49 | |
| ... | ... | @@ -56,7 +56,7 @@ LL | #[repr(C, packed)] |
| 56 | 56 | LL | / extern "C" fn example4() { |
| 57 | 57 | LL | | |
| 58 | 58 | LL | | |
| 59 | LL | | unsafe { naked_asm!("") } | |
| 59 | LL | | naked_asm!("") | |
| 60 | 60 | LL | | } |
| 61 | 61 | | |_- not a struct or union |
| 62 | 62 | |
| ... | ... | @@ -68,7 +68,7 @@ LL | #[repr(u8)] |
| 68 | 68 | ... |
| 69 | 69 | LL | / extern "C" fn example5() { |
| 70 | 70 | LL | | |
| 71 | LL | | unsafe { naked_asm!("") } | |
| 71 | LL | | naked_asm!("") | |
| 72 | 72 | LL | | } |
| 73 | 73 | | |_- not an enum |
| 74 | 74 |
tests/ui/asm/named-asm-labels.rs+8-8| ... | ... | @@ -175,9 +175,9 @@ fn main() { |
| 175 | 175 | |
| 176 | 176 | // Trigger on naked fns too, even though they can't be inlined, reusing a |
| 177 | 177 | // label or LTO can cause labels to break |
| 178 | #[naked] | |
| 178 | #[unsafe(naked)] | |
| 179 | 179 | pub extern "C" fn foo() -> i32 { |
| 180 | unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) } | |
| 180 | naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) | |
| 181 | 181 | //~^ ERROR avoid using named labels |
| 182 | 182 | } |
| 183 | 183 | |
| ... | ... | @@ -188,21 +188,21 @@ pub extern "C" fn bar() { |
| 188 | 188 | //~^ ERROR avoid using named labels |
| 189 | 189 | } |
| 190 | 190 | |
| 191 | #[naked] | |
| 191 | #[unsafe(naked)] | |
| 192 | 192 | pub extern "C" fn aaa() { |
| 193 | 193 | fn _local() {} |
| 194 | 194 | |
| 195 | unsafe { naked_asm!(".Laaa: nop; ret;") } //~ ERROR avoid using named labels | |
| 195 | naked_asm!(".Laaa: nop; ret;") //~ ERROR avoid using named labels | |
| 196 | 196 | } |
| 197 | 197 | |
| 198 | 198 | pub fn normal() { |
| 199 | 199 | fn _local1() {} |
| 200 | 200 | |
| 201 | #[naked] | |
| 201 | #[unsafe(naked)] | |
| 202 | 202 | pub extern "C" fn bbb() { |
| 203 | 203 | fn _very_local() {} |
| 204 | 204 | |
| 205 | unsafe { naked_asm!(".Lbbb: nop; ret;") } //~ ERROR avoid using named labels | |
| 205 | naked_asm!(".Lbbb: nop; ret;") //~ ERROR avoid using named labels | |
| 206 | 206 | } |
| 207 | 207 | |
| 208 | 208 | fn _local2() {} |
| ... | ... | @@ -219,8 +219,8 @@ fn closures() { |
| 219 | 219 | }; |
| 220 | 220 | |
| 221 | 221 | || { |
| 222 | #[naked] | |
| 223 | unsafe extern "C" fn _nested() { | |
| 222 | #[unsafe(naked)] | |
| 223 | extern "C" fn _nested() { | |
| 224 | 224 | naked_asm!("ret;"); |
| 225 | 225 | } |
| 226 | 226 |
tests/ui/asm/named-asm-labels.stderr+9-9| ... | ... | @@ -475,10 +475,10 @@ LL | #[warn(named_asm_labels)] |
| 475 | 475 | | ^^^^^^^^^^^^^^^^ |
| 476 | 476 | |
| 477 | 477 | error: avoid using named labels in inline assembly |
| 478 | --> $DIR/named-asm-labels.rs:180:26 | |
| 478 | --> $DIR/named-asm-labels.rs:180:17 | |
| 479 | 479 | | |
| 480 | LL | unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) } | |
| 481 | | ^^^^^ | |
| 480 | LL | naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) | |
| 481 | | ^^^^^ | |
| 482 | 482 | | |
| 483 | 483 | = help: only local labels of the form `<number>:` should be used in inline asm |
| 484 | 484 | = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information |
| ... | ... | @@ -493,19 +493,19 @@ LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret |
| 493 | 493 | = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information |
| 494 | 494 | |
| 495 | 495 | error: avoid using named labels in inline assembly |
| 496 | --> $DIR/named-asm-labels.rs:195:26 | |
| 496 | --> $DIR/named-asm-labels.rs:195:17 | |
| 497 | 497 | | |
| 498 | LL | unsafe { naked_asm!(".Laaa: nop; ret;") } | |
| 499 | | ^^^^^ | |
| 498 | LL | naked_asm!(".Laaa: nop; ret;") | |
| 499 | | ^^^^^ | |
| 500 | 500 | | |
| 501 | 501 | = help: only local labels of the form `<number>:` should be used in inline asm |
| 502 | 502 | = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information |
| 503 | 503 | |
| 504 | 504 | error: avoid using named labels in inline assembly |
| 505 | --> $DIR/named-asm-labels.rs:205:30 | |
| 505 | --> $DIR/named-asm-labels.rs:205:21 | |
| 506 | 506 | | |
| 507 | LL | unsafe { naked_asm!(".Lbbb: nop; ret;") } | |
| 508 | | ^^^^^ | |
| 507 | LL | naked_asm!(".Lbbb: nop; ret;") | |
| 508 | | ^^^^^ | |
| 509 | 509 | | |
| 510 | 510 | = help: only local labels of the form `<number>:` should be used in inline asm |
| 511 | 511 | = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information |
tests/ui/codegen/ref-dyn-trait-in-structs-and-enums.rs created+54| ... | ... | @@ -0,0 +1,54 @@ |
| 1 | //! Regression test for an LLVM assertion that used to be hit when: | |
| 2 | //! | |
| 3 | //! - There's a generic enum contained within a tuple struct | |
| 4 | //! - When the tuple struct is parameterized by some lifetime `'a` | |
| 5 | //! - The enum is concretized with its type argument being a reference to a trait object (of | |
| 6 | //! lifetime `'a`) | |
| 7 | //! | |
| 8 | //! Issue: <https://github.com/rust-lang/rust/issues/9719> | |
| 9 | ||
| 10 | //@ build-pass | |
| 11 | ||
| 12 | // Dummy trait implemented for `isize` to use in the test cases | |
| 13 | pub trait MyTrait { | |
| 14 | fn dummy(&self) {} | |
| 15 | } | |
| 16 | impl MyTrait for isize {} | |
| 17 | ||
| 18 | // `&dyn MyTrait` contained in enum variant | |
| 19 | pub struct EnumRefDynTrait<'a>(Enum<&'a (dyn MyTrait + 'a)>); | |
| 20 | pub enum Enum<T> { | |
| 21 | Variant(T), | |
| 22 | } | |
| 23 | ||
| 24 | fn enum_dyn_trait() { | |
| 25 | let x: isize = 42; | |
| 26 | let y = EnumRefDynTrait(Enum::Variant(&x as &dyn MyTrait)); | |
| 27 | let _ = y; | |
| 28 | } | |
| 29 | ||
| 30 | // `&dyn MyTrait` contained behind `Option` in named field of struct | |
| 31 | struct RefDynTraitNamed<'a> { | |
| 32 | x: Option<&'a (dyn MyTrait + 'a)>, | |
| 33 | } | |
| 34 | ||
| 35 | fn named_option_dyn_trait() { | |
| 36 | let x: isize = 42; | |
| 37 | let y = RefDynTraitNamed { x: Some(&x as &dyn MyTrait) }; | |
| 38 | let _ = y; | |
| 39 | } | |
| 40 | ||
| 41 | // `&dyn MyTrait` contained behind `Option` in unnamed field of struct | |
| 42 | pub struct RefDynTraitUnnamed<'a>(Option<&'a (dyn MyTrait + 'a)>); | |
| 43 | ||
| 44 | fn unnamed_option_dyn_trait() { | |
| 45 | let x: isize = 42; | |
| 46 | let y = RefDynTraitUnnamed(Some(&x as &dyn MyTrait)); | |
| 47 | let _ = y; | |
| 48 | } | |
| 49 | ||
| 50 | pub fn main() { | |
| 51 | enum_dyn_trait(); | |
| 52 | named_option_dyn_trait(); | |
| 53 | unnamed_option_dyn_trait(); | |
| 54 | } |
tests/ui/diagnostic_namespace/on_impl_trait.rs created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | // used to ICE, see <https://github.com/rust-lang/rust/issues/130627> | |
| 2 | // Instead it should just ignore the diagnostic attribute | |
| 3 | #![feature(trait_alias)] | |
| 4 | ||
| 5 | trait Test {} | |
| 6 | ||
| 7 | #[diagnostic::on_unimplemented(message = "blah", label = "blah", note = "blah")] | |
| 8 | //~^ WARN `#[diagnostic::on_unimplemented]` can only be applied to trait definitions | |
| 9 | trait Alias = Test; | |
| 10 | ||
| 11 | // Use trait alias as bound on type parameter. | |
| 12 | fn foo<T: Alias>(v: &T) {} | |
| 13 | ||
| 14 | pub fn main() { | |
| 15 | foo(&1); | |
| 16 | //~^ ERROR the trait bound `{integer}: Alias` is not satisfied | |
| 17 | } |
tests/ui/diagnostic_namespace/on_impl_trait.stderr created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions | |
| 2 | --> $DIR/on_impl_trait.rs:7:1 | |
| 3 | | | |
| 4 | LL | #[diagnostic::on_unimplemented(message = "blah", label = "blah", note = "blah")] | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default | |
| 8 | ||
| 9 | error[E0277]: the trait bound `{integer}: Alias` is not satisfied | |
| 10 | --> $DIR/on_impl_trait.rs:15:9 | |
| 11 | | | |
| 12 | LL | foo(&1); | |
| 13 | | --- ^^ the trait `Test` is not implemented for `{integer}` | |
| 14 | | | | |
| 15 | | required by a bound introduced by this call | |
| 16 | | | |
| 17 | help: this trait has no implementations, consider adding one | |
| 18 | --> $DIR/on_impl_trait.rs:5:1 | |
| 19 | | | |
| 20 | LL | trait Test {} | |
| 21 | | ^^^^^^^^^^ | |
| 22 | = note: required for `{integer}` to implement `Alias` | |
| 23 | note: required by a bound in `foo` | |
| 24 | --> $DIR/on_impl_trait.rs:12:11 | |
| 25 | | | |
| 26 | LL | fn foo<T: Alias>(v: &T) {} | |
| 27 | | ^^^^^ required by this bound in `foo` | |
| 28 | ||
| 29 | error: aborting due to 1 previous error; 1 warning emitted | |
| 30 | ||
| 31 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr+24-24| ... | ... | @@ -1,52 +1,52 @@ |
| 1 | 1 | warning: unmatched `}` found |
| 2 | --> $DIR/broken_format.rs:2:32 | |
| 2 | --> $DIR/broken_format.rs:2:42 | |
| 3 | 3 | | |
| 4 | 4 | LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 5 | | ^^^^^^^^^^^^^^^^ | |
| 6 | 6 | | |
| 7 | 7 | = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default |
| 8 | 8 | |
| 9 | 9 | warning: positional format arguments are not allowed here |
| 10 | --> $DIR/broken_format.rs:7:32 | |
| 10 | --> $DIR/broken_format.rs:7:49 | |
| 11 | 11 | | |
| 12 | 12 | LL | #[diagnostic::on_unimplemented(message = "Test {}")] |
| 13 | | ^^^^^^^^^^^^^^^^^^^ | |
| 13 | | ^ | |
| 14 | 14 | | |
| 15 | 15 | = help: only named format arguments with the name of one of the generic types are allowed in this context |
| 16 | 16 | |
| 17 | 17 | warning: positional format arguments are not allowed here |
| 18 | --> $DIR/broken_format.rs:12:32 | |
| 18 | --> $DIR/broken_format.rs:12:49 | |
| 19 | 19 | | |
| 20 | 20 | LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] |
| 21 | | ^^^^^^^^^^^^^^^^^^^^^ | |
| 21 | | ^ | |
| 22 | 22 | | |
| 23 | 23 | = help: only named format arguments with the name of one of the generic types are allowed in this context |
| 24 | 24 | |
| 25 | 25 | warning: invalid format specifier |
| 26 | --> $DIR/broken_format.rs:17:32 | |
| 26 | --> $DIR/broken_format.rs:17:42 | |
| 27 | 27 | | |
| 28 | 28 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] |
| 29 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 29 | | ^^^^^^^^^^^^^^^^^ | |
| 30 | 30 | | |
| 31 | 31 | = help: no format specifier are supported in this position |
| 32 | 32 | |
| 33 | 33 | warning: expected `}`, found `!` |
| 34 | --> $DIR/broken_format.rs:22:32 | |
| 34 | --> $DIR/broken_format.rs:22:42 | |
| 35 | 35 | | |
| 36 | 36 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] |
| 37 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 37 | | ^^^^^^^^^^^^^^^ | |
| 38 | 38 | |
| 39 | 39 | warning: unmatched `}` found |
| 40 | --> $DIR/broken_format.rs:22:32 | |
| 40 | --> $DIR/broken_format.rs:22:42 | |
| 41 | 41 | | |
| 42 | 42 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] |
| 43 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 43 | | ^^^^^^^^^^^^^^^ | |
| 44 | 44 | |
| 45 | 45 | warning: unmatched `}` found |
| 46 | --> $DIR/broken_format.rs:2:32 | |
| 46 | --> $DIR/broken_format.rs:2:42 | |
| 47 | 47 | | |
| 48 | 48 | LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] |
| 49 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 49 | | ^^^^^^^^^^^^^^^^ | |
| 50 | 50 | | |
| 51 | 51 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 52 | 52 | |
| ... | ... | @@ -70,10 +70,10 @@ LL | fn check_1(_: impl ImportantTrait1) {} |
| 70 | 70 | | ^^^^^^^^^^^^^^^ required by this bound in `check_1` |
| 71 | 71 | |
| 72 | 72 | warning: positional format arguments are not allowed here |
| 73 | --> $DIR/broken_format.rs:7:32 | |
| 73 | --> $DIR/broken_format.rs:7:49 | |
| 74 | 74 | | |
| 75 | 75 | LL | #[diagnostic::on_unimplemented(message = "Test {}")] |
| 76 | | ^^^^^^^^^^^^^^^^^^^ | |
| 76 | | ^ | |
| 77 | 77 | | |
| 78 | 78 | = help: only named format arguments with the name of one of the generic types are allowed in this context |
| 79 | 79 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| ... | ... | @@ -98,10 +98,10 @@ LL | fn check_2(_: impl ImportantTrait2) {} |
| 98 | 98 | | ^^^^^^^^^^^^^^^ required by this bound in `check_2` |
| 99 | 99 | |
| 100 | 100 | warning: positional format arguments are not allowed here |
| 101 | --> $DIR/broken_format.rs:12:32 | |
| 101 | --> $DIR/broken_format.rs:12:49 | |
| 102 | 102 | | |
| 103 | 103 | LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] |
| 104 | | ^^^^^^^^^^^^^^^^^^^^^ | |
| 104 | | ^ | |
| 105 | 105 | | |
| 106 | 106 | = help: only named format arguments with the name of one of the generic types are allowed in this context |
| 107 | 107 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| ... | ... | @@ -126,10 +126,10 @@ LL | fn check_3(_: impl ImportantTrait3) {} |
| 126 | 126 | | ^^^^^^^^^^^^^^^ required by this bound in `check_3` |
| 127 | 127 | |
| 128 | 128 | warning: invalid format specifier |
| 129 | --> $DIR/broken_format.rs:17:32 | |
| 129 | --> $DIR/broken_format.rs:17:42 | |
| 130 | 130 | | |
| 131 | 131 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] |
| 132 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 132 | | ^^^^^^^^^^^^^^^^^ | |
| 133 | 133 | | |
| 134 | 134 | = help: no format specifier are supported in this position |
| 135 | 135 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| ... | ... | @@ -154,18 +154,18 @@ LL | fn check_4(_: impl ImportantTrait4) {} |
| 154 | 154 | | ^^^^^^^^^^^^^^^ required by this bound in `check_4` |
| 155 | 155 | |
| 156 | 156 | warning: expected `}`, found `!` |
| 157 | --> $DIR/broken_format.rs:22:32 | |
| 157 | --> $DIR/broken_format.rs:22:42 | |
| 158 | 158 | | |
| 159 | 159 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] |
| 160 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 160 | | ^^^^^^^^^^^^^^^ | |
| 161 | 161 | | |
| 162 | 162 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 163 | 163 | |
| 164 | 164 | warning: unmatched `}` found |
| 165 | --> $DIR/broken_format.rs:22:32 | |
| 165 | --> $DIR/broken_format.rs:22:42 | |
| 166 | 166 | | |
| 167 | 167 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] |
| 168 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 168 | | ^^^^^^^^^^^^^^^ | |
| 169 | 169 | | |
| 170 | 170 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 171 | 171 |
tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr+40-40| ... | ... | @@ -39,82 +39,82 @@ LL | #[diagnostic::on_unimplemented = "Message"] |
| 39 | 39 | = help: only `message`, `note` and `label` are allowed as options |
| 40 | 40 | |
| 41 | 41 | warning: there is no parameter `from_desugaring` on trait `Baz` |
| 42 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | |
| 42 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:17 | |
| 43 | 43 | | |
| 44 | 44 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", |
| 45 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 45 | | ^^^^^^^^^^^^^^^ | |
| 46 | 46 | | |
| 47 | 47 | = help: expect either a generic argument name or `{Self}` as format argument |
| 48 | 48 | |
| 49 | 49 | warning: there is no parameter `direct` on trait `Baz` |
| 50 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | |
| 50 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:34 | |
| 51 | 51 | | |
| 52 | 52 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", |
| 53 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 53 | | ^^^^^^ | |
| 54 | 54 | | |
| 55 | 55 | = help: expect either a generic argument name or `{Self}` as format argument |
| 56 | 56 | |
| 57 | 57 | warning: there is no parameter `cause` on trait `Baz` |
| 58 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | |
| 58 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:42 | |
| 59 | 59 | | |
| 60 | 60 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", |
| 61 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 61 | | ^^^^^ | |
| 62 | 62 | | |
| 63 | 63 | = help: expect either a generic argument name or `{Self}` as format argument |
| 64 | 64 | |
| 65 | 65 | warning: there is no parameter `integral` on trait `Baz` |
| 66 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | |
| 66 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:49 | |
| 67 | 67 | | |
| 68 | 68 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", |
| 69 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 69 | | ^^^^^^^^ | |
| 70 | 70 | | |
| 71 | 71 | = help: expect either a generic argument name or `{Self}` as format argument |
| 72 | 72 | |
| 73 | 73 | warning: there is no parameter `integer` on trait `Baz` |
| 74 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | |
| 74 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:59 | |
| 75 | 75 | | |
| 76 | 76 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", |
| 77 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 77 | | ^^^^^^^ | |
| 78 | 78 | | |
| 79 | 79 | = help: expect either a generic argument name or `{Self}` as format argument |
| 80 | 80 | |
| 81 | 81 | warning: there is no parameter `float` on trait `Baz` |
| 82 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | |
| 82 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:15 | |
| 83 | 83 | | |
| 84 | 84 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" |
| 85 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 85 | | ^^^^^ | |
| 86 | 86 | | |
| 87 | 87 | = help: expect either a generic argument name or `{Self}` as format argument |
| 88 | 88 | |
| 89 | 89 | warning: there is no parameter `_Self` on trait `Baz` |
| 90 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | |
| 90 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:22 | |
| 91 | 91 | | |
| 92 | 92 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" |
| 93 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 93 | | ^^^^^ | |
| 94 | 94 | | |
| 95 | 95 | = help: expect either a generic argument name or `{Self}` as format argument |
| 96 | 96 | |
| 97 | 97 | warning: there is no parameter `crate_local` on trait `Baz` |
| 98 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | |
| 98 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:29 | |
| 99 | 99 | | |
| 100 | 100 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" |
| 101 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 101 | | ^^^^^^^^^^^ | |
| 102 | 102 | | |
| 103 | 103 | = help: expect either a generic argument name or `{Self}` as format argument |
| 104 | 104 | |
| 105 | 105 | warning: there is no parameter `Trait` on trait `Baz` |
| 106 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | |
| 106 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:42 | |
| 107 | 107 | | |
| 108 | 108 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" |
| 109 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 109 | | ^^^^^ | |
| 110 | 110 | | |
| 111 | 111 | = help: expect either a generic argument name or `{Self}` as format argument |
| 112 | 112 | |
| 113 | 113 | warning: there is no parameter `ItemContext` on trait `Baz` |
| 114 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | |
| 114 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:49 | |
| 115 | 115 | | |
| 116 | 116 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" |
| 117 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 117 | | ^^^^^^^^^^^ | |
| 118 | 118 | | |
| 119 | 119 | = help: expect either a generic argument name or `{Self}` as format argument |
| 120 | 120 | |
| ... | ... | @@ -191,91 +191,91 @@ LL | fn takes_bar(_: impl Bar) {} |
| 191 | 191 | | ^^^ required by this bound in `takes_bar` |
| 192 | 192 | |
| 193 | 193 | warning: there is no parameter `from_desugaring` on trait `Baz` |
| 194 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | |
| 194 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:17 | |
| 195 | 195 | | |
| 196 | 196 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", |
| 197 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 197 | | ^^^^^^^^^^^^^^^ | |
| 198 | 198 | | |
| 199 | 199 | = help: expect either a generic argument name or `{Self}` as format argument |
| 200 | 200 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 201 | 201 | |
| 202 | 202 | warning: there is no parameter `direct` on trait `Baz` |
| 203 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | |
| 203 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:34 | |
| 204 | 204 | | |
| 205 | 205 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", |
| 206 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 206 | | ^^^^^^ | |
| 207 | 207 | | |
| 208 | 208 | = help: expect either a generic argument name or `{Self}` as format argument |
| 209 | 209 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 210 | 210 | |
| 211 | 211 | warning: there is no parameter `cause` on trait `Baz` |
| 212 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | |
| 212 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:42 | |
| 213 | 213 | | |
| 214 | 214 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", |
| 215 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 215 | | ^^^^^ | |
| 216 | 216 | | |
| 217 | 217 | = help: expect either a generic argument name or `{Self}` as format argument |
| 218 | 218 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 219 | 219 | |
| 220 | 220 | warning: there is no parameter `integral` on trait `Baz` |
| 221 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | |
| 221 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:49 | |
| 222 | 222 | | |
| 223 | 223 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", |
| 224 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 224 | | ^^^^^^^^ | |
| 225 | 225 | | |
| 226 | 226 | = help: expect either a generic argument name or `{Self}` as format argument |
| 227 | 227 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 228 | 228 | |
| 229 | 229 | warning: there is no parameter `integer` on trait `Baz` |
| 230 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5 | |
| 230 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:59 | |
| 231 | 231 | | |
| 232 | 232 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", |
| 233 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 233 | | ^^^^^^^ | |
| 234 | 234 | | |
| 235 | 235 | = help: expect either a generic argument name or `{Self}` as format argument |
| 236 | 236 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 237 | 237 | |
| 238 | 238 | warning: there is no parameter `float` on trait `Baz` |
| 239 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | |
| 239 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:15 | |
| 240 | 240 | | |
| 241 | 241 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" |
| 242 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 242 | | ^^^^^ | |
| 243 | 243 | | |
| 244 | 244 | = help: expect either a generic argument name or `{Self}` as format argument |
| 245 | 245 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 246 | 246 | |
| 247 | 247 | warning: there is no parameter `_Self` on trait `Baz` |
| 248 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | |
| 248 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:22 | |
| 249 | 249 | | |
| 250 | 250 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" |
| 251 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 251 | | ^^^^^ | |
| 252 | 252 | | |
| 253 | 253 | = help: expect either a generic argument name or `{Self}` as format argument |
| 254 | 254 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 255 | 255 | |
| 256 | 256 | warning: there is no parameter `crate_local` on trait `Baz` |
| 257 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | |
| 257 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:29 | |
| 258 | 258 | | |
| 259 | 259 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" |
| 260 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 260 | | ^^^^^^^^^^^ | |
| 261 | 261 | | |
| 262 | 262 | = help: expect either a generic argument name or `{Self}` as format argument |
| 263 | 263 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 264 | 264 | |
| 265 | 265 | warning: there is no parameter `Trait` on trait `Baz` |
| 266 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | |
| 266 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:42 | |
| 267 | 267 | | |
| 268 | 268 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" |
| 269 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 269 | | ^^^^^ | |
| 270 | 270 | | |
| 271 | 271 | = help: expect either a generic argument name or `{Self}` as format argument |
| 272 | 272 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 273 | 273 | |
| 274 | 274 | warning: there is no parameter `ItemContext` on trait `Baz` |
| 275 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5 | |
| 275 | --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:49 | |
| 276 | 276 | | |
| 277 | 277 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" |
| 278 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 278 | | ^^^^^^^^^^^ | |
| 279 | 279 | | |
| 280 | 280 | = help: expect either a generic argument name or `{Self}` as format argument |
| 281 | 281 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr+4-4| ... | ... | @@ -47,10 +47,10 @@ LL | #[diagnostic::on_unimplemented] |
| 47 | 47 | = help: at least one of the `message`, `note` and `label` options are expected |
| 48 | 48 | |
| 49 | 49 | warning: there is no parameter `DoesNotExist` on trait `Test` |
| 50 | --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32 | |
| 50 | --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:44 | |
| 51 | 51 | | |
| 52 | 52 | LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] |
| 53 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 53 | | ^^^^^^^^^^^^ | |
| 54 | 54 | | |
| 55 | 55 | = help: expect either a generic argument name or `{Self}` as format argument |
| 56 | 56 | |
| ... | ... | @@ -167,10 +167,10 @@ LL | fn take_whatever(_: impl Whatever) {} |
| 167 | 167 | | ^^^^^^^^ required by this bound in `take_whatever` |
| 168 | 168 | |
| 169 | 169 | warning: there is no parameter `DoesNotExist` on trait `Test` |
| 170 | --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32 | |
| 170 | --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:44 | |
| 171 | 171 | | |
| 172 | 172 | LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] |
| 173 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 173 | | ^^^^^^^^^^^^ | |
| 174 | 174 | | |
| 175 | 175 | = help: expect either a generic argument name or `{Self}` as format argument |
| 176 | 176 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
tests/ui/feature-gates/feature-gate-naked_functions.rs+2-4| ... | ... | @@ -3,20 +3,18 @@ |
| 3 | 3 | use std::arch::naked_asm; |
| 4 | 4 | //~^ ERROR use of unstable library feature `naked_functions` |
| 5 | 5 | |
| 6 | #[naked] | |
| 6 | #[naked] //~ ERROR unsafe attribute used without unsafe | |
| 7 | 7 | //~^ ERROR the `#[naked]` attribute is an experimental feature |
| 8 | 8 | extern "C" fn naked() { |
| 9 | 9 | naked_asm!("") |
| 10 | 10 | //~^ ERROR use of unstable library feature `naked_functions` |
| 11 | //~| ERROR: requires unsafe | |
| 12 | 11 | } |
| 13 | 12 | |
| 14 | #[naked] | |
| 13 | #[naked] //~ ERROR unsafe attribute used without unsafe | |
| 15 | 14 | //~^ ERROR the `#[naked]` attribute is an experimental feature |
| 16 | 15 | extern "C" fn naked_2() -> isize { |
| 17 | 16 | naked_asm!("") |
| 18 | 17 | //~^ ERROR use of unstable library feature `naked_functions` |
| 19 | //~| ERROR: requires unsafe | |
| 20 | 18 | } |
| 21 | 19 | |
| 22 | 20 | fn main() {} |
tests/ui/feature-gates/feature-gate-naked_functions.stderr+25-20| ... | ... | @@ -9,7 +9,7 @@ LL | naked_asm!("") |
| 9 | 9 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date |
| 10 | 10 | |
| 11 | 11 | error[E0658]: use of unstable library feature `naked_functions` |
| 12 | --> $DIR/feature-gate-naked_functions.rs:17:5 | |
| 12 | --> $DIR/feature-gate-naked_functions.rs:16:5 | |
| 13 | 13 | | |
| 14 | 14 | LL | naked_asm!("") |
| 15 | 15 | | ^^^^^^^^^ |
| ... | ... | @@ -18,6 +18,28 @@ LL | naked_asm!("") |
| 18 | 18 | = help: add `#![feature(naked_functions)]` to the crate attributes to enable |
| 19 | 19 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date |
| 20 | 20 | |
| 21 | error: unsafe attribute used without unsafe | |
| 22 | --> $DIR/feature-gate-naked_functions.rs:6:3 | |
| 23 | | | |
| 24 | LL | #[naked] | |
| 25 | | ^^^^^ usage of unsafe attribute | |
| 26 | | | |
| 27 | help: wrap the attribute in `unsafe(...)` | |
| 28 | | | |
| 29 | LL | #[unsafe(naked)] | |
| 30 | | +++++++ + | |
| 31 | ||
| 32 | error: unsafe attribute used without unsafe | |
| 33 | --> $DIR/feature-gate-naked_functions.rs:13:3 | |
| 34 | | | |
| 35 | LL | #[naked] | |
| 36 | | ^^^^^ usage of unsafe attribute | |
| 37 | | | |
| 38 | help: wrap the attribute in `unsafe(...)` | |
| 39 | | | |
| 40 | LL | #[unsafe(naked)] | |
| 41 | | +++++++ + | |
| 42 | ||
| 21 | 43 | error[E0658]: the `#[naked]` attribute is an experimental feature |
| 22 | 44 | --> $DIR/feature-gate-naked_functions.rs:6:1 |
| 23 | 45 | | |
| ... | ... | @@ -29,7 +51,7 @@ LL | #[naked] |
| 29 | 51 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date |
| 30 | 52 | |
| 31 | 53 | error[E0658]: the `#[naked]` attribute is an experimental feature |
| 32 | --> $DIR/feature-gate-naked_functions.rs:14:1 | |
| 54 | --> $DIR/feature-gate-naked_functions.rs:13:1 | |
| 33 | 55 | | |
| 34 | 56 | LL | #[naked] |
| 35 | 57 | | ^^^^^^^^ |
| ... | ... | @@ -48,23 +70,6 @@ LL | use std::arch::naked_asm; |
| 48 | 70 | = help: add `#![feature(naked_functions)]` to the crate attributes to enable |
| 49 | 71 | = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date |
| 50 | 72 | |
| 51 | error[E0133]: use of inline assembly is unsafe and requires unsafe function or block | |
| 52 | --> $DIR/feature-gate-naked_functions.rs:9:5 | |
| 53 | | | |
| 54 | LL | naked_asm!("") | |
| 55 | | ^^^^^^^^^^^^^^ use of inline assembly | |
| 56 | | | |
| 57 | = note: inline assembly is entirely unchecked and can cause undefined behavior | |
| 58 | ||
| 59 | error[E0133]: use of inline assembly is unsafe and requires unsafe function or block | |
| 60 | --> $DIR/feature-gate-naked_functions.rs:17:5 | |
| 61 | | | |
| 62 | LL | naked_asm!("") | |
| 63 | | ^^^^^^^^^^^^^^ use of inline assembly | |
| 64 | | | |
| 65 | = note: inline assembly is entirely unchecked and can cause undefined behavior | |
| 66 | ||
| 67 | 73 | error: aborting due to 7 previous errors |
| 68 | 74 | |
| 69 | Some errors have detailed explanations: E0133, E0658. | |
| 70 | For more information about an error, try `rustc --explain E0133`. | |
| 75 | For more information about this error, try `rustc --explain E0658`. |
tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs+3-3| ... | ... | @@ -5,19 +5,19 @@ |
| 5 | 5 | |
| 6 | 6 | use std::arch::naked_asm; |
| 7 | 7 | |
| 8 | #[naked] | |
| 8 | #[unsafe(naked)] | |
| 9 | 9 | pub unsafe fn rust_implicit() { |
| 10 | 10 | //~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions |
| 11 | 11 | naked_asm!("ret"); |
| 12 | 12 | } |
| 13 | 13 | |
| 14 | #[naked] | |
| 14 | #[unsafe(naked)] | |
| 15 | 15 | pub unsafe extern "Rust" fn rust_explicit() { |
| 16 | 16 | //~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions |
| 17 | 17 | naked_asm!("ret"); |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | #[naked] | |
| 20 | #[unsafe(naked)] | |
| 21 | 21 | pub unsafe extern "rust-cold" fn rust_cold() { |
| 22 | 22 | //~^ ERROR `#[naked]` is currently unstable on `extern "rust-cold"` functions |
| 23 | 23 | naked_asm!("ret"); |
tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | |
| 6 | 6 | use std::arch::naked_asm; |
| 7 | 7 | |
| 8 | #[naked] | |
| 8 | #[unsafe(naked)] | |
| 9 | 9 | #[target_feature(enable = "avx2")] |
| 10 | 10 | //~^ ERROR: `#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions |
| 11 | 11 | extern "C" fn naked() { |
tests/ui/impl-unused-tps.stderr+17-17| ... | ... | @@ -7,23 +7,6 @@ LL | impl<T> Foo<T> for [isize; 0] { |
| 7 | 7 | LL | impl<T, U> Foo<T> for U { |
| 8 | 8 | | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]` |
| 9 | 9 | |
| 10 | error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates | |
| 11 | --> $DIR/impl-unused-tps.rs:32:9 | |
| 12 | | | |
| 13 | LL | impl<T, U> Bar for T { | |
| 14 | | ^ unconstrained type parameter | |
| 15 | ||
| 16 | error[E0119]: conflicting implementations of trait `Bar` | |
| 17 | --> $DIR/impl-unused-tps.rs:40:1 | |
| 18 | | | |
| 19 | LL | impl<T, U> Bar for T { | |
| 20 | | -------------------- first implementation here | |
| 21 | ... | |
| 22 | LL | / impl<T, U> Bar for T | |
| 23 | LL | | where | |
| 24 | LL | | T: Bar<Out = U>, | |
| 25 | | |____________________^ conflicting implementation | |
| 26 | ||
| 27 | 10 | error[E0119]: conflicting implementations of trait `Foo<[isize; 0]>` for type `[isize; 0]` |
| 28 | 11 | --> $DIR/impl-unused-tps.rs:49:1 |
| 29 | 12 | | |
| ... | ... | @@ -52,6 +35,12 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self |
| 52 | 35 | LL | impl<T, U> Foo<T> for [isize; 1] { |
| 53 | 36 | | ^ unconstrained type parameter |
| 54 | 37 | |
| 38 | error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates | |
| 39 | --> $DIR/impl-unused-tps.rs:32:9 | |
| 40 | | | |
| 41 | LL | impl<T, U> Bar for T { | |
| 42 | | ^ unconstrained type parameter | |
| 43 | ||
| 55 | 44 | error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates |
| 56 | 45 | --> $DIR/impl-unused-tps.rs:40:9 |
| 57 | 46 | | |
| ... | ... | @@ -70,6 +59,17 @@ error[E0207]: the type parameter `V` is not constrained by the impl trait, self |
| 70 | 59 | LL | impl<T, U, V> Foo<T> for T |
| 71 | 60 | | ^ unconstrained type parameter |
| 72 | 61 | |
| 62 | error[E0119]: conflicting implementations of trait `Bar` | |
| 63 | --> $DIR/impl-unused-tps.rs:40:1 | |
| 64 | | | |
| 65 | LL | impl<T, U> Bar for T { | |
| 66 | | -------------------- first implementation here | |
| 67 | ... | |
| 68 | LL | / impl<T, U> Bar for T | |
| 69 | LL | | where | |
| 70 | LL | | T: Bar<Out = U>, | |
| 71 | | |____________________^ conflicting implementation | |
| 72 | ||
| 73 | 73 | error: aborting due to 9 previous errors |
| 74 | 74 | |
| 75 | 75 | Some errors have detailed explanations: E0119, E0207. |
tests/ui/issues/auxiliary/issue-14421.rs deleted-25| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | #![crate_type="lib"] | |
| 2 | #![deny(warnings)] | |
| 3 | #![allow(dead_code)] | |
| 4 | ||
| 5 | pub use src::aliases::B; | |
| 6 | pub use src::hidden_core::make; | |
| 7 | ||
| 8 | mod src { | |
| 9 | pub mod aliases { | |
| 10 | use super::hidden_core::A; | |
| 11 | pub type B = A<f32>; | |
| 12 | } | |
| 13 | ||
| 14 | pub mod hidden_core { | |
| 15 | use super::aliases::B; | |
| 16 | ||
| 17 | pub struct A<T> { t: T } | |
| 18 | ||
| 19 | pub fn make() -> B { A { t: 1.0 } } | |
| 20 | ||
| 21 | impl<T> A<T> { | |
| 22 | pub fn foo(&mut self) { println!("called foo"); } | |
| 23 | } | |
| 24 | } | |
| 25 | } |
tests/ui/issues/issue-14421.rs deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | //@ run-pass | |
| 2 | #![allow(non_snake_case)] | |
| 3 | ||
| 4 | //@ aux-build:issue-14421.rs | |
| 5 | ||
| 6 | ||
| 7 | extern crate issue_14421 as bug_lib; | |
| 8 | ||
| 9 | use bug_lib::B; | |
| 10 | use bug_lib::make; | |
| 11 | ||
| 12 | pub fn main() { | |
| 13 | let mut an_A: B = make(); | |
| 14 | an_A.foo(); | |
| 15 | } |
tests/ui/issues/issue-16939.rs deleted-8| ... | ... | @@ -1,8 +0,0 @@ |
| 1 | // Make sure we don't ICE when making an overloaded call with the | |
| 2 | // wrong arity. | |
| 3 | ||
| 4 | fn _foo<F: Fn()> (f: F) { | |
| 5 | |t| f(t); //~ ERROR E0057 | |
| 6 | } | |
| 7 | ||
| 8 | fn main() {} |
tests/ui/issues/issue-16939.stderr deleted-20| ... | ... | @@ -1,20 +0,0 @@ |
| 1 | error[E0057]: this function takes 0 arguments but 1 argument was supplied | |
| 2 | --> $DIR/issue-16939.rs:5:9 | |
| 3 | | | |
| 4 | LL | |t| f(t); | |
| 5 | | ^ - unexpected argument | |
| 6 | | | |
| 7 | note: callable defined here | |
| 8 | --> $DIR/issue-16939.rs:4:12 | |
| 9 | | | |
| 10 | LL | fn _foo<F: Fn()> (f: F) { | |
| 11 | | ^^^^ | |
| 12 | help: remove the extra argument | |
| 13 | | | |
| 14 | LL - |t| f(t); | |
| 15 | LL + |t| f(); | |
| 16 | | | |
| 17 | ||
| 18 | error: aborting due to 1 previous error | |
| 19 | ||
| 20 | For more information about this error, try `rustc --explain E0057`. |
tests/ui/issues/issue-23808.rs deleted-59| ... | ... | @@ -1,59 +0,0 @@ |
| 1 | //@ run-pass | |
| 2 | ||
| 3 | #![deny(dead_code)] | |
| 4 | ||
| 5 | // use different types / traits to test all combinations | |
| 6 | ||
| 7 | trait Const { | |
| 8 | const C: (); | |
| 9 | } | |
| 10 | ||
| 11 | trait StaticFn { | |
| 12 | fn sfn(); | |
| 13 | } | |
| 14 | ||
| 15 | struct ConstStruct; | |
| 16 | struct StaticFnStruct; | |
| 17 | ||
| 18 | enum ConstEnum {} | |
| 19 | enum StaticFnEnum {} | |
| 20 | ||
| 21 | struct AliasedConstStruct; | |
| 22 | struct AliasedStaticFnStruct; | |
| 23 | ||
| 24 | enum AliasedConstEnum {} | |
| 25 | enum AliasedStaticFnEnum {} | |
| 26 | ||
| 27 | type AliasConstStruct = AliasedConstStruct; | |
| 28 | type AliasStaticFnStruct = AliasedStaticFnStruct; | |
| 29 | type AliasConstEnum = AliasedConstEnum; | |
| 30 | type AliasStaticFnEnum = AliasedStaticFnEnum; | |
| 31 | ||
| 32 | macro_rules! impl_Const {($($T:ident),*) => {$( | |
| 33 | impl Const for $T { | |
| 34 | const C: () = (); | |
| 35 | } | |
| 36 | )*}} | |
| 37 | ||
| 38 | macro_rules! impl_StaticFn {($($T:ident),*) => {$( | |
| 39 | impl StaticFn for $T { | |
| 40 | fn sfn() {} | |
| 41 | } | |
| 42 | )*}} | |
| 43 | ||
| 44 | impl_Const!(ConstStruct, ConstEnum, AliasedConstStruct, AliasedConstEnum); | |
| 45 | impl_StaticFn!(StaticFnStruct, StaticFnEnum, AliasedStaticFnStruct, AliasedStaticFnEnum); | |
| 46 | ||
| 47 | fn main() { | |
| 48 | let () = ConstStruct::C; | |
| 49 | let () = ConstEnum::C; | |
| 50 | ||
| 51 | StaticFnStruct::sfn(); | |
| 52 | StaticFnEnum::sfn(); | |
| 53 | ||
| 54 | let () = AliasConstStruct::C; | |
| 55 | let () = AliasConstEnum::C; | |
| 56 | ||
| 57 | AliasStaticFnStruct::sfn(); | |
| 58 | AliasStaticFnEnum::sfn(); | |
| 59 | } |
tests/ui/issues/issue-9719.rs deleted-40| ... | ... | @@ -1,40 +0,0 @@ |
| 1 | //@ build-pass | |
| 2 | #![allow(dead_code)] | |
| 3 | ||
| 4 | mod a { | |
| 5 | pub enum Enum<T> { | |
| 6 | A(T), | |
| 7 | } | |
| 8 | ||
| 9 | pub trait X { | |
| 10 | fn dummy(&self) { } | |
| 11 | } | |
| 12 | impl X for isize {} | |
| 13 | ||
| 14 | pub struct Z<'a>(Enum<&'a (dyn X + 'a)>); | |
| 15 | fn foo() { let x: isize = 42; let z = Z(Enum::A(&x as &dyn X)); let _ = z; } | |
| 16 | } | |
| 17 | ||
| 18 | mod b { | |
| 19 | trait X { | |
| 20 | fn dummy(&self) { } | |
| 21 | } | |
| 22 | impl X for isize {} | |
| 23 | struct Y<'a>{ | |
| 24 | x:Option<&'a (dyn X + 'a)>, | |
| 25 | } | |
| 26 | ||
| 27 | fn bar() { | |
| 28 | let x: isize = 42; | |
| 29 | let _y = Y { x: Some(&x as &dyn X) }; | |
| 30 | } | |
| 31 | } | |
| 32 | ||
| 33 | mod c { | |
| 34 | pub trait X { fn f(&self); } | |
| 35 | impl X for isize { fn f(&self) {} } | |
| 36 | pub struct Z<'a>(Option<&'a (dyn X + 'a)>); | |
| 37 | fn main() { let x: isize = 42; let z = Z(Some(&x as &dyn X)); let _ = z; } | |
| 38 | } | |
| 39 | ||
| 40 | pub fn main() {} |
tests/ui/lint/dead-code/auxiliary/no-dead-code-reexported-types-across-crates.rs created+33| ... | ... | @@ -0,0 +1,33 @@ |
| 1 | //! Auxilary file for testing `dead_code` lint. This crate is compiled as a library and exposes | |
| 2 | //! aliased types. When used externally, there should not be warnings of `dead_code` | |
| 3 | //! | |
| 4 | //! Issue: <https://github.com/rust-lang/rust/issues/14421> | |
| 5 | ||
| 6 | // Expose internal types to be used in external test | |
| 7 | pub use src::aliases::ExposedType; | |
| 8 | pub use src::hidden_core::new; | |
| 9 | ||
| 10 | mod src { | |
| 11 | pub mod aliases { | |
| 12 | use super::hidden_core::InternalStruct; | |
| 13 | pub type ExposedType = InternalStruct<f32>; | |
| 14 | } | |
| 15 | ||
| 16 | pub mod hidden_core { | |
| 17 | use super::aliases::ExposedType; | |
| 18 | ||
| 19 | pub struct InternalStruct<T> { | |
| 20 | _x: T, | |
| 21 | } | |
| 22 | ||
| 23 | pub fn new() -> ExposedType { | |
| 24 | InternalStruct { _x: 1.0 } | |
| 25 | } | |
| 26 | ||
| 27 | impl<T> InternalStruct<T> { | |
| 28 | pub fn foo(&mut self) { | |
| 29 | println!("called foo"); | |
| 30 | } | |
| 31 | } | |
| 32 | } | |
| 33 | } |
tests/ui/lint/dead-code/no-dead-code-for-static-trait-impl.rs created+61| ... | ... | @@ -0,0 +1,61 @@ |
| 1 | //! Regression test to ensure false positive `dead_code` diagnostic warnings are not triggered for | |
| 2 | //! structs and enums that implement static trait functions or use associated constants. | |
| 3 | //! | |
| 4 | //! Aliased versions of all cases are also tested | |
| 5 | //! | |
| 6 | //! Issue: <https://github.com/rust-lang/rust/issues/23808> | |
| 7 | ||
| 8 | //@ check-pass | |
| 9 | #![deny(dead_code)] | |
| 10 | ||
| 11 | trait Const { | |
| 12 | const C: (); | |
| 13 | } | |
| 14 | ||
| 15 | trait StaticFn { | |
| 16 | fn sfn(); | |
| 17 | } | |
| 18 | ||
| 19 | macro_rules! impl_const {($($T:ident),*) => {$( | |
| 20 | impl Const for $T { | |
| 21 | const C: () = (); | |
| 22 | } | |
| 23 | )*}} | |
| 24 | ||
| 25 | macro_rules! impl_static_fn {($($T:ident),*) => {$( | |
| 26 | impl StaticFn for $T { | |
| 27 | fn sfn() {} | |
| 28 | } | |
| 29 | )*}} | |
| 30 | ||
| 31 | struct ConstStruct; | |
| 32 | enum ConstEnum {} | |
| 33 | struct AliasedConstStruct; | |
| 34 | type AliasConstStruct = AliasedConstStruct; | |
| 35 | enum AliasedConstEnum {} | |
| 36 | type AliasConstEnum = AliasedConstEnum; | |
| 37 | ||
| 38 | impl_const!(ConstStruct, ConstEnum, AliasedConstStruct, AliasedConstEnum); | |
| 39 | ||
| 40 | struct StaticFnStruct; | |
| 41 | enum StaticFnEnum {} | |
| 42 | struct AliasedStaticFnStruct; | |
| 43 | type AliasStaticFnStruct = AliasedStaticFnStruct; | |
| 44 | enum AliasedStaticFnEnum {} | |
| 45 | type AliasStaticFnEnum = AliasedStaticFnEnum; | |
| 46 | ||
| 47 | impl_static_fn!(StaticFnStruct, StaticFnEnum, AliasedStaticFnStruct, AliasedStaticFnEnum); | |
| 48 | ||
| 49 | fn main() { | |
| 50 | // Use the associated constant for all the types, they should be considered "used" | |
| 51 | let () = ConstStruct::C; | |
| 52 | let () = ConstEnum::C; | |
| 53 | let () = AliasConstStruct::C; | |
| 54 | let () = AliasConstEnum::C; | |
| 55 | ||
| 56 | // Use the associated static function for all the types, they should be considered "used" | |
| 57 | StaticFnStruct::sfn(); | |
| 58 | StaticFnEnum::sfn(); | |
| 59 | AliasStaticFnStruct::sfn(); | |
| 60 | AliasStaticFnEnum::sfn(); | |
| 61 | } |
tests/ui/lint/dead-code/no-dead-code-reexported-types-across-crates.rs created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | //! Regression test to ensure that `dead_code` warning does not get triggered when using re-exported | |
| 2 | //! types that are exposed from a different crate | |
| 3 | //! | |
| 4 | //! Issue: <https://github.com/rust-lang/rust/issues/14421> | |
| 5 | ||
| 6 | //@ check-pass | |
| 7 | //@ aux-build:no-dead-code-reexported-types-across-crates.rs | |
| 8 | ||
| 9 | extern crate no_dead_code_reexported_types_across_crates as bug_lib; | |
| 10 | ||
| 11 | use bug_lib::ExposedType; | |
| 12 | use bug_lib::new; | |
| 13 | ||
| 14 | pub fn main() { | |
| 15 | let mut x: ExposedType = new(); | |
| 16 | x.foo(); | |
| 17 | } |
tests/ui/on-unimplemented/bad-annotation.rs+2-2| ... | ... | @@ -20,12 +20,12 @@ trait BadAnnotation1 |
| 20 | 20 | {} |
| 21 | 21 | |
| 22 | 22 | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] |
| 23 | //~^ ERROR there is no parameter `C` on trait `BadAnnotation2` | |
| 23 | //~^ ERROR cannot find parameter C on this trait | |
| 24 | 24 | trait BadAnnotation2<A,B> |
| 25 | 25 | {} |
| 26 | 26 | |
| 27 | 27 | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] |
| 28 | //~^ ERROR only named generic parameters are allowed | |
| 28 | //~^ ERROR positional format arguments are not allowed here | |
| 29 | 29 | trait BadAnnotation3<A,B> |
| 30 | 30 | {} |
| 31 | 31 |
tests/ui/on-unimplemented/bad-annotation.stderr+6-6| ... | ... | @@ -11,17 +11,17 @@ LL | #[rustc_on_unimplemented = "message"] |
| 11 | 11 | LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")] |
| 12 | 12 | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| 13 | 13 | |
| 14 | error[E0230]: there is no parameter `C` on trait `BadAnnotation2` | |
| 15 | --> $DIR/bad-annotation.rs:22:1 | |
| 14 | error[E0230]: cannot find parameter C on this trait | |
| 15 | --> $DIR/bad-annotation.rs:22:90 | |
| 16 | 16 | | |
| 17 | 17 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] |
| 18 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 18 | | ^ | |
| 19 | 19 | |
| 20 | error[E0231]: only named generic parameters are allowed | |
| 21 | --> $DIR/bad-annotation.rs:27:1 | |
| 20 | error[E0231]: positional format arguments are not allowed here | |
| 21 | --> $DIR/bad-annotation.rs:27:90 | |
| 22 | 22 | | |
| 23 | 23 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] |
| 24 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 24 | | ^ | |
| 25 | 25 | |
| 26 | 26 | error[E0232]: this attribute must have a valid value |
| 27 | 27 | --> $DIR/bad-annotation.rs:32:26 |
tests/ui/on-unimplemented/impl-substs.rs deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | #![feature(rustc_attrs)] | |
| 2 | ||
| 3 | trait Foo<A> { | |
| 4 | fn foo(self); | |
| 5 | } | |
| 6 | ||
| 7 | #[rustc_on_unimplemented = "an impl did not match: {A} {B} {C}"] | |
| 8 | impl<A, B, C> Foo<A> for (A, B, C) { | |
| 9 | fn foo(self) {} | |
| 10 | } | |
| 11 | ||
| 12 | fn main() { | |
| 13 | Foo::<usize>::foo((1i32, 1i32, 1i32)); | |
| 14 | //~^ ERROR the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied | |
| 15 | } |
tests/ui/on-unimplemented/impl-substs.stderr deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | error[E0277]: the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied | |
| 2 | --> $DIR/impl-substs.rs:13:23 | |
| 3 | | | |
| 4 | LL | Foo::<usize>::foo((1i32, 1i32, 1i32)); | |
| 5 | | ----------------- ^^^^^^^^^^^^^^^^^^ an impl did not match: usize _ _ | |
| 6 | | | | |
| 7 | | required by a bound introduced by this call | |
| 8 | | | |
| 9 | = help: the trait `Foo<usize>` is not implemented for `(i32, i32, i32)` | |
| 10 | but trait `Foo<i32>` is implemented for it | |
| 11 | = help: for that trait implementation, expected `i32`, found `usize` | |
| 12 | ||
| 13 | error: aborting due to 1 previous error | |
| 14 | ||
| 15 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/on-unimplemented/issue-104140.rs deleted-8| ... | ... | @@ -1,8 +0,0 @@ |
| 1 | #![feature(rustc_attrs)] | |
| 2 | ||
| 3 | trait Foo {} | |
| 4 | ||
| 5 | #[rustc_on_unimplemented] //~ ERROR malformed `rustc_on_unimplemented` attribute input | |
| 6 | impl Foo for u32 {} | |
| 7 | ||
| 8 | fn main() {} |
tests/ui/on-unimplemented/issue-104140.stderr deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | error: malformed `rustc_on_unimplemented` attribute input | |
| 2 | --> $DIR/issue-104140.rs:5:1 | |
| 3 | | | |
| 4 | LL | #[rustc_on_unimplemented] | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 6 | | | |
| 7 | help: the following are the possible correct uses | |
| 8 | | | |
| 9 | LL | #[rustc_on_unimplemented = "message"] | |
| 10 | | +++++++++++ | |
| 11 | LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")] | |
| 12 | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| 13 | ||
| 14 | error: aborting due to 1 previous error | |
| 15 |
tests/ui/on-unimplemented/multiple-impls.rs deleted-42| ... | ... | @@ -1,42 +0,0 @@ |
| 1 | // Test if the on_unimplemented message override works | |
| 2 | ||
| 3 | #![feature(rustc_attrs)] | |
| 4 | ||
| 5 | ||
| 6 | struct Foo<T>(T); | |
| 7 | struct Bar<T>(T); | |
| 8 | ||
| 9 | #[rustc_on_unimplemented = "trait message"] | |
| 10 | trait Index<Idx: ?Sized> { | |
| 11 | type Output: ?Sized; | |
| 12 | fn index(&self, index: Idx) -> &Self::Output; | |
| 13 | } | |
| 14 | ||
| 15 | #[rustc_on_unimplemented = "on impl for Foo"] | |
| 16 | impl Index<Foo<usize>> for [i32] { | |
| 17 | type Output = i32; | |
| 18 | fn index(&self, _index: Foo<usize>) -> &i32 { | |
| 19 | loop {} | |
| 20 | } | |
| 21 | } | |
| 22 | ||
| 23 | #[rustc_on_unimplemented = "on impl for Bar"] | |
| 24 | impl Index<Bar<usize>> for [i32] { | |
| 25 | type Output = i32; | |
| 26 | fn index(&self, _index: Bar<usize>) -> &i32 { | |
| 27 | loop {} | |
| 28 | } | |
| 29 | } | |
| 30 | ||
| 31 | ||
| 32 | fn main() { | |
| 33 | Index::index(&[] as &[i32], 2u32); | |
| 34 | //~^ ERROR E0277 | |
| 35 | //~| ERROR E0277 | |
| 36 | Index::index(&[] as &[i32], Foo(2u32)); | |
| 37 | //~^ ERROR E0277 | |
| 38 | //~| ERROR E0277 | |
| 39 | Index::index(&[] as &[i32], Bar(2u32)); | |
| 40 | //~^ ERROR E0277 | |
| 41 | //~| ERROR E0277 | |
| 42 | } |
tests/ui/on-unimplemented/multiple-impls.stderr deleted-75| ... | ... | @@ -1,75 +0,0 @@ |
| 1 | error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied | |
| 2 | --> $DIR/multiple-impls.rs:33:33 | |
| 3 | | | |
| 4 | LL | Index::index(&[] as &[i32], 2u32); | |
| 5 | | ------------ ^^^^ trait message | |
| 6 | | | | |
| 7 | | required by a bound introduced by this call | |
| 8 | | | |
| 9 | = help: the trait `Index<u32>` is not implemented for `[i32]` | |
| 10 | = help: the following other types implement trait `Index<Idx>`: | |
| 11 | `[i32]` implements `Index<Bar<usize>>` | |
| 12 | `[i32]` implements `Index<Foo<usize>>` | |
| 13 | ||
| 14 | error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied | |
| 15 | --> $DIR/multiple-impls.rs:36:33 | |
| 16 | | | |
| 17 | LL | Index::index(&[] as &[i32], Foo(2u32)); | |
| 18 | | ------------ ^^^^^^^^^ on impl for Foo | |
| 19 | | | | |
| 20 | | required by a bound introduced by this call | |
| 21 | | | |
| 22 | = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]` | |
| 23 | = help: the following other types implement trait `Index<Idx>`: | |
| 24 | `[i32]` implements `Index<Bar<usize>>` | |
| 25 | `[i32]` implements `Index<Foo<usize>>` | |
| 26 | ||
| 27 | error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied | |
| 28 | --> $DIR/multiple-impls.rs:39:33 | |
| 29 | | | |
| 30 | LL | Index::index(&[] as &[i32], Bar(2u32)); | |
| 31 | | ------------ ^^^^^^^^^ on impl for Bar | |
| 32 | | | | |
| 33 | | required by a bound introduced by this call | |
| 34 | | | |
| 35 | = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]` | |
| 36 | = help: the following other types implement trait `Index<Idx>`: | |
| 37 | `[i32]` implements `Index<Bar<usize>>` | |
| 38 | `[i32]` implements `Index<Foo<usize>>` | |
| 39 | ||
| 40 | error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied | |
| 41 | --> $DIR/multiple-impls.rs:33:5 | |
| 42 | | | |
| 43 | LL | Index::index(&[] as &[i32], 2u32); | |
| 44 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait message | |
| 45 | | | |
| 46 | = help: the trait `Index<u32>` is not implemented for `[i32]` | |
| 47 | = help: the following other types implement trait `Index<Idx>`: | |
| 48 | `[i32]` implements `Index<Bar<usize>>` | |
| 49 | `[i32]` implements `Index<Foo<usize>>` | |
| 50 | ||
| 51 | error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied | |
| 52 | --> $DIR/multiple-impls.rs:36:5 | |
| 53 | | | |
| 54 | LL | Index::index(&[] as &[i32], Foo(2u32)); | |
| 55 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Foo | |
| 56 | | | |
| 57 | = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]` | |
| 58 | = help: the following other types implement trait `Index<Idx>`: | |
| 59 | `[i32]` implements `Index<Bar<usize>>` | |
| 60 | `[i32]` implements `Index<Foo<usize>>` | |
| 61 | ||
| 62 | error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied | |
| 63 | --> $DIR/multiple-impls.rs:39:5 | |
| 64 | | | |
| 65 | LL | Index::index(&[] as &[i32], Bar(2u32)); | |
| 66 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Bar | |
| 67 | | | |
| 68 | = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]` | |
| 69 | = help: the following other types implement trait `Index<Idx>`: | |
| 70 | `[i32]` implements `Index<Bar<usize>>` | |
| 71 | `[i32]` implements `Index<Foo<usize>>` | |
| 72 | ||
| 73 | error: aborting due to 6 previous errors | |
| 74 | ||
| 75 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/on-unimplemented/on-impl.rs deleted-25| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | // Test if the on_unimplemented message override works | |
| 2 | ||
| 3 | #![feature(rustc_attrs)] | |
| 4 | ||
| 5 | ||
| 6 | #[rustc_on_unimplemented = "invalid"] | |
| 7 | trait Index<Idx: ?Sized> { | |
| 8 | type Output: ?Sized; | |
| 9 | fn index(&self, index: Idx) -> &Self::Output; | |
| 10 | } | |
| 11 | ||
| 12 | #[rustc_on_unimplemented = "a usize is required to index into a slice"] | |
| 13 | impl Index<usize> for [i32] { | |
| 14 | type Output = i32; | |
| 15 | fn index(&self, index: usize) -> &i32 { | |
| 16 | &self[index] | |
| 17 | } | |
| 18 | } | |
| 19 | ||
| 20 | ||
| 21 | fn main() { | |
| 22 | Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32); | |
| 23 | //~^ ERROR E0277 | |
| 24 | //~| ERROR E0277 | |
| 25 | } |
tests/ui/on-unimplemented/on-impl.stderr deleted-25| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied | |
| 2 | --> $DIR/on-impl.rs:22:47 | |
| 3 | | | |
| 4 | LL | Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32); | |
| 5 | | ------------------- ^^^^ a usize is required to index into a slice | |
| 6 | | | | |
| 7 | | required by a bound introduced by this call | |
| 8 | | | |
| 9 | = help: the trait `Index<u32>` is not implemented for `[i32]` | |
| 10 | but trait `Index<usize>` is implemented for it | |
| 11 | = help: for that trait implementation, expected `usize`, found `u32` | |
| 12 | ||
| 13 | error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied | |
| 14 | --> $DIR/on-impl.rs:22:5 | |
| 15 | | | |
| 16 | LL | Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32); | |
| 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice | |
| 18 | | | |
| 19 | = help: the trait `Index<u32>` is not implemented for `[i32]` | |
| 20 | but trait `Index<usize>` is implemented for it | |
| 21 | = help: for that trait implementation, expected `usize`, found `u32` | |
| 22 | ||
| 23 | error: aborting due to 2 previous errors | |
| 24 | ||
| 25 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/on-unimplemented/use_self_no_underscore.rs created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | #![feature(rustc_attrs)] | |
| 2 | ||
| 3 | #[rustc_on_unimplemented(on( | |
| 4 | all(A = "{integer}", any(Self = "[{integral}; _]",)), | |
| 5 | message = "an array of type `{Self}` cannot be built directly from an iterator", | |
| 6 | ))] | |
| 7 | pub trait FromIterator<A>: Sized { | |
| 8 | fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self; | |
| 9 | } | |
| 10 | fn main() { | |
| 11 | let iter = 0..42_8; | |
| 12 | let x: [u8; 8] = FromIterator::from_iter(iter); | |
| 13 | //~^ ERROR an array of type `[u8; 8]` cannot be built directly from an iterator | |
| 14 | } |
tests/ui/on-unimplemented/use_self_no_underscore.stderr created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | error[E0277]: an array of type `[u8; 8]` cannot be built directly from an iterator | |
| 2 | --> $DIR/use_self_no_underscore.rs:12:22 | |
| 3 | | | |
| 4 | LL | let x: [u8; 8] = FromIterator::from_iter(iter); | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromIterator<{integer}>` is not implemented for `[u8; 8]` | |
| 6 | | | |
| 7 | help: this trait has no implementations, consider adding one | |
| 8 | --> $DIR/use_self_no_underscore.rs:7:1 | |
| 9 | | | |
| 10 | LL | pub trait FromIterator<A>: Sized { | |
| 11 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 12 | ||
| 13 | error: aborting due to 1 previous error | |
| 14 | ||
| 15 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs+2-2| ... | ... | @@ -5,7 +5,7 @@ use std::arch::naked_asm; |
| 5 | 5 | |
| 6 | 6 | #[track_caller] //~ ERROR [E0736] |
| 7 | 7 | //~^ ERROR `#[track_caller]` requires Rust ABI |
| 8 | #[naked] | |
| 8 | #[unsafe(naked)] | |
| 9 | 9 | extern "C" fn f() { |
| 10 | 10 | unsafe { |
| 11 | 11 | naked_asm!(""); |
| ... | ... | @@ -17,7 +17,7 @@ struct S; |
| 17 | 17 | impl S { |
| 18 | 18 | #[track_caller] //~ ERROR [E0736] |
| 19 | 19 | //~^ ERROR `#[track_caller]` requires Rust ABI |
| 20 | #[naked] | |
| 20 | #[unsafe(naked)] | |
| 21 | 21 | extern "C" fn g() { |
| 22 | 22 | unsafe { |
| 23 | 23 | naked_asm!(""); |
tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr+8-8| ... | ... | @@ -1,20 +1,20 @@ |
| 1 | error[E0736]: attribute incompatible with `#[naked]` | |
| 1 | error[E0736]: attribute incompatible with `#[unsafe(naked)]` | |
| 2 | 2 | --> $DIR/error-with-naked.rs:6:1 |
| 3 | 3 | | |
| 4 | 4 | LL | #[track_caller] |
| 5 | | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[naked]` | |
| 5 | | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]` | |
| 6 | 6 | LL | |
| 7 | LL | #[naked] | |
| 8 | | -------- function marked with `#[naked]` here | |
| 7 | LL | #[unsafe(naked)] | |
| 8 | | ---------------- function marked with `#[unsafe(naked)]` here | |
| 9 | 9 | |
| 10 | error[E0736]: attribute incompatible with `#[naked]` | |
| 10 | error[E0736]: attribute incompatible with `#[unsafe(naked)]` | |
| 11 | 11 | --> $DIR/error-with-naked.rs:18:5 |
| 12 | 12 | | |
| 13 | 13 | LL | #[track_caller] |
| 14 | | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[naked]` | |
| 14 | | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]` | |
| 15 | 15 | LL | |
| 16 | LL | #[naked] | |
| 17 | | -------- function marked with `#[naked]` here | |
| 16 | LL | #[unsafe(naked)] | |
| 17 | | ---------------- function marked with `#[unsafe(naked)]` here | |
| 18 | 18 | |
| 19 | 19 | error[E0737]: `#[track_caller]` requires Rust ABI |
| 20 | 20 | --> $DIR/error-with-naked.rs:6:1 |
tests/ui/traits/next-solver/rpitit-cycle-due-to-rigid.rs created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | //@ compile-flags: -Znext-solver | |
| 2 | //@ check-pass | |
| 3 | //@ edition: 2024 | |
| 4 | ||
| 5 | // Ensure we don't end up in a query cycle due to trying to assemble an impl candidate | |
| 6 | // for an RPITIT normalizes-to goal, even though that impl candidate would *necessarily* | |
| 7 | // be made rigid by a where clause. This query cycle is thus avoidable by not assembling | |
| 8 | // that impl candidate which we *know* we are going to throw away anyways. | |
| 9 | ||
| 10 | use std::future::Future; | |
| 11 | ||
| 12 | pub trait ReactiveFunction: Send { | |
| 13 | type Output; | |
| 14 | ||
| 15 | fn invoke(self) -> Self::Output; | |
| 16 | } | |
| 17 | ||
| 18 | trait AttributeValue { | |
| 19 | fn resolve(self) -> impl Future<Output = ()> + Send; | |
| 20 | } | |
| 21 | ||
| 22 | impl<F, V> AttributeValue for F | |
| 23 | where | |
| 24 | F: ReactiveFunction<Output = V>, | |
| 25 | V: AttributeValue, | |
| 26 | { | |
| 27 | async fn resolve(self) { | |
| 28 | self.invoke().resolve().await | |
| 29 | } | |
| 30 | } | |
| 31 | ||
| 32 | fn main() {} |