From 3f98f76d70f229025594e7b23fe7c4d9563766d7 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 20 Dec 2024 19:26:02 -0800 Subject: [PATCH 1/7] Check that pretty-printer parenthesis test operates on the whole test case --- tests/ui-fulldeps/pprust-parenthesis-insertion.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs index 184458bad5551..3d020fb4431a4 100644 --- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs +++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs @@ -44,6 +44,7 @@ use rustc_ast::ast::{DUMMY_NODE_ID, Expr, ExprKind}; use rustc_ast::mut_visit::{self, DummyAstNode as _, MutVisitor}; use rustc_ast::node_id::NodeId; use rustc_ast::ptr::P; +use rustc_ast::token; use rustc_ast_pretty::pprust; use rustc_errors::Diag; use rustc_parse::parser::Recovery; @@ -177,7 +178,12 @@ fn parse_expr(psess: &ParseSess, source_code: &str) -> Option> { source_code.to_owned(), )); - let mut expr = parser.recovery(Recovery::Forbidden).parse_expr().map_err(Diag::cancel).ok()?; + let mut parser = parser.recovery(Recovery::Forbidden); + let mut expr = parser.parse_expr().map_err(Diag::cancel).ok()?; + if parser.token != token::Eof { + return None; + } + Normalize.visit_expr(&mut expr); Some(expr) } From da6616c54fad4af6459feaebd48bedb2cc7fae08 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Fri, 20 Dec 2024 14:58:37 -0800 Subject: [PATCH 2/7] Document `PointerLike` implementation restrictions. --- library/core/src/marker.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 3d79706f8ecf9..d0d8609f43f08 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -982,8 +982,14 @@ pub trait Tuple {} /// A marker for pointer-like types. /// -/// This trait can only be implemented for types that have the same size and alignment -/// as a `usize` or `*const ()`. +/// This trait can only be implemented for types that are certain to have +/// the same size and alignment as a [`usize`] or [`*const ()`](pointer). +/// To ensure this, there are special requirements on implementations +/// of `PointerLike` (other than the already-provided implementations +/// for built-in types): +/// +/// * The type must have `#[repr(transparent)]`. +/// * The type’s sole non-zero-sized field must itself implement `PointerLike`. #[unstable(feature = "pointer_like_trait", issue = "none")] #[lang = "pointer_like"] #[diagnostic::on_unimplemented( From f67a739611d66071fbddf0838cbfff1247e4fafc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 21 Dec 2024 23:41:50 +0000 Subject: [PATCH 3/7] Don't ICE on illegal dyn* casts --- compiler/rustc_hir_typeck/src/cast.rs | 12 +++++----- compiler/rustc_hir_typeck/src/coercion.rs | 6 +++-- tests/crashes/132127.rs | 9 -------- tests/ui/dyn-star/illegal.rs | 16 ++++++++++++++ tests/ui/dyn-star/illegal.stderr | 27 +++++++++++++++++++++++ 5 files changed, 52 insertions(+), 18 deletions(-) delete mode 100644 tests/crashes/132127.rs create mode 100644 tests/ui/dyn-star/illegal.rs create mode 100644 tests/ui/dyn-star/illegal.stderr diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 59c06cbc5b578..8190095971b64 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -721,13 +721,11 @@ impl<'a, 'tcx> CastCheck<'tcx> { use rustc_middle::ty::cast::IntTy::*; if self.cast_ty.is_dyn_star() { - if fcx.tcx.features().dyn_star() { - span_bug!(self.span, "should be handled by `coerce`"); - } else { - // Report "casting is invalid" rather than "non-primitive cast" - // if the feature is not enabled. - return Err(CastError::IllegalCast); - } + // This coercion will fail if the feature is not enabled, OR + // if the coercion is (currently) illegal (e.g. `dyn* Foo + Send` + // to `dyn* Foo`). Report "casting is invalid" rather than + // "non-primitive cast". + return Err(CastError::IllegalCast); } let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty)) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 541e16e42a7d9..f9e4a592d9207 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -737,8 +737,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(TypeError::Mismatch); } - if let ty::Dynamic(a_data, _, _) = a.kind() - && let ty::Dynamic(b_data, _, _) = b.kind() + // FIXME(dyn_star): We should probably allow things like casting from + // `dyn* Foo + Send` to `dyn* Foo`. + if let ty::Dynamic(a_data, _, ty::DynStar) = a.kind() + && let ty::Dynamic(b_data, _, ty::DynStar) = b.kind() && a_data.principal_def_id() == b_data.principal_def_id() { return self.unify_and(a, b, |_| vec![]); diff --git a/tests/crashes/132127.rs b/tests/crashes/132127.rs deleted file mode 100644 index cca354b98764e..0000000000000 --- a/tests/crashes/132127.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #132127 -#![feature(dyn_star)] - -trait Trait {} - -fn main() { - let x: dyn* Trait + Send = 1usize; - x as dyn* Trait; -} diff --git a/tests/ui/dyn-star/illegal.rs b/tests/ui/dyn-star/illegal.rs new file mode 100644 index 0000000000000..ce0d784fcd22e --- /dev/null +++ b/tests/ui/dyn-star/illegal.rs @@ -0,0 +1,16 @@ +#![feature(dyn_star)] +//~^ WARN the feature `dyn_star` is incomplete + +trait Foo {} + +pub fn lol(x: dyn* Foo + Send) { + x as dyn* Foo; + //~^ ERROR casting `(dyn* Foo + Send + 'static)` as `dyn* Foo` is invalid +} + +fn lol2(x: &dyn Foo) { + *x as dyn* Foo; + //~^ ERROR `dyn Foo` needs to have the same ABI as a pointer +} + +fn main() {} diff --git a/tests/ui/dyn-star/illegal.stderr b/tests/ui/dyn-star/illegal.stderr new file mode 100644 index 0000000000000..fdf3c813a231c --- /dev/null +++ b/tests/ui/dyn-star/illegal.stderr @@ -0,0 +1,27 @@ +warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/illegal.rs:1:12 + | +LL | #![feature(dyn_star)] + | ^^^^^^^^ + | + = note: see issue #102425 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0606]: casting `(dyn* Foo + Send + 'static)` as `dyn* Foo` is invalid + --> $DIR/illegal.rs:7:5 + | +LL | x as dyn* Foo; + | ^^^^^^^^^^^^^ + +error[E0277]: `dyn Foo` needs to have the same ABI as a pointer + --> $DIR/illegal.rs:12:5 + | +LL | *x as dyn* Foo; + | ^^ `dyn Foo` needs to be a pointer-like type + | + = help: the trait `PointerLike` is not implemented for `dyn Foo` + +error: aborting due to 2 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0277, E0606. +For more information about an error, try `rustc --explain E0277`. From 62d1f4faa172b409ea09a24acaf9dfccfd0c2710 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 22 Dec 2024 02:03:11 +0000 Subject: [PATCH 4/7] Make sure we note ambiguity causes on positive/negative impl conflicts --- .../src/traits/specialize/mod.rs | 22 +++++++++++-------- .../ambiguity-cause.negative_coherence.stderr | 14 ++++++++++++ .../traits/negative-impls/ambiguity-cause.rs | 13 +++++++++++ .../ambiguity-cause.simple.stderr | 14 ++++++++++++ 4 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 tests/ui/traits/negative-impls/ambiguity-cause.negative_coherence.stderr create mode 100644 tests/ui/traits/negative-impls/ambiguity-cause.rs create mode 100644 tests/ui/traits/negative-impls/ambiguity-cause.simple.stderr diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 1430cfae51f73..401b41c796dad 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -483,15 +483,19 @@ fn report_negative_positive_conflict<'tcx>( negative_impl_def_id: DefId, positive_impl_def_id: DefId, ) -> ErrorGuaranteed { - tcx.dcx() - .create_err(NegativePositiveConflict { - impl_span: tcx.def_span(local_impl_def_id), - trait_desc: overlap.trait_ref, - self_ty: overlap.self_ty, - negative_impl_span: tcx.span_of_impl(negative_impl_def_id), - positive_impl_span: tcx.span_of_impl(positive_impl_def_id), - }) - .emit() + let mut diag = tcx.dcx().create_err(NegativePositiveConflict { + impl_span: tcx.def_span(local_impl_def_id), + trait_desc: overlap.trait_ref, + self_ty: overlap.self_ty, + negative_impl_span: tcx.span_of_impl(negative_impl_def_id), + positive_impl_span: tcx.span_of_impl(positive_impl_def_id), + }); + + for cause in &overlap.intercrate_ambiguity_causes { + cause.add_intercrate_ambiguity_hint(&mut diag); + } + + diag.emit() } fn report_conflicting_impls<'tcx>( diff --git a/tests/ui/traits/negative-impls/ambiguity-cause.negative_coherence.stderr b/tests/ui/traits/negative-impls/ambiguity-cause.negative_coherence.stderr new file mode 100644 index 0000000000000..4ec3414a57bcc --- /dev/null +++ b/tests/ui/traits/negative-impls/ambiguity-cause.negative_coherence.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `MyTrait` for type `String` + --> $DIR/ambiguity-cause.rs:10:1 + | +LL | impl MyTrait for T { } + | --------------------------- first implementation here +LL | +LL | impl MyTrait for String { } + | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `String` + | + = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::string::String` in future versions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/negative-impls/ambiguity-cause.rs b/tests/ui/traits/negative-impls/ambiguity-cause.rs new file mode 100644 index 0000000000000..30a528c535d44 --- /dev/null +++ b/tests/ui/traits/negative-impls/ambiguity-cause.rs @@ -0,0 +1,13 @@ +//@ revisions: simple negative_coherence + +#![feature(negative_impls)] +#![cfg_attr(negative_coherence, feature(with_negative_coherence))] + +trait MyTrait {} + +impl MyTrait for T { } + +impl MyTrait for String { } +//~^ ERROR conflicting implementations of trait `MyTrait` for type `String` + +fn main() {} diff --git a/tests/ui/traits/negative-impls/ambiguity-cause.simple.stderr b/tests/ui/traits/negative-impls/ambiguity-cause.simple.stderr new file mode 100644 index 0000000000000..4ec3414a57bcc --- /dev/null +++ b/tests/ui/traits/negative-impls/ambiguity-cause.simple.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `MyTrait` for type `String` + --> $DIR/ambiguity-cause.rs:10:1 + | +LL | impl MyTrait for T { } + | --------------------------- first implementation here +LL | +LL | impl MyTrait for String { } + | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `String` + | + = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::string::String` in future versions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. From 65ba6ac9a3314b6ad31634f13a02d2e9705a405e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 20 Dec 2024 19:35:26 -0800 Subject: [PATCH 5/7] Extract ui-fulldeps expression parser into module --- tests/ui-fulldeps/auxiliary/parser.rs | 51 +++++++++++++++++++ .../pprust-parenthesis-insertion.rs | 45 ++-------------- 2 files changed, 55 insertions(+), 41 deletions(-) create mode 100644 tests/ui-fulldeps/auxiliary/parser.rs diff --git a/tests/ui-fulldeps/auxiliary/parser.rs b/tests/ui-fulldeps/auxiliary/parser.rs new file mode 100644 index 0000000000000..4ea0d814b1faa --- /dev/null +++ b/tests/ui-fulldeps/auxiliary/parser.rs @@ -0,0 +1,51 @@ +#![feature(rustc_private)] + +extern crate rustc_ast; +extern crate rustc_driver; +extern crate rustc_errors; +extern crate rustc_parse; +extern crate rustc_session; +extern crate rustc_span; + +use rustc_ast::ast::{DUMMY_NODE_ID, Expr}; +use rustc_ast::mut_visit::MutVisitor; +use rustc_ast::node_id::NodeId; +use rustc_ast::ptr::P; +use rustc_ast::token; +use rustc_errors::Diag; +use rustc_parse::parser::Recovery; +use rustc_session::parse::ParseSess; +use rustc_span::{DUMMY_SP, FileName, Span}; + +pub fn parse_expr(psess: &ParseSess, source_code: &str) -> Option> { + 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 parser = parser.recovery(Recovery::Forbidden); + let mut expr = parser.parse_expr().map_err(Diag::cancel).ok()?; + if parser.token != token::Eof { + return None; + } + + Normalize.visit_expr(&mut expr); + Some(expr) +} + +// 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; + } +} diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs index 3d020fb4431a4..0b6619e7ef1f9 100644 --- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs +++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs @@ -1,5 +1,7 @@ //@ run-pass //@ ignore-cross-compile +//@ aux-crate: parser=parser.rs +//@ edition: 2021 // This test covers the AST pretty-printer's automatic insertion of parentheses // into unparenthesized syntax trees according to precedence and various grammar @@ -31,8 +33,6 @@ 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; @@ -40,16 +40,12 @@ extern crate rustc_span; use std::mem; use std::process::ExitCode; -use rustc_ast::ast::{DUMMY_NODE_ID, Expr, ExprKind}; +use parser::parse_expr; +use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::mut_visit::{self, DummyAstNode as _, MutVisitor}; -use rustc_ast::node_id::NodeId; use rustc_ast::ptr::P; -use rustc_ast::token; 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}; // Every parenthesis in the following expressions is re-inserted by the // pretty-printer. @@ -155,39 +151,6 @@ impl MutVisitor for Unparenthesize { } } -// 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 parse_expr(psess: &ParseSess, source_code: &str) -> Option> { - 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 parser = parser.recovery(Recovery::Forbidden); - let mut expr = parser.parse_expr().map_err(Diag::cancel).ok()?; - if parser.token != token::Eof { - return None; - } - - Normalize.visit_expr(&mut expr); - Some(expr) -} - fn main() -> ExitCode { let mut status = ExitCode::SUCCESS; let mut fail = |description: &str, before: &str, after: &str| { From 822e8063fdc88a61ee82a0c3ffdcd33f4be15f8e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 20 Dec 2024 19:43:43 -0800 Subject: [PATCH 6/7] Switch pretty-printer roundtrip test to better parser --- tests/ui-fulldeps/pprust-expr-roundtrip.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs index 8379ca86494c4..37e328a315f1e 100644 --- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs @@ -1,5 +1,7 @@ //@ run-pass //@ ignore-cross-compile +//@ aux-crate: parser=parser.rs +//@ edition: 2021 // The general idea of this test is to enumerate all "interesting" expressions and check that // `parse(print(e)) == e` for all `e`. Here's what's interesting, for the purposes of this test: @@ -21,7 +23,6 @@ extern crate rustc_ast; extern crate rustc_ast_pretty; -extern crate rustc_data_structures; extern crate rustc_parse; extern crate rustc_session; extern crate rustc_span; @@ -32,28 +33,17 @@ extern crate thin_vec; #[allow(unused_extern_crates)] extern crate rustc_driver; +use parser::parse_expr; use rustc_ast::mut_visit::{visit_clobber, MutVisitor}; use rustc_ast::ptr::P; use rustc_ast::*; use rustc_ast_pretty::pprust; -use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; -use rustc_span::{FileName, DUMMY_SP}; +use rustc_span::DUMMY_SP; use thin_vec::{thin_vec, ThinVec}; -fn parse_expr(psess: &ParseSess, src: &str) -> Option> { - let src_as_string = src.to_string(); - - let mut p = unwrap_or_emit_fatal(new_parser_from_source_str( - psess, - FileName::Custom(src_as_string.clone()), - src_as_string, - )); - p.parse_expr().map_err(|e| e.cancel()).ok() -} - // Helper functions for building exprs fn expr(kind: ExprKind) -> P { P(Expr { id: DUMMY_NODE_ID, kind, span: DUMMY_SP, attrs: AttrVec::new(), tokens: None }) From 1f2028f93013df476888b34fad78944ae9e4e837 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 20 Dec 2024 19:44:54 -0800 Subject: [PATCH 7/7] Show which test case was found to be meaningless --- tests/ui-fulldeps/pprust-parenthesis-insertion.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs index 0b6619e7ef1f9..b09e9d07488ea 100644 --- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs +++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs @@ -166,7 +166,9 @@ fn main() -> ExitCode { let psess = &ParseSess::new(vec![rustc_parse::DEFAULT_LOCALE_RESOURCE]); for &source_code in EXPRS { - let expr = parse_expr(psess, source_code).unwrap(); + let Some(expr) = parse_expr(psess, source_code) else { + panic!("Failed to parse original test case: {source_code}"); + }; // Check for FALSE POSITIVE: pretty-printer inserting parentheses where not needed. // Pseudocode: