diff options
| author | bors <bors@rust-lang.org> | 2024-12-02 18:36:36 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-12-02 18:36:36 +0000 |
| commit | d49be02cf6d2e2a01264fcdef1e20c826710c0f5 (patch) | |
| tree | 873ce3d38ea75bfa910a38eab39e6d834c13ca17 /tests | |
| parent | 32eea2f4460b06b12acc98050a4211b8c0ccfd67 (diff) | |
| parent | 586591f4d6f656fc2eaf98f33f248bac2b1c3e4f (diff) | |
| download | rust-d49be02cf6d2e2a01264fcdef1e20c826710c0f5.tar.gz rust-d49be02cf6d2e2a01264fcdef1e20c826710c0f5.zip | |
Auto merge of #133760 - GuillaumeGomez:rollup-2c1y8c3, r=GuillaumeGomez
Rollup of 13 pull requests Successful merges: - #133603 (Eliminate magic numbers from expression precedence) - #133715 (rustdoc-json: Include safety of `static`s) - #133721 (rustdoc-json: Add test for `impl Trait for dyn Trait`) - #133725 (Remove `//@ compare-output-lines-by-subset`) - #133730 (Add pretty-printer parenthesis insertion test) - #133736 (Add `needs-target-has-atomic` directive) - #133739 (Re-add myself to rotation) - #133743 (Fix docs for `<[T]>::as_array`.) - #133744 (Fix typo README.md) - #133745 (Remove static HashSet for default IDs list) - #133749 (mir validator: don't store mir phase) - #133751 (remove `Ty::is_copy_modulo_regions`) - #133757 (`impl Default for EarlyDiagCtxt`) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/rustdoc-json/impls/trait-for-dyn-trait.rs | 15 | ||||
| -rw-r--r-- | tests/rustdoc-json/statics/extern.rs | 39 | ||||
| -rw-r--r-- | tests/rustdoc-json/statics/statics.rs | 12 | ||||
| -rw-r--r-- | tests/ui-fulldeps/pprust-parenthesis-insertion.rs | 242 | ||||
| -rw-r--r-- | tests/ui/README.md | 6 |
5 files changed, 311 insertions, 3 deletions
diff --git a/tests/rustdoc-json/impls/trait-for-dyn-trait.rs b/tests/rustdoc-json/impls/trait-for-dyn-trait.rs new file mode 100644 index 00000000000..0fbb4df0028 --- /dev/null +++ b/tests/rustdoc-json/impls/trait-for-dyn-trait.rs @@ -0,0 +1,15 @@ +//@ set t1 = '$.index[*][?(@.name=="T1")].id' +pub trait T1 {} + +//@ set t2 = '$.index[*][?(@.name=="T2")].id' +pub trait T2 {} + +/// Fun impl +impl T1 for dyn T2 {} + +//@ set impl = '$.index[*][?(@.docs=="Fun impl")].id' +//@ is '$.index[*][?(@.name=="T1")].inner.trait.implementations[*]' $impl +//@ is '$.index[*][?(@.name=="T2")].inner.trait.implementations' [] + +//@ is '$.index[*][?(@.docs=="Fun impl")].inner.impl.trait.id' $t1 +//@ is '$.index[*][?(@.docs=="Fun impl")].inner.impl.for.dyn_trait.traits[*].trait.id' $t2 diff --git a/tests/rustdoc-json/statics/extern.rs b/tests/rustdoc-json/statics/extern.rs new file mode 100644 index 00000000000..d38fdf1cd1c --- /dev/null +++ b/tests/rustdoc-json/statics/extern.rs @@ -0,0 +1,39 @@ +// ignore-tidy-linelength +//@ edition: 2021 + +extern "C" { + //@ is '$.index[*][?(@.name=="A")].inner.static.is_unsafe' true + //@ is '$.index[*][?(@.name=="A")].inner.static.is_mutable' false + pub static A: i32; + //@ is '$.index[*][?(@.name=="B")].inner.static.is_unsafe' true + //@ is '$.index[*][?(@.name=="B")].inner.static.is_mutable' true + pub static mut B: i32; + + // items in unadorned `extern` blocks cannot have safety qualifiers +} + +unsafe extern "C" { + //@ is '$.index[*][?(@.name=="C")].inner.static.is_unsafe' true + //@ is '$.index[*][?(@.name=="C")].inner.static.is_mutable' false + pub static C: i32; + //@ is '$.index[*][?(@.name=="D")].inner.static.is_unsafe' true + //@ is '$.index[*][?(@.name=="D")].inner.static.is_mutable' true + pub static mut D: i32; + + //@ is '$.index[*][?(@.name=="E")].inner.static.is_unsafe' false + //@ is '$.index[*][?(@.name=="E")].inner.static.is_mutable' false + pub safe static E: i32; + //@ is '$.index[*][?(@.name=="F")].inner.static.is_unsafe' false + //@ is '$.index[*][?(@.name=="F")].inner.static.is_mutable' true + pub safe static mut F: i32; + + //@ is '$.index[*][?(@.name=="G")].inner.static.is_unsafe' true + //@ is '$.index[*][?(@.name=="G")].inner.static.is_mutable' false + pub unsafe static G: i32; + //@ is '$.index[*][?(@.name=="H")].inner.static.is_unsafe' true + //@ is '$.index[*][?(@.name=="H")].inner.static.is_mutable' true + pub unsafe static mut H: i32; +} + +//@ ismany '$.index[*][?(@.inner.static)].inner.static.expr' '""' '""' '""' '""' '""' '""' '""' '""' +//@ ismany '$.index[*][?(@.inner.static)].inner.static.type.primitive' '"i32"' '"i32"' '"i32"' '"i32"' '"i32"' '"i32"' '"i32"' '"i32"' diff --git a/tests/rustdoc-json/statics/statics.rs b/tests/rustdoc-json/statics/statics.rs new file mode 100644 index 00000000000..a8af23cc87d --- /dev/null +++ b/tests/rustdoc-json/statics/statics.rs @@ -0,0 +1,12 @@ +//@ is '$.index[*][?(@.name=="A")].inner.static.type.primitive' '"i32"' +//@ is '$.index[*][?(@.name=="A")].inner.static.is_mutable' false +//@ is '$.index[*][?(@.name=="A")].inner.static.expr' '"5"' +//@ is '$.index[*][?(@.name=="A")].inner.static.is_unsafe' false +pub static A: i32 = 5; + +//@ is '$.index[*][?(@.name=="B")].inner.static.type.primitive' '"u32"' +//@ is '$.index[*][?(@.name=="B")].inner.static.is_mutable' true +// Expr value isn't gaurenteed, it'd be fine to change it. +//@ is '$.index[*][?(@.name=="B")].inner.static.expr' '"_"' +//@ is '$.index[*][?(@.name=="B")].inner.static.is_unsafe' false +pub static mut B: u32 = 2 + 3; diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs new file mode 100644 index 00000000000..fd6644d73c1 --- /dev/null +++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs @@ -0,0 +1,242 @@ +//@ run-pass +//@ ignore-cross-compile + +// This test covers the AST pretty-printer's automatic insertion of parentheses +// into unparenthesized syntax trees according to precedence and various grammar +// restrictions and edge cases. +// +// For example if the following syntax tree represents the expression a*(b+c), +// in which the parenthesis is necessary for precedence: +// +// Binary('*', Path("a"), Paren(Binary('+', Path("b"), Path("c")))) +// +// then the pretty-printer needs to be able to print the following +// unparenthesized syntax tree with an automatically inserted parenthesization. +// +// Binary('*', Path("a"), Binary('+', Path("b"), Path("c"))) +// +// Handling this correctly is relevant in real-world code when pretty-printing +// macro-generated syntax trees, in which expressions can get interpolated into +// one another without any parenthesization being visible in the syntax tree. +// +// macro_rules! repro { +// ($rhs:expr) => { +// a * $rhs +// }; +// } +// +// let _ = repro!(b + c); + +#![feature(rustc_private)] + +extern crate rustc_ast; +extern crate rustc_ast_pretty; +extern crate rustc_driver; +extern crate rustc_errors; +extern crate rustc_parse; +extern crate rustc_session; +extern crate rustc_span; +extern crate smallvec; + +use std::mem; +use std::process::ExitCode; + +use rustc_ast::ast::{DUMMY_NODE_ID, Expr, ExprKind, Stmt}; +use rustc_ast::mut_visit::{self, DummyAstNode as _, MutVisitor}; +use rustc_ast::node_id::NodeId; +use rustc_ast::ptr::P; +use rustc_ast_pretty::pprust; +use rustc_errors::Diag; +use rustc_parse::parser::Recovery; +use rustc_session::parse::ParseSess; +use rustc_span::{DUMMY_SP, FileName, Span}; +use smallvec::SmallVec; + +// Every parenthesis in the following expressions is re-inserted by the +// pretty-printer. +// +// FIXME: Some of them shouldn't be. +static EXPRS: &[&str] = &[ + // Straightforward binary operator precedence. + "2 * 2 + 2", + "2 + 2 * 2", + "(2 + 2) * 2", + "2 * (2 + 2)", + "2 + 2 + 2", + // Return has lower precedence than a binary operator. + "(return 2) + 2", + "2 + (return 2)", // FIXME: no parenthesis needed. + "(return) + 2", // FIXME: no parenthesis needed. + // These mean different things. + "return - 2", + "(return) - 2", + // These mean different things. + "if let _ = true && false {}", + "if let _ = (true && false) {}", + // Conditions end at the first curly brace, so struct expressions need to be + // parenthesized. Except in a match guard, where conditions end at arrow. + "if let _ = (Struct {}) {}", + "match 2 { _ if let _ = Struct {} => {} }", + // Match arms terminate eagerly, so parenthesization is needed around some + // expressions. + "match 2 { _ => 1 - 1 }", + "match 2 { _ => ({ 1 }) - 1 }", + // Grammar restriction: break value starting with a labeled loop is not + // allowed, except if the break is also labeled. + "break 'outer 'inner: loop {} + 2", + "break ('inner: loop {} + 2)", + // Grammar restriction: the value in let-else is not allowed to end in a + // curly brace. + "{ let _ = 1 + 1 else {}; }", + "{ let _ = (loop {}) else {}; }", + "{ let _ = mac!() else {}; }", + "{ let _ = (mac! {}) else {}; }", + // Parentheses are necessary to prevent an eager statement boundary. + "{ 2 - 1 }", + "{ (match 2 {}) - 1 }", + "{ (match 2 {})() - 1 }", + "{ (match 2 {})[0] - 1 }", + "{ (loop {}) - 1 }", + // Angle bracket is eagerly parsed as a path's generic argument list. + "(2 as T) < U", + "(2 as T<U>) < V", // FIXME: no parentheses needed. + /* + // FIXME: pretty-printer produces invalid syntax. `2 + 2 as T < U` + "(2 + 2 as T) < U", + */ + /* + // FIXME: pretty-printer produces invalid syntax. `if (let _ = () && Struct {}.x) {}` + "if let _ = () && (Struct {}).x {}", + */ + /* + // FIXME: pretty-printer produces invalid syntax. `(1 < 2 == false) as usize` + "((1 < 2) == false) as usize", + */ + /* + // FIXME: pretty-printer produces invalid syntax. `for _ in 1..{ 2 } {}` + "for _ in (1..{ 2 }) {}", + */ + /* + // FIXME: pretty-printer loses the attribute. `{ let Struct { field } = s; }` + "{ let Struct { #[attr] field } = s; }", + */ + /* + // FIXME: pretty-printer turns this into a range. `0..to_string()` + "(0.).to_string()", + "0. .. 1.", + */ + /* + // FIXME: pretty-printer loses the dyn*. `i as Trait` + "i as dyn* Trait", + */ +]; + +// Flatten the content of parenthesis nodes into their parent node. For example +// this syntax tree representing the expression a*(b+c): +// +// Binary('*', Path("a"), Paren(Binary('+', Path("b"), Path("c")))) +// +// would unparenthesize to: +// +// Binary('*', Path("a"), Binary('+', Path("b"), Path("c"))) +struct Unparenthesize; + +impl MutVisitor for Unparenthesize { + fn visit_expr(&mut self, e: &mut P<Expr>) { + while let ExprKind::Paren(paren) = &mut e.kind { + **e = mem::replace(&mut *paren, Expr::dummy()); + } + mut_visit::walk_expr(self, e); + } +} + +// Erase Span information that could distinguish between identical expressions +// parsed from different source strings. +struct Normalize; + +impl MutVisitor for Normalize { + const VISIT_TOKENS: bool = true; + + fn visit_id(&mut self, id: &mut NodeId) { + *id = DUMMY_NODE_ID; + } + + fn visit_span(&mut self, span: &mut Span) { + *span = DUMMY_SP; + } + + fn visit_expr(&mut self, expr: &mut P<Expr>) { + if let ExprKind::Binary(binop, _left, _right) = &mut expr.kind { + self.visit_span(&mut binop.span); + } + mut_visit::walk_expr(self, expr); + } + + fn flat_map_stmt(&mut self, mut stmt: Stmt) -> SmallVec<[Stmt; 1]> { + self.visit_span(&mut stmt.span); + mut_visit::walk_flat_map_stmt(self, stmt) + } +} + +fn parse_expr(psess: &ParseSess, source_code: &str) -> Option<P<Expr>> { + let parser = rustc_parse::unwrap_or_emit_fatal(rustc_parse::new_parser_from_source_str( + psess, + FileName::anon_source_code(source_code), + source_code.to_owned(), + )); + + let mut expr = parser.recovery(Recovery::Forbidden).parse_expr().map_err(Diag::cancel).ok()?; + Normalize.visit_expr(&mut expr); + Some(expr) +} + +fn main() -> ExitCode { + let mut status = ExitCode::SUCCESS; + let mut fail = |description: &str, before: &str, after: &str| { + status = ExitCode::FAILURE; + eprint!( + "{description}\n BEFORE: {before}\n AFTER: {after}\n\n", + before = before.replace('\n', "\n "), + after = after.replace('\n', "\n "), + ); + }; + + rustc_span::create_default_session_globals_then(|| { + let psess = &ParseSess::new(vec![rustc_parse::DEFAULT_LOCALE_RESOURCE]); + + for &source_code in EXPRS { + let expr = parse_expr(psess, source_code).unwrap(); + + // Check for FALSE POSITIVE: pretty-printer inserting parentheses where not needed. + // Pseudocode: + // assert(expr == parse(print(expr))) + let printed = &pprust::expr_to_string(&expr); + let Some(expr2) = parse_expr(psess, printed) else { + fail("Pretty-printer produced invalid syntax", source_code, printed); + continue; + }; + if format!("{expr:#?}") != format!("{expr2:#?}") { + fail("Pretty-printer inserted unnecessary parenthesis", source_code, printed); + continue; + } + + // Check for FALSE NEGATIVE: pretty-printer failing to place necessary parentheses. + // Pseudocode: + // assert(unparenthesize(expr) == unparenthesize(parse(print(unparenthesize(expr))))) + let mut expr = expr; + Unparenthesize.visit_expr(&mut expr); + let printed = &pprust::expr_to_string(&expr); + let Some(mut expr2) = parse_expr(psess, printed) else { + fail("Pretty-printer with no parens produced invalid syntax", source_code, printed); + continue; + }; + Unparenthesize.visit_expr(&mut expr2); + if format!("{expr:#?}") != format!("{expr2:#?}") { + fail("Pretty-printer lost necessary parentheses", source_code, printed); + continue; + } + } + }); + + status +} diff --git a/tests/ui/README.md b/tests/ui/README.md index c14d0ee78c8..aa36481ae06 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -6,9 +6,9 @@ This folder contains `rustc`'s ## Test Directives (Headers) Typically, a UI test will have some test directives / headers which are -special comments that tell compiletest how to build and intepret a test. +special comments that tell compiletest how to build and interpret a test. -As part of an on-going effort to rewrite compiletest +As part of an ongoing effort to rewrite compiletest (see <https://github.com/rust-lang/compiler-team/issues/536>), a major change proposal to change legacy compiletest-style headers `// <directive>` to [`ui_test`](https://github.com/oli-obk/ui_test)-style headers @@ -30,6 +30,6 @@ but in `ui_test` style, the header would be written as compiletest is changed to accept only `//@` directives for UI tests (currently), and will reject and report an error if it encounters any -comments `// <content>` that may be parsed as an legacy compiletest-style +comments `// <content>` that may be parsed as a legacy compiletest-style test header. To fix this, you should migrate to the `ui_test`-style header `//@ <content>`. |
