about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs22
-rw-r--r--library/core/src/marker.rs10
-rw-r--r--tests/crashes/132127.rs9
-rw-r--r--tests/ui-fulldeps/auxiliary/parser.rs51
-rw-r--r--tests/ui-fulldeps/pprust-expr-roundtrip.rs18
-rw-r--r--tests/ui-fulldeps/pprust-parenthesis-insertion.rs43
-rw-r--r--tests/ui/dyn-star/illegal.rs16
-rw-r--r--tests/ui/dyn-star/illegal.stderr27
-rw-r--r--tests/ui/traits/negative-impls/ambiguity-cause.negative_coherence.stderr14
-rw-r--r--tests/ui/traits/negative-impls/ambiguity-cause.rs13
-rw-r--r--tests/ui/traits/negative-impls/ambiguity-cause.simple.stderr14
13 files changed, 176 insertions, 79 deletions
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 59c06cbc5b5..8190095971b 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 541e16e42a7..f9e4a592d92 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 1430cfae51f..401b41c796d 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 3d79706f8ec..d0d8609f43f 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 cca354b9876..00000000000
--- 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 00000000000..4ea0d814b1f
--- /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<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 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 8379ca86494..37e328a315f 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<P<Expr>> {
-    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<Expr> {
     P(Expr { id: DUMMY_NODE_ID, kind, span: DUMMY_SP, attrs: AttrVec::new(), tokens: None })
diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
index d6021b559d6..94c7964392d 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,15 +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_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.
@@ -156,34 +153,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<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| {
@@ -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 00000000000..ce0d784fcd2
--- /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 00000000000..fdf3c813a23
--- /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 <https://github.com/rust-lang/rust/issues/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`.
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 00000000000..4ec3414a57b
--- /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<T: Copy> 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 00000000000..30a528c535d
--- /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<T: Copy> 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 00000000000..4ec3414a57b
--- /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<T: Copy> 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`.