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/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/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( 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-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-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 > {
- 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| {
@@ -199,7 +168,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:
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