diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 6a0ad2d19c45e..19affac7970b9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1778,9 +1778,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If this type is a GAT, and of the GAT args resolve to something new, // that means that we must have newly inferred something about the GAT. // We should give up in that case. + // FIXME(generic-associated-types): This only detects one layer of inference, + // which is probably not what we actually want, but fixing it causes some ambiguity: + // . if !generics.own_params.is_empty() && obligation.predicate.args[generics.parent_count..].iter().any(|&p| { - p.has_non_region_infer() && self.infcx.resolve_vars_if_possible(p) != p + p.has_non_region_infer() + && match p.unpack() { + ty::GenericArgKind::Const(ct) => { + self.infcx.shallow_resolve_const(ct) != ct + } + ty::GenericArgKind::Type(ty) => self.infcx.shallow_resolve(ty) != ty, + ty::GenericArgKind::Lifetime(_) => false, + } }) { ProjectionMatchesProjection::Ambiguous diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 2a859ad55eed2..335a1a8ffb370 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1940,8 +1940,10 @@ impl String { /// Converts this `String` into a [Box]<[str]>. /// - /// This will drop any excess capacity. + /// Before doing the conversion, this method discards excess capacity like [`shrink_to_fit`]. + /// Note that this call may reallocate and copy the bytes of the string. /// + /// [`shrink_to_fit`]: String::shrink_to_fit /// [str]: prim@str "str" /// /// # Examples @@ -1967,10 +1969,10 @@ impl String { /// this function is ideally used for data that lives for the remainder of the program's life, /// as dropping the returned reference will cause a memory leak. /// - /// It does not reallocate or shrink the `String`, - /// so the leaked allocation may include unused capacity that is not part - /// of the returned slice. If you don't want that, call [`into_boxed_str`], - /// and then [`Box::leak`]. + /// It does not reallocate or shrink the `String`, so the leaked allocation may include unused + /// capacity that is not part of the returned slice. If you want to discard excess capacity, + /// call [`into_boxed_str`], and then [`Box::leak`] instead. However, keep in mind that + /// trimming the capacity may result in a reallocation and copy. /// /// [`into_boxed_str`]: Self::into_boxed_str /// diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index a931782e8ccbe..6b8106bbc214a 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2915,7 +2915,6 @@ ui/macros/issue-95267.rs ui/macros/issue-95533.rs ui/macros/issue-98466-allow.rs ui/macros/issue-98466.rs -ui/macros/issue-98790.rs ui/macros/issue-99261.rs ui/macros/issue-99265.rs ui/macros/issue-99907.rs diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 94a0eee154d93..6e92dab1abc11 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -41,6 +41,7 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ "tests/ui/macros/not-utf8.bin", // testing including data with the include macros "tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include "tests/ui/proc-macro/auxiliary/included-file.txt", // more include + "tests/ui/unpretty/auxiliary/data.txt", // more include "tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer "tests/ui/sanitizer/dataflow-abilist.txt", // dataflow sanitizer ABI list file "tests/ui/shell-argfiles/shell-argfiles.args", // passing args via a file diff --git a/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs b/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs new file mode 100644 index 0000000000000..96a0f2f40bf49 --- /dev/null +++ b/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs @@ -0,0 +1,19 @@ +// Fix for . +//@ check-pass + +trait Tr { + type Gat; +} + +struct W(T); + +fn foo() where for<'a> &'a T: Tr> = i32> { + let x: <&T as Tr>::Gat> = 1i32; + // Previously, `match_projection_projections` only checked that + // `shallow_resolve(W) = W`. This won't prevent *all* inference guidance + // from projection predicates in the environment, just ones that guide the + // outermost type of each GAT constructor. This is definitely wrong, but there is + // code that relies on it in the wild :/ +} + +fn main() {} diff --git a/tests/ui/macros/issue-98790.rs b/tests/ui/macros/issue-98790.rs deleted file mode 100644 index b489efe9ce939..0000000000000 --- a/tests/ui/macros/issue-98790.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ run-pass - -macro_rules! stringify_item { - ($item:item) => { - stringify!($item) - }; -} - -macro_rules! repro { - ($expr:expr) => { - stringify_item! { - pub fn repro() -> bool { - $expr - } - } - }; -} - -fn main() { - assert_eq!( - repro!(match () { () => true } | true), - "pub fn repro() -> bool { (match () { () => true, }) | true }" - ); -} diff --git a/tests/ui/unpretty/auxiliary/data.txt b/tests/ui/unpretty/auxiliary/data.txt new file mode 100644 index 0000000000000..2f62e4609f40e --- /dev/null +++ b/tests/ui/unpretty/auxiliary/data.txt @@ -0,0 +1 @@ +data for include_bytes in ../expanded-exhaustive.rs diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs new file mode 100644 index 0000000000000..6aa032d7ed83e --- /dev/null +++ b/tests/ui/unpretty/expanded-exhaustive.rs @@ -0,0 +1,888 @@ +//@ compile-flags: -Zunpretty=expanded -Zunstable-options +//@ edition:2024 +//@ check-pass + +#![feature(async_closure)] +#![feature(auto_traits)] +#![feature(box_patterns)] +#![feature(builtin_syntax)] +#![feature(concat_idents)] +#![feature(const_trait_impl)] +#![feature(core_pattern_type)] +#![feature(decl_macro)] +#![feature(deref_patterns)] +#![feature(explicit_tail_calls)] +#![feature(gen_blocks)] +#![feature(let_chains)] +#![feature(more_qualified_paths)] +#![feature(never_patterns)] +#![feature(never_type)] +#![feature(pattern_types)] +#![feature(prelude_import)] +#![feature(raw_ref_op)] +#![feature(specialization)] +#![feature(trace_macros)] +#![feature(trait_alias)] +#![feature(try_blocks)] +#![feature(unnamed_fields)] +#![feature(yeet_expr)] +#![allow(incomplete_features)] + +#[prelude_import] +use self::prelude::*; + +mod prelude { + pub use std::prelude::rust_2024::*; + + pub type T = _; + + pub trait Trait { + const CONST: (); + } +} + +mod attributes { + //! inner single-line doc comment + /*! + * inner multi-line doc comment + */ + #![doc = "inner doc attribute"] + #![allow(dead_code, unused_variables)] + #![no_std] + + /// outer single-line doc comment + /** + * outer multi-line doc comment + */ + #[doc = "outer doc attribute"] + #[doc = concat!("mac", "ro")] + #[allow()] + #[repr(C)] + struct Struct; +} + +mod expressions { + /// ExprKind::Array + fn expr_array() { + []; + [true]; + [true,]; + [true, true]; + ["long........................................................................"]; + ["long............................................................", true]; + } + + /// ExprKind::ConstBlock + fn expr_const_block() { + const {}; + const { 1 }; + const { struct S; }; + } + + /// ExprKind::Call + fn expr_call() { + let f; + f(); + f::(); + f::<1>(); + f::<'static, u8, 1>(); + f(true); + f(true,); + ()(); + } + + /// ExprKind::MethodCall + fn expr_method_call() { + let x; + x.f(); + x.f::(); + x.collect::>(); + } + + /// ExprKind::Tup + fn expr_tup() { + (); + (true,); + (true, false); + (true, false,); + } + + /// ExprKind::Binary + fn expr_binary() { + let (a, b, c, d, x, y); + true || false; + true || false && false; + a < 1 && 2 < b && c > 3 && 4 > d; + a & b & !c; + a + b * c - d + -1 * -2 - -3; + x = !y; + } + + /// ExprKind::Unary + fn expr_unary() { + let expr; + *expr; + !expr; + -expr; + } + + /// ExprKind::Lit + fn expr_lit() { + 'x'; + 1_000_i8; + 1.00000000000000000000001; + } + + /// ExprKind::Cast + fn expr_cast() { + let expr; + expr as T; + expr as T; + } + + /// ExprKind::Type + fn expr_type() { + let expr; + builtin # type_ascribe(expr, T); + } + + /// ExprKind::Let + fn expr_let() { + let b; + if let Some(a) = b {} + if let _ = true && false {} + if let _ = (true && false) {} + } + + /// ExprKind::If + fn expr_if() { + if true {} + if !true {} + if let true = true {} else {} + if true {} else if false {} + if true {} else if false {} else {} + if true { return; } else if false { 0 } else { 0 } + } + + /// ExprKind::While + fn expr_while() { + while false {} + 'a: while false {} + while let true = true {} + } + + /// ExprKind::ForLoop + fn expr_for_loop() { + let x; + for _ in x {} + 'a: for _ in x {} + } + + /// ExprKind::Loop + fn expr_loop() { + loop {} + 'a: loop {} + } + + /// ExprKind::Match + fn expr_match() { + let value; + match value {} + match value { ok => 1 } + match value { + ok => 1, + err => 0, + } + } + + /// ExprKind::Closure + fn expr_closure() { + let value; + || {}; + |x| {}; + |x: u8| {}; + || (); + move || value; + async || value; + async move || value; + static || value; + static move || value; + (static async || value); + (static async move || value); + || -> u8 { value }; + 1 + || {}; + } + + /// ExprKind::Block + fn expr_block() { + {} + unsafe {} + 'a: {} + #[allow()] {} + { #![allow()] } + } + + /// ExprKind::Gen + fn expr_gen() { + async {}; + async move {}; + gen {}; + gen move {}; + async gen {}; + async gen move {}; + } + + /// ExprKind::Await + fn expr_await() { + let fut; + fut.await; + } + + /// ExprKind::TryBlock + fn expr_try_block() { + try {} + try { return; } + } + + /// ExprKind::Assign + fn expr_assign() { + let expr; + expr = true; + } + + /// ExprKind::AssignOp + fn expr_assign_op() { + let expr; + expr += true; + } + + /// ExprKind::Field + fn expr_field() { + let expr; + expr.field; + expr.0; + } + + /// ExprKind::Index + fn expr_index() { + let expr; + expr[true]; + } + + /// ExprKind::Range + fn expr_range() { + let (lo, hi); + ..; + ..hi; + lo..; + lo..hi; + lo .. hi; + ..=hi; + lo..=hi; + -2..=-1; + } + + /// ExprKind::Underscore + fn expr_underscore() { + _; + } + + /// ExprKind::Path + fn expr_path() { + let x; + crate::expressions::expr_path; + crate::expressions::expr_path::<'static>; + ::default; + ::default::<>; + x::(); + x::(T, T) -> T; + crate::() -> ()::expressions::() -> ()::expr_path; + core::()::marker::()::PhantomData; + } + + /// ExprKind::AddrOf + fn expr_addr_of() { + let expr; + &expr; + &mut expr; + &raw const expr; + &raw mut expr; + } + + /// ExprKind::Break + fn expr_break() { + 'a: { + break; + break 'a; + break true; + break 'a true; + } + } + + /// ExprKind::Continue + fn expr_continue() { + 'a: { + continue; + continue 'a; + } + } + + /// ExprKind::Ret + fn expr_ret() { + return; + return true; + } + + /// ExprKind::InlineAsm + fn expr_inline_asm() { + let x; + core::arch::asm!( + "mov {tmp}, {x}", + "shl {tmp}, 1", + "shl {x}, 2", + "add {x}, {tmp}", + x = inout(reg) x, + tmp = out(reg) _, + ); + } + + /// ExprKind::OffsetOf + fn expr_offset_of() { + core::mem::offset_of!(T, field); + } + + /// ExprKind::MacCall + fn expr_mac_call() { + stringify!(...); + stringify![...]; + stringify! { ... }; + } + + /// ExprKind::Struct + fn expr_struct() { + struct Struct {} + let (x, base); + Struct {}; + ::Owned {}; + Struct { .. }; + Struct { .. base }; + Struct { x }; + Struct { x, ..base }; + Struct { x: true }; + Struct { x: true, .. }; + Struct { x: true, ..base }; + Struct { 0: true, ..base }; + } + + /// ExprKind::Repeat + fn expr_repeat() { + [(); 0]; + } + + /// ExprKind::Paren + fn expr_paren() { + let expr; + (expr); + } + + /// ExprKind::Try + fn expr_try() { + let expr; + expr?; + } + + /// ExprKind::Yield + fn expr_yield() { + yield; + yield true; + } + + /// ExprKind::Yeet + fn expr_yeet() { + do yeet; + do yeet 0; + } + + /// ExprKind::Become + fn expr_become() { + become true; + } + + /// ExprKind::IncludedBytes + fn expr_include_bytes() { + include_bytes!("auxiliary/data.txt"); + } + + /// ExprKind::FormatArgs + fn expr_format_args() { + let expr; + format_args!(""); + format_args!("{}", expr); + } +} + +mod items { + /// ItemKind::ExternCrate + mod item_extern_crate { + extern crate core; + extern crate self as unpretty; + pub extern crate core as _; + } + + /// ItemKind::Use + mod item_use { + use crate::{expressions, items::item_use}; + pub use core::*; + } + + /// ItemKind::Static + mod item_static { + pub static A: () = {}; + static mut B: () = {}; + } + + /// ItemKind::Const + mod item_const { + pub const A: () = {}; + + trait TraitItems { + const B: (); + const C: () = {}; + } + } + + /// ItemKind::Fn + mod item_fn { + pub const unsafe extern "C" fn f() {} + pub async unsafe extern fn g() {} + fn h<'a, T>() where T: 'a {} + + trait TraitItems { + unsafe extern fn f(); + } + + impl TraitItems for _ { + default unsafe extern fn f() {} + } + } + + /// ItemKind::Mod + mod item_mod { + // ... + } + + /// ItemKind::ForeignMod + mod item_foreign_mod { + extern "C++" {} + extern {} + } + + /// ItemKind::GlobalAsm + mod item_global_asm { + core::arch::global_asm!(".globl my_asm_func"); + } + + /// ItemKind::TyAlias + mod item_ty_alias { + pub type Type<'a> where T: 'a, = T; + } + + /// ItemKind::Enum + mod item_enum { + pub enum Void {} + enum Empty { + Unit, + Tuple(), + Struct {}, + } + enum Generic<'a, T> + where + T: 'a, + { + Tuple(T), + Struct { t: T }, + } + } + + /// ItemKind::Struct + mod item_struct { + pub struct Unit; + struct Tuple(); + struct Newtype(Unit); + struct Struct {} + struct Generic<'a, T> + where + T: 'a, + { + t: T, + } + } + + /// ItemKind::Union + mod item_union { + union Generic<'a, T> + where + T: 'a, + { + t: T, + } + } + + /// ItemKind::Trait + mod item_trait { + pub unsafe auto trait Send {} + trait Trait<'a>: Sized + where + Self: 'a, + { + } + } + + /// ItemKind::TraitAlias + mod item_trait_alias { + pub trait Trait = Sized where for<'a> T: 'a; + } + + /// ItemKind::Impl + mod item_impl { + impl () {} + impl () {} + impl Default for () {} + impl const Default for () {} + } + + /// ItemKind::MacCall + mod item_mac_call { + trace_macros!(false); + trace_macros![false]; + trace_macros! { false } + } + + /// ItemKind::MacroDef + mod item_macro_def { + macro_rules! mac { () => {...}; } + pub macro stringify() {} + } + + /// ItemKind::Delegation + mod item_delegation { + /*! FIXME: todo */ + } + + /// ItemKind::DelegationMac + mod item_delegation_mac { + /*! FIXME: todo */ + } +} + +mod patterns { + /// PatKind::Wild + fn pat_wild() { + let _; + } + + /// PatKind::Ident + fn pat_ident() { + let x; + let ref x; + let mut x; + let ref mut x; + let ref mut x @ _; + } + + /// PatKind::Struct + fn pat_struct() { + let T {}; + let T:: {}; + let T::<'static> {}; + let T { x }; + let T { x: _x }; + let T { .. }; + let T { x, .. }; + let T { x: _x, .. }; + let T { 0: _x, .. }; + let ::Owned {}; + } + + /// PatKind::TupleStruct + fn pat_tuple_struct() { + struct Tuple(); + let Tuple(); + let Tuple::(); + let Tuple::<'static>(); + let Tuple(x); + let Tuple(..); + let Tuple(x, ..); + } + + /// PatKind::Or + fn pat_or() { + let (true | false); + let (| true); + let (|true| false); + } + + /// PatKind::Path + fn pat_path() { + let core::marker::PhantomData; + let core::marker::PhantomData::; + let core::marker::PhantomData::<'static>; + let ::CONST; + } + + /// PatKind::Tuple + fn pat_tuple() { + let (); + let (true,); + let (true, false); + } + + /// PatKind::Box + fn pat_box() { + let box pat; + } + + /// PatKind::Deref + fn pat_deref() { + let deref!(pat); + } + + /// PatKind::Ref + fn pat_ref() { + let &pat; + let &mut pat; + } + + /// PatKind::Lit + fn pat_lit() { + let 1_000_i8; + let -""; + } + + /// PatKind::Range + fn pat_range() { + let ..1; + let 0..; + let 0..1; + let 0..=1; + let -2..=-1; + } + + /// PatKind::Slice + fn pat_slice() { + let []; + let [true]; + let [true,]; + let [true, false]; + } + + /// PatKind::Rest + fn pat_rest() { + let ..; + } + + /// PatKind::Never + fn pat_never() { + let !; + let Some(!); + } + + /// PatKind::Paren + fn pat_paren() { + let (pat); + } + + /// PatKind::MacCall + fn pat_mac_call() { + let stringify!(); + let stringify![]; + let stringify! {}; + } +} + +mod statements { + /// StmtKind::Let + fn stmt_let() { + let _; + let _ = true; + let _: T = true; + let _ = true else { return; }; + } + + /// StmtKind::Item + fn stmt_item() { + struct Struct {} + struct Unit; + } + + /// StmtKind::Expr + fn stmt_expr() { + () + } + + /// StmtKind::Semi + fn stmt_semi() { + 1 + 1; + } + + /// StmtKind::Empty + fn stmt_empty() { + ; + } + + /// StmtKind::MacCall + fn stmt_mac_call() { + stringify!(...); + stringify![...]; + stringify! { ... }; + } +} + +mod types { + /// TyKind::Slice + fn ty_slice() { + let _: [T]; + } + + /// TyKind::Array + fn ty_array() { + let _: [T; 0]; + } + + /// TyKind::Ptr + fn ty_ptr() { + let _: *const T; + let _: *mut T; + } + + /// TyKind::Ref + fn ty_ref() { + let _: &T; + let _: &mut T; + let _: &'static T; + let _: &'static mut [T]; + let _: &T>>>; + let _: &T > > >; + } + + /// TyKind::BareFn + fn ty_bare_fn() { + let _: fn(); + let _: fn() -> (); + let _: fn(T); + let _: fn(t: T); + let _: for<> fn(); + let _: for<'a> fn(); + } + + /// TyKind::Never + fn ty_never() { + let _: !; + } + + /// TyKind::Tup + fn ty_tup() { + let _: (); + let _: (T,); + let _: (T, T); + } + + /// TyKind::AnonStruct + fn ty_anon_struct() { + struct Struct { + _: struct { t: T }, + } + } + + /// TyKind::AnonUnion + fn ty_anon_union() { + struct Struct { + _: union { t: T }, + } + } + + /// TyKind::Path + fn ty_path() { + let _: T; + let _: T<'static>; + let _: T; + let _: T::; + let _: T() -> !; + let _: ::Owned; + } + + /// TyKind::TraitObject + fn ty_trait_object() { + let _: dyn Send; + let _: dyn Send + 'static; + let _: dyn 'static + Send; + let _: dyn for<'a> Send; + } + + /// TyKind::ImplTrait + const fn ty_impl_trait() { + let _: impl Send; + let _: impl Send + 'static; + let _: impl 'static + Send; + let _: impl ?Sized; + let _: impl ~const Clone; + let _: impl for<'a> Send; + } + + /// TyKind::Paren + fn ty_paren() { + let _: (T); + } + + /// TyKind::Typeof + fn ty_typeof() { + /*! unused for now */ + } + + /// TyKind::Infer + fn ty_infer() { + let _: _; + } + + /// TyKind::ImplicitSelf + fn ty_implicit_self() { + /*! there is no syntax for this */ + } + + /// TyKind::MacCall + fn ty_mac_call() { + let _: concat_idents!(T); + let _: concat_idents![T]; + let _: concat_idents! { T }; + } + + /// TyKind::CVarArgs + fn ty_c_var_args() { + /*! FIXME: todo */ + } + + /// TyKind::Pat + fn ty_pat() { + let _: core::pattern_type!(u32 is 1..); + } +} + +mod visibilities { + /// VisibilityKind::Public + mod visibility_public { + pub struct Pub; + } + + /// VisibilityKind::Restricted + mod visibility_restricted { + pub(crate) struct PubCrate; + pub(self) struct PubSelf; + pub(super) struct PubSuper; + pub(in crate) struct PubInCrate; + pub(in self) struct PubInSelf; + pub(in super) struct PubInSuper; + pub(in crate::visibilities) struct PubInCrateVisibilities; + pub(in self::super) struct PubInSelfSuper; + pub(in super::visibility_restricted) struct PubInSuperMod; + } +} diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout new file mode 100644 index 0000000000000..325bace7b5624 --- /dev/null +++ b/tests/ui/unpretty/expanded-exhaustive.stdout @@ -0,0 +1,719 @@ +#![feature(prelude_import)] +//@ compile-flags: -Zunpretty=expanded -Zunstable-options +//@ edition:2024 +//@ check-pass + +#![feature(async_closure)] +#![feature(auto_traits)] +#![feature(box_patterns)] +#![feature(builtin_syntax)] +#![feature(concat_idents)] +#![feature(const_trait_impl)] +#![feature(core_pattern_type)] +#![feature(decl_macro)] +#![feature(deref_patterns)] +#![feature(explicit_tail_calls)] +#![feature(gen_blocks)] +#![feature(let_chains)] +#![feature(more_qualified_paths)] +#![feature(never_patterns)] +#![feature(never_type)] +#![feature(pattern_types)] +#![feature(prelude_import)] +#![feature(raw_ref_op)] +#![feature(specialization)] +#![feature(trace_macros)] +#![feature(trait_alias)] +#![feature(try_blocks)] +#![feature(unnamed_fields)] +#![feature(yeet_expr)] +#![allow(incomplete_features)] +#[prelude_import] +use std::prelude::rust_2024::*; +#[macro_use] +extern crate std; + +#[prelude_import] +use self::prelude::*; + +mod prelude { + pub use std::prelude::rust_2024::*; + + pub type T = _; + + pub trait Trait { + const CONST: (); + } +} + +mod attributes { + //! inner single-line doc comment + /*! + * inner multi-line doc comment + */ + #![doc = "inner doc attribute"] + #![allow(dead_code, unused_variables)] + #![no_std] + + /// outer single-line doc comment + /** + * outer multi-line doc comment + */ + #[doc = "outer doc attribute"] + #[doc = "macro"] + #[allow()] + #[repr(C)] + struct Struct; +} + +mod expressions { + /// ExprKind::Array + fn expr_array() { + []; + [true]; + [true]; + [true, true]; + ["long........................................................................"]; + ["long............................................................", + true]; + } + + /// ExprKind::ConstBlock + fn expr_const_block() { + const {}; + const { 1 }; + const { + struct S; + }; + } + + /// ExprKind::Call + fn expr_call() { + let f; + f(); + f::(); + f::<1>(); + f::<'static, u8, 1>(); + f(true); + f(true); + ()(); + } + + /// ExprKind::MethodCall + fn expr_method_call() { + let x; + x.f(); + x.f::(); + x.collect::>(); + } + + /// ExprKind::Tup + fn expr_tup() { (); (true,); (true, false); (true, false); } + + /// ExprKind::Binary + fn expr_binary() { + let (a, b, c, d, x, y); + true || false; + true || false && false; + a < 1 && 2 < b && c > 3 && 4 > d; + a & b & !c; + a + b * c - d + -1 * -2 - -3; + x = !y; + } + + /// ExprKind::Unary + fn expr_unary() { let expr; *expr; !expr; -expr; } + + /// ExprKind::Lit + fn expr_lit() { 'x'; 1_000_i8; 1.00000000000000000000001; } + + /// ExprKind::Cast + fn expr_cast() { let expr; expr as T; expr as T; } + + /// ExprKind::Type + fn expr_type() { let expr; builtin # type_ascribe(expr, T); } + + /// ExprKind::Let + fn expr_let() { + let b; + if let Some(a) = b {} + if let _ = true && false {} + if let _ = (true && false) {} + } + + /// ExprKind::If + fn expr_if() { + if true {} + if !true {} + if let true = true {} else {} + if true {} else if false {} + if true {} else if false {} else {} + if true { return; } else if false { 0 } else { 0 } + } + + /// ExprKind::While + fn expr_while() { + while false {} + 'a: while false {} + while let true = true {} + } + + /// ExprKind::ForLoop + fn expr_for_loop() { let x; for _ in x {} 'a: for _ in x {} } + + /// ExprKind::Loop + fn expr_loop() { loop {} 'a: loop {} } + + /// ExprKind::Match + fn expr_match() { + let value; + match value {} + match value { ok => 1, } + match value { ok => 1, err => 0, } + } + + /// ExprKind::Closure + fn expr_closure() { + let value; + || {}; + |x| {}; + |x: u8| {}; + || (); + move || value; + async || value; + async move || value; + static || value; + static move || value; + (static async || value); + (static async move || value); + || -> u8 { value }; + 1 + (|| {}); + } + + /// ExprKind::Block + fn expr_block() { + {} + unsafe {} + 'a: {} + + #[allow()] + {} + { + #![allow()] + } + } + + /// ExprKind::Gen + fn expr_gen() { + async {}; + async move {}; + gen {}; + gen move {}; + async gen {}; + async gen move {}; + } + + /// ExprKind::Await + fn expr_await() { let fut; fut.await; } + + /// ExprKind::TryBlock + fn expr_try_block() { try {} try { return; } } + + /// ExprKind::Assign + fn expr_assign() { let expr; expr = true; } + + /// ExprKind::AssignOp + fn expr_assign_op() { let expr; expr += true; } + + /// ExprKind::Field + fn expr_field() { let expr; expr.field; expr.0; } + + /// ExprKind::Index + fn expr_index() { let expr; expr[true]; } + + /// ExprKind::Range + fn expr_range() { + let (lo, hi); + ..; + ..hi; + lo..; + lo..hi; + lo..hi; + ..=hi; + lo..=hi; + -2..=-1; + } + + /// ExprKind::Underscore + fn expr_underscore() { _; } + + /// ExprKind::Path + fn expr_path() { + let x; + crate::expressions::expr_path; + crate::expressions::expr_path::<'static>; + ::default; + ::default::<>; + x::(); + x::(T, T) -> T; + crate::() -> ()::expressions::() -> ()::expr_path; + core::()::marker::()::PhantomData; + } + + /// ExprKind::AddrOf + fn expr_addr_of() { + let expr; + &expr; + &mut expr; + &raw const expr; + &raw mut expr; + } + + /// ExprKind::Break + fn expr_break() { 'a: { break; break 'a; break true; break 'a true; } } + + /// ExprKind::Continue + fn expr_continue() { 'a: { continue; continue 'a; } } + + /// ExprKind::Ret + fn expr_ret() { return; return true; } + + /// ExprKind::InlineAsm + fn expr_inline_asm() { + let x; + asm!("mov {1}, {0}\nshl {1}, 1\nshl {0}, 2\nadd {0}, {1}", + inout(reg) + x, + out(reg) + _); + } + + /// ExprKind::OffsetOf + fn expr_offset_of() { + + + + + + + + + + + + + + + + + + + + // ... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { builtin # offset_of(T, field) }; + } + /// ExprKind::MacCall + fn expr_mac_call() { "..."; "..."; "..."; } + /// ExprKind::Struct + fn expr_struct() { + struct Struct {} + let (x, base); + Struct {}; + ::Owned {}; + Struct { .. }; + Struct { ..base }; + Struct { x }; + Struct { x, ..base }; + Struct { x: true }; + Struct { x: true, .. }; + Struct { x: true, ..base }; + Struct { 0: true, ..base }; + } + /// ExprKind::Repeat + fn expr_repeat() { [(); 0]; } + /// ExprKind::Paren + fn expr_paren() { let expr; (expr); } + /// ExprKind::Try + fn expr_try() { let expr; expr?; } + /// ExprKind::Yield + fn expr_yield() { yield; yield true; } + /// ExprKind::Yeet + fn expr_yeet() { do yeet; do yeet 0; } + /// ExprKind::Become + fn expr_become() { become true; } + /// ExprKind::IncludedBytes + fn expr_include_bytes() { + b"data for include_bytes in ../expanded-exhaustive.rs\n"; + } + /// ExprKind::FormatArgs + fn expr_format_args() { + let expr; + format_args!(""); + format_args!("{0}", expr); + } +} +mod items { + /// ItemKind::ExternCrate + mod item_extern_crate { + extern crate core; + extern crate self as unpretty; + pub extern crate core as _; + } + /// ItemKind::Use + mod item_use { + use crate::{expressions, items::item_use}; + pub use core::*; + } + /// ItemKind::Static + mod item_static { + pub static A: () = {}; + static mut B: () = {}; + } + /// ItemKind::Const + mod item_const { + pub const A: () = {}; + trait TraitItems { + const B: (); + const C: () = {}; + } + } + /// ItemKind::Fn + mod item_fn { + pub const unsafe extern "C" fn f() {} + pub async unsafe extern fn g() {} + fn h<'a, T>() where T: 'a {} + trait TraitItems { + unsafe extern fn f(); + } + impl TraitItems for _ { + default unsafe extern fn f() {} + } + } + /// ItemKind::Mod + mod item_mod { } + /// ItemKind::ForeignMod + mod item_foreign_mod { + extern "C++" {} + extern {} + } + /// ItemKind::GlobalAsm + mod item_global_asm { + global_asm! (".globl my_asm_func"); + } + /// ItemKind::TyAlias + mod item_ty_alias { + pub type Type<'a> where T: 'a = T; + } + /// ItemKind::Enum + mod item_enum { + pub enum Void {} + enum Empty { Unit, Tuple(), Struct {}, } + enum Generic<'a, T> where T: 'a { + Tuple(T), + Struct { + t: T, + }, + } + } + /// ItemKind::Struct + mod item_struct { + pub struct Unit; + struct Tuple(); + struct Newtype(Unit); + struct Struct {} + struct Generic<'a, T> where T: 'a { + t: T, + } + } + /// ItemKind::Union + mod item_union { + union Generic<'a, T> where T: 'a { + t: T, + } + } + /// ItemKind::Trait + mod item_trait { + pub unsafe auto trait Send {} + trait Trait<'a>: Sized where Self: 'a {} + } + /// ItemKind::TraitAlias + mod item_trait_alias { + pub trait Trait = Sized where for<'a> T: 'a; + } + /// ItemKind::Impl + mod item_impl { + impl () {} + impl () {} + impl Default for () {} + impl const Default for () {} + } + /// ItemKind::MacCall + mod item_mac_call { } + /// ItemKind::MacroDef + mod item_macro_def { + macro_rules! mac { () => { ... }; } + pub macro stringify { () => {} } + } + /// ItemKind::Delegation + mod item_delegation { + /*! FIXME: todo */ + } + /// ItemKind::DelegationMac + mod item_delegation_mac { + /*! FIXME: todo */ + } +} +mod patterns { + /// PatKind::Wild + fn pat_wild() { let _; } + /// PatKind::Ident + fn pat_ident() { + let x; + let ref x; + let mut x; + let ref mut x; + let ref mut x @ _; + } + /// PatKind::Struct + fn pat_struct() { + let T {}; + let T:: {}; + let T::<'static> {}; + let T { x }; + let T { x: _x }; + let T { .. }; + let T { x, .. }; + let T { x: _x, .. }; + let T { 0: _x, .. }; + let ::Owned {}; + } + /// PatKind::TupleStruct + fn pat_tuple_struct() { + struct Tuple(); + let Tuple(); + let Tuple::(); + let Tuple::<'static>(); + let Tuple(x); + let Tuple(..); + let Tuple(x, ..); + } + /// PatKind::Or + fn pat_or() { let (true | false); let (true); let (true | false); } + /// PatKind::Path + fn pat_path() { + let core::marker::PhantomData; + let core::marker::PhantomData::; + let core::marker::PhantomData::<'static>; + let ::CONST; + } + /// PatKind::Tuple + fn pat_tuple() { let (); let (true,); let (true, false); } + /// PatKind::Box + fn pat_box() { let box pat; } + /// PatKind::Deref + fn pat_deref() { let deref!(pat); } + /// PatKind::Ref + fn pat_ref() { let &pat; let &mut pat; } + /// PatKind::Lit + fn pat_lit() { let 1_000_i8; let -""; } + /// PatKind::Range + fn pat_range() { let ..1; let 0..; let 0..1; let 0..=1; let -2..=-1; } + /// PatKind::Slice + fn pat_slice() { let []; let [true]; let [true]; let [true, false]; } + /// PatKind::Rest + fn pat_rest() { let ..; } + /// PatKind::Never + fn pat_never() { let !; let Some(!); } + /// PatKind::Paren + fn pat_paren() { let (pat); } + /// PatKind::MacCall + fn pat_mac_call() { let ""; let ""; let ""; } +} +mod statements { + /// StmtKind::Let + fn stmt_let() { + let _; + let _ = true; + let _: T = true; + let _ = true else { return; }; + } + /// StmtKind::Item + fn stmt_item() { + struct Struct {} + struct Unit; + } + /// StmtKind::Expr + fn stmt_expr() { () } + /// StmtKind::Semi + fn stmt_semi() { 1 + 1; } + /// StmtKind::Empty + fn stmt_empty() { ; } + /// StmtKind::MacCall + fn stmt_mac_call() { "..."; "..."; "..."; } +} +mod types { + /// TyKind::Slice + fn ty_slice() { let _: [T]; } + /// TyKind::Array + fn ty_array() { let _: [T; 0]; } + /// TyKind::Ptr + fn ty_ptr() { let _: *const T; let _: *mut T; } + /// TyKind::Ref + fn ty_ref() { + let _: &T; + let _: &mut T; + let _: &'static T; + let _: &'static mut [T]; + let _: &T>>>; + let _: &T>>>; + } + /// TyKind::BareFn + fn ty_bare_fn() { + let _: fn(); + let _: fn() -> (); + let _: fn(T); + let _: fn(t: T); + let _: fn(); + let _: for<'a> fn(); + } + /// TyKind::Never + fn ty_never() { let _: !; } + /// TyKind::Tup + fn ty_tup() { let _: (); let _: (T,); let _: (T, T); } + /// TyKind::AnonStruct + fn ty_anon_struct() { + struct Struct { + _: struct { + t: T, + }, + } + } + /// TyKind::AnonUnion + fn ty_anon_union() { + struct Struct { + _: union { + t: T, + }, + } + } + /// TyKind::Path + fn ty_path() { + let _: T; + let _: T<'static>; + let _: T; + let _: T; + let _: T() -> !; + let _: ::Owned; + } + /// TyKind::TraitObject + fn ty_trait_object() { + let _: dyn Send; + let _: dyn Send + 'static; + let _: dyn 'static + Send; + let _: dyn for<'a> Send; + } + /// TyKind::ImplTrait + const fn ty_impl_trait() { + let _: impl Send; + let _: impl Send + 'static; + let _: impl 'static + Send; + let _: impl ?Sized; + let _: impl ~const Clone; + let _: impl for<'a> Send; + } + /// TyKind::Paren + fn ty_paren() { let _: (T); } + /// TyKind::Typeof + fn ty_typeof() { + /*! unused for now */ + } + /// TyKind::Infer + fn ty_infer() { let _: _; } + /// TyKind::ImplicitSelf + fn ty_implicit_self() { + /*! there is no syntax for this */ + } + /// TyKind::MacCall + fn ty_mac_call() { let _: T; let _: T; let _: T; } + /// TyKind::CVarArgs + fn ty_c_var_args() { + /*! FIXME: todo */ + } + /// TyKind::Pat + fn ty_pat() { let _: u32 is 1..; } +} +mod visibilities { + /// VisibilityKind::Public + mod visibility_public { + pub struct Pub; + } + /// VisibilityKind::Restricted + mod visibility_restricted { + pub(crate) struct PubCrate; + pub(self) struct PubSelf; + pub(super) struct PubSuper; + pub(in crate) struct PubInCrate; + pub(in self) struct PubInSelf; + pub(in super) struct PubInSuper; + pub(in crate::visibilities) struct PubInCrateVisibilities; + pub(in self::super) struct PubInSelfSuper; + pub(in super::visibility_restricted) struct PubInSuperMod; + } +} diff --git a/tests/ui/unpretty/expanded-interpolation.rs b/tests/ui/unpretty/expanded-interpolation.rs new file mode 100644 index 0000000000000..8f0e21ce870d3 --- /dev/null +++ b/tests/ui/unpretty/expanded-interpolation.rs @@ -0,0 +1,106 @@ +//@ compile-flags: -Zunpretty=expanded +//@ check-pass + +// This test covers the AST pretty-printer's insertion of parentheses in some +// macro metavariable edge cases. Synthetic parentheses (i.e. not appearing in +// the syntax tree) need to be printed in order for the printed code to be valid +// Rust syntax. We also test negative cases: the pretty-printer should not be +// synthesizing parentheses indiscriminately; only where necessary. + +#![feature(let_chains)] +#![feature(if_let_guard)] + +macro_rules! expr { + ($expr:expr) => { $expr }; +} + +macro_rules! stmt { + ($stmt:stmt) => { $stmt }; +} + +fn if_let() { + macro_rules! if_let { + ($pat:pat, $expr:expr) => { + if let $pat = $expr {} + }; + } + + if let no_paren = true && false {} + if_let!(paren_around_binary, true && false); + if_let!(no_paren, true); + + struct Struct {} + match () { + _ if let no_paren = Struct {} => {} + } +} + +fn let_else() { + let no_paren = expr!(1 + 1) else { return; }; + let paren_around_loop = expr!(loop {}) else { return; }; +} + +fn local() { + macro_rules! let_expr_minus_one { + ($pat:pat, $expr:expr) => { + let $pat = $expr - 1; + }; + } + + let void; + let_expr_minus_one!(no_paren, match void {}); + + macro_rules! let_expr_else_return { + ($pat:pat, $expr:expr) => { + let $pat = $expr else { return; }; + }; + } + + let_expr_else_return!(no_paren, void()); +} + +fn match_arm() { + macro_rules! match_arm { + ($pat:pat, $expr:expr) => { + match () { $pat => $expr } + }; + } + + match_arm!(no_paren, 1 - 1); + match_arm!(paren_around_brace, { 1 } - 1); +} + +/// https://github.com/rust-lang/rust/issues/98790 +fn stmt_boundary() { + macro_rules! expr_as_stmt { + ($expr:expr) => { + stmt!($expr) + }; + } + + let paren_around_match; + expr_as_stmt!(match paren_around_match {} | true); + + macro_rules! minus_one { + ($expr:expr) => { + expr_as_stmt!($expr - 1) + }; + } + + let (no_paren, paren_around_loop); + minus_one!(no_paren); + minus_one!(match paren_around_match {}); + minus_one!(match paren_around_match {}()); + minus_one!(match paren_around_match {}[0]); + minus_one!(loop { break paren_around_loop; }); +} + +fn vis_inherited() { + macro_rules! vis_inherited { + ($vis:vis struct) => { + $vis struct Struct; + }; + } + + vis_inherited!(struct); +} diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/expanded-interpolation.stdout new file mode 100644 index 0000000000000..73322b50f2d6e --- /dev/null +++ b/tests/ui/unpretty/expanded-interpolation.stdout @@ -0,0 +1,92 @@ +#![feature(prelude_import)] +#![no_std] +//@ compile-flags: -Zunpretty=expanded +//@ check-pass + +// This test covers the AST pretty-printer's insertion of parentheses in some +// macro metavariable edge cases. Synthetic parentheses (i.e. not appearing in +// the syntax tree) need to be printed in order for the printed code to be valid +// Rust syntax. We also test negative cases: the pretty-printer should not be +// synthesizing parentheses indiscriminately; only where necessary. + +#![feature(let_chains)] +#![feature(if_let_guard)] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; + +macro_rules! expr { ($expr:expr) => { $expr }; } + +macro_rules! stmt { ($stmt:stmt) => { $stmt }; } + +fn if_let() { + macro_rules! if_let { + ($pat:pat, $expr:expr) => { if let $pat = $expr {} }; + } + + if let no_paren = true && false {} + if let paren_around_binary = (true && false) {}; + if let no_paren = true {}; + + struct Struct {} + match () { _ if let no_paren = Struct {} => {} } +} + +fn let_else() { + let no_paren = 1 + 1 else { return; }; + let paren_around_loop = (loop {}) else { return; }; +} + +fn local() { + macro_rules! let_expr_minus_one { + ($pat:pat, $expr:expr) => { let $pat = $expr - 1; }; + } + + let void; + let no_paren = match void {} - 1; + + macro_rules! let_expr_else_return { + ($pat:pat, $expr:expr) => { let $pat = $expr else { return; }; }; + } + let + + no_paren = void() else { return; }; +} + +fn match_arm() { + macro_rules! match_arm { + ($pat:pat, $expr:expr) => { match () { $pat => $expr } }; + } + match () { + + + no_paren => 1 - 1, + }; + match () { paren_around_brace => ({ 1 }) - 1, }; +} + +/// https://github.com/rust-lang/rust/issues/98790 +fn stmt_boundary() { + macro_rules! expr_as_stmt { ($expr:expr) => { stmt!($expr) }; } + + let paren_around_match; + (match paren_around_match {}) | true; + + macro_rules! minus_one { ($expr:expr) => { expr_as_stmt!($expr - 1) }; } + + let (no_paren, paren_around_loop); + no_paren - 1; + (match paren_around_match {}) - 1; + (match paren_around_match {})() - 1; + (match paren_around_match {})[0] - 1; + (loop { break paren_around_loop; }) - 1; +} + +fn vis_inherited() { + macro_rules! vis_inherited { + ($vis:vis struct) => { $vis struct Struct; }; + } + struct Struct; + +} diff --git a/tests/ui/unpretty/let-else.rs b/tests/ui/unpretty/let-else.rs deleted file mode 100644 index 4db6eca99b18f..0000000000000 --- a/tests/ui/unpretty/let-else.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ compile-flags: -Zunpretty=expanded -//@ check-pass - -macro_rules! expr { - ($e:expr) => { $e }; -} - -fn main() { - let _ = expr!(1 + 1) else { return; }; - let _ = expr!(loop {}) else { return; }; -} diff --git a/tests/ui/unpretty/let-else.stdout b/tests/ui/unpretty/let-else.stdout deleted file mode 100644 index 4bc4d9e085f97..0000000000000 --- a/tests/ui/unpretty/let-else.stdout +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(prelude_import)] -#![no_std] -#[prelude_import] -use ::std::prelude::rust_2015::*; -#[macro_use] -extern crate std; -//@ compile-flags: -Zunpretty=expanded -//@ check-pass - -macro_rules! expr { ($e:expr) => { $e }; } - -fn main() { - let _ = 1 + 1 else { return; }; - let _ = (loop {}) else { return; }; -}