authorbors <bors@rust-lang.org> 2025-04-20 02:08:02 UTC
committerbors <bors@rust-lang.org> 2025-04-20 02:08:02 UTC
log49e5e4e3a5610c240a717cb99003a5d5d3356679
treef7d71ca252f47aa55dedab1ee31180dea2334d98
parent90fd16eb5be9255006c95e8af12a0d43854dc1a9
parentf0a0efdcdc326cf94d232b8f6f93c8e7ad2809c2

Auto merge of #140043 - ChrisDenton:rollup-vwf0s9j, r=ChrisDenton

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: rollup

139 files changed, 3027 insertions(+), 1790 deletions(-)

bootstrap.example.toml+8
......@@ -19,6 +19,14 @@
1919# Note that this has no default value (x.py uses the defaults in `bootstrap.example.toml`).
2020#profile = <none>
2121
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
2230# Keeps track of major changes made to this configuration.
2331#
2432# 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
247247 .suggestion = make `{$ident}` default
248248
249249builtin_macros_naked_functions_testing_attribute =
250 cannot use `#[naked]` with testing attributes
250 cannot use `#[unsafe(naked)]` with testing attributes
251251 .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
253253
254254builtin_macros_no_default_variant = `#[derive(Default)]` on enum with no `#[default]`
255255 .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! {
387387}
388388
389389#[cfg(all(not(jit), target_arch = "x86_64"))]
390#[naked]
390#[unsafe(naked)]
391391extern "C" fn naked_test() {
392 unsafe {
393 naked_asm!("ret");
394 }
392 naked_asm!("ret")
395393}
396394
397395#[repr(C)]
compiler/rustc_error_codes/src/error_codes/E0736.md+1-1
......@@ -11,7 +11,7 @@ Erroneous code example:
1111
1212```compile_fail,E0736
1313#[inline]
14#[naked]
14#[unsafe(naked)]
1515fn foo() {}
1616```
1717
compiler/rustc_error_codes/src/error_codes/E0787.md+1-1
......@@ -5,7 +5,7 @@ Erroneous code example:
55```compile_fail,E0787
66#![feature(naked_functions)]
77
8#[naked]
8#[unsafe(naked)]
99pub extern "C" fn f() -> u32 {
1010 42
1111}
compiler/rustc_feature/src/builtin_attrs.rs+1-1
......@@ -517,7 +517,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
517517
518518 // Linking:
519519 gated!(
520 naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
520 unsafe naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
521521 naked_functions, experimental!(naked)
522522 ),
523523
compiler/rustc_metadata/src/locator.rs+15-6
......@@ -427,12 +427,21 @@ impl<'a> CrateLocator<'a> {
427427
428428 let (rlibs, rmetas, dylibs) =
429429 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();
436445 match kind {
437446 CrateFlavor::Rlib => rlibs.insert(path, search_path.kind),
438447 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> {
564564 }
565565 }
566566 ExprKind::InlineAsm(box InlineAsmExpr {
567 asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm,
567 asm_macro: asm_macro @ (AsmMacro::Asm | AsmMacro::NakedAsm),
568568 ref operands,
569569 template: _,
570570 options: _,
571571 line_spans: _,
572572 }) => {
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 }
574578
575579 // For inline asm, do not use `walk_expr`, since we want to handle the label block
576580 // specially.
compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs+54-33
......@@ -288,6 +288,21 @@ where
288288 ) -> Vec<Candidate<I>>;
289289}
290290
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>.
298pub(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
291306impl<D, I> EvalCtxt<'_, D>
292307where
293308 D: SolverDelegate<Interner = I>,
......@@ -296,6 +311,7 @@ where
296311 pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
297312 &mut self,
298313 goal: Goal<I, G>,
314 assemble_from: AssembleCandidatesFrom,
299315 ) -> Vec<Candidate<I>> {
300316 let Ok(normalized_self_ty) =
301317 self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
......@@ -322,16 +338,18 @@ where
322338 }
323339 }
324340
325 self.assemble_impl_candidates(goal, &mut candidates);
326
327 self.assemble_builtin_impl_candidates(goal, &mut candidates);
328
329341 self.assemble_alias_bound_candidates(goal, &mut candidates);
330
331 self.assemble_object_bound_candidates(goal, &mut candidates);
332
333342 self.assemble_param_env_candidates(goal, &mut candidates);
334343
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
335353 candidates
336354 }
337355
......@@ -754,6 +772,9 @@ where
754772 })
755773 }
756774
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 ///
757778 /// We sadly can't simply take all possible candidates for normalization goals
758779 /// and check whether they result in the same constraints. We want to make sure
759780 /// that trying to normalize an alias doesn't result in constraints which aren't
......@@ -782,47 +803,44 @@ where
782803 ///
783804 /// See trait-system-refactor-initiative#124 for more details.
784805 #[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>>(
786807 &mut self,
787808 proven_via: Option<TraitGoalProvenVia>,
788 candidates: Vec<Candidate<I>>,
809 goal: Goal<I, G>,
789810 inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
790811 ) -> QueryResult<I> {
791812 let Some(proven_via) = proven_via else {
792813 // We don't care about overflow. If proving the trait goal overflowed, then
793814 // it's enough to report an overflow error for that, we don't also have to
794815 // 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);
796820 };
797821
798822 match proven_via {
799823 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
808824 // Even when a trait bound has been proven using a where-bound, we
809825 // 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
812830 // 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 };
826844
827845 // If the trait goal has been proven by using the environment, we want to treat
828846 // aliases as rigid if there are no applicable projection bounds in the environment.
......@@ -839,6 +857,9 @@ where
839857 }
840858 }
841859 TraitGoalProvenVia::Misc => {
860 let candidates =
861 self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
862
842863 // Prefer "orphaned" param-env normalization predicates, which are used
843864 // (for example, and ideally only) when proving item bounds for an impl.
844865 let candidates_from_env: Vec<_> = candidates
compiler/rustc_next_trait_solver/src/solve/effect_goals.rs+1-2
......@@ -399,12 +399,11 @@ where
399399 &mut self,
400400 goal: Goal<I, ty::HostEffectPredicate<I>>,
401401 ) -> QueryResult<I> {
402 let candidates = self.assemble_and_evaluate_candidates(goal);
403402 let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
404403 let trait_goal: Goal<I, ty::TraitPredicate<I>> =
405404 goal.with(ecx.cx(), goal.predicate.trait_ref);
406405 ecx.compute_trait_goal(trait_goal)
407406 })?;
408 self.merge_candidates(proven_via, candidates, |_ecx| Err(NoSolution))
407 self.assemble_and_merge_candidates(proven_via, goal, |_ecx| Err(NoSolution))
409408 }
410409}
compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs+1-2
......@@ -32,14 +32,13 @@ where
3232 let cx = self.cx();
3333 match goal.predicate.alias.kind(cx) {
3434 ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
35 let candidates = self.assemble_and_evaluate_candidates(goal);
3635 let trait_ref = goal.predicate.alias.trait_ref(cx);
3736 let (_, proven_via) =
3837 self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
3938 let trait_goal: Goal<I, ty::TraitPredicate<I>> = goal.with(cx, trait_ref);
4039 ecx.compute_trait_goal(trait_goal)
4140 })?;
42 self.merge_candidates(proven_via, candidates, |ecx| {
41 self.assemble_and_merge_candidates(proven_via, goal, |ecx| {
4342 ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| {
4443 this.structurally_instantiate_normalizes_to_term(
4544 goal,
compiler/rustc_next_trait_solver/src/solve/trait_goals.rs+2-2
......@@ -13,7 +13,7 @@ use tracing::{instrument, trace};
1313
1414use crate::delegate::SolverDelegate;
1515use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
16use crate::solve::assembly::{self, Candidate};
16use crate::solve::assembly::{self, AssembleCandidatesFrom, Candidate};
1717use crate::solve::inspect::ProbeKind;
1818use crate::solve::{
1919 BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
......@@ -1365,7 +1365,7 @@ where
13651365 &mut self,
13661366 goal: Goal<I, TraitPredicate<I>>,
13671367 ) -> 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);
13691369 self.merge_trait_candidates(goal, candidates)
13701370 }
13711371}
compiler/rustc_parse/src/validate_attr.rs-6
......@@ -194,12 +194,6 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr:
194194 }
195195 }
196196 } 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
203197 psess.dcx().emit_err(errors::InvalidAttrUnsafe {
204198 span: unsafe_span,
205199 name: attr_item.path.clone(),
compiler/rustc_passes/messages.ftl+4-4
......@@ -508,7 +508,7 @@ passes_must_use_no_effect =
508508 `#[must_use]` has no effect when applied to {$article} {$target}
509509
510510passes_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)]`
512512
513513passes_naked_functions_asm_block =
514514 naked functions must contain a single `naked_asm!` invocation
......@@ -516,9 +516,9 @@ passes_naked_functions_asm_block =
516516 .label_non_asm = not allowed in naked functions
517517
518518passes_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
522522
523523passes_naked_functions_must_naked_asm =
524524 the `asm!` macro is not allowed in naked functions
compiler/rustc_span/src/hygiene.rs+19
......@@ -1232,6 +1232,25 @@ impl DesugaringKind {
12321232 DesugaringKind::PatTyRange => "pattern type",
12331233 }
12341234 }
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 }
12351254}
12361255
12371256#[derive(Default)]
compiler/rustc_span/src/symbol.rs+1
......@@ -372,6 +372,7 @@ symbols! {
372372 SyncUnsafeCell,
373373 T,
374374 Target,
375 This,
375376 ToOwned,
376377 ToString,
377378 TokenStream,
compiler/rustc_target/src/spec/base/linux_musl.rs+7-8
......@@ -1,12 +1,11 @@
11use crate::spec::{LinkSelfContainedDefault, TargetOptions, base, crt_objects};
22
33pub(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 }
1211}
compiler/rustc_target/src/spec/base/linux_ohos.rs+7-8
......@@ -1,12 +1,11 @@
11use crate::spec::{TargetOptions, TlsModel, base};
22
33pub(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 }
1211}
compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs+2
......@@ -2,6 +2,8 @@ pub mod ambiguity;
22pub mod call_kind;
33mod fulfillment_errors;
44pub mod on_unimplemented;
5pub mod on_unimplemented_condition;
6pub mod on_unimplemented_format;
57mod overflow;
68pub mod suggestions;
79
compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs+253-368
......@@ -1,44 +1,31 @@
11use std::iter;
22use std::path::PathBuf;
33
4use rustc_ast::MetaItemInner;
5use rustc_data_structures::fx::FxHashMap;
4use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
65use rustc_errors::codes::*;
76use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
87use rustc_hir::def_id::{DefId, LocalDefId};
98use rustc_hir::{AttrArgs, Attribute};
109use rustc_macros::LintDiagnostic;
1110use rustc_middle::bug;
12use rustc_middle::ty::print::PrintTraitRefExt as _;
13use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt};
14use rustc_parse_format::{ParseMode, Parser, Piece, Position};
11use rustc_middle::ty::print::PrintTraitRefExt;
12use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt};
1513use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
16use rustc_span::{Ident, Span, Symbol, kw, sym};
14use rustc_span::{Span, Symbol, sym};
1715use tracing::{debug, info};
1816use {rustc_attr_parsing as attr, rustc_hir as hir};
1917
2018use super::{ObligationCauseCode, PredicateObligation};
2119use crate::error_reporting::TypeErrCtxt;
20use crate::error_reporting::traits::on_unimplemented_condition::{Condition, ConditionOptions};
21use crate::error_reporting::traits::on_unimplemented_format::{
22 Ctx, FormatArgs, FormatString, FormatWarning,
23};
2224use crate::errors::{
2325 EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
2426};
2527use crate::infer::InferCtxtExt;
2628
27/// The symbols which are always allowed in a format string
28static 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
4229impl<'tcx> TypeErrCtxt<'_, 'tcx> {
4330 fn impl_similar_to(
4431 &self,
......@@ -121,86 +108,78 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
121108 .unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args));
122109 let trait_pred = trait_pred.skip_binder();
123110
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;
125114 // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs,
126115 // but I guess we could synthesize one here. We don't see any errors that rely on
127116 // 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("");
130118
131 match obligation.cause.code() {
119 let direct = match obligation.cause.code() {
132120 ObligationCauseCode::BuiltinDerived(..)
133121 | ObligationCauseCode::ImplDerived(..)
134 | ObligationCauseCode::WellFormedDerived(..) => {}
122 | ObligationCauseCode::WellFormedDerived(..) => false,
135123 _ => {
136124 // this is a "direct", user-specified, rather than derived,
137125 // obligation.
138 flags.push((sym::direct, None));
126 true
139127 }
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 };
146129
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();
150131
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 };
152137
153138 // Add all types without trimmed paths or visible paths, ensuring they end up with
154139 // their "canonical" def path.
155140 ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({
156141 let generics = self.tcx.generics_of(def_id);
157142 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());
161144 if let Some(def) = self_ty.ty_adt_def() {
162145 // We also want to be able to select self's original
163146 // 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());
168148 }
169149
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 {
172152 GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
173 args[param.index as usize].to_string()
153 args[*index as usize].to_string()
174154 }
175155 GenericParamDefKind::Lifetime => continue,
176156 };
177 let name = param.name;
178 flags.push((name, Some(value)));
157 generic_args.push((*name, value));
179158
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();
182161 if let Some(def) = param_ty.ty_adt_def() {
183162 // We also want to be able to select the parameter's
184163 // 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(),
188167 ));
189168 }
190169 }
191170 }
192171
193172 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;
195174 }
196175
197176 // Allow targeting all integers using `{integral}`, even if the exact type was resolved
198177 if self_ty.is_integral() {
199 flags.push((sym::_Self, Some("{integral}".to_owned())));
178 self_types.push("{integral}".to_owned());
200179 }
201180
202181 if self_ty.is_array_slice() {
203 flags.push((sym::_Self, Some("&[]".to_owned())));
182 self_types.push("&[]".to_owned());
204183 }
205184
206185 if self_ty.is_fn() {
......@@ -215,53 +194,51 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
215194 hir::Safety::Unsafe => "unsafe fn",
216195 }
217196 };
218 flags.push((sym::_Self, Some(shortname.to_owned())));
197 self_types.push(shortname.to_owned());
219198 }
220199
221200 // Slices give us `[]`, `[{ty}]`
222201 if let ty::Slice(aty) = self_ty.kind() {
223 flags.push((sym::_Self, Some("[]".to_string())));
202 self_types.push("[]".to_owned());
224203 if let Some(def) = aty.ty_adt_def() {
225204 // We also want to be able to select the slice's type's original
226205 // 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()));
231208 }
232209 if aty.is_integral() {
233 flags.push((sym::_Self, Some("[{integral}]".to_string())));
210 self_types.push("[{integral}]".to_string());
234211 }
235212 }
236213
237214 // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
238215 if let ty::Array(aty, len) = self_ty.kind() {
239 flags.push((sym::_Self, Some("[]".to_string())));
216 self_types.push("[]".to_string());
240217 let len = len.try_to_target_usize(self.tcx);
241 flags.push((sym::_Self, Some(format!("[{aty}; _]"))));
218 self_types.push(format!("[{aty}; _]"));
242219 if let Some(n) = len {
243 flags.push((sym::_Self, Some(format!("[{aty}; {n}]"))));
220 self_types.push(format!("[{aty}; {n}]"));
244221 }
245222 if let Some(def) = aty.ty_adt_def() {
246223 // We also want to be able to select the array's type's original
247224 // signature with no type arguments resolved
248225 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}; _]"));
250227 if let Some(n) = len {
251 flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]"))));
228 self_types.push(format!("[{def_ty}; {n}]"));
252229 }
253230 }
254231 if aty.is_integral() {
255 flags.push((sym::_Self, Some("[{integral}; _]".to_string())));
232 self_types.push("[{integral}; _]".to_string());
256233 if let Some(n) = len {
257 flags.push((sym::_Self, Some(format!("[{{integral}}; {n}]"))));
234 self_types.push(format!("[{{integral}}; {n}]"));
258235 }
259236 }
260237 }
261238 if let ty::Dynamic(traits, _, _) = self_ty.kind() {
262239 for t in traits.iter() {
263240 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));
265242 }
266243 }
267244 }
......@@ -271,31 +248,76 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
271248 && let ty::Slice(sty) = ref_ty.kind()
272249 && sty.is_integral()
273250 {
274 flags.push((sym::_Self, Some("&[{integral}]".to_owned())));
251 self_types.push("&[{integral}]".to_owned());
275252 }
276253 }));
277254
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
278296 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)
280298 } else {
281299 OnUnimplementedNote::default()
282300 }
283301 }
284302}
285303
304/// Represents a format string in a on_unimplemented attribute,
305/// like the "content" in `#[diagnostic::on_unimplemented(message = "content")]`
286306#[derive(Clone, Debug)]
287307pub 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,
291313}
292314
293315#[derive(Debug)]
294316pub struct OnUnimplementedDirective {
295 pub condition: Option<MetaItemInner>,
317 pub condition: Option<Condition>,
296318 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)>,
299321 pub notes: Vec<OnUnimplementedFormatString>,
300322 pub parent_label: Option<OnUnimplementedFormatString>,
301323 pub append_const_msg: Option<AppendConstMessage>,
......@@ -329,7 +351,7 @@ pub struct MalformedOnUnimplementedAttrLint {
329351}
330352
331353impl MalformedOnUnimplementedAttrLint {
332 fn new(span: Span) -> Self {
354 pub fn new(span: Span) -> Self {
333355 Self { span }
334356 }
335357}
......@@ -350,7 +372,7 @@ pub struct IgnoredDiagnosticOption {
350372}
351373
352374impl IgnoredDiagnosticOption {
353 fn maybe_emit_warning<'tcx>(
375 pub fn maybe_emit_warning<'tcx>(
354376 tcx: TyCtxt<'tcx>,
355377 item_def_id: DefId,
356378 new: Option<Span>,
......@@ -370,29 +392,11 @@ impl IgnoredDiagnosticOption {
370392 }
371393}
372394
373#[derive(LintDiagnostic)]
374#[diag(trait_selection_unknown_format_parameter_for_on_unimplemented_attr)]
375#[help]
376pub struct UnknownFormatParameterForOnUnimplementedAttr {
377 argument_name: Symbol,
378 trait_name: Ident,
379}
380
381#[derive(LintDiagnostic)]
382#[diag(trait_selection_disallowed_positional_argument)]
383#[help]
384pub struct DisallowedPositionalArgument;
385
386#[derive(LintDiagnostic)]
387#[diag(trait_selection_invalid_format_specifier)]
388#[help]
389pub struct InvalidFormatSpecifier;
390
391395#[derive(LintDiagnostic)]
392396#[diag(trait_selection_wrapped_parser_error)]
393397pub struct WrappedParserError {
394 description: String,
395 label: String,
398 pub description: String,
399 pub label: String,
396400}
397401
398402impl<'tcx> OnUnimplementedDirective {
......@@ -407,12 +411,12 @@ impl<'tcx> OnUnimplementedDirective {
407411 let mut errored = None;
408412 let mut item_iter = items.iter();
409413
410 let parse_value = |value_str, value_span| {
414 let parse_value = |value_str, span| {
411415 OnUnimplementedFormatString::try_parse(
412416 tcx,
413417 item_def_id,
414418 value_str,
415 value_span,
419 span,
416420 is_diagnostic_namespace_variant,
417421 )
418422 .map(Some)
......@@ -434,7 +438,7 @@ impl<'tcx> OnUnimplementedDirective {
434438 }
435439 true
436440 });
437 Some(cond.clone())
441 Some(Condition { inner: cond.clone() })
438442 };
439443
440444 let mut message = None;
......@@ -444,24 +448,36 @@ impl<'tcx> OnUnimplementedDirective {
444448 let mut subcommands = vec![];
445449 let mut append_const_msg = None;
446450
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
447465 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);
456479 continue;
457480 }
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 }
465481 } else if item.has_name(sym::parent_label)
466482 && parent_label.is_none()
467483 && !is_diagnostic_namespace_variant
......@@ -539,6 +555,13 @@ impl<'tcx> OnUnimplementedDirective {
539555 }
540556
541557 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 }
542565 if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) {
543566 return Self::parse_attribute(attr, false, tcx, item_def_id);
544567 } else {
......@@ -554,15 +577,15 @@ impl<'tcx> OnUnimplementedDirective {
554577 IgnoredDiagnosticOption::maybe_emit_warning(
555578 tcx,
556579 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),
559582 "message",
560583 );
561584 IgnoredDiagnosticOption::maybe_emit_warning(
562585 tcx,
563586 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),
566589 "label",
567590 );
568591 IgnoredDiagnosticOption::maybe_emit_warning(
......@@ -636,13 +659,16 @@ impl<'tcx> OnUnimplementedDirective {
636659 condition: None,
637660 message: None,
638661 subcommands: vec![],
639 label: Some(OnUnimplementedFormatString::try_parse(
640 tcx,
641 item_def_id,
642 value,
662 label: Some((
643663 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 )),
646672 notes: Vec::new(),
647673 parent_label: None,
648674 append_const_msg: None,
......@@ -702,43 +728,23 @@ impl<'tcx> OnUnimplementedDirective {
702728 &self,
703729 tcx: TyCtxt<'tcx>,
704730 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>,
707733 ) -> OnUnimplementedNote {
708734 let mut message = None;
709735 let mut label = None;
710736 let mut notes = Vec::new();
711737 let mut parent_label = None;
712738 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 );
717743
718744 for command in self.subcommands.iter().chain(Some(self)).rev() {
719745 debug!(?command);
720746 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)
742748 {
743749 debug!("evaluate: skipping {:?} due to condition", command);
744750 continue;
......@@ -762,14 +768,10 @@ impl<'tcx> OnUnimplementedDirective {
762768 }
763769
764770 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)),
773775 append_const_msg,
774776 }
775777 }
......@@ -780,142 +782,95 @@ impl<'tcx> OnUnimplementedFormatString {
780782 tcx: TyCtxt<'tcx>,
781783 item_def_id: DefId,
782784 from: Symbol,
783 value_span: Span,
785 span: Span,
784786 is_diagnostic_namespace_variant: bool,
785787 ) -> 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 };
791790 result.verify(tcx, item_def_id)?;
792791 Ok(result)
793792 }
794793
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 }
798801 } 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 }
801803 };
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
806805 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)
826814 }
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);
872828 }
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, .. } => {
886830 let reported = struct_span_code_err!(
887831 tcx.dcx(),
888 self.span,
832 span,
889833 E0231,
890 "only named generic parameters are allowed"
834 "positional format arguments are not allowed here"
891835 )
892836 .emit();
893837 result = Err(reported);
894838 }
839 FormatWarning::InvalidSpecifier { .. }
840 | FormatWarning::FutureIncompat { .. } => {}
895841 }
896842 }
897843 }
898844 }
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 }
914873 }
915 } else {
916 let reported =
917 struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,).emit();
918 result = Err(reported);
919874 }
920875 }
921876
......@@ -926,98 +881,28 @@ impl<'tcx> OnUnimplementedFormatString {
926881 &self,
927882 tcx: TyCtxt<'tcx>,
928883 trait_ref: ty::TraitRef<'tcx>,
929 options: &FxHashMap<Symbol, String>,
930 long_ty_file: &mut Option<PathBuf>,
884 args: &FormatArgs<'tcx>,
931885 ) -> 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)
1019895 } 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()
1021906 }
1022907 }
1023908}
compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs created+120
......@@ -0,0 +1,120 @@
1use rustc_ast::MetaItemInner;
2use rustc_attr_parsing as attr;
3use rustc_middle::ty::{self, TyCtxt};
4use rustc_parse_format::{ParseMode, Parser, Piece, Position};
5use 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)]
10pub struct Condition {
11 pub inner: MetaItemInner,
12}
13
14impl 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)]
88pub 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
103impl 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 @@
1use std::fmt;
2
3use errors::*;
4use rustc_middle::ty::TyCtxt;
5use rustc_middle::ty::print::TraitRefPrintSugared;
6use rustc_parse_format::{
7 Alignment, Argument, Count, FormatSpec, InnerSpan, ParseError, ParseMode, Parser,
8 Piece as RpfPiece, Position,
9};
10use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
11use rustc_span::def_id::DefId;
12use 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)]
17pub 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)]
27enum Piece {
28 Lit(String),
29 Arg(FormatArg),
30}
31
32#[derive(Debug)]
33enum 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
50pub 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)]
58pub 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
65impl 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)]
148pub 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
155impl 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
226fn 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.
314fn 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
339fn 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
351pub 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 {
950950/// Constants associated with the current target
951951#[stable(feature = "env", since = "1.0.0")]
952952pub mod consts {
953 use crate::sys::env::os;
953 use crate::sys::env_consts::os;
954954
955955 /// A string describing the architecture of the CPU that is currently in use.
956956 /// 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!.
6macro 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
16cfg_unordered! {
17
18#[cfg(target_os = "aix")]
19pub 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")]
30pub 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")]
41pub 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")]
52pub 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")]
63pub 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")]
74pub 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")]
85pub 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")]
96pub 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")]
107pub 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")]
118pub 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")]
129pub 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")]
140pub 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")]
151pub 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")]
162pub 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")]
173pub 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")]
184pub 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")]
195pub 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")]
206pub 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")]
217pub 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")]
228pub 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")]
239pub 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")]
250pub 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")]
261pub 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"))]
272pub 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")]
283pub 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")]
294pub 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")]
305pub 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")]
316pub 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")]
327pub 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")]
338pub 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")]
349pub 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"))))]
360pub 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")]
371pub 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")]
382pub 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]
394pub 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;
1212pub mod args;
1313pub mod backtrace;
1414pub mod cmath;
15pub mod env_consts;
1516pub mod exit_guard;
1617pub mod fd;
1718pub mod fs;
library/std/src/sys/pal/hermit/env.rs deleted-9
......@@ -1,9 +0,0 @@
1pub 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 @@
1818
1919use crate::os::raw::c_char;
2020
21pub mod env;
2221pub mod futex;
2322pub mod os;
2423#[path = "../unsupported/pipe.rs"]
library/std/src/sys/pal/sgx/env.rs deleted-9
......@@ -1,9 +0,0 @@
1pub 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;
99use crate::sync::atomic::{AtomicBool, Ordering};
1010
1111pub mod abi;
12pub mod env;
1312mod libunwind_integration;
1413pub mod os;
1514#[path = "../unsupported/pipe.rs"]
library/std/src/sys/pal/solid/env.rs deleted-9
......@@ -1,9 +0,0 @@
1pub 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 {
1616 use super::unsupported;
1717}
1818
19pub mod env;
2019// `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as
2120// `crate::sys::error`
2221pub(crate) mod error;
library/std/src/sys/pal/teeos/mod.rs-3
......@@ -6,9 +6,6 @@
66#![allow(unused_variables)]
77#![allow(dead_code)]
88
9#[path = "../unsupported/env.rs"]
10pub mod env;
11//pub mod fd;
129pub mod os;
1310#[path = "../unsupported/pipe.rs"]
1411pub mod pipe;
library/std/src/sys/pal/trusty/mod.rs-2
......@@ -3,8 +3,6 @@
33#[path = "../unsupported/common.rs"]
44#[deny(unsafe_op_in_unsafe_fn)]
55mod common;
6#[path = "../unsupported/env.rs"]
7pub mod env;
86#[path = "../unsupported/os.rs"]
97pub mod os;
108#[path = "../unsupported/pipe.rs"]
library/std/src/sys/pal/uefi/env.rs deleted-9
......@@ -1,9 +0,0 @@
1pub 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 @@
1313//! [`OsString`]: crate::ffi::OsString
1414#![forbid(unsafe_op_in_unsafe_fn)]
1515
16pub mod env;
1716pub mod helpers;
1817pub mod os;
1918#[path = "../unsupported/pipe.rs"]
library/std/src/sys/pal/unix/env.rs deleted-307
......@@ -1,307 +0,0 @@
1#[cfg(target_os = "linux")]
2pub 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")]
13pub 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")]
24pub 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")]
35pub 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")]
46pub 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")]
57pub 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")]
68pub 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")]
79pub 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")]
90pub 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")]
101pub 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")]
112pub 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")]
123pub 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")]
134pub 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")]
145pub 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")]
156pub 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")]
167pub 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")]
178pub 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")]
189pub 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"))]
200pub 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")]
211pub 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")]
222pub 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")]
233pub 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")]
244pub 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")]
255pub 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")]
266pub 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")]
277pub 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")]
288pub 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")]
299pub 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;
66#[macro_use]
77pub mod weak;
88
9pub mod env;
109#[cfg(target_os = "fuchsia")]
1110pub mod fuchsia;
1211pub mod futex;
library/std/src/sys/pal/unsupported/env.rs deleted-9
......@@ -1,9 +0,0 @@
1pub 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 @@
11#![deny(unsafe_op_in_unsafe_fn)]
22
3pub mod env;
43pub mod os;
54pub mod pipe;
65pub mod thread;
library/std/src/sys/pal/wasi/env.rs deleted-11
......@@ -1,11 +0,0 @@
1#![forbid(unsafe_op_in_unsafe_fn)]
2
3pub 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 @@
1313//! compiling for wasm. That way it's a compile time error for something that's
1414//! guaranteed to be a runtime error!
1515
16pub mod env;
1716#[allow(unused)]
1817#[path = "../wasm/atomics/futex.rs"]
1918pub mod futex;
library/std/src/sys/pal/wasip2/mod.rs-2
......@@ -6,8 +6,6 @@
66//! To begin with, this target mirrors the wasi target 1 to 1, but over
77//! time this will change significantly.
88
9#[path = "../wasi/env.rs"]
10pub mod env;
119#[allow(unused)]
1210#[path = "../wasm/atomics/futex.rs"]
1311pub mod futex;
library/std/src/sys/pal/wasm/env.rs deleted-9
......@@ -1,9 +0,0 @@
1pub 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 @@
1616
1717#![deny(unsafe_op_in_unsafe_fn)]
1818
19pub mod env;
2019#[path = "../unsupported/os.rs"]
2120pub mod os;
2221#[path = "../unsupported/pipe.rs"]
library/std/src/sys/pal/windows/env.rs deleted-9
......@@ -1,9 +0,0 @@
1pub 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;
1515pub mod api;
1616
1717pub mod c;
18pub mod env;
1918#[cfg(not(target_vendor = "win7"))]
2019pub mod futex;
2120pub mod handle;
library/std/src/sys/pal/xous/mod.rs-2
......@@ -1,7 +1,5 @@
11#![forbid(unsafe_op_in_unsafe_fn)]
22
3#[path = "../unsupported/env.rs"]
4pub mod env;
53pub mod os;
64#[path = "../unsupported/pipe.rs"]
75pub mod pipe;
library/std/src/sys/pal/zkvm/mod.rs-1
......@@ -11,7 +11,6 @@
1111pub const WORD_SIZE: usize = size_of::<u32>();
1212
1313pub mod abi;
14pub mod env;
1514pub mod os;
1615#[path = "../unsupported/pipe.rs"]
1716pub mod pipe;
src/bootstrap/src/core/config/config.rs+115-18
......@@ -6,6 +6,7 @@
66use std::cell::{Cell, RefCell};
77use std::collections::{BTreeSet, HashMap, HashSet};
88use std::fmt::{self, Display};
9use std::hash::Hash;
910use std::io::IsTerminal;
1011use std::path::{Path, PathBuf, absolute};
1112use std::process::Command;
......@@ -701,6 +702,7 @@ pub(crate) struct TomlConfig {
701702 target: Option<HashMap<String, TomlTarget>>,
702703 dist: Option<Dist>,
703704 profile: Option<String>,
705 include: Option<Vec<PathBuf>>,
704706}
705707
706708/// This enum is used for deserializing change IDs from TOML, allowing both numeric values and the string `"ignore"`.
......@@ -747,27 +749,35 @@ enum ReplaceOpt {
747749}
748750
749751trait 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 );
751759}
752760
753761impl Merge for TomlConfig {
754762 fn merge(
755763 &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,
757767 replace: ReplaceOpt,
758768 ) {
759769 fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) {
760770 if let Some(new) = y {
761771 if let Some(original) = x {
762 original.merge(new, replace);
772 original.merge(None, &mut Default::default(), new, replace);
763773 } else {
764774 *x = Some(new);
765775 }
766776 }
767777 }
768778
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);
771781
772782 do_merge(&mut self.build, build, replace);
773783 do_merge(&mut self.install, install, replace);
......@@ -782,13 +792,50 @@ impl Merge for TomlConfig {
782792 (Some(original_target), Some(new_target)) => {
783793 for (triple, new) in new_target {
784794 if let Some(original) = original_target.get_mut(&triple) {
785 original.merge(new, replace);
795 original.merge(None, &mut Default::default(), new, replace);
786796 } else {
787797 original_target.insert(triple, new);
788798 }
789799 }
790800 }
791801 }
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 }
792839 }
793840}
794841
......@@ -803,7 +850,13 @@ macro_rules! define_config {
803850 }
804851
805852 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 ) {
807860 $(
808861 match replace {
809862 ReplaceOpt::IgnoreDuplicate => {
......@@ -903,7 +956,13 @@ macro_rules! define_config {
903956}
904957
905958impl<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 ) {
907966 match replace {
908967 ReplaceOpt::IgnoreDuplicate => {
909968 if self.is_none() {
......@@ -1363,13 +1422,15 @@ impl Config {
13631422 Self::get_toml(&builder_config_path)
13641423 }
13651424
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)
13691431 }
13701432
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> {
13731434 let contents =
13741435 t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
13751436 // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
......@@ -1548,7 +1609,8 @@ impl Config {
15481609 // but not if `bootstrap.toml` hasn't been created.
15491610 let mut toml = if !using_default_path || toml_path.exists() {
15501611 config.config = Some(if cfg!(not(test)) {
1551 toml_path.canonicalize().unwrap()
1612 toml_path = toml_path.canonicalize().unwrap();
1613 toml_path.clone()
15521614 } else {
15531615 toml_path.clone()
15541616 });
......@@ -1576,6 +1638,26 @@ impl Config {
15761638 toml.profile = Some("dist".into());
15771639 }
15781640
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
15791661 if let Some(include) = &toml.profile {
15801662 // Allows creating alias for profile names, allowing
15811663 // profiles to be renamed while maintaining back compatibility
......@@ -1597,7 +1679,12 @@ impl Config {
15971679 );
15981680 exit!(2);
15991681 });
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 );
16011688 }
16021689
16031690 let mut override_toml = TomlConfig::default();
......@@ -1608,7 +1695,12 @@ impl Config {
16081695
16091696 let mut err = match get_table(option) {
16101697 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 );
16121704 continue;
16131705 }
16141706 Err(e) => e,
......@@ -1619,7 +1711,12 @@ impl Config {
16191711 if !value.contains('"') {
16201712 match get_table(&format!(r#"{key}="{value}""#)) {
16211713 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 );
16231720 continue;
16241721 }
16251722 Err(e) => err = e,
......@@ -1629,7 +1726,7 @@ impl Config {
16291726 eprintln!("failed to parse override `{option}`: `{err}");
16301727 exit!(2)
16311728 }
1632 toml.merge(override_toml, ReplaceOpt::Override);
1729 toml.merge(None, &mut Default::default(), override_toml, ReplaceOpt::Override);
16331730
16341731 config.change_id = toml.change_id.inner;
16351732
src/bootstrap/src/core/config/tests.rs+209-2
......@@ -1,8 +1,8 @@
11use std::collections::BTreeSet;
2use std::env;
32use std::fs::{File, remove_file};
43use std::io::Write;
5use std::path::Path;
4use std::path::{Path, PathBuf};
5use std::{env, fs};
66
77use build_helper::ci::CiEnv;
88use clap::CommandFactory;
......@@ -23,6 +23,27 @@ pub(crate) fn parse(config: &str) -> Config {
2323 )
2424}
2525
26fn 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.
33fn 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
2647#[test]
2748fn download_ci_llvm() {
2849 let config = parse("llvm.download-ci-llvm = false");
......@@ -539,3 +560,189 @@ fn test_ci_flag() {
539560 let config = Config::parse_inner(Flags::parse(&["check".into()]), |&_| toml::from_str(""));
540561 assert_eq!(config.is_running_on_ci, CiEnv::is_ci());
541562}
563
564#[test]
565fn 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")]
608fn 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")]
631fn 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]
665fn 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]
684fn 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]
723fn 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] = &[
396396 severity: ChangeSeverity::Info,
397397 summary: "Added a new option `build.compiletest-use-stage0-libtest` to force `compiletest` to use the stage 0 libtest.",
398398 },
399 ChangeInfo {
400 change_id: 138934,
401 severity: ChangeSeverity::Info,
402 summary: "Added new option `include` to create config extensions.",
403 },
399404];
src/ci/citool/Cargo.lock+67
......@@ -64,12 +64,63 @@ version = "1.0.95"
6464source = "registry+https://github.com/rust-lang/crates.io-index"
6565checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
6666
67[[package]]
68name = "askama"
69version = "0.13.1"
70source = "registry+https://github.com/rust-lang/crates.io-index"
71checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7"
72dependencies = [
73 "askama_derive",
74 "itoa",
75 "percent-encoding",
76 "serde",
77 "serde_json",
78]
79
80[[package]]
81name = "askama_derive"
82version = "0.13.1"
83source = "registry+https://github.com/rust-lang/crates.io-index"
84checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac"
85dependencies = [
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]]
98name = "askama_parser"
99version = "0.13.0"
100source = "registry+https://github.com/rust-lang/crates.io-index"
101checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f"
102dependencies = [
103 "memchr",
104 "serde",
105 "serde_derive",
106 "winnow",
107]
108
67109[[package]]
68110name = "base64"
69111version = "0.22.1"
70112source = "registry+https://github.com/rust-lang/crates.io-index"
71113checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
72114
115[[package]]
116name = "basic-toml"
117version = "0.1.10"
118source = "registry+https://github.com/rust-lang/crates.io-index"
119checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
120dependencies = [
121 "serde",
122]
123
73124[[package]]
74125name = "build_helper"
75126version = "0.1.0"
......@@ -104,6 +155,7 @@ name = "citool"
104155version = "0.1.0"
105156dependencies = [
106157 "anyhow",
158 "askama",
107159 "build_helper",
108160 "clap",
109161 "csv",
......@@ -646,6 +698,12 @@ dependencies = [
646698 "windows-sys 0.52.0",
647699]
648700
701[[package]]
702name = "rustc-hash"
703version = "2.1.1"
704source = "registry+https://github.com/rust-lang/crates.io-index"
705checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
706
649707[[package]]
650708name = "rustls"
651709version = "0.23.23"
......@@ -1026,6 +1084,15 @@ version = "0.52.6"
10261084source = "registry+https://github.com/rust-lang/crates.io-index"
10271085checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
10281086
1087[[package]]
1088name = "winnow"
1089version = "0.7.6"
1090source = "registry+https://github.com/rust-lang/crates.io-index"
1091checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
1092dependencies = [
1093 "memchr",
1094]
1095
10291096[[package]]
10301097name = "write16"
10311098version = "1.0.0"
src/ci/citool/Cargo.toml+1
......@@ -5,6 +5,7 @@ edition = "2021"
55
66[dependencies]
77anyhow = "1"
8askama = "0.13"
89clap = { version = "4.5", features = ["derive"] }
910csv = "1"
1011diff = "0.1"
src/ci/citool/src/analysis.rs+6-7
......@@ -8,9 +8,9 @@ use build_helper::metrics::{
88};
99
1010use crate::github::JobInfoResolver;
11use crate::metrics;
1211use crate::metrics::{JobMetrics, JobName, get_test_suites};
1312use crate::utils::{output_details, pluralize};
13use crate::{metrics, utils};
1414
1515/// Outputs durations of individual bootstrap steps from the gathered bootstrap invocations,
1616/// and also a table with summarized information about executed tests.
......@@ -394,18 +394,17 @@ fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData {
394394 // Poor man's detection of doctests based on the "(line XYZ)" suffix
395395 let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. })
396396 && 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 };
398402 tests.insert(test_entry, test.outcome.clone());
399403 }
400404 }
401405 TestSuiteData { tests }
402406}
403407
404/// Normalizes Windows-style path delimiters to Unix-style paths.
405fn generate_test_name(name: &str) -> String {
406 name.replace('\\', "/")
407}
408
409408/// Prints test changes in Markdown format to stdout.
410409fn report_test_diffs(
411410 diff: AggregatedTestDiffs,
src/ci/citool/src/main.rs+31-3
......@@ -4,6 +4,7 @@ mod datadog;
44mod github;
55mod jobs;
66mod metrics;
7mod test_dashboard;
78mod utils;
89
910use std::collections::{BTreeMap, HashMap};
......@@ -22,7 +23,8 @@ use crate::datadog::upload_datadog_metric;
2223use crate::github::JobInfoResolver;
2324use crate::jobs::RunType;
2425use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics};
25use crate::utils::load_env_var;
26use crate::test_dashboard::generate_test_dashboard;
27use crate::utils::{load_env_var, output_details};
2628
2729const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/..");
2830const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker");
......@@ -180,12 +182,26 @@ fn postprocess_metrics(
180182}
181183
182184fn 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)?;
184186
185187 println!("\nComparing {parent} (parent) -> {current} (this PR)\n");
186188
187189 let mut job_info_resolver = JobInfoResolver::new();
188190 output_test_diffs(&metrics, &mut job_info_resolver);
191
192 output_details("Test dashboard", || {
193 println!(
194 r#"\nRun
195
196```bash
197cargo run --manifest-path src/ci/citool/Cargo.toml -- \
198 test-dashboard {current} --output-dir test-dashboard
199```
200And then open `test-dashboard/index.html` in your browser to see an overview of all executed tests.
201"#
202 );
203 });
204
189205 output_largest_duration_changes(&metrics, &mut job_info_resolver);
190206
191207 Ok(())
......@@ -234,6 +250,14 @@ enum Args {
234250 /// Current commit that will be compared to `parent`.
235251 current: String,
236252 },
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 },
237261}
238262
239263#[derive(clap::ValueEnum, Clone)]
......@@ -275,7 +299,11 @@ fn main() -> anyhow::Result<()> {
275299 postprocess_metrics(metrics_path, parent, job_name)?;
276300 }
277301 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)?;
279307 }
280308 }
281309
src/ci/citool/src/metrics.rs+12-11
......@@ -46,24 +46,25 @@ pub struct JobMetrics {
4646/// `parent` and `current` should be commit SHAs.
4747pub fn download_auto_job_metrics(
4848 job_db: &JobDatabase,
49 parent: &str,
49 parent: Option<&str>,
5050 current: &str,
5151) -> anyhow::Result<HashMap<JobName, JobMetrics>> {
5252 let mut jobs = HashMap::default();
5353
5454 for job in &job_db.auto_jobs {
5555 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:?}.
6162Maybe it was newly added?"#,
62 job.name
63 );
64 None
65 }
66 };
63 job.name
64 );
65 None
66 }
67 });
6768 let metrics_current = download_job_metrics(&job.name, current)?;
6869 jobs.insert(
6970 job.name.clone(),
src/ci/citool/src/test_dashboard.rs created+216
......@@ -0,0 +1,216 @@
1use std::collections::{BTreeMap, HashMap};
2use std::fs::File;
3use std::io::BufWriter;
4use std::path::{Path, PathBuf};
5
6use askama::Template;
7use build_helper::metrics::{TestOutcome, TestSuiteMetadata};
8
9use crate::jobs::JobDatabase;
10use crate::metrics::{JobMetrics, JobName, download_auto_job_metrics, get_test_suites};
11use crate::utils::normalize_path_delimiters;
12
13/// Generate a set of HTML files into a directory that contain a dashboard of test results.
14pub 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
30fn 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
36fn 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.
104fn 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.
139fn 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
148struct TestSuites<'a> {
149 suites: Vec<TestSuite<'a>>,
150}
151
152impl<'a> TestSuites<'a> {
153 fn test_count(&self) -> u64 {
154 self.suites.iter().map(|suite| suite.group.test_count()).sum::<u64>()
155 }
156}
157
158struct TestSuite<'a> {
159 group: TestGroup<'a>,
160}
161
162struct TestResults<'a> {
163 passed: Vec<TestMetadata<'a>>,
164 ignored: Vec<TestMetadata<'a>>,
165}
166
167struct Test<'a> {
168 revisions: BTreeMap<String, TestResults<'a>>,
169}
170
171impl<'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)]
185struct 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
196struct 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
204impl<'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")]
213struct TestSuitesPage<'a> {
214 suites: TestSuites<'a>,
215 test_count: u64,
216}
src/ci/citool/src/utils.rs+6
......@@ -1,3 +1,4 @@
1use std::borrow::Cow;
12use std::path::Path;
23
34use anyhow::Context;
......@@ -28,3 +29,8 @@ where
2829 func();
2930 println!("</details>\n");
3031}
32
33/// Normalizes Windows-style path delimiters to Unix-style paths.
34pub 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) -%}
2passed: {{ 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>
6Here's how to interpret the "passed" and "ignored" counts:
7the 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 %}
32h1 {
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
54ul {
55 padding-left: 0;
56}
57
58li {
59 list-style: none;
60 padding-left: 20px;
61}
62summary {
63 margin-bottom: 5px;
64 padding: 6px;
65 background-color: #F4F4F4;
66 border: 1px solid #ddd;
67 border-radius: 4px;
68 cursor: pointer;
69}
70summary:hover {
71 background-color: #CFCFCF;
72}
73
74/* Style the disclosure triangles */
75details > summary {
76 list-style: none;
77 position: relative;
78}
79
80details > summary::before {
81 content: "â–¶";
82 position: absolute;
83 left: -15px;
84 transform: rotate(0);
85 transition: transform 0.2s;
86}
87
88details[open] > summary::before {
89 transform: rotate(90deg);
90}
91{% endblock %}
92
93{% block scripts %}
94<script type="text/javascript">
95function openAll() {
96 const details = document.getElementsByTagName("details");
97 for (const elem of details) {
98 elem.open = true;
99 }
100}
101function 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!).
2020
2121You can also install the hook as a step of running `./x setup`!
2222
23## Config extensions
24
25When working on different tasks, you might need to switch between different bootstrap configurations.
26Sometimes you may want to keep an old configuration for future use. But saving raw config values in
27random files and manually copying and pasting them can quickly become messy, especially if you have a
28long history of different configurations.
29
30To simplify managing multiple configurations, you can create config extensions.
31
32For example, you can create a simple config file named `cross.toml`:
33
34```toml
35[build]
36build = "x86_64-unknown-linux-gnu"
37host = ["i686-unknown-linux-gnu"]
38target = ["i686-unknown-linux-gnu"]
39
40
41[llvm]
42download-ci-llvm = false
43
44[target.x86_64-unknown-linux-gnu]
45llvm-config = "/path/to/llvm-19/bin/llvm-config"
46```
47
48Then, include this in your `bootstrap.toml`:
49
50```toml
51include = ["cross.toml"]
52```
53
54You 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,
57in `include = ["a.toml", "b.toml"]`, extension `b.toml` overrides `a.toml`. Also, parent extensions
58always overrides the inner ones.
59
2360## Configuring `rust-analyzer` for `rustc`
2461
2562### 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.
247247```rust,ignore (making doc tests pass cross-platform is hard)
248248#![feature(naked_functions)]
249249
250use std::arch::asm;
250use std::arch::naked_asm;
251251use std::mem;
252252
253253fn add_one(x: i32) -> i32 {
254254 x + 1
255255}
256256
257#[naked]
257#[unsafe(naked)]
258258pub extern "C" fn add_two(x: i32) {
259259 // 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 );
278275}
279276
280277fn 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
13971397ui/issues/auxiliary/issue-13620-2.rs
13981398ui/issues/auxiliary/issue-14344-1.rs
13991399ui/issues/auxiliary/issue-14344-2.rs
1400ui/issues/auxiliary/issue-14421.rs
14011400ui/issues/auxiliary/issue-14422.rs
14021401ui/issues/auxiliary/issue-15562.rs
14031402ui/issues/auxiliary/issue-16643.rs
......@@ -1564,7 +1563,6 @@ ui/issues/issue-14366.rs
15641563ui/issues/issue-14382.rs
15651564ui/issues/issue-14393.rs
15661565ui/issues/issue-14399.rs
1567ui/issues/issue-14421.rs
15681566ui/issues/issue-14422.rs
15691567ui/issues/issue-14541.rs
15701568ui/issues/issue-14721.rs
......@@ -1629,7 +1627,6 @@ ui/issues/issue-16774.rs
16291627ui/issues/issue-16783.rs
16301628ui/issues/issue-16819.rs
16311629ui/issues/issue-16922-rpass.rs
1632ui/issues/issue-16939.rs
16331630ui/issues/issue-16966.rs
16341631ui/issues/issue-16994.rs
16351632ui/issues/issue-17001.rs
......@@ -1867,7 +1864,6 @@ ui/issues/issue-23550.rs
18671864ui/issues/issue-23589.rs
18681865ui/issues/issue-23699.rs
18691866ui/issues/issue-2380-b.rs
1870ui/issues/issue-23808.rs
18711867ui/issues/issue-2383.rs
18721868ui/issues/issue-23891.rs
18731869ui/issues/issue-23898.rs
......@@ -2607,7 +2603,6 @@ ui/issues/issue-9249.rs
26072603ui/issues/issue-9259.rs
26082604ui/issues/issue-92741.rs
26092605ui/issues/issue-9446.rs
2610ui/issues/issue-9719.rs
26112606ui/issues/issue-9725.rs
26122607ui/issues/issue-9737.rs
26132608ui/issues/issue-9814.rs
......@@ -3138,7 +3133,6 @@ ui/nll/user-annotations/issue-55241.rs
31383133ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs
31393134ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs
31403135ui/numbers-arithmetic/issue-8460.rs
3141ui/on-unimplemented/issue-104140.rs
31423136ui/or-patterns/issue-64879-trailing-before-guard.rs
31433137ui/or-patterns/issue-67514-irrefutable-param.rs
31443138ui/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;
1717const ENTRY_LIMIT: u32 = 901;
1818// FIXME: The following limits should be reduced eventually.
1919
20const ISSUES_ENTRY_LIMIT: u32 = 1631;
20const ISSUES_ENTRY_LIMIT: u32 = 1626;
2121
2222const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
2323 "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;
1313// LLVM implements this via making sure of that, even for functions with the naked attribute.
1414// So, we must emit an appropriate instruction instead!
1515#[no_mangle]
16#[naked]
17pub unsafe extern "C" fn _hlt() -> ! {
16#[unsafe(naked)]
17pub extern "C" fn _hlt() -> ! {
1818 // CHECK-NOT: hint #34
1919 // CHECK: hlt #0x1
2020 naked_asm!("hlt #1")
tests/assembly/naked-functions/aix.rs+2-2
......@@ -29,7 +29,7 @@ use minicore::*;
2929// CHECK-LABEL: blr:
3030// CHECK: blr
3131#[no_mangle]
32#[naked]
33unsafe extern "C" fn blr() {
32#[unsafe(naked)]
33extern "C" fn blr() {
3434 naked_asm!("blr")
3535}
tests/assembly/naked-functions/wasm32.rs+30-30
......@@ -22,8 +22,8 @@ use minicore::*;
2222// CHECK-NOT: .size
2323// CHECK: end_function
2424#[no_mangle]
25#[naked]
26unsafe extern "C" fn nop() {
25#[unsafe(naked)]
26extern "C" fn nop() {
2727 naked_asm!("nop")
2828}
2929
......@@ -34,11 +34,11 @@ unsafe extern "C" fn nop() {
3434// CHECK-NOT: .size
3535// CHECK: end_function
3636#[no_mangle]
37#[naked]
37#[unsafe(naked)]
3838#[linkage = "weak"]
3939// wasm functions cannot be aligned, so this has no effect
4040#[repr(align(32))]
41unsafe extern "C" fn weak_aligned_nop() {
41extern "C" fn weak_aligned_nop() {
4242 naked_asm!("nop")
4343}
4444
......@@ -51,48 +51,48 @@ unsafe extern "C" fn weak_aligned_nop() {
5151//
5252// CHECK-NEXT: end_function
5353#[no_mangle]
54#[naked]
55unsafe extern "C" fn fn_i8_i8(num: i8) -> i8 {
54#[unsafe(naked)]
55extern "C" fn fn_i8_i8(num: i8) -> i8 {
5656 naked_asm!("local.get 0", "local.get 0", "i32.mul")
5757}
5858
5959// CHECK-LABEL: fn_i8_i8_i8:
6060// CHECK: .functype fn_i8_i8_i8 (i32, i32) -> (i32)
6161#[no_mangle]
62#[naked]
63unsafe extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 {
62#[unsafe(naked)]
63extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 {
6464 naked_asm!("local.get 1", "local.get 0", "i32.mul")
6565}
6666
6767// CHECK-LABEL: fn_unit_i8:
6868// CHECK: .functype fn_unit_i8 () -> (i32)
6969#[no_mangle]
70#[naked]
71unsafe extern "C" fn fn_unit_i8() -> i8 {
70#[unsafe(naked)]
71extern "C" fn fn_unit_i8() -> i8 {
7272 naked_asm!("i32.const 42")
7373}
7474
7575// CHECK-LABEL: fn_i8_unit:
7676// CHECK: .functype fn_i8_unit (i32) -> ()
7777#[no_mangle]
78#[naked]
79unsafe extern "C" fn fn_i8_unit(_: i8) {
78#[unsafe(naked)]
79extern "C" fn fn_i8_unit(_: i8) {
8080 naked_asm!("nop")
8181}
8282
8383// CHECK-LABEL: fn_i32_i32:
8484// CHECK: .functype fn_i32_i32 (i32) -> (i32)
8585#[no_mangle]
86#[naked]
87unsafe extern "C" fn fn_i32_i32(num: i32) -> i32 {
86#[unsafe(naked)]
87extern "C" fn fn_i32_i32(num: i32) -> i32 {
8888 naked_asm!("local.get 0", "local.get 0", "i32.mul")
8989}
9090
9191// CHECK-LABEL: fn_i64_i64:
9292// CHECK: .functype fn_i64_i64 (i64) -> (i64)
9393#[no_mangle]
94#[naked]
95unsafe extern "C" fn fn_i64_i64(num: i64) -> i64 {
94#[unsafe(naked)]
95extern "C" fn fn_i64_i64(num: i64) -> i64 {
9696 naked_asm!("local.get 0", "local.get 0", "i64.mul")
9797}
9898
......@@ -101,8 +101,8 @@ unsafe extern "C" fn fn_i64_i64(num: i64) -> i64 {
101101// wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> ()
102102#[allow(improper_ctypes_definitions)]
103103#[no_mangle]
104#[naked]
105unsafe extern "C" fn fn_i128_i128(num: i128) -> i128 {
104#[unsafe(naked)]
105extern "C" fn fn_i128_i128(num: i128) -> i128 {
106106 naked_asm!(
107107 "local.get 0",
108108 "local.get 2",
......@@ -117,8 +117,8 @@ unsafe extern "C" fn fn_i128_i128(num: i128) -> i128 {
117117// wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> ()
118118// wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> ()
119119#[no_mangle]
120#[naked]
121unsafe extern "C" fn fn_f128_f128(num: f128) -> f128 {
120#[unsafe(naked)]
121extern "C" fn fn_f128_f128(num: f128) -> f128 {
122122 naked_asm!(
123123 "local.get 0",
124124 "local.get 2",
......@@ -139,8 +139,8 @@ struct Compound {
139139// wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> ()
140140// wasm64-unknown: .functype fn_compound_compound (i64, i64) -> ()
141141#[no_mangle]
142#[naked]
143unsafe extern "C" fn fn_compound_compound(_: Compound) -> Compound {
142#[unsafe(naked)]
143extern "C" fn fn_compound_compound(_: Compound) -> Compound {
144144 // this is the wasm32-wasip1 assembly
145145 naked_asm!(
146146 "local.get 0",
......@@ -160,8 +160,8 @@ struct WrapperI32(i32);
160160// CHECK-LABEL: fn_wrapperi32_wrapperi32:
161161// CHECK: .functype fn_wrapperi32_wrapperi32 (i32) -> (i32)
162162#[no_mangle]
163#[naked]
164unsafe extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 {
163#[unsafe(naked)]
164extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 {
165165 naked_asm!("local.get 0")
166166}
167167
......@@ -171,8 +171,8 @@ struct WrapperI64(i64);
171171// CHECK-LABEL: fn_wrapperi64_wrapperi64:
172172// CHECK: .functype fn_wrapperi64_wrapperi64 (i64) -> (i64)
173173#[no_mangle]
174#[naked]
175unsafe extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 {
174#[unsafe(naked)]
175extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 {
176176 naked_asm!("local.get 0")
177177}
178178
......@@ -182,8 +182,8 @@ struct WrapperF32(f32);
182182// CHECK-LABEL: fn_wrapperf32_wrapperf32:
183183// CHECK: .functype fn_wrapperf32_wrapperf32 (f32) -> (f32)
184184#[no_mangle]
185#[naked]
186unsafe extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 {
185#[unsafe(naked)]
186extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 {
187187 naked_asm!("local.get 0")
188188}
189189
......@@ -193,7 +193,7 @@ struct WrapperF64(f64);
193193// CHECK-LABEL: fn_wrapperf64_wrapperf64:
194194// CHECK: .functype fn_wrapperf64_wrapperf64 (f64) -> (f64)
195195#[no_mangle]
196#[naked]
197unsafe extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 {
196#[unsafe(naked)]
197extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 {
198198 naked_asm!("local.get 0")
199199}
tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs+2-2
......@@ -13,8 +13,8 @@ use std::arch::naked_asm;
1313// works by using an instruction for each possible landing site,
1414// and LLVM implements this via making sure of that.
1515#[no_mangle]
16#[naked]
17pub unsafe extern "sysv64" fn will_halt() -> ! {
16#[unsafe(naked)]
17pub extern "sysv64" fn will_halt() -> ! {
1818 // CHECK-NOT: endbr{{32|64}}
1919 // CHECK: hlt
2020 naked_asm!("hlt")
tests/codegen/cffi/c-variadic-naked.rs+2-4
......@@ -8,11 +8,9 @@
88#![feature(naked_functions)]
99#![no_std]
1010
11#[naked]
11#[unsafe(naked)]
1212pub unsafe extern "C" fn c_variadic(_: usize, _: ...) {
1313 // CHECK-NOT: va_start
1414 // CHECK-NOT: alloca
15 core::arch::naked_asm! {
16 "ret",
17 }
15 core::arch::naked_asm!("ret")
1816}
tests/codegen/naked-asan.rs+2-2
......@@ -13,10 +13,10 @@ pub fn caller() {
1313}
1414
1515// CHECK: declare x86_intrcc void @page_fault_handler(ptr {{.*}}, i64{{.*}}){{.*}}#[[ATTRS:[0-9]+]]
16#[naked]
16#[unsafe(naked)]
1717#[no_mangle]
1818pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) {
19 unsafe { core::arch::naked_asm!("ud2") };
19 core::arch::naked_asm!("ud2")
2020}
2121
2222// CHECK: #[[ATTRS]] =
tests/codegen/naked-fn/aligned.rs+3-3
......@@ -10,8 +10,8 @@ use std::arch::naked_asm;
1010// CHECK-LABEL: naked_empty:
1111#[repr(align(16))]
1212#[no_mangle]
13#[naked]
14pub unsafe extern "C" fn naked_empty() {
13#[unsafe(naked)]
14pub extern "C" fn naked_empty() {
1515 // CHECK: ret
16 naked_asm!("ret");
16 naked_asm!("ret")
1717}
tests/codegen/naked-fn/generics.rs+21-25
......@@ -28,21 +28,19 @@ fn test(x: u64) {
2828// CHECK: add rax, 1
2929// CHECK: add rax, 42
3030
31#[naked]
31#[unsafe(naked)]
3232pub extern "C" fn using_const_generics<const N: u64>(x: u64) -> u64 {
3333 const M: u64 = 42;
3434
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 )
4644}
4745
4846trait Invert {
......@@ -60,16 +58,14 @@ impl Invert for i64 {
6058// CHECK: call
6159// CHECK: ret
6260
63#[naked]
61#[unsafe(naked)]
6462#[no_mangle]
6563pub 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 )
7369}
7470
7571#[derive(Copy, Clone)]
......@@ -81,10 +77,10 @@ struct Foo(u64);
8177// CHECK: mov rax, rdi
8278
8379impl Foo {
84 #[naked]
80 #[unsafe(naked)]
8581 #[no_mangle]
8682 extern "C" fn method(self) -> u64 {
87 unsafe { naked_asm!("mov rax, rdi", "ret") }
83 naked_asm!("mov rax, rdi", "ret")
8884 }
8985}
9086
......@@ -97,10 +93,10 @@ trait Bar {
9793}
9894
9995impl Bar for Foo {
100 #[naked]
96 #[unsafe(naked)]
10197 #[no_mangle]
10298 extern "C" fn trait_method(self) -> u64 {
103 unsafe { naked_asm!("mov rax, rdi", "ret") }
99 naked_asm!("mov rax, rdi", "ret")
104100 }
105101}
106102
......@@ -109,7 +105,7 @@ impl Bar for Foo {
109105// CHECK: lea rax, [rdi + rsi]
110106
111107// this previously ICE'd, see https://github.com/rust-lang/rust/issues/124375
112#[naked]
108#[unsafe(naked)]
113109#[no_mangle]
114110pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
115111 naked_asm!("lea rax, [rdi + rsi]", "ret");
tests/codegen/naked-fn/instruction-set.rs+6-6
......@@ -20,8 +20,8 @@ use minicore::*;
2020// arm-mode: .arm
2121// thumb-mode: .thumb
2222#[no_mangle]
23#[naked]
24unsafe extern "C" fn test_unspecified() {
23#[unsafe(naked)]
24extern "C" fn test_unspecified() {
2525 naked_asm!("bx lr");
2626}
2727
......@@ -33,9 +33,9 @@ unsafe extern "C" fn test_unspecified() {
3333// arm-mode: .arm
3434// thumb-mode: .thumb
3535#[no_mangle]
36#[naked]
36#[unsafe(naked)]
3737#[instruction_set(arm::t32)]
38unsafe extern "C" fn test_thumb() {
38extern "C" fn test_thumb() {
3939 naked_asm!("bx lr");
4040}
4141
......@@ -46,8 +46,8 @@ unsafe extern "C" fn test_thumb() {
4646// arm-mode: .arm
4747// thumb-mode: .thumb
4848#[no_mangle]
49#[naked]
49#[unsafe(naked)]
5050#[instruction_set(arm::a32)]
51unsafe extern "C" fn test_arm() {
51extern "C" fn test_arm() {
5252 naked_asm!("bx lr");
5353}
tests/codegen/naked-fn/min-function-alignment.rs+8-8
......@@ -9,24 +9,24 @@
99//
1010// CHECK: .balign 16
1111#[no_mangle]
12#[naked]
13pub unsafe extern "C" fn naked_no_explicit_align() {
12#[unsafe(naked)]
13pub extern "C" fn naked_no_explicit_align() {
1414 core::arch::naked_asm!("ret")
1515}
1616
1717// CHECK: .balign 16
1818#[no_mangle]
1919#[repr(align(8))]
20#[naked]
21pub unsafe extern "C" fn naked_lower_align() {
20#[unsafe(naked)]
21pub extern "C" fn naked_lower_align() {
2222 core::arch::naked_asm!("ret")
2323}
2424
2525// CHECK: .balign 32
2626#[no_mangle]
2727#[repr(align(32))]
28#[naked]
29pub unsafe extern "C" fn naked_higher_align() {
28#[unsafe(naked)]
29pub extern "C" fn naked_higher_align() {
3030 core::arch::naked_asm!("ret")
3131}
3232
......@@ -38,7 +38,7 @@ pub unsafe extern "C" fn naked_higher_align() {
3838// CHECK: .balign 16
3939#[no_mangle]
4040#[cold]
41#[naked]
42pub unsafe extern "C" fn no_explicit_align_cold() {
41#[unsafe(naked)]
42pub extern "C" fn no_explicit_align_cold() {
4343 core::arch::naked_asm!("ret")
4444}
tests/codegen/naked-fn/naked-functions.rs+8-8
......@@ -60,8 +60,8 @@ use minicore::*;
6060// linux,win: .att_syntax
6161
6262#[no_mangle]
63#[naked]
64pub unsafe extern "C" fn naked_empty() {
63#[unsafe(naked)]
64pub extern "C" fn naked_empty() {
6565 #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))]
6666 naked_asm!("ret");
6767
......@@ -114,8 +114,8 @@ pub unsafe extern "C" fn naked_empty() {
114114// linux,win: .att_syntax
115115
116116#[no_mangle]
117#[naked]
118pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
117#[unsafe(naked)]
118pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
119119 #[cfg(any(target_os = "windows", target_os = "linux"))]
120120 {
121121 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
138138// thumb: .pushsection .text.some_different_name,\22ax\22, %progbits
139139// CHECK-LABEL: test_link_section:
140140#[no_mangle]
141#[naked]
141#[unsafe(naked)]
142142#[link_section = ".text.some_different_name"]
143pub unsafe extern "C" fn test_link_section() {
143pub extern "C" fn test_link_section() {
144144 #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))]
145145 naked_asm!("ret");
146146
......@@ -159,7 +159,7 @@ pub unsafe extern "C" fn test_link_section() {
159159// win_i686-LABEL: @fastcall_cc@4:
160160#[cfg(target_os = "windows")]
161161#[no_mangle]
162#[naked]
163pub unsafe extern "fastcall" fn fastcall_cc(x: i32) -> i32 {
162#[unsafe(naked)]
163pub extern "fastcall" fn fastcall_cc(x: i32) -> i32 {
164164 naked_asm!("ret");
165165}
tests/crashes/130627.rs deleted-20
......@@ -1,20 +0,0 @@
1//@ known-bug: #130627
2
3#![feature(trait_alias)]
4
5trait Test {}
6
7#[diagnostic::on_unimplemented(
8 message="message",
9 label="label",
10 note="note"
11)]
12trait Alias = Test;
13
14// Use trait alias as bound on type parameter.
15fn foo<T: Alias>(v: &T) {
16}
17
18pub 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
4pub 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
4pub fn f() -> isize {
5 20
6}
tests/run-make/crate-loading-multiple-candidates/multiple-candidates.rs created+3
......@@ -0,0 +1,3 @@
1extern crate crateresolve1;
2
3fn main() {}
tests/run-make/crate-loading-multiple-candidates/multiple-candidates.stderr created+12
......@@ -0,0 +1,12 @@
1error[E0464]: multiple candidates for `rlib` dependency `crateresolve1` found
2 --> multiple-candidates.rs:1:1
3 |
4LL | extern crate crateresolve1;
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
6 |
7 = note: candidate #1: ./mylibs/libcrateresolve1-1.rlib
8 = note: candidate #2: ./mylibs/libcrateresolve1-2.rlib
9
10error: aborting due to 1 previous error
11
12For 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
7use run_make_support::{bare_rustc, diff, rfs, rustc};
8
9fn 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
22fn 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 {
2626 42
2727}
2828
29#[naked]
29#[unsafe(naked)]
3030extern "C" fn private_naked() -> u32 {
31 unsafe { naked_asm!("mov rax, 42", "ret") }
31 naked_asm!("mov rax, 42", "ret")
3232}
3333
3434#[no_mangle]
......@@ -36,19 +36,19 @@ pub extern "C" fn public_vanilla() -> u32 {
3636 42
3737}
3838
39#[naked]
39#[unsafe(naked)]
4040#[no_mangle]
4141pub extern "C" fn public_naked_nongeneric() -> u32 {
42 unsafe { naked_asm!("mov rax, 42", "ret") }
42 naked_asm!("mov rax, 42", "ret")
4343}
4444
4545pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 {
4646 T::COUNT
4747}
4848
49#[naked]
49#[unsafe(naked)]
5050pub 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)
5252}
5353
5454#[linkage = "external"]
......@@ -56,10 +56,10 @@ extern "C" fn vanilla_external_linkage() -> u32 {
5656 42
5757}
5858
59#[naked]
59#[unsafe(naked)]
6060#[linkage = "external"]
6161extern "C" fn naked_external_linkage() -> u32 {
62 unsafe { naked_asm!("mov rax, 42", "ret") }
62 naked_asm!("mov rax, 42", "ret")
6363}
6464
6565#[cfg(not(windows))]
......@@ -68,11 +68,11 @@ extern "C" fn vanilla_weak_linkage() -> u32 {
6868 42
6969}
7070
71#[naked]
71#[unsafe(naked)]
7272#[cfg(not(windows))]
7373#[linkage = "weak"]
7474extern "C" fn naked_weak_linkage() -> u32 {
75 unsafe { naked_asm!("mov rax, 42", "ret") }
75 naked_asm!("mov rax, 42", "ret")
7676}
7777
7878// 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
15fn foo<T: Fn()>(t: T) {
26 t(1i32);
37 //~^ ERROR function takes 0 arguments but 1 argument was supplied
48}
59
10/// Regression test for <https://github.com/rust-lang/rust/issues/16939>
11fn foo2<T: Fn()>(f: T) {
12 |t| f(t);
13 //~^ ERROR function takes 0 arguments but 1 argument was supplied
14}
15
616fn bar(t: impl Fn()) {
717 t(1i32);
818 //~^ ERROR function takes 0 arguments but 1 argument was supplied
tests/ui/argument-suggestions/exotic-calls.stderr+26-9
......@@ -1,11 +1,11 @@
11error[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
33 |
44LL | t(1i32);
55 | ^ ---- unexpected argument of type `i32`
66 |
77note: callable defined here
8 --> $DIR/exotic-calls.rs:1:11
8 --> $DIR/exotic-calls.rs:5:11
99 |
1010LL | fn foo<T: Fn()>(t: T) {
1111 | ^^^^
......@@ -16,13 +16,30 @@ LL + t();
1616 |
1717
1818error[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 |
21LL | |t| f(t);
22 | ^ - unexpected argument
23 |
24note: callable defined here
25 --> $DIR/exotic-calls.rs:11:12
26 |
27LL | fn foo2<T: Fn()>(f: T) {
28 | ^^^^
29help: remove the extra argument
30 |
31LL - |t| f(t);
32LL + |t| f();
33 |
34
35error[E0057]: this function takes 0 arguments but 1 argument was supplied
36 --> $DIR/exotic-calls.rs:17:5
2037 |
2138LL | t(1i32);
2239 | ^ ---- unexpected argument of type `i32`
2340 |
2441note: type parameter defined here
25 --> $DIR/exotic-calls.rs:6:11
42 --> $DIR/exotic-calls.rs:16:11
2643 |
2744LL | fn bar(t: impl Fn()) {
2845 | ^^^^^^^^^
......@@ -33,13 +50,13 @@ LL + t();
3350 |
3451
3552error[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
3754 |
3855LL | baz()(1i32)
3956 | ^^^^^ ---- unexpected argument of type `i32`
4057 |
4158note: opaque type defined here
42 --> $DIR/exotic-calls.rs:11:13
59 --> $DIR/exotic-calls.rs:21:13
4360 |
4461LL | fn baz() -> impl Fn() {
4562 | ^^^^^^^^^
......@@ -50,13 +67,13 @@ LL + baz()()
5067 |
5168
5269error[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
5471 |
5572LL | x(1i32);
5673 | ^ ---- unexpected argument of type `i32`
5774 |
5875note: closure defined here
59 --> $DIR/exotic-calls.rs:21:13
76 --> $DIR/exotic-calls.rs:31:13
6077 |
6178LL | let x = || {};
6279 | ^^
......@@ -66,6 +83,6 @@ LL - x(1i32);
6683LL + x();
6784 |
6885
69error: aborting due to 4 previous errors
86error: aborting due to 5 previous errors
7087
7188For 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() {
1212 test1();
1313}
1414
15#[naked]
15#[unsafe(naked)]
1616extern "C" fn test1() {
17 unsafe { naked_asm!("") }
17 naked_asm!("")
1818}
1919
2020extern "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)]`
2323}
2424
2525extern "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)]`
2828}
2929
3030fn test4() {
3131 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)]`
3434 };
3535}
tests/ui/asm/naked-asm-outside-naked-fn.stderr+12-12
......@@ -1,20 +1,20 @@
1error: the `naked_asm!` macro can only be used in functions marked with `#[naked]`
2 --> $DIR/naked-asm-outside-naked-fn.rs:21:14
1error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
2 --> $DIR/naked-asm-outside-naked-fn.rs:21:5
33 |
4LL | unsafe { naked_asm!("") }
5 | ^^^^^^^^^^^^^^
4LL | naked_asm!("")
5 | ^^^^^^^^^^^^^^
66
7error: the `naked_asm!` macro can only be used in functions marked with `#[naked]`
8 --> $DIR/naked-asm-outside-naked-fn.rs:26:18
7error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
8 --> $DIR/naked-asm-outside-naked-fn.rs:26:9
99 |
10LL | unsafe { (|| naked_asm!(""))() }
11 | ^^^^^^^^^^^^^^
10LL | (|| naked_asm!(""))()
11 | ^^^^^^^^^^^^^^
1212
13error: the `naked_asm!` macro can only be used in functions marked with `#[naked]`
14 --> $DIR/naked-asm-outside-naked-fn.rs:32:19
13error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
14 --> $DIR/naked-asm-outside-naked-fn.rs:32:9
1515 |
16LL | unsafe { naked_asm!("") } ;
17 | ^^^^^^^^^^^^^^
16LL | naked_asm!("");
17 | ^^^^^^^^^^^^^^
1818
1919error: aborting due to 3 previous errors
2020
tests/ui/asm/naked-functions-ffi.rs+2-4
......@@ -5,11 +5,9 @@
55
66use std::arch::naked_asm;
77
8#[naked]
8#[unsafe(naked)]
99pub extern "C" fn naked(p: char) -> u128 {
1010 //~^ WARN uses type `char`
1111 //~| WARN uses type `u128`
12 unsafe {
13 naked_asm!("");
14 }
12 naked_asm!("")
1513}
tests/ui/asm/naked-functions-inline.rs+10-10
......@@ -4,35 +4,35 @@
44
55use std::arch::naked_asm;
66
7#[naked]
8pub unsafe extern "C" fn inline_none() {
7#[unsafe(naked)]
8pub extern "C" fn inline_none() {
99 naked_asm!("");
1010}
1111
12#[naked]
12#[unsafe(naked)]
1313#[inline]
1414//~^ ERROR [E0736]
15pub unsafe extern "C" fn inline_hint() {
15pub extern "C" fn inline_hint() {
1616 naked_asm!("");
1717}
1818
19#[naked]
19#[unsafe(naked)]
2020#[inline(always)]
2121//~^ ERROR [E0736]
22pub unsafe extern "C" fn inline_always() {
22pub extern "C" fn inline_always() {
2323 naked_asm!("");
2424}
2525
26#[naked]
26#[unsafe(naked)]
2727#[inline(never)]
2828//~^ ERROR [E0736]
29pub unsafe extern "C" fn inline_never() {
29pub extern "C" fn inline_never() {
3030 naked_asm!("");
3131}
3232
33#[naked]
33#[unsafe(naked)]
3434#[cfg_attr(all(), inline(never))]
3535//~^ ERROR [E0736]
36pub unsafe extern "C" fn conditional_inline_never() {
36pub extern "C" fn conditional_inline_never() {
3737 naked_asm!("");
3838}
tests/ui/asm/naked-functions-inline.stderr+16-16
......@@ -1,34 +1,34 @@
1error[E0736]: attribute incompatible with `#[naked]`
1error[E0736]: attribute incompatible with `#[unsafe(naked)]`
22 --> $DIR/naked-functions-inline.rs:13:1
33 |
4LL | #[naked]
5 | -------- function marked with `#[naked]` here
4LL | #[unsafe(naked)]
5 | ---------------- function marked with `#[unsafe(naked)]` here
66LL | #[inline]
7 | ^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]`
7 | ^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]`
88
9error[E0736]: attribute incompatible with `#[naked]`
9error[E0736]: attribute incompatible with `#[unsafe(naked)]`
1010 --> $DIR/naked-functions-inline.rs:20:1
1111 |
12LL | #[naked]
13 | -------- function marked with `#[naked]` here
12LL | #[unsafe(naked)]
13 | ---------------- function marked with `#[unsafe(naked)]` here
1414LL | #[inline(always)]
15 | ^^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]`
15 | ^^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]`
1616
17error[E0736]: attribute incompatible with `#[naked]`
17error[E0736]: attribute incompatible with `#[unsafe(naked)]`
1818 --> $DIR/naked-functions-inline.rs:27:1
1919 |
20LL | #[naked]
21 | -------- function marked with `#[naked]` here
20LL | #[unsafe(naked)]
21 | ---------------- function marked with `#[unsafe(naked)]` here
2222LL | #[inline(never)]
23 | ^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]`
23 | ^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]`
2424
25error[E0736]: attribute incompatible with `#[naked]`
25error[E0736]: attribute incompatible with `#[unsafe(naked)]`
2626 --> $DIR/naked-functions-inline.rs:34:19
2727 |
28LL | #[naked]
29 | -------- function marked with `#[naked]` here
28LL | #[unsafe(naked)]
29 | ---------------- function marked with `#[unsafe(naked)]` here
3030LL | #[cfg_attr(all(), inline(never))]
31 | ^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]`
31 | ^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]`
3232
3333error: aborting due to 4 previous errors
3434
tests/ui/asm/naked-functions-instruction-set.rs+4-4
......@@ -12,15 +12,15 @@ extern crate minicore;
1212use minicore::*;
1313
1414#[no_mangle]
15#[naked]
15#[unsafe(naked)]
1616#[instruction_set(arm::t32)]
17unsafe extern "C" fn test_thumb() {
17extern "C" fn test_thumb() {
1818 naked_asm!("bx lr");
1919}
2020
2121#[no_mangle]
22#[naked]
22#[unsafe(naked)]
2323#[instruction_set(arm::a32)]
24unsafe extern "C" fn test_arm() {
24extern "C" fn test_arm() {
2525 naked_asm!("bx lr");
2626}
tests/ui/asm/naked-functions-rustic-abi.rs+6-6
......@@ -11,17 +11,17 @@
1111
1212use std::arch::{asm, naked_asm};
1313
14#[naked]
15pub unsafe fn rust_implicit() {
14#[unsafe(naked)]
15pub fn rust_implicit() {
1616 naked_asm!("ret");
1717}
1818
19#[naked]
20pub unsafe extern "Rust" fn rust_explicit() {
19#[unsafe(naked)]
20pub extern "Rust" fn rust_explicit() {
2121 naked_asm!("ret");
2222}
2323
24#[naked]
25pub unsafe extern "rust-cold" fn rust_cold() {
24#[unsafe(naked)]
25pub extern "rust-cold" fn rust_cold() {
2626 naked_asm!("ret");
2727}
tests/ui/asm/naked-functions-target-feature.rs+6-6
......@@ -8,14 +8,14 @@ use std::arch::{asm, naked_asm};
88
99#[cfg(target_arch = "x86_64")]
1010#[target_feature(enable = "sse2")]
11#[naked]
12pub unsafe extern "C" fn compatible_target_feature() {
13 naked_asm!("");
11#[unsafe(naked)]
12pub extern "C" fn compatible_target_feature() {
13 naked_asm!("ret");
1414}
1515
1616#[cfg(target_arch = "aarch64")]
1717#[target_feature(enable = "neon")]
18#[naked]
19pub unsafe extern "C" fn compatible_target_feature() {
20 naked_asm!("");
18#[unsafe(naked)]
19pub extern "C" fn compatible_target_feature() {
20 naked_asm!("ret");
2121}
tests/ui/asm/naked-functions-testattrs.rs+8-8
......@@ -8,31 +8,31 @@
88use std::arch::naked_asm;
99
1010#[test]
11#[naked]
11#[unsafe(naked)]
1212//~^ ERROR [E0736]
1313extern "C" fn test_naked() {
14 unsafe { naked_asm!("") };
14 naked_asm!("")
1515}
1616
1717#[should_panic]
1818#[test]
19#[naked]
19#[unsafe(naked)]
2020//~^ ERROR [E0736]
2121extern "C" fn test_naked_should_panic() {
22 unsafe { naked_asm!("") };
22 naked_asm!("")
2323}
2424
2525#[ignore]
2626#[test]
27#[naked]
27#[unsafe(naked)]
2828//~^ ERROR [E0736]
2929extern "C" fn test_naked_ignore() {
30 unsafe { naked_asm!("") };
30 naked_asm!("")
3131}
3232
3333#[bench]
34#[naked]
34#[unsafe(naked)]
3535//~^ ERROR [E0736]
3636extern "C" fn bench_naked() {
37 unsafe { naked_asm!("") };
37 naked_asm!("")
3838}
tests/ui/asm/naked-functions-testattrs.stderr+12-12
......@@ -1,34 +1,34 @@
1error[E0736]: cannot use `#[naked]` with testing attributes
1error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes
22 --> $DIR/naked-functions-testattrs.rs:11:1
33 |
44LL | #[test]
55 | ------- function marked with testing attribute here
6LL | #[naked]
7 | ^^^^^^^^ `#[naked]` is incompatible with testing attributes
6LL | #[unsafe(naked)]
7 | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes
88
9error[E0736]: cannot use `#[naked]` with testing attributes
9error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes
1010 --> $DIR/naked-functions-testattrs.rs:19:1
1111 |
1212LL | #[test]
1313 | ------- function marked with testing attribute here
14LL | #[naked]
15 | ^^^^^^^^ `#[naked]` is incompatible with testing attributes
14LL | #[unsafe(naked)]
15 | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes
1616
17error[E0736]: cannot use `#[naked]` with testing attributes
17error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes
1818 --> $DIR/naked-functions-testattrs.rs:27:1
1919 |
2020LL | #[test]
2121 | ------- function marked with testing attribute here
22LL | #[naked]
23 | ^^^^^^^^ `#[naked]` is incompatible with testing attributes
22LL | #[unsafe(naked)]
23 | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes
2424
25error[E0736]: cannot use `#[naked]` with testing attributes
25error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes
2626 --> $DIR/naked-functions-testattrs.rs:34:1
2727 |
2828LL | #[bench]
2929 | -------- function marked with testing attribute here
30LL | #[naked]
31 | ^^^^^^^^ `#[naked]` is incompatible with testing attributes
30LL | #[unsafe(naked)]
31 | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes
3232
3333error: aborting due to 4 previous errors
3434
tests/ui/asm/naked-functions-unused.rs+10-20
......@@ -64,44 +64,34 @@ pub mod normal {
6464pub mod naked {
6565 use std::arch::naked_asm;
6666
67 #[naked]
67 #[unsafe(naked)]
6868 pub extern "C" fn function(a: usize, b: usize) -> usize {
69 unsafe {
70 naked_asm!("");
71 }
69 naked_asm!("")
7270 }
7371
7472 pub struct Naked;
7573
7674 impl Naked {
77 #[naked]
75 #[unsafe(naked)]
7876 pub extern "C" fn associated(a: usize, b: usize) -> usize {
79 unsafe {
80 naked_asm!("");
81 }
77 naked_asm!("")
8278 }
8379
84 #[naked]
80 #[unsafe(naked)]
8581 pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
86 unsafe {
87 naked_asm!("");
88 }
82 naked_asm!("")
8983 }
9084 }
9185
9286 impl super::Trait for Naked {
93 #[naked]
87 #[unsafe(naked)]
9488 extern "C" fn trait_associated(a: usize, b: usize) -> usize {
95 unsafe {
96 naked_asm!("");
97 }
89 naked_asm!("")
9890 }
9991
100 #[naked]
92 #[unsafe(naked)]
10193 extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
102 unsafe {
103 naked_asm!("");
104 }
94 naked_asm!("")
10595 }
10696 }
10797}
tests/ui/asm/naked-functions.rs+28-34
......@@ -9,8 +9,8 @@
99use std::arch::{asm, naked_asm};
1010
1111#[unsafe(naked)]
12pub unsafe extern "C" fn inline_asm_macro() {
13 asm!("", options(raw));
12pub extern "C" fn inline_asm_macro() {
13 unsafe { asm!("", options(raw)) };
1414 //~^ERROR the `asm!` macro is not allowed in naked functions
1515}
1616
......@@ -21,7 +21,7 @@ pub struct P {
2121}
2222
2323#[unsafe(naked)]
24pub unsafe extern "C" fn patterns(
24pub extern "C" fn patterns(
2525 mut a: u32,
2626 //~^ ERROR patterns not allowed in naked function parameters
2727 &b: &i32,
......@@ -35,7 +35,7 @@ pub unsafe extern "C" fn patterns(
3535}
3636
3737#[unsafe(naked)]
38pub unsafe extern "C" fn inc(a: u32) -> u32 {
38pub extern "C" fn inc(a: u32) -> u32 {
3939 //~^ ERROR naked functions must contain a single `naked_asm!` invocation
4040 a + 1
4141 //~^ ERROR referencing function parameters is not allowed in naked functions
......@@ -43,19 +43,19 @@ pub unsafe extern "C" fn inc(a: u32) -> u32 {
4343
4444#[unsafe(naked)]
4545#[allow(asm_sub_register)]
46pub unsafe extern "C" fn inc_asm(a: u32) -> u32 {
46pub extern "C" fn inc_asm(a: u32) -> u32 {
4747 naked_asm!("/* {0} */", in(reg) a)
4848 //~^ ERROR the `in` operand cannot be used with `naked_asm!`
4949}
5050
5151#[unsafe(naked)]
52pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
52pub extern "C" fn inc_closure(a: u32) -> u32 {
5353 //~^ ERROR naked functions must contain a single `naked_asm!` invocation
5454 (|| a + 1)()
5555}
5656
5757#[unsafe(naked)]
58pub unsafe extern "C" fn unsupported_operands() {
58pub extern "C" fn unsupported_operands() {
5959 //~^ ERROR naked functions must contain a single `naked_asm!` invocation
6060 let mut a = 0usize;
6161 let mut b = 0usize;
......@@ -84,11 +84,10 @@ pub extern "C" fn missing_assembly() {
8484#[unsafe(naked)]
8585pub extern "C" fn too_many_asm_blocks() {
8686 //~^ 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!("");
9291}
9392
9493pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
......@@ -124,49 +123,44 @@ unsafe extern "C" fn invalid_may_unwind() {
124123
125124#[unsafe(naked)]
126125pub extern "C" fn valid_a<T>() -> T {
127 unsafe {
128 naked_asm!("");
129 }
126 naked_asm!("");
130127}
131128
132129#[unsafe(naked)]
133130pub extern "C" fn valid_b() {
134 unsafe {
131 {
135132 {
136 {
137 naked_asm!("");
138 };
133 naked_asm!("");
139134 };
140 }
135 };
141136}
142137
143138#[unsafe(naked)]
144pub unsafe extern "C" fn valid_c() {
139pub extern "C" fn valid_c() {
145140 naked_asm!("");
146141}
147142
148143#[cfg(target_arch = "x86_64")]
149144#[unsafe(naked)]
150pub unsafe extern "C" fn valid_att_syntax() {
145pub extern "C" fn valid_att_syntax() {
151146 naked_asm!("", options(att_syntax));
152147}
153148
154149#[unsafe(naked)]
155#[unsafe(naked)]
156pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 {
150pub extern "C" fn allow_compile_error(a: u32) -> u32 {
157151 compile_error!("this is a user specified error")
158152 //~^ ERROR this is a user specified error
159153}
160154
161155#[unsafe(naked)]
162pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 {
156pub extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 {
163157 compile_error!("this is a user specified error");
164158 //~^ ERROR this is a user specified error
165159 naked_asm!("")
166160}
167161
168162#[unsafe(naked)]
169pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 {
163pub extern "C" fn invalid_asm_syntax(a: u32) -> u32 {
170164 naked_asm!(invalid_syntax)
171165 //~^ ERROR asm template must be a string literal
172166}
......@@ -174,7 +168,7 @@ pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 {
174168#[cfg(target_arch = "x86_64")]
175169#[cfg_attr(target_pointer_width = "64", no_mangle)]
176170#[unsafe(naked)]
177pub unsafe extern "C" fn compatible_cfg_attributes() {
171pub extern "C" fn compatible_cfg_attributes() {
178172 naked_asm!("", options(att_syntax));
179173}
180174
......@@ -183,20 +177,20 @@ pub unsafe extern "C" fn compatible_cfg_attributes() {
183177#[deny(dead_code)]
184178#[forbid(dead_code)]
185179#[unsafe(naked)]
186pub unsafe extern "C" fn compatible_diagnostic_attributes() {
180pub extern "C" fn compatible_diagnostic_attributes() {
187181 naked_asm!("", options(raw));
188182}
189183
190184#[deprecated = "test"]
191185#[unsafe(naked)]
192pub unsafe extern "C" fn compatible_deprecated_attributes() {
186pub extern "C" fn compatible_deprecated_attributes() {
193187 naked_asm!("", options(raw));
194188}
195189
196190#[cfg(target_arch = "x86_64")]
197191#[must_use]
198192#[unsafe(naked)]
199pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 {
193pub extern "C" fn compatible_must_use_attributes() -> u64 {
200194 naked_asm!(
201195 "
202196 mov rax, 42
......@@ -208,13 +202,13 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 {
208202#[export_name = "exported_function_name"]
209203#[link_section = ".custom_section"]
210204#[unsafe(naked)]
211pub unsafe extern "C" fn compatible_ffi_attributes_1() {
205pub extern "C" fn compatible_ffi_attributes_1() {
212206 naked_asm!("", options(raw));
213207}
214208
215209#[cold]
216210#[unsafe(naked)]
217pub unsafe extern "C" fn compatible_codegen_attributes() {
211pub extern "C" fn compatible_codegen_attributes() {
218212 naked_asm!("", options(raw));
219213}
220214
......@@ -223,12 +217,12 @@ pub unsafe extern "C" fn compatible_codegen_attributes() {
223217// a normal comment
224218#[doc(alias = "ADocAlias")]
225219#[unsafe(naked)]
226pub unsafe extern "C" fn compatible_doc_attributes() {
220pub extern "C" fn compatible_doc_attributes() {
227221 naked_asm!("", options(raw));
228222}
229223
230224#[linkage = "external"]
231225#[unsafe(naked)]
232pub unsafe extern "C" fn compatible_linkage() {
226pub extern "C" fn compatible_linkage() {
233227 naked_asm!("", options(raw));
234228}
tests/ui/asm/naked-functions.stderr+25-25
......@@ -11,70 +11,70 @@ LL | in(reg) a,
1111 | ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it
1212
1313error: the `noreturn` option cannot be used with `naked_asm!`
14 --> $DIR/naked-functions.rs:88:32
14 --> $DIR/naked-functions.rs:88:28
1515 |
16LL | naked_asm!("", options(noreturn));
17 | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly
16LL | naked_asm!("", options(noreturn));
17 | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly
1818
1919error: the `nomem` option cannot be used with `naked_asm!`
20 --> $DIR/naked-functions.rs:106:28
20 --> $DIR/naked-functions.rs:105:28
2121 |
2222LL | naked_asm!("", options(nomem, preserves_flags));
2323 | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly
2424
2525error: the `preserves_flags` option cannot be used with `naked_asm!`
26 --> $DIR/naked-functions.rs:106:35
26 --> $DIR/naked-functions.rs:105:35
2727 |
2828LL | naked_asm!("", options(nomem, preserves_flags));
2929 | ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly
3030
3131error: the `readonly` option cannot be used with `naked_asm!`
32 --> $DIR/naked-functions.rs:113:28
32 --> $DIR/naked-functions.rs:112:28
3333 |
3434LL | naked_asm!("", options(readonly, nostack), options(pure));
3535 | ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly
3636
3737error: the `nostack` option cannot be used with `naked_asm!`
38 --> $DIR/naked-functions.rs:113:38
38 --> $DIR/naked-functions.rs:112:38
3939 |
4040LL | naked_asm!("", options(readonly, nostack), options(pure));
4141 | ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly
4242
4343error: the `pure` option cannot be used with `naked_asm!`
44 --> $DIR/naked-functions.rs:113:56
44 --> $DIR/naked-functions.rs:112:56
4545 |
4646LL | naked_asm!("", options(readonly, nostack), options(pure));
4747 | ^^^^ the `pure` option is not meaningful for global-scoped inline assembly
4848
4949error: the `may_unwind` option cannot be used with `naked_asm!`
50 --> $DIR/naked-functions.rs:121:28
50 --> $DIR/naked-functions.rs:120:28
5151 |
5252LL | naked_asm!("", options(may_unwind));
5353 | ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly
5454
5555error: this is a user specified error
56 --> $DIR/naked-functions.rs:157:5
56 --> $DIR/naked-functions.rs:151:5
5757 |
5858LL | compile_error!("this is a user specified error")
5959 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6060
6161error: this is a user specified error
62 --> $DIR/naked-functions.rs:163:5
62 --> $DIR/naked-functions.rs:157:5
6363 |
6464LL | compile_error!("this is a user specified error");
6565 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6666
6767error: asm template must be a string literal
68 --> $DIR/naked-functions.rs:170:16
68 --> $DIR/naked-functions.rs:164:16
6969 |
7070LL | naked_asm!(invalid_syntax)
7171 | ^^^^^^^^^^^^^^
7272
7373error[E0787]: the `asm!` macro is not allowed in naked functions
74 --> $DIR/naked-functions.rs:13:5
74 --> $DIR/naked-functions.rs:13:14
7575 |
76LL | asm!("", options(raw));
77 | ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead
76LL | unsafe { asm!("", options(raw)) };
77 | ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead
7878
7979error: patterns not allowed in naked function parameters
8080 --> $DIR/naked-functions.rs:25:5
......@@ -111,8 +111,8 @@ LL | a + 1
111111error[E0787]: naked functions must contain a single `naked_asm!` invocation
112112 --> $DIR/naked-functions.rs:38:1
113113 |
114LL | pub unsafe extern "C" fn inc(a: u32) -> u32 {
115 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
114LL | pub extern "C" fn inc(a: u32) -> u32 {
115 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
116116LL |
117117LL | a + 1
118118 | ----- not allowed in naked functions
......@@ -120,8 +120,8 @@ LL | a + 1
120120error[E0787]: naked functions must contain a single `naked_asm!` invocation
121121 --> $DIR/naked-functions.rs:52:1
122122 |
123LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
124 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
123LL | pub extern "C" fn inc_closure(a: u32) -> u32 {
124 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
125125LL |
126126LL | (|| a + 1)()
127127 | ------------ not allowed in naked functions
......@@ -129,8 +129,8 @@ LL | (|| a + 1)()
129129error[E0787]: naked functions must contain a single `naked_asm!` invocation
130130 --> $DIR/naked-functions.rs:58:1
131131 |
132LL | pub unsafe extern "C" fn unsupported_operands() {
133 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
132LL | pub extern "C" fn unsupported_operands() {
133 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
134134LL |
135135LL | let mut a = 0usize;
136136 | ------------------- not allowed in naked functions
......@@ -155,11 +155,11 @@ error[E0787]: naked functions must contain a single `naked_asm!` invocation
155155LL | pub extern "C" fn too_many_asm_blocks() {
156156 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
157157...
158LL | naked_asm!("");
159 | -------------- multiple `naked_asm!` invocations are not allowed in naked functions
158LL | naked_asm!("");
159 | -------------- multiple `naked_asm!` invocations are not allowed in naked functions
160160
161161error: referencing function parameters is not allowed in naked functions
162 --> $DIR/naked-functions.rs:98:11
162 --> $DIR/naked-functions.rs:97:11
163163 |
164164LL | *&y
165165 | ^
......@@ -167,7 +167,7 @@ LL | *&y
167167 = help: follow the calling convention in asm block to use parameters
168168
169169error[E0787]: naked functions must contain a single `naked_asm!` invocation
170 --> $DIR/naked-functions.rs:96:5
170 --> $DIR/naked-functions.rs:95:5
171171 |
172172LL | pub extern "C" fn inner(y: usize) -> usize {
173173 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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.
22//
33//@ needs-asm-support
44#![feature(naked_functions)]
5#![naked] //~ ERROR should be applied to a function definition
5#![unsafe(naked)] //~ ERROR should be applied to a function definition
66
77use std::arch::naked_asm;
88
99extern "C" {
10 #[naked] //~ ERROR should be applied to a function definition
10 #[unsafe(naked)] //~ ERROR should be applied to a function definition
1111 fn f();
1212}
1313
14#[naked] //~ ERROR should be applied to a function definition
14#[unsafe(naked)] //~ ERROR should be applied to a function definition
1515#[repr(C)]
1616struct S {
1717 a: u32,
......@@ -19,35 +19,35 @@ struct S {
1919}
2020
2121trait Invoke {
22 #[naked] //~ ERROR should be applied to a function definition
22 #[unsafe(naked)] //~ ERROR should be applied to a function definition
2323 extern "C" fn invoke(&self);
2424}
2525
2626impl Invoke for S {
27 #[naked]
27 #[unsafe(naked)]
2828 extern "C" fn invoke(&self) {
29 unsafe { naked_asm!("") }
29 naked_asm!("")
3030 }
3131}
3232
33#[naked]
33#[unsafe(naked)]
3434extern "C" fn ok() {
35 unsafe { naked_asm!("") }
35 naked_asm!("")
3636}
3737
3838impl S {
39 #[naked]
39 #[unsafe(naked)]
4040 extern "C" fn g() {
41 unsafe { naked_asm!("") }
41 naked_asm!("")
4242 }
4343
44 #[naked]
44 #[unsafe(naked)]
4545 extern "C" fn h(&self) {
46 unsafe { naked_asm!("") }
46 naked_asm!("")
4747 }
4848}
4949
5050fn main() {
51 #[naked] //~ ERROR should be applied to a function definition
51 #[unsafe(naked)] //~ ERROR should be applied to a function definition
5252 || {};
5353}
tests/ui/asm/naked-invalid-attr.stderr+10-10
......@@ -1,8 +1,8 @@
11error: attribute should be applied to a function definition
22 --> $DIR/naked-invalid-attr.rs:14:1
33 |
4LL | #[naked]
5 | ^^^^^^^^
4LL | #[unsafe(naked)]
5 | ^^^^^^^^^^^^^^^^
66LL | #[repr(C)]
77LL | / struct S {
88LL | | a: u32,
......@@ -13,32 +13,32 @@ LL | | }
1313error: attribute should be applied to a function definition
1414 --> $DIR/naked-invalid-attr.rs:51:5
1515 |
16LL | #[naked]
17 | ^^^^^^^^
16LL | #[unsafe(naked)]
17 | ^^^^^^^^^^^^^^^^
1818LL | || {};
1919 | ----- not a function definition
2020
2121error: attribute should be applied to a function definition
2222 --> $DIR/naked-invalid-attr.rs:22:5
2323 |
24LL | #[naked]
25 | ^^^^^^^^
24LL | #[unsafe(naked)]
25 | ^^^^^^^^^^^^^^^^
2626LL | extern "C" fn invoke(&self);
2727 | ---------------------------- not a function definition
2828
2929error: attribute should be applied to a function definition
3030 --> $DIR/naked-invalid-attr.rs:10:5
3131 |
32LL | #[naked]
33 | ^^^^^^^^
32LL | #[unsafe(naked)]
33 | ^^^^^^^^^^^^^^^^
3434LL | fn f();
3535 | ------- not a function definition
3636
3737error: attribute should be applied to a function definition
3838 --> $DIR/naked-invalid-attr.rs:5:1
3939 |
40LL | #![naked]
41 | ^^^^^^^^^ cannot be applied to crates
40LL | #![unsafe(naked)]
41 | ^^^^^^^^^^^^^^^^^ cannot be applied to crates
4242
4343error: aborting due to 5 previous errors
4444
tests/ui/asm/naked-with-invalid-repr-attr.rs+10-10
......@@ -6,43 +6,43 @@ use std::arch::naked_asm;
66
77#[repr(C)]
88//~^ ERROR attribute should be applied to a struct, enum, or union [E0517]
9#[naked]
9#[unsafe(naked)]
1010extern "C" fn example1() {
1111 //~^ NOTE not a struct, enum, or union
12 unsafe { naked_asm!("") }
12 naked_asm!("")
1313}
1414
1515#[repr(transparent)]
1616//~^ ERROR attribute should be applied to a struct, enum, or union [E0517]
17#[naked]
17#[unsafe(naked)]
1818extern "C" fn example2() {
1919 //~^ NOTE not a struct, enum, or union
20 unsafe { naked_asm!("") }
20 naked_asm!("")
2121}
2222
2323#[repr(align(16), C)]
2424//~^ ERROR attribute should be applied to a struct, enum, or union [E0517]
25#[naked]
25#[unsafe(naked)]
2626extern "C" fn example3() {
2727 //~^ NOTE not a struct, enum, or union
28 unsafe { naked_asm!("") }
28 naked_asm!("")
2929}
3030
3131// note: two errors because of packed and C
3232#[repr(C, packed)]
3333//~^ ERROR attribute should be applied to a struct or union [E0517]
3434//~| ERROR attribute should be applied to a struct, enum, or union [E0517]
35#[naked]
35#[unsafe(naked)]
3636extern "C" fn example4() {
3737 //~^ NOTE not a struct, enum, or union
3838 //~| NOTE not a struct or union
39 unsafe { naked_asm!("") }
39 naked_asm!("")
4040}
4141
4242#[repr(u8)]
4343//~^ ERROR attribute should be applied to an enum [E0517]
44#[naked]
44#[unsafe(naked)]
4545extern "C" fn example5() {
4646 //~^ NOTE not an enum
47 unsafe { naked_asm!("") }
47 naked_asm!("")
4848}
tests/ui/asm/naked-with-invalid-repr-attr.stderr+6-6
......@@ -6,7 +6,7 @@ LL | #[repr(C)]
66...
77LL | / extern "C" fn example1() {
88LL | |
9LL | | unsafe { naked_asm!("") }
9LL | | naked_asm!("")
1010LL | | }
1111 | |_- not a struct, enum, or union
1212
......@@ -18,7 +18,7 @@ LL | #[repr(transparent)]
1818...
1919LL | / extern "C" fn example2() {
2020LL | |
21LL | | unsafe { naked_asm!("") }
21LL | | naked_asm!("")
2222LL | | }
2323 | |_- not a struct, enum, or union
2424
......@@ -30,7 +30,7 @@ LL | #[repr(align(16), C)]
3030...
3131LL | / extern "C" fn example3() {
3232LL | |
33LL | | unsafe { naked_asm!("") }
33LL | | naked_asm!("")
3434LL | | }
3535 | |_- not a struct, enum, or union
3636
......@@ -43,7 +43,7 @@ LL | #[repr(C, packed)]
4343LL | / extern "C" fn example4() {
4444LL | |
4545LL | |
46LL | | unsafe { naked_asm!("") }
46LL | | naked_asm!("")
4747LL | | }
4848 | |_- not a struct, enum, or union
4949
......@@ -56,7 +56,7 @@ LL | #[repr(C, packed)]
5656LL | / extern "C" fn example4() {
5757LL | |
5858LL | |
59LL | | unsafe { naked_asm!("") }
59LL | | naked_asm!("")
6060LL | | }
6161 | |_- not a struct or union
6262
......@@ -68,7 +68,7 @@ LL | #[repr(u8)]
6868...
6969LL | / extern "C" fn example5() {
7070LL | |
71LL | | unsafe { naked_asm!("") }
71LL | | naked_asm!("")
7272LL | | }
7373 | |_- not an enum
7474
tests/ui/asm/named-asm-labels.rs+8-8
......@@ -175,9 +175,9 @@ fn main() {
175175
176176// Trigger on naked fns too, even though they can't be inlined, reusing a
177177// label or LTO can cause labels to break
178#[naked]
178#[unsafe(naked)]
179179pub 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)
181181 //~^ ERROR avoid using named labels
182182}
183183
......@@ -188,21 +188,21 @@ pub extern "C" fn bar() {
188188 //~^ ERROR avoid using named labels
189189}
190190
191#[naked]
191#[unsafe(naked)]
192192pub extern "C" fn aaa() {
193193 fn _local() {}
194194
195 unsafe { naked_asm!(".Laaa: nop; ret;") } //~ ERROR avoid using named labels
195 naked_asm!(".Laaa: nop; ret;") //~ ERROR avoid using named labels
196196}
197197
198198pub fn normal() {
199199 fn _local1() {}
200200
201 #[naked]
201 #[unsafe(naked)]
202202 pub extern "C" fn bbb() {
203203 fn _very_local() {}
204204
205 unsafe { naked_asm!(".Lbbb: nop; ret;") } //~ ERROR avoid using named labels
205 naked_asm!(".Lbbb: nop; ret;") //~ ERROR avoid using named labels
206206 }
207207
208208 fn _local2() {}
......@@ -219,8 +219,8 @@ fn closures() {
219219 };
220220
221221 || {
222 #[naked]
223 unsafe extern "C" fn _nested() {
222 #[unsafe(naked)]
223 extern "C" fn _nested() {
224224 naked_asm!("ret;");
225225 }
226226
tests/ui/asm/named-asm-labels.stderr+9-9
......@@ -475,10 +475,10 @@ LL | #[warn(named_asm_labels)]
475475 | ^^^^^^^^^^^^^^^^
476476
477477error: avoid using named labels in inline assembly
478 --> $DIR/named-asm-labels.rs:180:26
478 --> $DIR/named-asm-labels.rs:180:17
479479 |
480LL | unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) }
481 | ^^^^^
480LL | naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1)
481 | ^^^^^
482482 |
483483 = help: only local labels of the form `<number>:` should be used in inline asm
484484 = 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
493493 = 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
494494
495495error: avoid using named labels in inline assembly
496 --> $DIR/named-asm-labels.rs:195:26
496 --> $DIR/named-asm-labels.rs:195:17
497497 |
498LL | unsafe { naked_asm!(".Laaa: nop; ret;") }
499 | ^^^^^
498LL | naked_asm!(".Laaa: nop; ret;")
499 | ^^^^^
500500 |
501501 = help: only local labels of the form `<number>:` should be used in inline asm
502502 = 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
503503
504504error: avoid using named labels in inline assembly
505 --> $DIR/named-asm-labels.rs:205:30
505 --> $DIR/named-asm-labels.rs:205:21
506506 |
507LL | unsafe { naked_asm!(".Lbbb: nop; ret;") }
508 | ^^^^^
507LL | naked_asm!(".Lbbb: nop; ret;")
508 | ^^^^^
509509 |
510510 = help: only local labels of the form `<number>:` should be used in inline asm
511511 = 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
13pub trait MyTrait {
14 fn dummy(&self) {}
15}
16impl MyTrait for isize {}
17
18// `&dyn MyTrait` contained in enum variant
19pub struct EnumRefDynTrait<'a>(Enum<&'a (dyn MyTrait + 'a)>);
20pub enum Enum<T> {
21 Variant(T),
22}
23
24fn 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
31struct RefDynTraitNamed<'a> {
32 x: Option<&'a (dyn MyTrait + 'a)>,
33}
34
35fn 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
42pub struct RefDynTraitUnnamed<'a>(Option<&'a (dyn MyTrait + 'a)>);
43
44fn unnamed_option_dyn_trait() {
45 let x: isize = 42;
46 let y = RefDynTraitUnnamed(Some(&x as &dyn MyTrait));
47 let _ = y;
48}
49
50pub 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
5trait Test {}
6
7#[diagnostic::on_unimplemented(message = "blah", label = "blah", note = "blah")]
8//~^ WARN `#[diagnostic::on_unimplemented]` can only be applied to trait definitions
9trait Alias = Test;
10
11// Use trait alias as bound on type parameter.
12fn foo<T: Alias>(v: &T) {}
13
14pub 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 @@
1warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions
2 --> $DIR/on_impl_trait.rs:7:1
3 |
4LL | #[diagnostic::on_unimplemented(message = "blah", label = "blah", note = "blah")]
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6 |
7 = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
8
9error[E0277]: the trait bound `{integer}: Alias` is not satisfied
10 --> $DIR/on_impl_trait.rs:15:9
11 |
12LL | foo(&1);
13 | --- ^^ the trait `Test` is not implemented for `{integer}`
14 | |
15 | required by a bound introduced by this call
16 |
17help: this trait has no implementations, consider adding one
18 --> $DIR/on_impl_trait.rs:5:1
19 |
20LL | trait Test {}
21 | ^^^^^^^^^^
22 = note: required for `{integer}` to implement `Alias`
23note: required by a bound in `foo`
24 --> $DIR/on_impl_trait.rs:12:11
25 |
26LL | fn foo<T: Alias>(v: &T) {}
27 | ^^^^^ required by this bound in `foo`
28
29error: aborting due to 1 previous error; 1 warning emitted
30
31For more information about this error, try `rustc --explain E0277`.
tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr+24-24
......@@ -1,52 +1,52 @@
11warning: unmatched `}` found
2 --> $DIR/broken_format.rs:2:32
2 --> $DIR/broken_format.rs:2:42
33 |
44LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^
5 | ^^^^^^^^^^^^^^^^
66 |
77 = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
88
99warning: positional format arguments are not allowed here
10 --> $DIR/broken_format.rs:7:32
10 --> $DIR/broken_format.rs:7:49
1111 |
1212LL | #[diagnostic::on_unimplemented(message = "Test {}")]
13 | ^^^^^^^^^^^^^^^^^^^
13 | ^
1414 |
1515 = help: only named format arguments with the name of one of the generic types are allowed in this context
1616
1717warning: positional format arguments are not allowed here
18 --> $DIR/broken_format.rs:12:32
18 --> $DIR/broken_format.rs:12:49
1919 |
2020LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
21 | ^^^^^^^^^^^^^^^^^^^^^
21 | ^
2222 |
2323 = help: only named format arguments with the name of one of the generic types are allowed in this context
2424
2525warning: invalid format specifier
26 --> $DIR/broken_format.rs:17:32
26 --> $DIR/broken_format.rs:17:42
2727 |
2828LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
29 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
29 | ^^^^^^^^^^^^^^^^^
3030 |
3131 = help: no format specifier are supported in this position
3232
3333warning: expected `}`, found `!`
34 --> $DIR/broken_format.rs:22:32
34 --> $DIR/broken_format.rs:22:42
3535 |
3636LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
37 | ^^^^^^^^^^^^^^^^^^^^^^^^^
37 | ^^^^^^^^^^^^^^^
3838
3939warning: unmatched `}` found
40 --> $DIR/broken_format.rs:22:32
40 --> $DIR/broken_format.rs:22:42
4141 |
4242LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
43 | ^^^^^^^^^^^^^^^^^^^^^^^^^
43 | ^^^^^^^^^^^^^^^
4444
4545warning: unmatched `}` found
46 --> $DIR/broken_format.rs:2:32
46 --> $DIR/broken_format.rs:2:42
4747 |
4848LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
49 | ^^^^^^^^^^^^^^^^^^^^^^^^^^
49 | ^^^^^^^^^^^^^^^^
5050 |
5151 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
5252
......@@ -70,10 +70,10 @@ LL | fn check_1(_: impl ImportantTrait1) {}
7070 | ^^^^^^^^^^^^^^^ required by this bound in `check_1`
7171
7272warning: positional format arguments are not allowed here
73 --> $DIR/broken_format.rs:7:32
73 --> $DIR/broken_format.rs:7:49
7474 |
7575LL | #[diagnostic::on_unimplemented(message = "Test {}")]
76 | ^^^^^^^^^^^^^^^^^^^
76 | ^
7777 |
7878 = help: only named format arguments with the name of one of the generic types are allowed in this context
7979 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
......@@ -98,10 +98,10 @@ LL | fn check_2(_: impl ImportantTrait2) {}
9898 | ^^^^^^^^^^^^^^^ required by this bound in `check_2`
9999
100100warning: positional format arguments are not allowed here
101 --> $DIR/broken_format.rs:12:32
101 --> $DIR/broken_format.rs:12:49
102102 |
103103LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
104 | ^^^^^^^^^^^^^^^^^^^^^
104 | ^
105105 |
106106 = help: only named format arguments with the name of one of the generic types are allowed in this context
107107 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
......@@ -126,10 +126,10 @@ LL | fn check_3(_: impl ImportantTrait3) {}
126126 | ^^^^^^^^^^^^^^^ required by this bound in `check_3`
127127
128128warning: invalid format specifier
129 --> $DIR/broken_format.rs:17:32
129 --> $DIR/broken_format.rs:17:42
130130 |
131131LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
132 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
132 | ^^^^^^^^^^^^^^^^^
133133 |
134134 = help: no format specifier are supported in this position
135135 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
......@@ -154,18 +154,18 @@ LL | fn check_4(_: impl ImportantTrait4) {}
154154 | ^^^^^^^^^^^^^^^ required by this bound in `check_4`
155155
156156warning: expected `}`, found `!`
157 --> $DIR/broken_format.rs:22:32
157 --> $DIR/broken_format.rs:22:42
158158 |
159159LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
160 | ^^^^^^^^^^^^^^^^^^^^^^^^^
160 | ^^^^^^^^^^^^^^^
161161 |
162162 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
163163
164164warning: unmatched `}` found
165 --> $DIR/broken_format.rs:22:32
165 --> $DIR/broken_format.rs:22:42
166166 |
167167LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
168 | ^^^^^^^^^^^^^^^^^^^^^^^^^
168 | ^^^^^^^^^^^^^^^
169169 |
170170 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
171171
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"]
3939 = help: only `message`, `note` and `label` are allowed as options
4040
4141warning: 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
4343 |
4444LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
45 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
45 | ^^^^^^^^^^^^^^^
4646 |
4747 = help: expect either a generic argument name or `{Self}` as format argument
4848
4949warning: 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
5151 |
5252LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
53 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
53 | ^^^^^^
5454 |
5555 = help: expect either a generic argument name or `{Self}` as format argument
5656
5757warning: 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
5959 |
6060LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
61 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
61 | ^^^^^
6262 |
6363 = help: expect either a generic argument name or `{Self}` as format argument
6464
6565warning: 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
6767 |
6868LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
69 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
69 | ^^^^^^^^
7070 |
7171 = help: expect either a generic argument name or `{Self}` as format argument
7272
7373warning: 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
7575 |
7676LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
77 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
77 | ^^^^^^^
7878 |
7979 = help: expect either a generic argument name or `{Self}` as format argument
8080
8181warning: 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
8383 |
8484LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
85 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
85 | ^^^^^
8686 |
8787 = help: expect either a generic argument name or `{Self}` as format argument
8888
8989warning: 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
9191 |
9292LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
93 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
93 | ^^^^^
9494 |
9595 = help: expect either a generic argument name or `{Self}` as format argument
9696
9797warning: 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
9999 |
100100LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
101 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
101 | ^^^^^^^^^^^
102102 |
103103 = help: expect either a generic argument name or `{Self}` as format argument
104104
105105warning: 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
107107 |
108108LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
109 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
109 | ^^^^^
110110 |
111111 = help: expect either a generic argument name or `{Self}` as format argument
112112
113113warning: 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
115115 |
116116LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
117 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
117 | ^^^^^^^^^^^
118118 |
119119 = help: expect either a generic argument name or `{Self}` as format argument
120120
......@@ -191,91 +191,91 @@ LL | fn takes_bar(_: impl Bar) {}
191191 | ^^^ required by this bound in `takes_bar`
192192
193193warning: 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
195195 |
196196LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
197 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
197 | ^^^^^^^^^^^^^^^
198198 |
199199 = help: expect either a generic argument name or `{Self}` as format argument
200200 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
201201
202202warning: 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
204204 |
205205LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
206 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
206 | ^^^^^^
207207 |
208208 = help: expect either a generic argument name or `{Self}` as format argument
209209 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
210210
211211warning: 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
213213 |
214214LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
215 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
215 | ^^^^^
216216 |
217217 = help: expect either a generic argument name or `{Self}` as format argument
218218 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
219219
220220warning: 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
222222 |
223223LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
224 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
224 | ^^^^^^^^
225225 |
226226 = help: expect either a generic argument name or `{Self}` as format argument
227227 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
228228
229229warning: 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
231231 |
232232LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
233 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
233 | ^^^^^^^
234234 |
235235 = help: expect either a generic argument name or `{Self}` as format argument
236236 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
237237
238238warning: 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
240240 |
241241LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
242 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
242 | ^^^^^
243243 |
244244 = help: expect either a generic argument name or `{Self}` as format argument
245245 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
246246
247247warning: 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
249249 |
250250LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
251 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
251 | ^^^^^
252252 |
253253 = help: expect either a generic argument name or `{Self}` as format argument
254254 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
255255
256256warning: 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
258258 |
259259LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
260 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
260 | ^^^^^^^^^^^
261261 |
262262 = help: expect either a generic argument name or `{Self}` as format argument
263263 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
264264
265265warning: 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
267267 |
268268LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
269 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
269 | ^^^^^
270270 |
271271 = help: expect either a generic argument name or `{Self}` as format argument
272272 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
273273
274274warning: 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
276276 |
277277LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
278 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
278 | ^^^^^^^^^^^
279279 |
280280 = help: expect either a generic argument name or `{Self}` as format argument
281281 = 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]
4747 = help: at least one of the `message`, `note` and `label` options are expected
4848
4949warning: 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
5151 |
5252LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")]
53 | ^^^^^^^^^^^^^^^^^^^^^^^^^^
53 | ^^^^^^^^^^^^
5454 |
5555 = help: expect either a generic argument name or `{Self}` as format argument
5656
......@@ -167,10 +167,10 @@ LL | fn take_whatever(_: impl Whatever) {}
167167 | ^^^^^^^^ required by this bound in `take_whatever`
168168
169169warning: 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
171171 |
172172LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")]
173 | ^^^^^^^^^^^^^^^^^^^^^^^^^^
173 | ^^^^^^^^^^^^
174174 |
175175 = help: expect either a generic argument name or `{Self}` as format argument
176176 = 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 @@
33use std::arch::naked_asm;
44//~^ ERROR use of unstable library feature `naked_functions`
55
6#[naked]
6#[naked] //~ ERROR unsafe attribute used without unsafe
77//~^ ERROR the `#[naked]` attribute is an experimental feature
88extern "C" fn naked() {
99 naked_asm!("")
1010 //~^ ERROR use of unstable library feature `naked_functions`
11 //~| ERROR: requires unsafe
1211}
1312
14#[naked]
13#[naked] //~ ERROR unsafe attribute used without unsafe
1514//~^ ERROR the `#[naked]` attribute is an experimental feature
1615extern "C" fn naked_2() -> isize {
1716 naked_asm!("")
1817 //~^ ERROR use of unstable library feature `naked_functions`
19 //~| ERROR: requires unsafe
2018}
2119
2220fn main() {}
tests/ui/feature-gates/feature-gate-naked_functions.stderr+25-20
......@@ -9,7 +9,7 @@ LL | naked_asm!("")
99 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
1010
1111error[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
1313 |
1414LL | naked_asm!("")
1515 | ^^^^^^^^^
......@@ -18,6 +18,28 @@ LL | naked_asm!("")
1818 = help: add `#![feature(naked_functions)]` to the crate attributes to enable
1919 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
2020
21error: unsafe attribute used without unsafe
22 --> $DIR/feature-gate-naked_functions.rs:6:3
23 |
24LL | #[naked]
25 | ^^^^^ usage of unsafe attribute
26 |
27help: wrap the attribute in `unsafe(...)`
28 |
29LL | #[unsafe(naked)]
30 | +++++++ +
31
32error: unsafe attribute used without unsafe
33 --> $DIR/feature-gate-naked_functions.rs:13:3
34 |
35LL | #[naked]
36 | ^^^^^ usage of unsafe attribute
37 |
38help: wrap the attribute in `unsafe(...)`
39 |
40LL | #[unsafe(naked)]
41 | +++++++ +
42
2143error[E0658]: the `#[naked]` attribute is an experimental feature
2244 --> $DIR/feature-gate-naked_functions.rs:6:1
2345 |
......@@ -29,7 +51,7 @@ LL | #[naked]
2951 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
3052
3153error[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
3355 |
3456LL | #[naked]
3557 | ^^^^^^^^
......@@ -48,23 +70,6 @@ LL | use std::arch::naked_asm;
4870 = help: add `#![feature(naked_functions)]` to the crate attributes to enable
4971 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
5072
51error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
52 --> $DIR/feature-gate-naked_functions.rs:9:5
53 |
54LL | naked_asm!("")
55 | ^^^^^^^^^^^^^^ use of inline assembly
56 |
57 = note: inline assembly is entirely unchecked and can cause undefined behavior
58
59error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
60 --> $DIR/feature-gate-naked_functions.rs:17:5
61 |
62LL | naked_asm!("")
63 | ^^^^^^^^^^^^^^ use of inline assembly
64 |
65 = note: inline assembly is entirely unchecked and can cause undefined behavior
66
6773error: aborting due to 7 previous errors
6874
69Some errors have detailed explanations: E0133, E0658.
70For more information about an error, try `rustc --explain E0133`.
75For 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 @@
55
66use std::arch::naked_asm;
77
8#[naked]
8#[unsafe(naked)]
99pub unsafe fn rust_implicit() {
1010 //~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions
1111 naked_asm!("ret");
1212}
1313
14#[naked]
14#[unsafe(naked)]
1515pub unsafe extern "Rust" fn rust_explicit() {
1616 //~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions
1717 naked_asm!("ret");
1818}
1919
20#[naked]
20#[unsafe(naked)]
2121pub unsafe extern "rust-cold" fn rust_cold() {
2222 //~^ ERROR `#[naked]` is currently unstable on `extern "rust-cold"` functions
2323 naked_asm!("ret");
tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs+1-1
......@@ -5,7 +5,7 @@
55
66use std::arch::naked_asm;
77
8#[naked]
8#[unsafe(naked)]
99#[target_feature(enable = "avx2")]
1010//~^ ERROR: `#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions
1111extern "C" fn naked() {
tests/ui/impl-unused-tps.stderr+17-17
......@@ -7,23 +7,6 @@ LL | impl<T> Foo<T> for [isize; 0] {
77LL | impl<T, U> Foo<T> for U {
88 | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]`
99
10error[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 |
13LL | impl<T, U> Bar for T {
14 | ^ unconstrained type parameter
15
16error[E0119]: conflicting implementations of trait `Bar`
17 --> $DIR/impl-unused-tps.rs:40:1
18 |
19LL | impl<T, U> Bar for T {
20 | -------------------- first implementation here
21...
22LL | / impl<T, U> Bar for T
23LL | | where
24LL | | T: Bar<Out = U>,
25 | |____________________^ conflicting implementation
26
2710error[E0119]: conflicting implementations of trait `Foo<[isize; 0]>` for type `[isize; 0]`
2811 --> $DIR/impl-unused-tps.rs:49:1
2912 |
......@@ -52,6 +35,12 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self
5235LL | impl<T, U> Foo<T> for [isize; 1] {
5336 | ^ unconstrained type parameter
5437
38error[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 |
41LL | impl<T, U> Bar for T {
42 | ^ unconstrained type parameter
43
5544error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
5645 --> $DIR/impl-unused-tps.rs:40:9
5746 |
......@@ -70,6 +59,17 @@ error[E0207]: the type parameter `V` is not constrained by the impl trait, self
7059LL | impl<T, U, V> Foo<T> for T
7160 | ^ unconstrained type parameter
7261
62error[E0119]: conflicting implementations of trait `Bar`
63 --> $DIR/impl-unused-tps.rs:40:1
64 |
65LL | impl<T, U> Bar for T {
66 | -------------------- first implementation here
67...
68LL | / impl<T, U> Bar for T
69LL | | where
70LL | | T: Bar<Out = U>,
71 | |____________________^ conflicting implementation
72
7373error: aborting due to 9 previous errors
7474
7575Some 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
5pub use src::aliases::B;
6pub use src::hidden_core::make;
7
8mod 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
7extern crate issue_14421 as bug_lib;
8
9use bug_lib::B;
10use bug_lib::make;
11
12pub 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
4fn _foo<F: Fn()> (f: F) {
5 |t| f(t); //~ ERROR E0057
6}
7
8fn main() {}
tests/ui/issues/issue-16939.stderr deleted-20
......@@ -1,20 +0,0 @@
1error[E0057]: this function takes 0 arguments but 1 argument was supplied
2 --> $DIR/issue-16939.rs:5:9
3 |
4LL | |t| f(t);
5 | ^ - unexpected argument
6 |
7note: callable defined here
8 --> $DIR/issue-16939.rs:4:12
9 |
10LL | fn _foo<F: Fn()> (f: F) {
11 | ^^^^
12help: remove the extra argument
13 |
14LL - |t| f(t);
15LL + |t| f();
16 |
17
18error: aborting due to 1 previous error
19
20For 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
7trait Const {
8 const C: ();
9}
10
11trait StaticFn {
12 fn sfn();
13}
14
15struct ConstStruct;
16struct StaticFnStruct;
17
18enum ConstEnum {}
19enum StaticFnEnum {}
20
21struct AliasedConstStruct;
22struct AliasedStaticFnStruct;
23
24enum AliasedConstEnum {}
25enum AliasedStaticFnEnum {}
26
27type AliasConstStruct = AliasedConstStruct;
28type AliasStaticFnStruct = AliasedStaticFnStruct;
29type AliasConstEnum = AliasedConstEnum;
30type AliasStaticFnEnum = AliasedStaticFnEnum;
31
32macro_rules! impl_Const {($($T:ident),*) => {$(
33 impl Const for $T {
34 const C: () = ();
35 }
36)*}}
37
38macro_rules! impl_StaticFn {($($T:ident),*) => {$(
39 impl StaticFn for $T {
40 fn sfn() {}
41 }
42)*}}
43
44impl_Const!(ConstStruct, ConstEnum, AliasedConstStruct, AliasedConstEnum);
45impl_StaticFn!(StaticFnStruct, StaticFnEnum, AliasedStaticFnStruct, AliasedStaticFnEnum);
46
47fn 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
4mod 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
18mod 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
33mod 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
40pub 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
7pub use src::aliases::ExposedType;
8pub use src::hidden_core::new;
9
10mod 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
11trait Const {
12 const C: ();
13}
14
15trait StaticFn {
16 fn sfn();
17}
18
19macro_rules! impl_const {($($T:ident),*) => {$(
20 impl Const for $T {
21 const C: () = ();
22 }
23)*}}
24
25macro_rules! impl_static_fn {($($T:ident),*) => {$(
26 impl StaticFn for $T {
27 fn sfn() {}
28 }
29)*}}
30
31struct ConstStruct;
32enum ConstEnum {}
33struct AliasedConstStruct;
34type AliasConstStruct = AliasedConstStruct;
35enum AliasedConstEnum {}
36type AliasConstEnum = AliasedConstEnum;
37
38impl_const!(ConstStruct, ConstEnum, AliasedConstStruct, AliasedConstEnum);
39
40struct StaticFnStruct;
41enum StaticFnEnum {}
42struct AliasedStaticFnStruct;
43type AliasStaticFnStruct = AliasedStaticFnStruct;
44enum AliasedStaticFnEnum {}
45type AliasStaticFnEnum = AliasedStaticFnEnum;
46
47impl_static_fn!(StaticFnStruct, StaticFnEnum, AliasedStaticFnStruct, AliasedStaticFnEnum);
48
49fn 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
9extern crate no_dead_code_reexported_types_across_crates as bug_lib;
10
11use bug_lib::ExposedType;
12use bug_lib::new;
13
14pub 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
2020{}
2121
2222#[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
2424trait BadAnnotation2<A,B>
2525{}
2626
2727#[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
2929trait BadAnnotation3<A,B>
3030{}
3131
tests/ui/on-unimplemented/bad-annotation.stderr+6-6
......@@ -11,17 +11,17 @@ LL | #[rustc_on_unimplemented = "message"]
1111LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]
1212 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1313
14error[E0230]: there is no parameter `C` on trait `BadAnnotation2`
15 --> $DIR/bad-annotation.rs:22:1
14error[E0230]: cannot find parameter C on this trait
15 --> $DIR/bad-annotation.rs:22:90
1616 |
1717LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
18 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18 | ^
1919
20error[E0231]: only named generic parameters are allowed
21 --> $DIR/bad-annotation.rs:27:1
20error[E0231]: positional format arguments are not allowed here
21 --> $DIR/bad-annotation.rs:27:90
2222 |
2323LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"]
24 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24 | ^
2525
2626error[E0232]: this attribute must have a valid value
2727 --> $DIR/bad-annotation.rs:32:26
tests/ui/on-unimplemented/impl-substs.rs deleted-15
......@@ -1,15 +0,0 @@
1#![feature(rustc_attrs)]
2
3trait Foo<A> {
4 fn foo(self);
5}
6
7#[rustc_on_unimplemented = "an impl did not match: {A} {B} {C}"]
8impl<A, B, C> Foo<A> for (A, B, C) {
9 fn foo(self) {}
10}
11
12fn 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 @@
1error[E0277]: the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied
2 --> $DIR/impl-substs.rs:13:23
3 |
4LL | 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
13error: aborting due to 1 previous error
14
15For 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
3trait Foo {}
4
5#[rustc_on_unimplemented] //~ ERROR malformed `rustc_on_unimplemented` attribute input
6impl Foo for u32 {}
7
8fn main() {}
tests/ui/on-unimplemented/issue-104140.stderr deleted-15
......@@ -1,15 +0,0 @@
1error: malformed `rustc_on_unimplemented` attribute input
2 --> $DIR/issue-104140.rs:5:1
3 |
4LL | #[rustc_on_unimplemented]
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^
6 |
7help: the following are the possible correct uses
8 |
9LL | #[rustc_on_unimplemented = "message"]
10 | +++++++++++
11LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]
12 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13
14error: 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
6struct Foo<T>(T);
7struct Bar<T>(T);
8
9#[rustc_on_unimplemented = "trait message"]
10trait 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"]
16impl 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"]
24impl Index<Bar<usize>> for [i32] {
25 type Output = i32;
26 fn index(&self, _index: Bar<usize>) -> &i32 {
27 loop {}
28 }
29}
30
31
32fn 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 @@
1error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
2 --> $DIR/multiple-impls.rs:33:33
3 |
4LL | 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
14error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
15 --> $DIR/multiple-impls.rs:36:33
16 |
17LL | 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
27error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
28 --> $DIR/multiple-impls.rs:39:33
29 |
30LL | 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
40error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
41 --> $DIR/multiple-impls.rs:33:5
42 |
43LL | 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
51error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
52 --> $DIR/multiple-impls.rs:36:5
53 |
54LL | 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
62error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
63 --> $DIR/multiple-impls.rs:39:5
64 |
65LL | 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
73error: aborting due to 6 previous errors
74
75For 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"]
7trait 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"]
13impl Index<usize> for [i32] {
14 type Output = i32;
15 fn index(&self, index: usize) -> &i32 {
16 &self[index]
17 }
18}
19
20
21fn 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 @@
1error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
2 --> $DIR/on-impl.rs:22:47
3 |
4LL | 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
13error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
14 --> $DIR/on-impl.rs:22:5
15 |
16LL | 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
23error: aborting due to 2 previous errors
24
25For 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))]
7pub trait FromIterator<A>: Sized {
8 fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
9}
10fn 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 @@
1error[E0277]: an array of type `[u8; 8]` cannot be built directly from an iterator
2 --> $DIR/use_self_no_underscore.rs:12:22
3 |
4LL | let x: [u8; 8] = FromIterator::from_iter(iter);
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromIterator<{integer}>` is not implemented for `[u8; 8]`
6 |
7help: this trait has no implementations, consider adding one
8 --> $DIR/use_self_no_underscore.rs:7:1
9 |
10LL | pub trait FromIterator<A>: Sized {
11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12
13error: aborting due to 1 previous error
14
15For 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;
55
66#[track_caller] //~ ERROR [E0736]
77//~^ ERROR `#[track_caller]` requires Rust ABI
8#[naked]
8#[unsafe(naked)]
99extern "C" fn f() {
1010 unsafe {
1111 naked_asm!("");
......@@ -17,7 +17,7 @@ struct S;
1717impl S {
1818 #[track_caller] //~ ERROR [E0736]
1919 //~^ ERROR `#[track_caller]` requires Rust ABI
20 #[naked]
20 #[unsafe(naked)]
2121 extern "C" fn g() {
2222 unsafe {
2323 naked_asm!("");
tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr+8-8
......@@ -1,20 +1,20 @@
1error[E0736]: attribute incompatible with `#[naked]`
1error[E0736]: attribute incompatible with `#[unsafe(naked)]`
22 --> $DIR/error-with-naked.rs:6:1
33 |
44LL | #[track_caller]
5 | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[naked]`
5 | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]`
66LL |
7LL | #[naked]
8 | -------- function marked with `#[naked]` here
7LL | #[unsafe(naked)]
8 | ---------------- function marked with `#[unsafe(naked)]` here
99
10error[E0736]: attribute incompatible with `#[naked]`
10error[E0736]: attribute incompatible with `#[unsafe(naked)]`
1111 --> $DIR/error-with-naked.rs:18:5
1212 |
1313LL | #[track_caller]
14 | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[naked]`
14 | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]`
1515LL |
16LL | #[naked]
17 | -------- function marked with `#[naked]` here
16LL | #[unsafe(naked)]
17 | ---------------- function marked with `#[unsafe(naked)]` here
1818
1919error[E0737]: `#[track_caller]` requires Rust ABI
2020 --> $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
10use std::future::Future;
11
12pub trait ReactiveFunction: Send {
13 type Output;
14
15 fn invoke(self) -> Self::Output;
16}
17
18trait AttributeValue {
19 fn resolve(self) -> impl Future<Output = ()> + Send;
20}
21
22impl<F, V> AttributeValue for F
23where
24 F: ReactiveFunction<Output = V>,
25 V: AttributeValue,
26{
27 async fn resolve(self) {
28 self.invoke().resolve().await
29 }
30}
31
32fn main() {}