From e3029abfaec4252ab0ae7010780be0094d8870e0 Mon Sep 17 00:00:00 2001 From: VulnBandit <183613941+VulnBandit@users.noreply.github.com> Date: Wed, 2 Oct 2024 15:11:16 +0200 Subject: [PATCH 01/11] Improve duplicate derive Copy/Clone diagnostics --- .../src/diagnostics/move_errors.rs | 17 ++++++++++++++ ...duplicate-derive-copy-clone-diagnostics.rs | 11 +++++++++ ...icate-derive-copy-clone-diagnostics.stderr | 23 +++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs create mode 100644 tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 3871816777c7f..15cc9c20ab7dc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -10,6 +10,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex}; use rustc_span::{BytePos, ExpnKind, MacroKind, Span}; use rustc_trait_selection::error_reporting::traits::FindExprBySpan; +use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; use crate::MirBorrowckCtxt; @@ -267,6 +268,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { kind, self.is_upvar_field_projection(original_path.as_ref()) ); + if self.has_ambiguous_copy(original_path.ty(self.body, self.infcx.tcx).ty) { + // If the type may implement Copy, skip the error. + // It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check + self.dcx().span_delayed_bug( + span, + "Type may implement copy, but there is no other error.", + ); + return; + } ( match kind { &IllegalMoveOriginKind::BorrowedContent { target_place } => self @@ -291,6 +301,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.buffer_error(err); } + fn has_ambiguous_copy(&mut self, ty: Ty<'tcx>) -> bool { + let Some(copy_trait_def) = self.infcx.tcx.lang_items().copy_trait() else { return false }; + // This is only going to be ambiguous if there are incoherent impls, because otherwise + // ambiguity should never happen in MIR. + self.infcx.type_implements_trait(copy_trait_def, [ty], self.param_env).may_apply() + } + fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'infcx> { let description = if place.projection.len() == 1 { format!("static item {}", self.describe_any_place(place.as_ref())) diff --git a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs new file mode 100644 index 0000000000000..c4fb620fea4f3 --- /dev/null +++ b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs @@ -0,0 +1,11 @@ +// Duplicate implementations of Copy/Clone should not trigger +// borrow check warnings +// See #131083 + +#[derive(Copy, Clone)] +#[derive(Copy, Clone)] +//~^ ERROR conflicting implementations of trait `Clone` for type `E` +//~| ERROR conflicting implementations of trait `Copy` for type `E` +enum E {} + +fn main() {} diff --git a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr new file mode 100644 index 0000000000000..f8e1db33f5363 --- /dev/null +++ b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr @@ -0,0 +1,23 @@ +error[E0119]: conflicting implementations of trait `Copy` for type `E` + --> $DIR/duplicate-derive-copy-clone-diagnostics.rs:6:10 + | +LL | #[derive(Copy, Clone)] + | ---- first implementation here +LL | #[derive(Copy, Clone)] + | ^^^^ conflicting implementation for `E` + | + = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `Clone` for type `E` + --> $DIR/duplicate-derive-copy-clone-diagnostics.rs:6:16 + | +LL | #[derive(Copy, Clone)] + | ----- first implementation here +LL | #[derive(Copy, Clone)] + | ^^^^^ conflicting implementation for `E` + | + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0119`. From 10b60eba9bc55449721db912fe75bab11de43c4e Mon Sep 17 00:00:00 2001 From: Duncan Proctor Date: Tue, 22 Oct 2024 01:51:54 -0400 Subject: [PATCH 02/11] add third help hint to diagnostic error E0027 --- compiler/rustc_hir_typeck/src/pat.rs | 19 +++++++++++++++++++ .../struct_destructure_fail.stderr | 4 ++++ tests/ui/error-codes/E0027.stderr | 16 ++++++++++++++++ .../usefulness/doc-hidden-fields.stderr | 12 ++++++++++++ .../usefulness/stable-gated-fields.stderr | 4 ++++ .../usefulness/unstable-gated-fields.stderr | 8 ++++++++ tests/ui/structs/struct-field-cfg.stderr | 4 ++++ .../structs/struct-pat-derived-error.stderr | 4 ++++ .../structs/struct-tuple-field-names.stderr | 4 ++++ ...ing-field-when-specifying-same-type.stderr | 16 ++++++++++++++++ ...-missing-inaccessible-field-pattern.stderr | 4 ++++ 11 files changed, 95 insertions(+) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index e961752b24c2c..5868c4bc1fa51 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2070,6 +2070,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { s = pluralize!(len), them = if len == 1 { "it" } else { "them" }, ), + format!( + "{}{}{}{}", + prefix, + unmentioned_fields + .iter() + .map(|(_, name)| { + let field_name = name.to_string(); + format!("{field_name}: _") + }) + .collect::>() + .join(", "), + if have_inaccessible_fields { ", .." } else { "" }, + postfix, + ), + Applicability::MachineApplicable, + ); + err.span_suggestion( + sp, + "or always ignore missing fields here", format!("{prefix}..{postfix}"), Applicability::MachineApplicable, ); diff --git a/tests/ui/destructuring-assignment/struct_destructure_fail.stderr b/tests/ui/destructuring-assignment/struct_destructure_fail.stderr index 57851ed417ea8..4c4f0663eeb43 100644 --- a/tests/ui/destructuring-assignment/struct_destructure_fail.stderr +++ b/tests/ui/destructuring-assignment/struct_destructure_fail.stderr @@ -41,6 +41,10 @@ LL | Struct { a, b } = Struct { a: 1, b: 2 }; | ~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Struct { a, b: _ } = Struct { a: 1, b: 2 }; + | ~~~~~~~~ +help: or always ignore missing fields here + | LL | Struct { a, .. } = Struct { a: 1, b: 2 }; | ~~~~~~ diff --git a/tests/ui/error-codes/E0027.stderr b/tests/ui/error-codes/E0027.stderr index 9ae97e4a994da..7bbafcf0a27ab 100644 --- a/tests/ui/error-codes/E0027.stderr +++ b/tests/ui/error-codes/E0027.stderr @@ -10,6 +10,10 @@ LL | Dog { age: x, name } => {} | ~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Dog { age: x, name: _ } => {} + | ~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | Dog { age: x, .. } => {} | ~~~~~~ @@ -25,6 +29,10 @@ LL | Dog { name: x, age } => {} | ~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Dog { name: x, age: _ } => {} + | ~~~~~~~~~~ +help: or always ignore missing fields here + | LL | Dog { name: x, .. } => {} | ~~~~~~ @@ -40,6 +48,10 @@ LL | Dog { name: x, age } => {} | ~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Dog { name: x, age: _ } => {} + | ~~~~~~~~~~ +help: or always ignore missing fields here + | LL | Dog { name: x, .. } => {} | ~~~~~~ @@ -55,6 +67,10 @@ LL | Dog { name, age } => {} | ~~~~~~~~~~~~~ help: if you don't care about these missing fields, you can explicitly ignore them | +LL | Dog { name: _, age: _ } => {} + | ~~~~~~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | Dog { .. } => {} | ~~~~~~ diff --git a/tests/ui/pattern/usefulness/doc-hidden-fields.stderr b/tests/ui/pattern/usefulness/doc-hidden-fields.stderr index f277bfbc884fb..158eac9a1bd14 100644 --- a/tests/ui/pattern/usefulness/doc-hidden-fields.stderr +++ b/tests/ui/pattern/usefulness/doc-hidden-fields.stderr @@ -21,6 +21,10 @@ LL | let HiddenStruct { one, two, .. } = HiddenStruct::default(); | ~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let HiddenStruct { one, two: _, .. } = HiddenStruct::default(); + | ~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let HiddenStruct { one, .. } = HiddenStruct::default(); | ~~~~~~ @@ -36,6 +40,10 @@ LL | let HiddenStruct { one, hide, two } = HiddenStruct::default(); | ~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let HiddenStruct { one, hide, two: _ } = HiddenStruct::default(); + | ~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let HiddenStruct { one, hide, .. } = HiddenStruct::default(); | ~~~~~~ @@ -51,6 +59,10 @@ LL | let InCrate { a, b, im_hidden } = InCrate { a: 0, b: false, im_hidden: | ~~~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let InCrate { a, b, im_hidden: _ } = InCrate { a: 0, b: false, im_hidden: 0 }; + | ~~~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let InCrate { a, b, .. } = InCrate { a: 0, b: false, im_hidden: 0 }; | ~~~~~~ diff --git a/tests/ui/pattern/usefulness/stable-gated-fields.stderr b/tests/ui/pattern/usefulness/stable-gated-fields.stderr index cf98c51a2b41e..d6e9bac7c136b 100644 --- a/tests/ui/pattern/usefulness/stable-gated-fields.stderr +++ b/tests/ui/pattern/usefulness/stable-gated-fields.stderr @@ -10,6 +10,10 @@ LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); | ~~~~~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let UnstableStruct { stable, stable2: _, .. } = UnstableStruct::default(); + | ~~~~~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let UnstableStruct { stable, .. } = UnstableStruct::default(); | ~~~~~~ diff --git a/tests/ui/pattern/usefulness/unstable-gated-fields.stderr b/tests/ui/pattern/usefulness/unstable-gated-fields.stderr index e4f5fa06b3ff5..bb10e439ee23d 100644 --- a/tests/ui/pattern/usefulness/unstable-gated-fields.stderr +++ b/tests/ui/pattern/usefulness/unstable-gated-fields.stderr @@ -10,6 +10,10 @@ LL | let UnstableStruct { stable, stable2, unstable } = UnstableStruct::defa | ~~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let UnstableStruct { stable, stable2, unstable: _ } = UnstableStruct::default(); + | ~~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); | ~~~~~~ @@ -25,6 +29,10 @@ LL | let UnstableStruct { stable, unstable, stable2 } = UnstableStruct::defa | ~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let UnstableStruct { stable, unstable, stable2: _ } = UnstableStruct::default(); + | ~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let UnstableStruct { stable, unstable, .. } = UnstableStruct::default(); | ~~~~~~ diff --git a/tests/ui/structs/struct-field-cfg.stderr b/tests/ui/structs/struct-field-cfg.stderr index 2b9ba85ddcb88..f30d343d58287 100644 --- a/tests/ui/structs/struct-field-cfg.stderr +++ b/tests/ui/structs/struct-field-cfg.stderr @@ -24,6 +24,10 @@ LL | let Foo { present } = foo; | ~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let Foo { present: _ } = foo; + | ~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let Foo { .. } = foo; | ~~~~~~ diff --git a/tests/ui/structs/struct-pat-derived-error.stderr b/tests/ui/structs/struct-pat-derived-error.stderr index 78bb018cb4be7..d1d68121cf168 100644 --- a/tests/ui/structs/struct-pat-derived-error.stderr +++ b/tests/ui/structs/struct-pat-derived-error.stderr @@ -27,6 +27,10 @@ LL | let A { x, y, b, c } = self.d; | ~~~~~~~~ help: if you don't care about these missing fields, you can explicitly ignore them | +LL | let A { x, y, b: _, c: _ } = self.d; + | ~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let A { x, y, .. } = self.d; | ~~~~~~ diff --git a/tests/ui/structs/struct-tuple-field-names.stderr b/tests/ui/structs/struct-tuple-field-names.stderr index 0b837a47a8254..5f1ab2f9d6823 100644 --- a/tests/ui/structs/struct-tuple-field-names.stderr +++ b/tests/ui/structs/struct-tuple-field-names.stderr @@ -32,6 +32,10 @@ LL | if let E::S { 0: a, 1: _ } = x { | ~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | if let E::S { 0: a, 1: _ } = x { + | ~~~~~~~~ +help: or always ignore missing fields here + | LL | if let E::S { 0: a, .. } = x { | ~~~~~~ diff --git a/tests/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr b/tests/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr index e8503f540c288..af530e2b75931 100644 --- a/tests/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr +++ b/tests/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr @@ -19,6 +19,10 @@ LL | Foo::Bar { a, aa: 1, c, b } => (), | ~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Foo::Bar { a, aa: 1, c, b: _ } => (), + | ~~~~~~~~ +help: or always ignore missing fields here + | LL | Foo::Bar { a, aa: 1, c, .. } => (), | ~~~~~~ @@ -43,6 +47,10 @@ LL | Foo::Baz { bb: 1.0, a } => (), | ~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Foo::Baz { bb: 1.0, a: _ } => (), + | ~~~~~~~~ +help: or always ignore missing fields here + | LL | Foo::Baz { bb: 1.0, .. } => (), | ~~~~~~ @@ -64,6 +72,10 @@ LL | Foo::Bar { a, aa: "", c, b } => (), | ~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Foo::Bar { a, aa: "", c, b: _ } => (), + | ~~~~~~~~ +help: or always ignore missing fields here + | LL | Foo::Bar { a, aa: "", c, .. } => (), | ~~~~~~ @@ -85,6 +97,10 @@ LL | Foo::Baz { bb: "", a } => (), | ~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Foo::Baz { bb: "", a: _ } => (), + | ~~~~~~~~ +help: or always ignore missing fields here + | LL | Foo::Baz { bb: "", .. } => (), | ~~~~~~ diff --git a/tests/ui/typeck/issue-87872-missing-inaccessible-field-pattern.stderr b/tests/ui/typeck/issue-87872-missing-inaccessible-field-pattern.stderr index 96ac481438f7a..b9bdf6f9a3990 100644 --- a/tests/ui/typeck/issue-87872-missing-inaccessible-field-pattern.stderr +++ b/tests/ui/typeck/issue-87872-missing-inaccessible-field-pattern.stderr @@ -10,6 +10,10 @@ LL | let foo::Foo { visible, .. } = foo::Foo::default(); | ~~~~~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let foo::Foo { visible: _, .. } = foo::Foo::default(); + | ~~~~~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let foo::Foo { .. } = foo::Foo::default(); | ~~~~~~ From a645342720cbfd735325f8ccef7ffbcfe988cec1 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Mon, 28 Oct 2024 22:48:32 -0400 Subject: [PATCH 03/11] More test for non-exhaustive C-like enums in FFI Add a few more possibly false-positive tests for the `improper_ctypes` lint --- .../improper_ctypes/auxiliary/types.rs | 6 ++++++ .../improper_ctypes/extern_crate_improper.rs | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs index 4dc5932feab40..5d9a8cfcac1dd 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs @@ -38,3 +38,9 @@ pub enum NonExhaustiveCLikeEnum { Four = 4, Five = 5, } + +#[repr(C)] +pub struct NormalStructWithNonExhaustiveCLikeEnum { + one: u8, + two: NonExhaustiveCLikeEnum, +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs index c7f470fb787a7..858e3374eacfc 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs @@ -8,7 +8,7 @@ extern crate types; use types::{ NonExhaustiveCLikeEnum, NonExhaustiveEnum, NonExhaustiveVariants, - NormalStruct, TupleStruct, UnitStruct, + NormalStruct, TupleStruct, UnitStruct, NormalStructWithNonExhaustiveCLikeEnum }; extern "C" { @@ -27,6 +27,9 @@ extern "C" { // These should pass without remark, as they're C-compatible, despite being "non-exhaustive". extern "C" { pub fn non_exhaustive_c_compat_enum(_: NonExhaustiveCLikeEnum); + pub fn non_exhaustive_c_compat_enum_ret() -> *mut NonExhaustiveCLikeEnum; + pub fn struct_w_non_exhaustive_c_like_enum(_: NormalStructWithNonExhaustiveCLikeEnum); + pub fn struct_w_non_exhaustive_c_like_enum_ret() -> *mut NormalStructWithNonExhaustiveCLikeEnum; } fn main() {} From d19517dcd0e31ce6591ab36e7160681b2f589acf Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 2 Nov 2024 20:26:08 +0900 Subject: [PATCH 04/11] Support clobber_abi and vector registers (clobber-only) in PowerPC inline assembly --- compiler/rustc_codegen_gcc/src/asm.rs | 6 +- compiler/rustc_codegen_llvm/src/asm.rs | 8 +- compiler/rustc_target/src/asm/mod.rs | 30 ++ compiler/rustc_target/src/asm/powerpc.rs | 78 +++++- .../asm-experimental-arch.md | 22 +- tests/codegen/asm/powerpc-clobbers.rs | 26 +- tests/ui/asm/powerpc/bad-reg.aix64.stderr | 264 ++++++++++++++++++ tests/ui/asm/powerpc/bad-reg.powerpc.stderr | 264 ++++++++++++++++++ tests/ui/asm/powerpc/bad-reg.powerpc64.stderr | 264 ++++++++++++++++++ .../ui/asm/powerpc/bad-reg.powerpc64le.stderr | 264 ++++++++++++++++++ tests/ui/asm/powerpc/bad-reg.rs | 124 ++++++++ 11 files changed, 1332 insertions(+), 18 deletions(-) create mode 100644 tests/ui/asm/powerpc/bad-reg.aix64.stderr create mode 100644 tests/ui/asm/powerpc/bad-reg.powerpc.stderr create mode 100644 tests/ui/asm/powerpc/bad-reg.powerpc64.stderr create mode 100644 tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr create mode 100644 tests/ui/asm/powerpc/bad-reg.rs diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index a04cd4735f478..b44d4aa8cc82b 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -654,7 +654,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f", InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) - | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => { unreachable!("clobber-only") } InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", @@ -729,7 +730,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) - | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => { unreachable!("clobber-only") } InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 53758967552d4..bdff1ce75a95d 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -638,7 +638,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> PowerPC(PowerPCInlineAsmRegClass::reg) => "r", PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b", PowerPC(PowerPCInlineAsmRegClass::freg) => "f", - PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => { + PowerPC(PowerPCInlineAsmRegClass::cr) + | PowerPC(PowerPCInlineAsmRegClass::xer) + | PowerPC(PowerPCInlineAsmRegClass::vreg) => { unreachable!("clobber-only") } RiscV(RiscVInlineAsmRegClass::reg) => "r", @@ -800,7 +802,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(), PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), - PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => { + PowerPC(PowerPCInlineAsmRegClass::cr) + | PowerPC(PowerPCInlineAsmRegClass::xer) + | PowerPC(PowerPCInlineAsmRegClass::vreg) => { unreachable!("clobber-only") } RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 4b539eb8e2088..460b6e4b64702 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -893,6 +893,7 @@ pub enum InlineAsmClobberAbi { Arm64EC, RiscV, LoongArch, + PowerPC, S390x, Msp430, } @@ -944,6 +945,10 @@ impl InlineAsmClobberAbi { "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch), _ => Err(&["C", "system"]), }, + InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => match name { + "C" | "system" => Ok(InlineAsmClobberAbi::PowerPC), + _ => Err(&["C", "system"]), + }, InlineAsmArch::S390x => match name { "C" | "system" => Ok(InlineAsmClobberAbi::S390x), _ => Err(&["C", "system"]), @@ -1121,6 +1126,31 @@ impl InlineAsmClobberAbi { f16, f17, f18, f19, f20, f21, f22, f23, } }, + InlineAsmClobberAbi::PowerPC => clobbered_regs! { + PowerPC PowerPCInlineAsmReg { + // r0, r3-r12 + r0, + r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, + + // f0-f13 + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, + + // v0-v19 + // FIXME: PPC32 SysV ABI does not mention vector registers processing. + // https://refspecs.linuxfoundation.org/elf/elfspec_ppc.pdf + v0, v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, + + // cr0-cr1, cr5-cr7, xer + cr0, cr1, + cr5, cr6, cr7, + xer, + // lr and ctr are reserved + } + }, InlineAsmClobberAbi::S390x => clobbered_regs! { S390x S390xInlineAsmReg { r0, r1, r2, r3, r4, r5, diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index b2416466132d7..aa8b26170bee1 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -1,14 +1,17 @@ use std::fmt; +use rustc_data_structures::fx::FxIndexSet; use rustc_span::Symbol; use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; +use crate::spec::{RelocModel, Target}; def_reg_class! { PowerPC PowerPCInlineAsmRegClass { reg, reg_nonzero, freg, + vreg, cr, xer, } @@ -48,11 +51,44 @@ impl PowerPCInlineAsmRegClass { } } Self::freg => types! { _: F32, F64; }, + Self::vreg => &[], Self::cr | Self::xer => &[], } } } +fn reserved_r13( + arch: InlineAsmArch, + _reloc_model: RelocModel, + _target_features: &FxIndexSet, + target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + if target.is_like_aix && arch == InlineAsmArch::PowerPC { + Ok(()) + } else { + Err("r13 is a reserved register on this target") + } +} + +fn reserved_v20to31( + _arch: InlineAsmArch, + _reloc_model: RelocModel, + _target_features: &FxIndexSet, + target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + if target.is_like_aix { + match &*target.options.abi { + "vec-default" => Err("v20-v31 are reserved on vec-default ABI"), + "vec-extabi" => Ok(()), + _ => unreachable!("unrecognized AIX ABI"), + } + } else { + Ok(()) + } +} + def_regs! { PowerPC PowerPCInlineAsmReg PowerPCInlineAsmRegClass { r0: reg = ["r0", "0"], @@ -66,6 +102,7 @@ def_regs! { r10: reg, reg_nonzero = ["r10", "10"], r11: reg, reg_nonzero = ["r11", "11"], r12: reg, reg_nonzero = ["r12", "12"], + r13: reg, reg_nonzero = ["r13", "13"] % reserved_r13, r14: reg, reg_nonzero = ["r14", "14"], r15: reg, reg_nonzero = ["r15", "15"], r16: reg, reg_nonzero = ["r16", "16"], @@ -113,6 +150,38 @@ def_regs! { f29: freg = ["f29", "fr29"], f30: freg = ["f30", "fr30"], f31: freg = ["f31", "fr31"], + v0: vreg = ["v0"], + v1: vreg = ["v1"], + v2: vreg = ["v2"], + v3: vreg = ["v3"], + v4: vreg = ["v4"], + v5: vreg = ["v5"], + v6: vreg = ["v6"], + v7: vreg = ["v7"], + v8: vreg = ["v8"], + v9: vreg = ["v9"], + v10: vreg = ["v10"], + v11: vreg = ["v11"], + v12: vreg = ["v12"], + v13: vreg = ["v13"], + v14: vreg = ["v14"], + v15: vreg = ["v15"], + v16: vreg = ["v16"], + v17: vreg = ["v17"], + v18: vreg = ["v18"], + v19: vreg = ["v19"], + v20: vreg = ["v20"] % reserved_v20to31, + v21: vreg = ["v21"] % reserved_v20to31, + v22: vreg = ["v22"] % reserved_v20to31, + v23: vreg = ["v23"] % reserved_v20to31, + v24: vreg = ["v24"] % reserved_v20to31, + v25: vreg = ["v25"] % reserved_v20to31, + v26: vreg = ["v26"] % reserved_v20to31, + v27: vreg = ["v27"] % reserved_v20to31, + v28: vreg = ["v28"] % reserved_v20to31, + v29: vreg = ["v29"] % reserved_v20to31, + v30: vreg = ["v30"] % reserved_v20to31, + v31: vreg = ["v31"] % reserved_v20to31, cr: cr = ["cr"], cr0: cr = ["cr0"], cr1: cr = ["cr1"], @@ -127,8 +196,6 @@ def_regs! { "the stack pointer cannot be used as an operand for inline asm", #error = ["r2", "2"] => "r2 is a system reserved register and cannot be used as an operand for inline asm", - #error = ["r13", "13"] => - "r13 is a system reserved register and cannot be used as an operand for inline asm", #error = ["r29", "29"] => "r29 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["r30", "30"] => @@ -163,13 +230,17 @@ impl PowerPCInlineAsmReg { // Strip off the leading prefix. do_emit! { (r0, "0"), (r3, "3"), (r4, "4"), (r5, "5"), (r6, "6"), (r7, "7"); - (r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r14, "14"), (r15, "15"); + (r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r13, "13"), (r14, "14"), (r15, "15"); (r16, "16"), (r17, "17"), (r18, "18"), (r19, "19"), (r20, "20"), (r21, "21"), (r22, "22"), (r23, "23"); (r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28"); (f0, "0"), (f1, "1"), (f2, "2"), (f3, "3"), (f4, "4"), (f5, "5"), (f6, "6"), (f7, "7"); (f8, "8"), (f9, "9"), (f10, "10"), (f11, "11"), (f12, "12"), (f13, "13"), (f14, "14"), (f15, "15"); (f16, "16"), (f17, "17"), (f18, "18"), (f19, "19"), (f20, "20"), (f21, "21"), (f22, "22"), (f23, "23"); (f24, "24"), (f25, "25"), (f26, "26"), (f27, "27"), (f28, "28"), (f29, "29"), (f30, "30"), (f31, "31"); + (v0, "0"), (v1, "1"), (v2, "2"), (v3, "3"), (v4, "4"), (v5, "5"), (v6, "6"), (v7, "7"); + (v8, "8"), (v9, "9"), (v10, "10"), (v11, "11"), (v12, "12"), (v13, "13"), (v14, "14"), (v15, "15"); + (v16, "16"), (v17, "17"), (v18, "18"), (v19, "19"), (v20, "20"), (v21, "21"), (v22, "22"), (v23, "23"); + (v24, "24"), (v25, "25"), (v26, "26"), (v27, "27"), (v28, "28"), (v29, "29"), (v30, "30"), (v31, "31"); (cr, "cr"); (cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7"); (xer, "xer"); @@ -201,5 +272,6 @@ impl PowerPCInlineAsmReg { reg_conflicts! { cr : cr0 cr1 cr2 cr3 cr4 cr5 cr6 cr7; } + // f0-f31 (vsr0-vsr31) and v0-v31 (vsr32-vsr63) do not conflict. } } diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index b1c429c7676ef..5264f778a93b5 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -31,9 +31,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | NVPTX | `reg32` | None\* | `r` | | NVPTX | `reg64` | None\* | `l` | | Hexagon | `reg` | `r[0-28]` | `r` | -| PowerPC | `reg` | `r[0-31]` | `r` | -| PowerPC | `reg_nonzero` | `r[1-31]` | `b` | +| PowerPC | `reg` | `r0`, `r[3-12]`, `r[14-28]` | `r` | +| PowerPC | `reg_nonzero` | `r[3-12]`, `r[14-28]` | `b` | | PowerPC | `freg` | `f[0-31]` | `f` | +| PowerPC | `vreg` | `v[0-31]` | Only clobbers | | PowerPC | `cr` | `cr[0-7]`, `cr` | Only clobbers | | PowerPC | `xer` | `xer` | Only clobbers | | wasm32 | `local` | None\* | `r` | @@ -76,9 +77,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` | | NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | | Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` | -| PowerPC | `reg` | None | `i8`, `i16`, `i32` | -| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` | +| PowerPC | `reg` | None | `i8`, `i16`, `i32`, `i64` (powerpc64 only) | +| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32`, `i64` (powerpc64 only) | | PowerPC | `freg` | None | `f32`, `f64` | +| PowerPC | `vreg` | N/A | Only clobbers | | PowerPC | `cr` | N/A | Only clobbers | | PowerPC | `xer` | N/A | Only clobbers | | wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` | @@ -105,6 +107,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Hexagon | `r29` | `sp` | | Hexagon | `r30` | `fr` | | Hexagon | `r31` | `lr` | +| PowerPC | `r1` | `sp` | +| PowerPC | `r31` | `fp` | +| PowerPC | `r[0-31]` | `[0-31]` | +| PowerPC | `f[0-31]` | `fr[0-31]`| | BPF | `r[0-10]` | `w[0-10]` | | AVR | `XH` | `r27` | | AVR | `XL` | `r26` | @@ -145,14 +151,18 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Architecture | Unsupported register | Reason | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | All | `sp`, `r15` (s390x) | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. | -| All | `r19` (Hexagon), `x19` (Arm64EC) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | +| All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. | +| All | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC), `x19` (Arm64EC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | | MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | | MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. | | MIPS | `$ra` | Return address cannot be used as inputs or outputs. | | Hexagon | `lr` | This is the link register which cannot be used as an input or output. | +| PowerPC | `r2`, `r13` | These are system reserved registers. | +| PowerPC | `lr` | The link register cannot be used as an input or output. | +| PowerPC | `ctr` | The counter register cannot be used as an input or output. | +| PowerPC | `vrsave` | The vrsave register cannot be used as an input or output. | | AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. | |MSP430 | `r0`, `r2`, `r3` | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to. | | M68k | `a4`, `a5` | Used internally by LLVM for the base pointer and global base pointer. | diff --git a/tests/codegen/asm/powerpc-clobbers.rs b/tests/codegen/asm/powerpc-clobbers.rs index 0be1b66bd99ea..e97e8300ca74b 100644 --- a/tests/codegen/asm/powerpc-clobbers.rs +++ b/tests/codegen/asm/powerpc-clobbers.rs @@ -1,10 +1,12 @@ -//@ revisions: powerpc powerpc64 powerpc64le +//@ revisions: powerpc powerpc64 powerpc64le aix64 //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu //@[powerpc] needs-llvm-components: powerpc //@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu //@[powerpc64] needs-llvm-components: powerpc //@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu //@[powerpc64le] needs-llvm-components: powerpc +//@[aix64] compile-flags: --target powerpc64-ibm-aix +//@[aix64] needs-llvm-components: powerpc #![crate_type = "rlib"] #![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)] @@ -22,26 +24,40 @@ macro_rules! asm { // CHECK: call void asm sideeffect "", "~{cr}"() #[no_mangle] pub unsafe fn cr_clobber() { - asm!("", out("cr") _, options(nostack, nomem)); + asm!("", out("cr") _, options(nostack, nomem, preserves_flags)); } // CHECK-LABEL: @cr0_clobber // CHECK: call void asm sideeffect "", "~{cr0}"() #[no_mangle] pub unsafe fn cr0_clobber() { - asm!("", out("cr0") _, options(nostack, nomem)); + asm!("", out("cr0") _, options(nostack, nomem, preserves_flags)); } // CHECK-LABEL: @cr5_clobber // CHECK: call void asm sideeffect "", "~{cr5}"() #[no_mangle] pub unsafe fn cr5_clobber() { - asm!("", out("cr5") _, options(nostack, nomem)); + asm!("", out("cr5") _, options(nostack, nomem, preserves_flags)); } // CHECK-LABEL: @xer_clobber // CHECK: call void asm sideeffect "", "~{xer}"() #[no_mangle] pub unsafe fn xer_clobber() { - asm!("", out("xer") _, options(nostack, nomem)); + asm!("", out("xer") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @v0_clobber +// CHECK: call void asm sideeffect "", "~{v0}"() +#[no_mangle] +pub unsafe fn v0_clobber() { + asm!("", out("v0") _, options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @clobber_abi +// CHECK: asm sideeffect "", "={r0},={r3},={r4},={r5},={r6},={r7},={r8},={r9},={r10},={r11},={r12},={f0},={f1},={f2},={f3},={f4},={f5},={f6},={f7},={f8},={f9},={f10},={f11},={f12},={f13},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6},~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19},~{cr0},~{cr1},~{cr5},~{cr6},~{cr7},~{xer}"() +#[no_mangle] +pub unsafe fn clobber_abi() { + asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); } diff --git a/tests/ui/asm/powerpc/bad-reg.aix64.stderr b/tests/ui/asm/powerpc/bad-reg.aix64.stderr new file mode 100644 index 0000000000000..34105ceac049b --- /dev/null +++ b/tests/ui/asm/powerpc/bad-reg.aix64.stderr @@ -0,0 +1,264 @@ +error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:32:18 + | +LL | asm!("", out("sp") _); + | ^^^^^^^^^^^ + +error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:34:18 + | +LL | asm!("", out("r2") _); + | ^^^^^^^^^^^ + +error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:38:18 + | +LL | asm!("", out("r29") _); + | ^^^^^^^^^^^^ + +error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:40:18 + | +LL | asm!("", out("r30") _); + | ^^^^^^^^^^^^ + +error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:42:18 + | +LL | asm!("", out("fp") _); + | ^^^^^^^^^^^ + +error: invalid register `lr`: the link register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:44:18 + | +LL | asm!("", out("lr") _); + | ^^^^^^^^^^^ + +error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:46:18 + | +LL | asm!("", out("ctr") _); + | ^^^^^^^^^^^^ + +error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:48:18 + | +LL | asm!("", out("vrsave") _); + | ^^^^^^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:66:18 + | +LL | asm!("", in("cr") x); + | ^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:69:18 + | +LL | asm!("", out("cr") x); + | ^^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:72:26 + | +LL | asm!("/* {} */", in(cr) x); + | ^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:75:26 + | +LL | asm!("/* {} */", out(cr) _); + | ^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:79:18 + | +LL | asm!("", in("xer") x); + | ^^^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:82:18 + | +LL | asm!("", out("xer") x); + | ^^^^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:85:26 + | +LL | asm!("/* {} */", in(xer) x); + | ^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:88:26 + | +LL | asm!("/* {} */", out(xer) _); + | ^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:93:18 + | +LL | asm!("", in("v0") x); + | ^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:96:18 + | +LL | asm!("", out("v0") x); + | ^^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:99:26 + | +LL | asm!("/* {} */", in(vreg) x); + | ^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:102:26 + | +LL | asm!("/* {} */", out(vreg) _); + | ^^^^^^^^^^^ + +error: register `cr0` conflicts with register `cr` + --> $DIR/bad-reg.rs:106:31 + | +LL | asm!("", out("cr") _, out("cr0") _); + | ----------- ^^^^^^^^^^^^ register `cr0` + | | + | register `cr` + +error: register `cr1` conflicts with register `cr` + --> $DIR/bad-reg.rs:108:31 + | +LL | asm!("", out("cr") _, out("cr1") _); + | ----------- ^^^^^^^^^^^^ register `cr1` + | | + | register `cr` + +error: register `cr2` conflicts with register `cr` + --> $DIR/bad-reg.rs:110:31 + | +LL | asm!("", out("cr") _, out("cr2") _); + | ----------- ^^^^^^^^^^^^ register `cr2` + | | + | register `cr` + +error: register `cr3` conflicts with register `cr` + --> $DIR/bad-reg.rs:112:31 + | +LL | asm!("", out("cr") _, out("cr3") _); + | ----------- ^^^^^^^^^^^^ register `cr3` + | | + | register `cr` + +error: register `cr4` conflicts with register `cr` + --> $DIR/bad-reg.rs:114:31 + | +LL | asm!("", out("cr") _, out("cr4") _); + | ----------- ^^^^^^^^^^^^ register `cr4` + | | + | register `cr` + +error: register `cr5` conflicts with register `cr` + --> $DIR/bad-reg.rs:116:31 + | +LL | asm!("", out("cr") _, out("cr5") _); + | ----------- ^^^^^^^^^^^^ register `cr5` + | | + | register `cr` + +error: register `cr6` conflicts with register `cr` + --> $DIR/bad-reg.rs:118:31 + | +LL | asm!("", out("cr") _, out("cr6") _); + | ----------- ^^^^^^^^^^^^ register `cr6` + | | + | register `cr` + +error: register `cr7` conflicts with register `cr` + --> $DIR/bad-reg.rs:120:31 + | +LL | asm!("", out("cr") _, out("cr7") _); + | ----------- ^^^^^^^^^^^^ register `cr7` + | | + | register `cr` + +error: cannot use register `r13`: r13 is a reserved register on this target + --> $DIR/bad-reg.rs:36:18 + | +LL | asm!("", out("r13") _); + | ^^^^^^^^^^^^ + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:66:27 + | +LL | asm!("", in("cr") x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:69:28 + | +LL | asm!("", out("cr") x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:72:33 + | +LL | asm!("/* {} */", in(cr) x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:79:28 + | +LL | asm!("", in("xer") x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:82:29 + | +LL | asm!("", out("xer") x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:85:34 + | +LL | asm!("/* {} */", in(xer) x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:93:27 + | +LL | asm!("", in("v0") x); + | ^ + | + = note: register class `vreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:96:28 + | +LL | asm!("", out("v0") x); + | ^ + | + = note: register class `vreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:99:35 + | +LL | asm!("/* {} */", in(vreg) x); + | ^ + | + = note: register class `vreg` supports these types: + +error: aborting due to 38 previous errors + diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr new file mode 100644 index 0000000000000..34105ceac049b --- /dev/null +++ b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr @@ -0,0 +1,264 @@ +error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:32:18 + | +LL | asm!("", out("sp") _); + | ^^^^^^^^^^^ + +error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:34:18 + | +LL | asm!("", out("r2") _); + | ^^^^^^^^^^^ + +error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:38:18 + | +LL | asm!("", out("r29") _); + | ^^^^^^^^^^^^ + +error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:40:18 + | +LL | asm!("", out("r30") _); + | ^^^^^^^^^^^^ + +error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:42:18 + | +LL | asm!("", out("fp") _); + | ^^^^^^^^^^^ + +error: invalid register `lr`: the link register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:44:18 + | +LL | asm!("", out("lr") _); + | ^^^^^^^^^^^ + +error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:46:18 + | +LL | asm!("", out("ctr") _); + | ^^^^^^^^^^^^ + +error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:48:18 + | +LL | asm!("", out("vrsave") _); + | ^^^^^^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:66:18 + | +LL | asm!("", in("cr") x); + | ^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:69:18 + | +LL | asm!("", out("cr") x); + | ^^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:72:26 + | +LL | asm!("/* {} */", in(cr) x); + | ^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:75:26 + | +LL | asm!("/* {} */", out(cr) _); + | ^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:79:18 + | +LL | asm!("", in("xer") x); + | ^^^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:82:18 + | +LL | asm!("", out("xer") x); + | ^^^^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:85:26 + | +LL | asm!("/* {} */", in(xer) x); + | ^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:88:26 + | +LL | asm!("/* {} */", out(xer) _); + | ^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:93:18 + | +LL | asm!("", in("v0") x); + | ^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:96:18 + | +LL | asm!("", out("v0") x); + | ^^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:99:26 + | +LL | asm!("/* {} */", in(vreg) x); + | ^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:102:26 + | +LL | asm!("/* {} */", out(vreg) _); + | ^^^^^^^^^^^ + +error: register `cr0` conflicts with register `cr` + --> $DIR/bad-reg.rs:106:31 + | +LL | asm!("", out("cr") _, out("cr0") _); + | ----------- ^^^^^^^^^^^^ register `cr0` + | | + | register `cr` + +error: register `cr1` conflicts with register `cr` + --> $DIR/bad-reg.rs:108:31 + | +LL | asm!("", out("cr") _, out("cr1") _); + | ----------- ^^^^^^^^^^^^ register `cr1` + | | + | register `cr` + +error: register `cr2` conflicts with register `cr` + --> $DIR/bad-reg.rs:110:31 + | +LL | asm!("", out("cr") _, out("cr2") _); + | ----------- ^^^^^^^^^^^^ register `cr2` + | | + | register `cr` + +error: register `cr3` conflicts with register `cr` + --> $DIR/bad-reg.rs:112:31 + | +LL | asm!("", out("cr") _, out("cr3") _); + | ----------- ^^^^^^^^^^^^ register `cr3` + | | + | register `cr` + +error: register `cr4` conflicts with register `cr` + --> $DIR/bad-reg.rs:114:31 + | +LL | asm!("", out("cr") _, out("cr4") _); + | ----------- ^^^^^^^^^^^^ register `cr4` + | | + | register `cr` + +error: register `cr5` conflicts with register `cr` + --> $DIR/bad-reg.rs:116:31 + | +LL | asm!("", out("cr") _, out("cr5") _); + | ----------- ^^^^^^^^^^^^ register `cr5` + | | + | register `cr` + +error: register `cr6` conflicts with register `cr` + --> $DIR/bad-reg.rs:118:31 + | +LL | asm!("", out("cr") _, out("cr6") _); + | ----------- ^^^^^^^^^^^^ register `cr6` + | | + | register `cr` + +error: register `cr7` conflicts with register `cr` + --> $DIR/bad-reg.rs:120:31 + | +LL | asm!("", out("cr") _, out("cr7") _); + | ----------- ^^^^^^^^^^^^ register `cr7` + | | + | register `cr` + +error: cannot use register `r13`: r13 is a reserved register on this target + --> $DIR/bad-reg.rs:36:18 + | +LL | asm!("", out("r13") _); + | ^^^^^^^^^^^^ + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:66:27 + | +LL | asm!("", in("cr") x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:69:28 + | +LL | asm!("", out("cr") x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:72:33 + | +LL | asm!("/* {} */", in(cr) x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:79:28 + | +LL | asm!("", in("xer") x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:82:29 + | +LL | asm!("", out("xer") x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:85:34 + | +LL | asm!("/* {} */", in(xer) x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:93:27 + | +LL | asm!("", in("v0") x); + | ^ + | + = note: register class `vreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:96:28 + | +LL | asm!("", out("v0") x); + | ^ + | + = note: register class `vreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:99:35 + | +LL | asm!("/* {} */", in(vreg) x); + | ^ + | + = note: register class `vreg` supports these types: + +error: aborting due to 38 previous errors + diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr new file mode 100644 index 0000000000000..34105ceac049b --- /dev/null +++ b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr @@ -0,0 +1,264 @@ +error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:32:18 + | +LL | asm!("", out("sp") _); + | ^^^^^^^^^^^ + +error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:34:18 + | +LL | asm!("", out("r2") _); + | ^^^^^^^^^^^ + +error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:38:18 + | +LL | asm!("", out("r29") _); + | ^^^^^^^^^^^^ + +error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:40:18 + | +LL | asm!("", out("r30") _); + | ^^^^^^^^^^^^ + +error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:42:18 + | +LL | asm!("", out("fp") _); + | ^^^^^^^^^^^ + +error: invalid register `lr`: the link register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:44:18 + | +LL | asm!("", out("lr") _); + | ^^^^^^^^^^^ + +error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:46:18 + | +LL | asm!("", out("ctr") _); + | ^^^^^^^^^^^^ + +error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:48:18 + | +LL | asm!("", out("vrsave") _); + | ^^^^^^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:66:18 + | +LL | asm!("", in("cr") x); + | ^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:69:18 + | +LL | asm!("", out("cr") x); + | ^^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:72:26 + | +LL | asm!("/* {} */", in(cr) x); + | ^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:75:26 + | +LL | asm!("/* {} */", out(cr) _); + | ^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:79:18 + | +LL | asm!("", in("xer") x); + | ^^^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:82:18 + | +LL | asm!("", out("xer") x); + | ^^^^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:85:26 + | +LL | asm!("/* {} */", in(xer) x); + | ^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:88:26 + | +LL | asm!("/* {} */", out(xer) _); + | ^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:93:18 + | +LL | asm!("", in("v0") x); + | ^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:96:18 + | +LL | asm!("", out("v0") x); + | ^^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:99:26 + | +LL | asm!("/* {} */", in(vreg) x); + | ^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:102:26 + | +LL | asm!("/* {} */", out(vreg) _); + | ^^^^^^^^^^^ + +error: register `cr0` conflicts with register `cr` + --> $DIR/bad-reg.rs:106:31 + | +LL | asm!("", out("cr") _, out("cr0") _); + | ----------- ^^^^^^^^^^^^ register `cr0` + | | + | register `cr` + +error: register `cr1` conflicts with register `cr` + --> $DIR/bad-reg.rs:108:31 + | +LL | asm!("", out("cr") _, out("cr1") _); + | ----------- ^^^^^^^^^^^^ register `cr1` + | | + | register `cr` + +error: register `cr2` conflicts with register `cr` + --> $DIR/bad-reg.rs:110:31 + | +LL | asm!("", out("cr") _, out("cr2") _); + | ----------- ^^^^^^^^^^^^ register `cr2` + | | + | register `cr` + +error: register `cr3` conflicts with register `cr` + --> $DIR/bad-reg.rs:112:31 + | +LL | asm!("", out("cr") _, out("cr3") _); + | ----------- ^^^^^^^^^^^^ register `cr3` + | | + | register `cr` + +error: register `cr4` conflicts with register `cr` + --> $DIR/bad-reg.rs:114:31 + | +LL | asm!("", out("cr") _, out("cr4") _); + | ----------- ^^^^^^^^^^^^ register `cr4` + | | + | register `cr` + +error: register `cr5` conflicts with register `cr` + --> $DIR/bad-reg.rs:116:31 + | +LL | asm!("", out("cr") _, out("cr5") _); + | ----------- ^^^^^^^^^^^^ register `cr5` + | | + | register `cr` + +error: register `cr6` conflicts with register `cr` + --> $DIR/bad-reg.rs:118:31 + | +LL | asm!("", out("cr") _, out("cr6") _); + | ----------- ^^^^^^^^^^^^ register `cr6` + | | + | register `cr` + +error: register `cr7` conflicts with register `cr` + --> $DIR/bad-reg.rs:120:31 + | +LL | asm!("", out("cr") _, out("cr7") _); + | ----------- ^^^^^^^^^^^^ register `cr7` + | | + | register `cr` + +error: cannot use register `r13`: r13 is a reserved register on this target + --> $DIR/bad-reg.rs:36:18 + | +LL | asm!("", out("r13") _); + | ^^^^^^^^^^^^ + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:66:27 + | +LL | asm!("", in("cr") x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:69:28 + | +LL | asm!("", out("cr") x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:72:33 + | +LL | asm!("/* {} */", in(cr) x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:79:28 + | +LL | asm!("", in("xer") x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:82:29 + | +LL | asm!("", out("xer") x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:85:34 + | +LL | asm!("/* {} */", in(xer) x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:93:27 + | +LL | asm!("", in("v0") x); + | ^ + | + = note: register class `vreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:96:28 + | +LL | asm!("", out("v0") x); + | ^ + | + = note: register class `vreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:99:35 + | +LL | asm!("/* {} */", in(vreg) x); + | ^ + | + = note: register class `vreg` supports these types: + +error: aborting due to 38 previous errors + diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr new file mode 100644 index 0000000000000..34105ceac049b --- /dev/null +++ b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr @@ -0,0 +1,264 @@ +error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:32:18 + | +LL | asm!("", out("sp") _); + | ^^^^^^^^^^^ + +error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:34:18 + | +LL | asm!("", out("r2") _); + | ^^^^^^^^^^^ + +error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:38:18 + | +LL | asm!("", out("r29") _); + | ^^^^^^^^^^^^ + +error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:40:18 + | +LL | asm!("", out("r30") _); + | ^^^^^^^^^^^^ + +error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:42:18 + | +LL | asm!("", out("fp") _); + | ^^^^^^^^^^^ + +error: invalid register `lr`: the link register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:44:18 + | +LL | asm!("", out("lr") _); + | ^^^^^^^^^^^ + +error: invalid register `ctr`: the counter register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:46:18 + | +LL | asm!("", out("ctr") _); + | ^^^^^^^^^^^^ + +error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:48:18 + | +LL | asm!("", out("vrsave") _); + | ^^^^^^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:66:18 + | +LL | asm!("", in("cr") x); + | ^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:69:18 + | +LL | asm!("", out("cr") x); + | ^^^^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:72:26 + | +LL | asm!("/* {} */", in(cr) x); + | ^^^^^^^^ + +error: register class `cr` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:75:26 + | +LL | asm!("/* {} */", out(cr) _); + | ^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:79:18 + | +LL | asm!("", in("xer") x); + | ^^^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:82:18 + | +LL | asm!("", out("xer") x); + | ^^^^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:85:26 + | +LL | asm!("/* {} */", in(xer) x); + | ^^^^^^^^^ + +error: register class `xer` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:88:26 + | +LL | asm!("/* {} */", out(xer) _); + | ^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:93:18 + | +LL | asm!("", in("v0") x); + | ^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:96:18 + | +LL | asm!("", out("v0") x); + | ^^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:99:26 + | +LL | asm!("/* {} */", in(vreg) x); + | ^^^^^^^^^^ + +error: register class `vreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:102:26 + | +LL | asm!("/* {} */", out(vreg) _); + | ^^^^^^^^^^^ + +error: register `cr0` conflicts with register `cr` + --> $DIR/bad-reg.rs:106:31 + | +LL | asm!("", out("cr") _, out("cr0") _); + | ----------- ^^^^^^^^^^^^ register `cr0` + | | + | register `cr` + +error: register `cr1` conflicts with register `cr` + --> $DIR/bad-reg.rs:108:31 + | +LL | asm!("", out("cr") _, out("cr1") _); + | ----------- ^^^^^^^^^^^^ register `cr1` + | | + | register `cr` + +error: register `cr2` conflicts with register `cr` + --> $DIR/bad-reg.rs:110:31 + | +LL | asm!("", out("cr") _, out("cr2") _); + | ----------- ^^^^^^^^^^^^ register `cr2` + | | + | register `cr` + +error: register `cr3` conflicts with register `cr` + --> $DIR/bad-reg.rs:112:31 + | +LL | asm!("", out("cr") _, out("cr3") _); + | ----------- ^^^^^^^^^^^^ register `cr3` + | | + | register `cr` + +error: register `cr4` conflicts with register `cr` + --> $DIR/bad-reg.rs:114:31 + | +LL | asm!("", out("cr") _, out("cr4") _); + | ----------- ^^^^^^^^^^^^ register `cr4` + | | + | register `cr` + +error: register `cr5` conflicts with register `cr` + --> $DIR/bad-reg.rs:116:31 + | +LL | asm!("", out("cr") _, out("cr5") _); + | ----------- ^^^^^^^^^^^^ register `cr5` + | | + | register `cr` + +error: register `cr6` conflicts with register `cr` + --> $DIR/bad-reg.rs:118:31 + | +LL | asm!("", out("cr") _, out("cr6") _); + | ----------- ^^^^^^^^^^^^ register `cr6` + | | + | register `cr` + +error: register `cr7` conflicts with register `cr` + --> $DIR/bad-reg.rs:120:31 + | +LL | asm!("", out("cr") _, out("cr7") _); + | ----------- ^^^^^^^^^^^^ register `cr7` + | | + | register `cr` + +error: cannot use register `r13`: r13 is a reserved register on this target + --> $DIR/bad-reg.rs:36:18 + | +LL | asm!("", out("r13") _); + | ^^^^^^^^^^^^ + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:66:27 + | +LL | asm!("", in("cr") x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:69:28 + | +LL | asm!("", out("cr") x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:72:33 + | +LL | asm!("/* {} */", in(cr) x); + | ^ + | + = note: register class `cr` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:79:28 + | +LL | asm!("", in("xer") x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:82:29 + | +LL | asm!("", out("xer") x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:85:34 + | +LL | asm!("/* {} */", in(xer) x); + | ^ + | + = note: register class `xer` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:93:27 + | +LL | asm!("", in("v0") x); + | ^ + | + = note: register class `vreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:96:28 + | +LL | asm!("", out("v0") x); + | ^ + | + = note: register class `vreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:99:35 + | +LL | asm!("/* {} */", in(vreg) x); + | ^ + | + = note: register class `vreg` supports these types: + +error: aborting due to 38 previous errors + diff --git a/tests/ui/asm/powerpc/bad-reg.rs b/tests/ui/asm/powerpc/bad-reg.rs new file mode 100644 index 0000000000000..5023ad51838a9 --- /dev/null +++ b/tests/ui/asm/powerpc/bad-reg.rs @@ -0,0 +1,124 @@ +//@ revisions: powerpc powerpc64 powerpc64le aix64 +//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu +//@[powerpc] needs-llvm-components: powerpc +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[powerpc64] needs-llvm-components: powerpc +//@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu +//@[powerpc64le] needs-llvm-components: powerpc +//@[aix64] compile-flags: --target powerpc64-ibm-aix +//@[aix64] needs-llvm-components: powerpc +//@ needs-asm-support + +#![crate_type = "rlib"] +#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +impl Copy for i32 {} + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} + +fn f() { + let mut x = 0; + unsafe { + // Unsupported registers + asm!("", out("sp") _); + //~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + asm!("", out("r2") _); + //~^ ERROR invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm + asm!("", out("r13") _); + //~^ ERROR cannot use register `r13`: r13 is a reserved register on this target + asm!("", out("r29") _); + //~^ ERROR invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm + asm!("", out("r30") _); + //~^ ERROR invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm + asm!("", out("fp") _); + //~^ ERROR invalid register `fp`: the frame pointer cannot be used as an operand for inline asm + asm!("", out("lr") _); + //~^ ERROR invalid register `lr`: the link register cannot be used as an operand for inline asm + asm!("", out("ctr") _); + //~^ ERROR invalid register `ctr`: the counter register cannot be used as an operand for inline asm + asm!("", out("vrsave") _); + //~^ ERROR invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm + asm!("", out("v20") _); + asm!("", out("v21") _); + asm!("", out("v22") _); + asm!("", out("v23") _); + asm!("", out("v24") _); + asm!("", out("v25") _); + asm!("", out("v26") _); + asm!("", out("v27") _); + asm!("", out("v28") _); + asm!("", out("v29") _); + asm!("", out("v30") _); + asm!("", out("v31") _); + + // Clobber-only registers + // cr + asm!("", out("cr") _); // ok + asm!("", in("cr") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("", out("cr") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("/* {} */", in(cr) x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("/* {} */", out(cr) _); + //~^ ERROR can only be used as a clobber + // xer + asm!("", out("xer") _); // ok + asm!("", in("xer") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("", out("xer") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("/* {} */", in(xer) x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("/* {} */", out(xer) _); + //~^ ERROR can only be used as a clobber + // vreg + asm!("", out("v0") _); // ok + // FIXME: will be supported in the subsequent patch: https://github.com/rust-lang/rust/pull/131551 + asm!("", in("v0") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("", out("v0") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("/* {} */", in(vreg) x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("/* {} */", out(vreg) _); + //~^ ERROR can only be used as a clobber + + // Overlapping-only registers + asm!("", out("cr") _, out("cr0") _); + //~^ ERROR register `cr0` conflicts with register `cr` + asm!("", out("cr") _, out("cr1") _); + //~^ ERROR register `cr1` conflicts with register `cr` + asm!("", out("cr") _, out("cr2") _); + //~^ ERROR register `cr2` conflicts with register `cr` + asm!("", out("cr") _, out("cr3") _); + //~^ ERROR register `cr3` conflicts with register `cr` + asm!("", out("cr") _, out("cr4") _); + //~^ ERROR register `cr4` conflicts with register `cr` + asm!("", out("cr") _, out("cr5") _); + //~^ ERROR register `cr5` conflicts with register `cr` + asm!("", out("cr") _, out("cr6") _); + //~^ ERROR register `cr6` conflicts with register `cr` + asm!("", out("cr") _, out("cr7") _); + //~^ ERROR register `cr7` conflicts with register `cr` + asm!("", out("f0") _, out("v0") _); // ok + } +} From 7faa84e20e02c8b7a4afb7c5741e8b59819d7b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Mon, 4 Nov 2024 12:28:26 +0100 Subject: [PATCH 05/11] Stabilise 'const_char_encode_utf16'; --- library/core/src/char/methods.rs | 7 +++++-- library/core/src/lib.rs | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 701e34b135e23..39f421df22747 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -711,7 +711,7 @@ impl char { /// '𝕊'.encode_utf16(&mut b); /// ``` #[stable(feature = "unicode_encode_char", since = "1.15.0")] - #[rustc_const_unstable(feature = "const_char_encode_utf16", issue = "130660")] + #[rustc_const_stable(feature = "const_char_encode_utf16", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { encode_utf16_raw(self as u32, dst) @@ -1819,7 +1819,10 @@ pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { /// Panics if the buffer is not large enough. /// A buffer of length 2 is large enough to encode any `char`. #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] -#[rustc_const_unstable(feature = "const_char_encode_utf16", issue = "130660")] +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_char_encode_utf16", since = "CURRENT_RUSTC_VERSION") +)] #[doc(hidden)] #[inline] pub const fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 12f6997dbeae7..ecebddaa0aef2 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -114,7 +114,6 @@ #![feature(const_align_of_val_raw)] #![feature(const_alloc_layout)] #![feature(const_black_box)] -#![feature(const_char_encode_utf16)] #![feature(const_eval_select)] #![feature(const_exact_div)] #![feature(const_float_methods)] From 02a1ab807191891e888c19b4b8b54de33dba081b Mon Sep 17 00:00:00 2001 From: Eugene Shamis Date: Fri, 1 Nov 2024 15:33:07 -0400 Subject: [PATCH 06/11] Replace checked slice indexing by unchecked to support panic-free code Fixes #126425 Replace the potentially panicking `[]` indexing with `get_unchecked()` to prevent linking with panic-related code. --- library/core/src/fmt/num.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index f1540803f978d..aaf429bac8e7f 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -88,7 +88,9 @@ unsafe trait GenericRadix: Sized { }; } } - let buf = &buf[curr..]; + // SAFETY: `curr` is initialized to `buf.len()` and is only decremented, + // so it is always in bounds. + let buf = unsafe { buf.get_unchecked(curr..) }; // SAFETY: The only chars in `buf` are created by `Self::digit` which are assumed to be // valid UTF-8 let buf = unsafe { From 37f48da802f2f76e210c82731fc7483d7ae96bfd Mon Sep 17 00:00:00 2001 From: Eugene Shamis Date: Mon, 4 Nov 2024 09:50:08 -0500 Subject: [PATCH 07/11] Updated SAFETY comment to address underflow --- library/core/src/fmt/num.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index aaf429bac8e7f..5a5c4d600745f 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -88,8 +88,9 @@ unsafe trait GenericRadix: Sized { }; } } - // SAFETY: `curr` is initialized to `buf.len()` and is only decremented, - // so it is always in bounds. + // SAFETY: `curr` is initialized to `buf.len()` and is only decremented, so it can't overflow. It is + // decremented exactly once for each digit. Since u128 is the widest fixed width integer format dupported, + // the maximum number of digits (bits) is 128 for base-2, so `curr` won't underflow as well. let buf = unsafe { buf.get_unchecked(curr..) }; // SAFETY: The only chars in `buf` are created by `Self::digit` which are assumed to be // valid UTF-8 From 65d8f1b8bfe79a3b88048ce24629456b007f8f4a Mon Sep 17 00:00:00 2001 From: Eugene Shamis Date: Mon, 4 Nov 2024 12:43:57 -0500 Subject: [PATCH 08/11] Fixed typo, rebased --- library/core/src/fmt/num.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 5a5c4d600745f..d43f25d9fd129 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -89,7 +89,7 @@ unsafe trait GenericRadix: Sized { } } // SAFETY: `curr` is initialized to `buf.len()` and is only decremented, so it can't overflow. It is - // decremented exactly once for each digit. Since u128 is the widest fixed width integer format dupported, + // decremented exactly once for each digit. Since u128 is the widest fixed width integer format supported, // the maximum number of digits (bits) is 128 for base-2, so `curr` won't underflow as well. let buf = unsafe { buf.get_unchecked(curr..) }; // SAFETY: The only chars in `buf` are created by `Self::digit` which are assumed to be From 4872b6bcbd8f2800b370b7e05b1ca1e18054a166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Mon, 4 Nov 2024 19:08:28 +0100 Subject: [PATCH 09/11] Improve example of `impl Pattern for &[char]` The previous version used `['l', 'l']` as pattern, which would suggest that it matches the `ll` of `Hello world` as a whole. --- library/core/src/str/pattern.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 665c9fc67d01e..52e2364893eb1 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -886,8 +886,8 @@ impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {} /// # Examples /// /// ``` -/// assert_eq!("Hello world".find(&['l', 'l'] as &[_]), Some(2)); -/// assert_eq!("Hello world".find(&['l', 'l'][..]), Some(2)); +/// assert_eq!("Hello world".find(&['o', 'l'][..]), Some(2)); +/// assert_eq!("Hello world".find(&['h', 'w'][..]), Some(6)); /// ``` impl<'b> Pattern for &'b [char] { pattern_methods!('a, CharSliceSearcher<'a, 'b>, MultiCharEqPattern, CharSliceSearcher); From 107b4fdba21d437e7e36b2a62bc803d6a8f31021 Mon Sep 17 00:00:00 2001 From: NotWearingPants <26556598+NotWearingPants@users.noreply.github.com> Date: Mon, 4 Nov 2024 20:42:21 +0200 Subject: [PATCH 10/11] docs: fix grammar in doc comment at unix/process.rs --- library/std/src/os/unix/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index ef5adaf229088..7c3fa7d6507e7 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -143,7 +143,7 @@ pub trait CommandExt: Sealed { /// /// This function, unlike `spawn`, will **not** `fork` the process to create /// a new child. Like spawn, however, the default behavior for the stdio - /// descriptors will be to inherited from the current process. + /// descriptors will be to inherit them from the current process. /// /// # Notes /// From f4b72dcff01f03b0479b737c007c49c97039d3a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Mon, 4 Nov 2024 14:55:07 +0100 Subject: [PATCH 11/11] Move two attribute lints to be early pass (post expansion) --- .../src/attrs/allow_attributes.rs | 4 +- .../attrs/allow_attributes_without_reason.rs | 4 +- .../attrs/blanket_clippy_restriction_lints.rs | 6 +- .../src/attrs/deprecated_semver.rs | 4 +- .../src/attrs/duplicated_attributes.rs | 8 +- .../src/attrs/mixed_attributes_style.rs | 6 +- .../clippy/clippy_lints/src/attrs/mod.rs | 128 +++++++++++------- .../src/attrs/should_panic_without_expect.rs | 6 +- .../src/attrs/useless_attribute.rs | 8 +- src/tools/clippy/clippy_lints/src/lib.rs | 2 + .../clippy_utils/src/check_proc_macro.rs | 5 +- .../clippy/tests/ui/allow_attributes.stderr | 10 +- .../ui/allow_attributes_without_reason.stderr | 11 +- src/tools/clippy/tests/ui/attrs.stderr | 18 +-- .../blanket_clippy_restriction_lints.stderr | 14 +- 15 files changed, 122 insertions(+), 112 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs index a5a7b9f74a693..1879391ec290b 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs @@ -3,11 +3,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use rustc_ast::{AttrStyle, Attribute}; use rustc_errors::Applicability; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::{EarlyContext, LintContext}; use rustc_middle::lint::in_external_macro; // Separate each crate's features. -pub fn check<'cx>(cx: &LateContext<'cx>, attr: &'cx Attribute) { +pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) { if !in_external_macro(cx.sess(), attr.span) && let AttrStyle::Outer = attr.style && let Some(ident) = attr.ident() diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs index 5d4e864b9b0b5..788377fe83ce4 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -2,12 +2,12 @@ use super::{ALLOW_ATTRIBUTES_WITHOUT_REASON, Attribute}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use rustc_ast::{MetaItemInner, MetaItemKind}; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::{EarlyContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_span::sym; use rustc_span::symbol::Symbol; -pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[MetaItemInner], attr: &'cx Attribute) { +pub(super) fn check<'cx>(cx: &EarlyContext<'cx>, name: Symbol, items: &[MetaItemInner], attr: &'cx Attribute) { // Check if the reason is present if let Some(item) = items.last().and_then(MetaItemInner::meta_item) && let MetaItemKind::NameValue(_) = &item.kind diff --git a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs index 0baf889faa076..fecf316640636 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs @@ -2,11 +2,11 @@ use super::BLANKET_CLIPPY_RESTRICTION_LINTS; use super::utils::extract_clippy_lint; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use rustc_ast::MetaItemInner; -use rustc_lint::{LateContext, Level, LintContext}; +use rustc_lint::{EarlyContext, Level, LintContext}; use rustc_span::symbol::Symbol; use rustc_span::{DUMMY_SP, sym}; -pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[MetaItemInner]) { +pub(super) fn check(cx: &EarlyContext<'_>, name: Symbol, items: &[MetaItemInner]) { for lint in items { if let Some(lint_name) = extract_clippy_lint(lint) { if lint_name.as_str() == "restriction" && name != sym::allow { @@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[MetaItemInner]) } } -pub(super) fn check_command_line(cx: &LateContext<'_>) { +pub(super) fn check_command_line(cx: &EarlyContext<'_>) { for (name, level) in &cx.sess().opts.lint_opts { if name == "clippy::restriction" && *level > Level::Allow { span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs index 1898c145c76a9..d3153ec6613b5 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs @@ -1,11 +1,11 @@ use super::DEPRECATED_SEMVER; use clippy_utils::diagnostics::span_lint; use rustc_ast::{LitKind, MetaItemLit}; -use rustc_lint::LateContext; +use rustc_lint::EarlyContext; use rustc_span::Span; use semver::Version; -pub(super) fn check(cx: &LateContext<'_>, span: Span, lit: &MetaItemLit) { +pub(super) fn check(cx: &EarlyContext<'_>, span: Span, lit: &MetaItemLit) { if let LitKind::Str(is, _) = lit.kind { if is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok() { return; diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs index 55f8e1072db74..2ddbc7a6a76dc 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs @@ -2,12 +2,12 @@ use super::DUPLICATED_ATTRIBUTES; use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::{Attribute, MetaItem}; use rustc_data_structures::fx::FxHashMap; -use rustc_lint::LateContext; +use rustc_lint::EarlyContext; use rustc_span::{Span, sym}; use std::collections::hash_map::Entry; fn emit_if_duplicated( - cx: &LateContext<'_>, + cx: &EarlyContext<'_>, attr: &MetaItem, attr_paths: &mut FxHashMap, complete_path: String, @@ -26,7 +26,7 @@ fn emit_if_duplicated( } fn check_duplicated_attr( - cx: &LateContext<'_>, + cx: &EarlyContext<'_>, attr: &MetaItem, attr_paths: &mut FxHashMap, parent: &mut Vec, @@ -65,7 +65,7 @@ fn check_duplicated_attr( } } -pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { +pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { let mut attr_paths = FxHashMap::default(); for attr in attrs { diff --git a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs index 5d2ea36b366c1..32c28c09c3602 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::{AttrKind, AttrStyle, Attribute}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::{EarlyContext, LintContext}; use rustc_span::source_map::SourceMap; use rustc_span::{SourceFile, Span, Symbol}; @@ -32,7 +32,7 @@ impl From<&AttrKind> for SimpleAttrKind { } } -pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) { +pub(super) fn check(cx: &EarlyContext<'_>, item_span: Span, attrs: &[Attribute]) { let mut inner_attr_kind: FxHashSet = FxHashSet::default(); let mut outer_attr_kind: FxHashSet = FxHashSet::default(); @@ -64,7 +64,7 @@ pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) } } -fn lint_mixed_attrs(cx: &LateContext<'_>, attrs: &[Attribute]) { +fn lint_mixed_attrs(cx: &EarlyContext<'_>, attrs: &[Attribute]) { let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion()); let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) { first.span.with_hi(last.span.hi()) diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 1a34ca99fc2b9..684756ce87f1d 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -14,8 +14,8 @@ mod utils; use clippy_config::Conf; use clippy_config::msrvs::{self, Msrv}; -use rustc_ast::{Attribute, MetaItemInner, MetaItemKind}; -use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; +use rustc_ast::{Attribute, MetaItemInner, MetaItemKind, self as ast}; +use rustc_hir::{ImplItem, Item, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::sym; @@ -414,15 +414,7 @@ pub struct Attributes { } impl_lint_pass!(Attributes => [ - ALLOW_ATTRIBUTES, - ALLOW_ATTRIBUTES_WITHOUT_REASON, INLINE_ALWAYS, - DEPRECATED_SEMVER, - USELESS_ATTRIBUTE, - BLANKET_CLIPPY_RESTRICTION_LINTS, - SHOULD_PANIC_WITHOUT_EXPECT, - MIXED_ATTRIBUTES_STYLE, - DUPLICATED_ATTRIBUTES, ]); impl Attributes { @@ -434,53 +426,11 @@ impl Attributes { } impl<'tcx> LateLintPass<'tcx> for Attributes { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - blanket_clippy_restriction_lints::check_command_line(cx); - duplicated_attributes::check(cx, cx.tcx.hir().krate_attrs()); - } - - fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) { - if let Some(items) = &attr.meta_item_list() { - if let Some(ident) = attr.ident() { - if is_lint_level(ident.name, attr.id) { - blanket_clippy_restriction_lints::check(cx, ident.name, items); - } - if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { - allow_attributes::check(cx, attr); - } - if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) - { - allow_attributes_without_reason::check(cx, ident.name, items, attr); - } - if items.is_empty() || !attr.has_name(sym::deprecated) { - return; - } - for item in items { - if let MetaItemInner::MetaItem(mi) = &item - && let MetaItemKind::NameValue(lit) = &mi.kind - && mi.has_name(sym::since) - { - deprecated_semver::check(cx, item.span(), lit); - } - } - } - } - if attr.has_name(sym::should_panic) { - should_panic_without_expect::check(cx, attr); - } - } - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); if is_relevant_item(cx, item) { inline_always::check(cx, item.span, item.ident.name, attrs); } - match item.kind { - ItemKind::ExternCrate(..) | ItemKind::Use(..) => useless_attribute::check(cx, item, attrs), - _ => {}, - } - mixed_attributes_style::check(cx, item.span, attrs); - duplicated_attributes::check(cx, attrs); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { @@ -526,3 +476,77 @@ impl EarlyLintPass for EarlyAttributes { extract_msrv_attr!(EarlyContext); } + +pub struct PostExpansionEarlyAttributes { + msrv: Msrv, +} + +impl PostExpansionEarlyAttributes { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} + +impl_lint_pass!(PostExpansionEarlyAttributes => [ + ALLOW_ATTRIBUTES, + ALLOW_ATTRIBUTES_WITHOUT_REASON, + DEPRECATED_SEMVER, + USELESS_ATTRIBUTE, + BLANKET_CLIPPY_RESTRICTION_LINTS, + SHOULD_PANIC_WITHOUT_EXPECT, + MIXED_ATTRIBUTES_STYLE, + DUPLICATED_ATTRIBUTES, +]); + +impl EarlyLintPass for PostExpansionEarlyAttributes { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) { + blanket_clippy_restriction_lints::check_command_line(cx); + duplicated_attributes::check(cx, &krate.attrs); + } + + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { + if let Some(items) = &attr.meta_item_list() { + if let Some(ident) = attr.ident() { + if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + allow_attributes::check(cx, attr); + } + if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) + { + allow_attributes_without_reason::check(cx, ident.name, items, attr); + } + if is_lint_level(ident.name, attr.id) { + blanket_clippy_restriction_lints::check(cx, ident.name, items); + } + if items.is_empty() || !attr.has_name(sym::deprecated) { + return; + } + for item in items { + if let MetaItemInner::MetaItem(mi) = &item + && let MetaItemKind::NameValue(lit) = &mi.kind + && mi.has_name(sym::since) + { + deprecated_semver::check(cx, item.span(), lit); + } + } + } + } + + if attr.has_name(sym::should_panic) { + should_panic_without_expect::check(cx, attr); + } + } + + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &'_ ast::Item) { + match item.kind { + ast::ItemKind::ExternCrate(..) | ast::ItemKind::Use(..) => useless_attribute::check(cx, item, &item.attrs), + _ => {}, + } + + mixed_attributes_style::check(cx, item.span, &item.attrs); + duplicated_attributes::check(cx, &item.attrs); + } + + extract_msrv_attr!(EarlyContext); +} diff --git a/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs b/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs index 2d45cbbf621f4..fadd527288028 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs @@ -4,12 +4,12 @@ use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::TokenTree; use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind}; use rustc_errors::Applicability; -use rustc_lint::LateContext; +use rustc_lint::EarlyContext; use rustc_span::sym; -pub(super) fn check(cx: &LateContext<'_>, attr: &Attribute) { +pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { if let AttrKind::Normal(normal_attr) = &attr.kind { - if let AttrArgs::Eq(_, AttrArgsEq::Hir(_)) = &normal_attr.item.args { + if let AttrArgs::Eq(_, AttrArgsEq::Ast(_)) = &normal_attr.item.args { // `#[should_panic = ".."]` found, good return; } diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index 72e6ce59d5980..92b9f9cba5251 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -1,15 +1,15 @@ use super::utils::{extract_clippy_lint, is_lint_level, is_word}; -use super::{Attribute, USELESS_ATTRIBUTE}; +use super::USELESS_ATTRIBUTE; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{SpanRangeExt, first_line_of_span}; use rustc_ast::MetaItemInner; use rustc_errors::Applicability; -use rustc_hir::{Item, ItemKind}; -use rustc_lint::{LateContext, LintContext}; +use rustc_ast::{Item, ItemKind, Attribute}; +use rustc_lint::{EarlyContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_span::sym; -pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute]) { +pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use)); for attr in attrs { diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 14110539709d6..3fd07ced0e4ae 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -412,6 +412,8 @@ use rustc_lint::{Lint, LintId}; pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes::new(conf))); + + store.register_early_pass(move || Box::new(attrs::PostExpansionEarlyAttributes::new(conf))); } #[derive(Default)] diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index bfb3a76ad251c..c5e2c8c09a277 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -21,7 +21,7 @@ use rustc_hir::{ ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, }; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::{LateContext, LintContext, EarlyContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::symbol::{Ident, kw}; @@ -429,11 +429,12 @@ impl_with_search_pat!((_cx: LateContext<'tcx>, self: ImplItem<'_>) => impl_item_ impl_with_search_pat!((_cx: LateContext<'tcx>, self: FieldDef<'_>) => field_def_search_pat(self)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Variant<'_>) => variant_search_pat(self)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ty<'_>) => ty_search_pat(self)); -impl_with_search_pat!((_cx: LateContext<'tcx>, self: Attribute) => attr_search_pat(self)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ident) => ident_search_pat(*self)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Lit) => lit_search_pat(&self.node)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Path<'_>) => path_search_pat(self)); +impl_with_search_pat!((_cx: EarlyContext<'tcx>, self: Attribute) => attr_search_pat(self)); + impl<'cx> WithSearchPat<'cx> for (&FnKind<'cx>, &Body<'cx>, HirId, Span) { type Context = LateContext<'cx>; diff --git a/src/tools/clippy/tests/ui/allow_attributes.stderr b/src/tools/clippy/tests/ui/allow_attributes.stderr index 10dac0bc80808..023b4d7e40439 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.stderr +++ b/src/tools/clippy/tests/ui/allow_attributes.stderr @@ -19,13 +19,5 @@ error: #[allow] attribute found LL | #[allow(unused)] | ^^^^^ help: replace it with: `expect` -error: #[allow] attribute found - --> tests/ui/allow_attributes.rs:52:7 - | -LL | #[allow(unused)] - | ^^^^^ help: replace it with: `expect` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr index 86d7845df0416..9c1ac5af91b06 100644 --- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr +++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr @@ -43,14 +43,5 @@ LL | #[allow(unused)] | = help: try adding a reason at the end with `, reason = ".."` -error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:46:5 - | -LL | #[allow(unused)] - | ^^^^^^^^^^^^^^^^ - | - = help: try adding a reason at the end with `, reason = ".."` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/attrs.stderr b/src/tools/clippy/tests/ui/attrs.stderr index cd409fc8701b6..a7fdceaba6f39 100644 --- a/src/tools/clippy/tests/ui/attrs.stderr +++ b/src/tools/clippy/tests/ui/attrs.stderr @@ -1,12 +1,3 @@ -error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea - --> tests/ui/attrs.rs:5:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::inline-always` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::inline_always)]` - error: the since field must contain a semver-compliant version --> tests/ui/attrs.rs:27:14 | @@ -22,5 +13,14 @@ error: the since field must contain a semver-compliant version LL | #[deprecated(since = "1")] | ^^^^^^^^^^^ +error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea + --> tests/ui/attrs.rs:5:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::inline-always` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inline_always)]` + error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr index d410f25b2c274..1bad259b09a36 100644 --- a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr +++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr @@ -1,3 +1,10 @@ +error: `clippy::restriction` is not meant to be enabled as a group + | + = note: because of the command line `--warn clippy::restriction` + = help: enable the restriction lints you need individually + = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::blanket_clippy_restriction_lints)]` + error: `clippy::restriction` is not meant to be enabled as a group --> tests/ui/blanket_clippy_restriction_lints.rs:6:9 | @@ -5,8 +12,6 @@ LL | #![warn(clippy::restriction)] | ^^^^^^^^^^^^^^^^^^^ | = help: enable the restriction lints you need individually - = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::blanket_clippy_restriction_lints)]` error: `clippy::restriction` is not meant to be enabled as a group --> tests/ui/blanket_clippy_restriction_lints.rs:8:9 @@ -24,10 +29,5 @@ LL | #![forbid(clippy::restriction)] | = help: enable the restriction lints you need individually -error: `clippy::restriction` is not meant to be enabled as a group - | - = note: because of the command line `--warn clippy::restriction` - = help: enable the restriction lints you need individually - error: aborting due to 4 previous errors