about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-07-27 15:41:45 +0000
committerbors <bors@rust-lang.org>2019-07-27 15:41:45 +0000
commita5e7bb3e2bae3e8d31c10de66e91cdcea42a97df (patch)
tree3bda6c31bb326cb96e871a1d751a0d9756e8a7b6 /src
parent0e9b465d729d07101b29b4d096d83edf9be82df0 (diff)
parent51769b3012b3f2819bbcde05a574e6f3015b7d37 (diff)
downloadrust-a5e7bb3e2bae3e8d31c10de66e91cdcea42a97df.tar.gz
rust-a5e7bb3e2bae3e8d31c10de66e91cdcea42a97df.zip
Auto merge of #63043 - Centril:rollup-f4baee4, r=Centril
Rollup of 6 pull requests

Successful merges:

 - #62423 (Fix cycle error with existential types)
 - #62979 (Cleanup save-analysis JsonDumper)
 - #62982 (Don't access a static just for its size and alignment)
 - #63013 (add `repr(transparent)` to `IoSliceMut` where missing)
 - #63014 (Stop bare trait lint applying to macro call sites)
 - #63036 (Add lib section to rustc_lexer's Cargo.toml)

Failed merges:

r? @ghost
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/lowering.rs22
-rw-r--r--src/librustc_lexer/Cargo.toml6
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs38
-rw-r--r--src/librustc_mir/interpret/memory.rs75
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs20
-rw-r--r--src/librustc_save_analysis/dumper.rs (renamed from src/librustc_save_analysis/json_dumper.rs)61
-rw-r--r--src/librustc_save_analysis/lib.rs32
-rw-r--r--src/librustc_typeck/check/writeback.rs55
-rw-r--r--src/libstd/sys/unix/io.rs1
-rw-r--r--src/libstd/sys/wasi/io.rs1
-rw-r--r--src/libstd/sys/windows/io.rs1
-rw-r--r--src/test/ui/consts/static-cycle-error.rs11
-rw-r--r--src/test/ui/existential_types/existential-types-with-cycle-error.rs2
-rw-r--r--src/test/ui/existential_types/existential-types-with-cycle-error.stderr24
-rw-r--r--src/test/ui/existential_types/existential-types-with-cycle-error2.rs2
-rw-r--r--src/test/ui/existential_types/existential-types-with-cycle-error2.stderr24
-rw-r--r--src/test/ui/existential_types/existential_type_const.rs20
-rw-r--r--src/test/ui/existential_types/existential_type_const.stderr6
-rw-r--r--src/test/ui/existential_types/existential_type_fns.rs27
-rw-r--r--src/test/ui/existential_types/existential_type_tuple.rs33
-rw-r--r--src/test/ui/existential_types/no_inferrable_concrete_type.rs6
-rw-r--r--src/test/ui/existential_types/no_inferrable_concrete_type.stderr21
-rw-r--r--src/test/ui/suggestions/auxiliary/issue-61963-1.rs40
-rw-r--r--src/test/ui/suggestions/auxiliary/issue-61963.rs41
-rw-r--r--src/test/ui/suggestions/issue-61963.rs24
-rw-r--r--src/test/ui/suggestions/issue-61963.stderr14
26 files changed, 388 insertions, 219 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 2d1835514d4..639994ed14d 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -5753,13 +5753,21 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) {
-        self.sess.buffer_lint_with_diagnostic(
-            builtin::BARE_TRAIT_OBJECTS,
-            id,
-            span,
-            "trait objects without an explicit `dyn` are deprecated",
-            builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global),
-        )
+        // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
+        // call site which do not have a macro backtrace. See #61963.
+        let is_macro_callsite = self.sess.source_map()
+            .span_to_snippet(span)
+            .map(|snippet| snippet.starts_with("#["))
+            .unwrap_or(true);
+        if !is_macro_callsite {
+            self.sess.buffer_lint_with_diagnostic(
+                builtin::BARE_TRAIT_OBJECTS,
+                id,
+                span,
+                "trait objects without an explicit `dyn` are deprecated",
+                builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global),
+            )
+        }
     }
 
     fn wrap_in_try_constructor(
diff --git a/src/librustc_lexer/Cargo.toml b/src/librustc_lexer/Cargo.toml
index 9c0230e8322..0dbcda618ec 100644
--- a/src/librustc_lexer/Cargo.toml
+++ b/src/librustc_lexer/Cargo.toml
@@ -7,3 +7,9 @@ edition = "2018"
 # Note that this crate purposefully does not depend on other rustc crates
 [dependencies]
 unicode-xid = { version = "0.1.0", optional = true }
+
+# Note: do not remove this blank `[lib]` section.
+# This will be used when publishing this crate as `rustc-ap-rustc_lexer`.
+[lib]
+doctest = false
+name = "rustc_lexer"
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 59a8c8d34d2..45b806bd286 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -1281,15 +1281,43 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let opaque_defn_ty = tcx.type_of(opaque_def_id);
                         let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
                         let opaque_defn_ty = renumber::renumber_regions(infcx, &opaque_defn_ty);
+                        let concrete_is_opaque = infcx
+                            .resolve_vars_if_possible(&opaque_decl.concrete_ty).is_impl_trait();
+
                         debug!(
-                            "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
+                            "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?} \
+                            concrete_is_opaque={}",
                             opaque_decl.concrete_ty,
                             infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty),
-                            opaque_defn_ty
+                            opaque_defn_ty,
+                            concrete_is_opaque
                         );
-                        obligations.add(infcx
-                            .at(&ObligationCause::dummy(), param_env)
-                            .eq(opaque_decl.concrete_ty, opaque_defn_ty)?);
+
+                        // concrete_is_opaque is `true` when we're using an existential
+                        // type without 'revealing' it. For example, code like this:
+                        //
+                        // existential type Foo: Debug;
+                        // fn foo1() -> Foo { ... }
+                        // fn foo2() -> Foo { foo1() }
+                        //
+                        // In `foo2`, we're not revealing the type of `Foo` - we're
+                        // just treating it as the opaque type.
+                        //
+                        // When this occurs, we do *not* want to try to equate
+                        // the concrete type with the underlying defining type
+                        // of the existential type - this will always fail, since
+                        // the defining type of an existential type is always
+                        // some other type (e.g. not itself)
+                        // Essentially, none of the normal obligations apply here -
+                        // we're just passing around some unknown opaque type,
+                        // without actually looking at the underlying type it
+                        // gets 'revealed' into
+
+                        if !concrete_is_opaque {
+                            obligations.add(infcx
+                                .at(&ObligationCause::dummy(), param_env)
+                                .eq(opaque_decl.concrete_ty, opaque_defn_ty)?);
+                        }
                     }
 
                     debug!("eq_opaque_type_and_type: equated");
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 3f2a76a77be..4575784ac37 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -535,41 +535,48 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         id: AllocId,
         liveness: AllocCheck,
     ) -> InterpResult<'static, (Size, Align)> {
-        // Regular allocations.
-        if let Ok(alloc) = self.get(id) {
-            return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align));
-        }
-        // Function pointers.
-        if let Ok(_) = self.get_fn_alloc(id) {
-            return if let AllocCheck::Dereferencable = liveness {
-                // The caller requested no function pointers.
-                err!(DerefFunctionPointer)
-            } else {
-                Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
-            };
-        }
-        // Foreign statics.
-        // Can't do this in the match argument, we may get cycle errors since the lock would
-        // be held throughout the match.
-        let alloc = self.tcx.alloc_map.lock().get(id);
-        match alloc {
-            Some(GlobalAlloc::Static(did)) => {
-                assert!(self.tcx.is_foreign_item(did));
-                // Use size and align of the type
-                let ty = self.tcx.type_of(did);
-                let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
-                return Ok((layout.size, layout.align.abi));
+        // Don't use `self.get` here as that will
+        // a) cause cycles in case `id` refers to a static
+        // b) duplicate a static's allocation in miri
+        match self.alloc_map.get_or(id, || Err(())) {
+            Ok((_, alloc)) => Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)),
+            Err(()) => {
+                // Not a local allocation, check the global `tcx.alloc_map`.
+
+                // Can't do this in the match argument, we may get cycle errors since the lock would
+                // be held throughout the match.
+                let alloc = self.tcx.alloc_map.lock().get(id);
+                match alloc {
+                    Some(GlobalAlloc::Static(did)) => {
+                        // Use size and align of the type.
+                        let ty = self.tcx.type_of(did);
+                        let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
+                        Ok((layout.size, layout.align.abi))
+                    },
+                    Some(GlobalAlloc::Memory(alloc)) =>
+                        // Need to duplicate the logic here, because the global allocations have
+                        // different associated types than the interpreter-local ones.
+                        Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)),
+                    Some(GlobalAlloc::Function(_)) => {
+                        if let AllocCheck::Dereferencable = liveness {
+                            // The caller requested no function pointers.
+                            err!(DerefFunctionPointer)
+                        } else {
+                            Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
+                        }
+                    },
+                    // The rest must be dead.
+                    None => if let AllocCheck::MaybeDead = liveness {
+                        // Deallocated pointers are allowed, we should be able to find
+                        // them in the map.
+                        Ok(*self.dead_alloc_map.get(&id)
+                            .expect("deallocated pointers should all be recorded in \
+                                    `dead_alloc_map`"))
+                    } else {
+                        err!(DanglingPointerDeref)
+                    },
+                }
             }
-            _ => {}
-        }
-        // The rest must be dead.
-        if let AllocCheck::MaybeDead = liveness {
-            // Deallocated pointers are allowed, we should be able to find
-            // them in the map.
-            Ok(*self.dead_alloc_map.get(&id)
-                .expect("deallocated pointers should all be recorded in `dead_alloc_map`"))
-        } else {
-            err!(DanglingPointerDeref)
         }
     }
 
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index dfdf560d419..2b349613dc5 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -10,7 +10,7 @@
 //!
 //! SpanUtils is used to manipulate spans. In particular, to extract sub-spans
 //! from spans (e.g., the span for `bar` from the above example path).
-//! DumpVisitor walks the AST and processes it, and JsonDumper is used for
+//! DumpVisitor walks the AST and processes it, and Dumper is used for
 //! recording the output.
 
 use rustc::hir::def::{Res, DefKind as HirDefKind};
@@ -38,7 +38,7 @@ use syntax_pos::*;
 
 use crate::{escape, generated_code, id_from_def_id, id_from_node_id, lower_attributes,
             PathCollector, SaveContext};
-use crate::json_dumper::{Access, DumpOutput, JsonDumper};
+use crate::dumper::{Access, Dumper};
 use crate::span_utils::SpanUtils;
 use crate::sig;
 
@@ -75,10 +75,10 @@ macro_rules! access_from_vis {
     };
 }
 
-pub struct DumpVisitor<'l, 'tcx, 'll, O: DumpOutput> {
+pub struct DumpVisitor<'l, 'tcx, 'll> {
     save_ctxt: SaveContext<'l, 'tcx>,
     tcx: TyCtxt<'tcx>,
-    dumper: &'ll mut JsonDumper<O>,
+    dumper: &'ll mut Dumper,
 
     span: SpanUtils<'l>,
 
@@ -92,11 +92,11 @@ pub struct DumpVisitor<'l, 'tcx, 'll, O: DumpOutput> {
     // macro_calls: FxHashSet<Span>,
 }
 
-impl<'l, 'tcx, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
+impl<'l, 'tcx, 'll> DumpVisitor<'l, 'tcx, 'll> {
     pub fn new(
         save_ctxt: SaveContext<'l, 'tcx>,
-        dumper: &'ll mut JsonDumper<O>,
-    ) -> DumpVisitor<'l, 'tcx, 'll, O> {
+        dumper: &'ll mut Dumper,
+    ) -> DumpVisitor<'l, 'tcx, 'll> {
         let span_utils = SpanUtils::new(&save_ctxt.tcx.sess);
         DumpVisitor {
             tcx: save_ctxt.tcx,
@@ -111,7 +111,7 @@ impl<'l, 'tcx, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
 
     fn nest_scope<F>(&mut self, scope_id: NodeId, f: F)
     where
-        F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, O>),
+        F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll>),
     {
         let parent_scope = self.cur_scope;
         self.cur_scope = scope_id;
@@ -121,7 +121,7 @@ impl<'l, 'tcx, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
 
     fn nest_tables<F>(&mut self, item_id: NodeId, f: F)
     where
-        F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, O>),
+        F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll>),
     {
         let item_def_id = self.tcx.hir().local_def_id_from_node_id(item_id);
         if self.tcx.has_typeck_tables(item_def_id) {
@@ -1311,7 +1311,7 @@ impl<'l, 'tcx, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
     }
 }
 
-impl<'l, 'tcx, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, O> {
+impl<'l, 'tcx, 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll> {
     fn visit_mod(&mut self, m: &'l ast::Mod, span: Span, attrs: &[ast::Attribute], id: NodeId) {
         // Since we handle explicit modules ourselves in visit_item, this should
         // only get called for the root module of a crate.
diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/dumper.rs
index 82b78369e13..6fb55e6c990 100644
--- a/src/librustc_save_analysis/json_dumper.rs
+++ b/src/librustc_save_analysis/dumper.rs
@@ -1,80 +1,33 @@
-use std::io::Write;
-
 use rls_data::config::Config;
 use rls_data::{self, Analysis, CompilationOptions, CratePreludeData, Def, DefKind, Impl, Import,
                MacroRef, Ref, RefKind, Relation};
 use rls_span::{Column, Row};
 
-use log::error;
-
 #[derive(Debug)]
 pub struct Access {
     pub reachable: bool,
     pub public: bool,
 }
 
-pub struct JsonDumper<O: DumpOutput> {
+pub struct Dumper {
     result: Analysis,
     config: Config,
-    output: O,
-}
-
-pub trait DumpOutput {
-    fn dump(&mut self, result: &Analysis);
-}
-
-pub struct WriteOutput<'b, W: Write> {
-    output: &'b mut W,
-}
-
-impl<'b, W: Write> DumpOutput for WriteOutput<'b, W> {
-    fn dump(&mut self, result: &Analysis) {
-        if let Err(e) = serde_json::to_writer(self.output.by_ref(), result) {
-            error!("Can't serialize save-analysis: {:?}", e);
-        }
-    }
-}
-
-pub struct CallbackOutput<'b> {
-    callback: &'b mut dyn FnMut(&Analysis),
-}
-
-impl<'b> DumpOutput for CallbackOutput<'b> {
-    fn dump(&mut self, result: &Analysis) {
-        (self.callback)(result)
-    }
 }
 
-impl<'b, W: Write> JsonDumper<WriteOutput<'b, W>> {
-    pub fn new(writer: &'b mut W, config: Config) -> JsonDumper<WriteOutput<'b, W>> {
-        JsonDumper {
-            output: WriteOutput { output: writer },
+impl Dumper {
+    pub fn new(config: Config) -> Dumper {
+        Dumper {
             config: config.clone(),
             result: Analysis::new(config),
         }
     }
-}
-
-impl<'b> JsonDumper<CallbackOutput<'b>> {
-    pub fn with_callback(
-        callback: &'b mut dyn FnMut(&Analysis),
-        config: Config,
-    ) -> JsonDumper<CallbackOutput<'b>> {
-        JsonDumper {
-            output: CallbackOutput { callback },
-            config: config.clone(),
-            result: Analysis::new(config),
-        }
-    }
-}
 
-impl<O: DumpOutput> Drop for JsonDumper<O> {
-    fn drop(&mut self) {
-        self.output.dump(&self.result);
+    pub fn to_output(self, f: impl FnOnce(&Analysis)) {
+        f(&self.result)
     }
 }
 
-impl<'b, O: DumpOutput + 'b> JsonDumper<O> {
+impl Dumper {
     pub fn crate_prelude(&mut self, data: CratePreludeData) {
         self.result.prelude = Some(data)
     }
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index c987a46b567..ade5e2eca60 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -7,7 +7,7 @@
 #![recursion_limit="256"]
 
 
-mod json_dumper;
+mod dumper;
 mod dump_visitor;
 #[macro_use]
 mod span_utils;
@@ -39,7 +39,7 @@ use syntax::visit::{self, Visitor};
 use syntax::print::pprust::{arg_to_string, ty_to_string};
 use syntax_pos::*;
 
-use json_dumper::JsonDumper;
+use dumper::Dumper;
 use dump_visitor::DumpVisitor;
 use span_utils::SpanUtils;
 
@@ -1075,17 +1075,19 @@ impl<'a> SaveHandler for DumpHandler<'a> {
         input: &'l Input,
     ) {
         let sess = &save_ctxt.tcx.sess;
-        let file_name = {
-            let (mut output, file_name) = self.output_file(&save_ctxt);
-            let mut dumper = JsonDumper::new(&mut output, save_ctxt.config.clone());
-            let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
+        let (output, file_name) = self.output_file(&save_ctxt);
+        let mut dumper = Dumper::new(save_ctxt.config.clone());
+        let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
 
-            visitor.dump_crate_info(cratename, krate);
-            visitor.dump_compilation_options(input, cratename);
-            visit::walk_crate(&mut visitor, krate);
+        visitor.dump_crate_info(cratename, krate);
+        visitor.dump_compilation_options(input, cratename);
+        visit::walk_crate(&mut visitor, krate);
 
-            file_name
-        };
+        dumper.to_output(|analysis| {
+            if let Err(e) = serde_json::to_writer(output, analysis) {
+                error!("Can't serialize save-analysis: {:?}", e);
+            }
+        });
 
         if sess.opts.debugging_opts.emit_artifact_notifications {
             sess.parse_sess.span_diagnostic
@@ -1107,17 +1109,19 @@ impl<'b> SaveHandler for CallbackHandler<'b> {
         cratename: &str,
         input: &'l Input,
     ) {
-        // We're using the JsonDumper here because it has the format of the
+        // We're using the Dumper here because it has the format of the
         // save-analysis results that we will pass to the callback. IOW, we are
-        // using the JsonDumper to collect the save-analysis results, but not
+        // using the Dumper to collect the save-analysis results, but not
         // actually to dump them to a file. This is all a bit convoluted and
         // there is certainly a simpler design here trying to get out (FIXME).
-        let mut dumper = JsonDumper::with_callback(self.callback, save_ctxt.config.clone());
+        let mut dumper = Dumper::new(save_ctxt.config.clone());
         let mut visitor = DumpVisitor::new(save_ctxt, &mut dumper);
 
         visitor.dump_crate_info(cratename, krate);
         visitor.dump_compilation_options(input, cratename);
         visit::walk_crate(&mut visitor, krate);
+
+        dumper.to_output(|a| (self.callback)(a))
     }
 }
 
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 145b37ff907..cfafdd02a6a 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -453,36 +453,43 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
                 def_id, opaque_defn, instantiated_ty, span);
 
+            let mut skip_add = false;
+
             if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.sty {
                 if def_id == defin_ty_def_id {
-                    // Concrete type resolved to the existential type itself.
-                    // Force a cycle error.
-                    // FIXME(oli-obk): we could just not insert it into `concrete_existential_types`
-                    // which simply would make this use not a defining use.
-                    self.tcx().at(span).type_of(defin_ty_def_id);
+                    debug!("Skipping adding concrete definition for opaque type {:?} {:?}",
+                           opaque_defn, defin_ty_def_id);
+                    skip_add = true;
                 }
             }
 
             if !opaque_defn.substs.has_local_value() {
-                let new = ty::ResolvedOpaqueTy {
-                    concrete_type: definition_ty,
-                    substs: opaque_defn.substs,
-                };
-
-                let old = self.tables
-                    .concrete_existential_types
-                    .insert(def_id, new);
-                if let Some(old) = old {
-                    if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
-                        span_bug!(
-                            span,
-                            "visit_opaque_types tried to write \
-                            different types for the same existential type: {:?}, {:?}, {:?}, {:?}",
-                            def_id,
-                            definition_ty,
-                            opaque_defn,
-                            old,
-                        );
+                // We only want to add an entry into `concrete_existential_types`
+                // if we actually found a defining usage of this existential type.
+                // Otherwise, we do nothing - we'll either find a defining usage
+                // in some other location, or we'll end up emitting an error due
+                // to the lack of defining usage
+                if !skip_add {
+                    let new = ty::ResolvedOpaqueTy {
+                        concrete_type: definition_ty,
+                        substs: opaque_defn.substs,
+                    };
+
+                    let old = self.tables
+                        .concrete_existential_types
+                        .insert(def_id, new);
+                    if let Some(old) = old {
+                        if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
+                            span_bug!(
+                                span,
+                                "visit_opaque_types tried to write different types for the same \
+                                existential type: {:?}, {:?}, {:?}, {:?}",
+                                def_id,
+                                definition_ty,
+                                opaque_defn,
+                                old,
+                            );
+                        }
                     }
                 }
             } else {
diff --git a/src/libstd/sys/unix/io.rs b/src/libstd/sys/unix/io.rs
index 72954ff20ef..bc854e772e1 100644
--- a/src/libstd/sys/unix/io.rs
+++ b/src/libstd/sys/unix/io.rs
@@ -29,6 +29,7 @@ impl<'a> IoSlice<'a> {
     }
 }
 
+#[repr(transparent)]
 pub struct IoSliceMut<'a> {
     vec: iovec,
     _p: PhantomData<&'a mut [u8]>,
diff --git a/src/libstd/sys/wasi/io.rs b/src/libstd/sys/wasi/io.rs
index cc8f1e16fa0..a5bddad708b 100644
--- a/src/libstd/sys/wasi/io.rs
+++ b/src/libstd/sys/wasi/io.rs
@@ -29,6 +29,7 @@ impl<'a> IoSlice<'a> {
     }
 }
 
+#[repr(transparent)]
 pub struct IoSliceMut<'a> {
     vec: __wasi_iovec_t,
     _p: PhantomData<&'a mut [u8]>,
diff --git a/src/libstd/sys/windows/io.rs b/src/libstd/sys/windows/io.rs
index c045a63e911..f0da2323f4f 100644
--- a/src/libstd/sys/windows/io.rs
+++ b/src/libstd/sys/windows/io.rs
@@ -29,6 +29,7 @@ impl<'a> IoSlice<'a> {
     }
 }
 
+#[repr(transparent)]
 pub struct IoSliceMut<'a> {
     vec: c::WSABUF,
     _p: PhantomData<&'a mut [u8]>,
diff --git a/src/test/ui/consts/static-cycle-error.rs b/src/test/ui/consts/static-cycle-error.rs
new file mode 100644
index 00000000000..9ce050aae21
--- /dev/null
+++ b/src/test/ui/consts/static-cycle-error.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+struct Foo {
+    foo: Option<&'static Foo>
+}
+
+static FOO: Foo = Foo {
+    foo: Some(&FOO),
+};
+
+fn main() {}
diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error.rs b/src/test/ui/existential_types/existential-types-with-cycle-error.rs
index 3f0190892eb..38fcabb5cc1 100644
--- a/src/test/ui/existential_types/existential-types-with-cycle-error.rs
+++ b/src/test/ui/existential_types/existential-types-with-cycle-error.rs
@@ -1,7 +1,7 @@
 #![feature(existential_type)]
 
 existential type Foo: Fn() -> Foo;
-//~^ ERROR: cycle detected when processing `Foo`
+//~^ ERROR: could not find defining uses
 
 fn crash(x: Foo) -> Foo {
     x
diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error.stderr b/src/test/ui/existential_types/existential-types-with-cycle-error.stderr
index 56057a9caa4..98a269d5271 100644
--- a/src/test/ui/existential_types/existential-types-with-cycle-error.stderr
+++ b/src/test/ui/existential_types/existential-types-with-cycle-error.stderr
@@ -1,30 +1,8 @@
-error[E0391]: cycle detected when processing `Foo`
+error: could not find defining uses
   --> $DIR/existential-types-with-cycle-error.rs:3:1
    |
 LL | existential type Foo: Fn() -> Foo;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires processing `crash`...
-  --> $DIR/existential-types-with-cycle-error.rs:6:25
-   |
-LL |   fn crash(x: Foo) -> Foo {
-   |  _________________________^
-LL | |     x
-LL | | }
-   | |_^
-   = note: ...which again requires processing `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
-  --> $DIR/existential-types-with-cycle-error.rs:1:1
-   |
-LL | / #![feature(existential_type)]
-LL | |
-LL | | existential type Foo: Fn() -> Foo;
-LL | |
-...  |
-LL | |
-LL | | }
-   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error2.rs b/src/test/ui/existential_types/existential-types-with-cycle-error2.rs
index 29410309ef2..f9e6bdb67d4 100644
--- a/src/test/ui/existential_types/existential-types-with-cycle-error2.rs
+++ b/src/test/ui/existential_types/existential-types-with-cycle-error2.rs
@@ -5,7 +5,7 @@ pub trait Bar<T> {
 }
 
 existential type Foo: Bar<Foo, Item = Foo>;
-//~^ ERROR: cycle detected when processing `Foo`
+//~^ ERROR: could not find defining uses
 
 fn crash(x: Foo) -> Foo {
     x
diff --git a/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr b/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr
index 8c7bf52470a..830305d8631 100644
--- a/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr
+++ b/src/test/ui/existential_types/existential-types-with-cycle-error2.stderr
@@ -1,30 +1,8 @@
-error[E0391]: cycle detected when processing `Foo`
+error: could not find defining uses
   --> $DIR/existential-types-with-cycle-error2.rs:7:1
    |
 LL | existential type Foo: Bar<Foo, Item = Foo>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires processing `crash`...
-  --> $DIR/existential-types-with-cycle-error2.rs:10:25
-   |
-LL |   fn crash(x: Foo) -> Foo {
-   |  _________________________^
-LL | |     x
-LL | | }
-   | |_^
-   = note: ...which again requires processing `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
-  --> $DIR/existential-types-with-cycle-error2.rs:1:1
-   |
-LL | / #![feature(existential_type)]
-LL | |
-LL | | pub trait Bar<T> {
-LL | |     type Item;
-...  |
-LL | |
-LL | | }
-   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/existential_types/existential_type_const.rs b/src/test/ui/existential_types/existential_type_const.rs
new file mode 100644
index 00000000000..646e9a73424
--- /dev/null
+++ b/src/test/ui/existential_types/existential_type_const.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+#![feature(existential_type)]
+// Currently, the `existential_type` feature implicitly
+// depends on `impl_trait_in_bindings` in order to work properly.
+// Specifically, this line requires `impl_trait_in_bindings` to be enabled:
+// https://github.com/rust-lang/rust/blob/481068a707679257e2a738b40987246e0420e787/src/librustc_typeck/check/mod.rs#L856
+#![feature(impl_trait_in_bindings)]
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+
+// Ensures that `const` items can constrain an `existential type`.
+
+use std::fmt::Debug;
+
+pub existential type Foo: Debug;
+
+const _FOO: Foo = 5;
+
+fn main() {
+}
diff --git a/src/test/ui/existential_types/existential_type_const.stderr b/src/test/ui/existential_types/existential_type_const.stderr
new file mode 100644
index 00000000000..049b4f75dd2
--- /dev/null
+++ b/src/test/ui/existential_types/existential_type_const.stderr
@@ -0,0 +1,6 @@
+warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+  --> $DIR/existential_type_const.rs:8:12
+   |
+LL | #![feature(impl_trait_in_bindings)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/src/test/ui/existential_types/existential_type_fns.rs b/src/test/ui/existential_types/existential_type_fns.rs
new file mode 100644
index 00000000000..6f22eef2849
--- /dev/null
+++ b/src/test/ui/existential_types/existential_type_fns.rs
@@ -0,0 +1,27 @@
+// check-pass
+
+#![feature(existential_type)]
+
+// Regression test for issue #61863
+
+pub trait MyTrait {}
+
+#[derive(Debug)]
+pub struct MyStruct {
+  v: u64
+}
+
+impl MyTrait for MyStruct {}
+
+pub fn bla() -> TE {
+    return MyStruct {v:1}
+}
+
+pub fn bla2() -> TE {
+    bla()
+}
+
+
+existential type TE: MyTrait;
+
+fn main() {}
diff --git a/src/test/ui/existential_types/existential_type_tuple.rs b/src/test/ui/existential_types/existential_type_tuple.rs
new file mode 100644
index 00000000000..0f134a52897
--- /dev/null
+++ b/src/test/ui/existential_types/existential_type_tuple.rs
@@ -0,0 +1,33 @@
+// check-pass
+
+#![feature(existential_type)]
+#![allow(dead_code)]
+
+pub trait MyTrait {}
+
+impl MyTrait for bool {}
+
+struct Blah {
+    my_foo: Foo,
+    my_u8: u8
+}
+
+impl Blah {
+    fn new() -> Blah {
+        Blah {
+            my_foo: make_foo(),
+            my_u8: 12
+        }
+    }
+    fn into_inner(self) -> (Foo, u8) {
+        (self.my_foo, self.my_u8)
+    }
+}
+
+fn make_foo() -> Foo {
+    true
+}
+
+existential type Foo: MyTrait;
+
+fn main() {}
diff --git a/src/test/ui/existential_types/no_inferrable_concrete_type.rs b/src/test/ui/existential_types/no_inferrable_concrete_type.rs
index 6bbe8bdc0cd..eec8a4be63d 100644
--- a/src/test/ui/existential_types/no_inferrable_concrete_type.rs
+++ b/src/test/ui/existential_types/no_inferrable_concrete_type.rs
@@ -1,9 +1,9 @@
-// Issue 52985: Cause cycle error if user code provides no use case that allows an existential type
-// to be inferred to a concrete type. This results in an infinite cycle during type normalization.
+// Issue 52985: user code provides no use case that allows an existential type
+// We now emit a 'could not find defining uses' error
 
 #![feature(existential_type)]
 
-existential type Foo: Copy; //~ cycle detected
+existential type Foo: Copy; //~ could not find defining uses
 
 // make compiler happy about using 'Foo'
 fn bar(x: Foo) -> Foo { x }
diff --git a/src/test/ui/existential_types/no_inferrable_concrete_type.stderr b/src/test/ui/existential_types/no_inferrable_concrete_type.stderr
index 4605332ef5b..bc9a883c836 100644
--- a/src/test/ui/existential_types/no_inferrable_concrete_type.stderr
+++ b/src/test/ui/existential_types/no_inferrable_concrete_type.stderr
@@ -1,27 +1,8 @@
-error[E0391]: cycle detected when processing `Foo`
+error: could not find defining uses
   --> $DIR/no_inferrable_concrete_type.rs:6:1
    |
 LL | existential type Foo: Copy;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires processing `bar`...
-  --> $DIR/no_inferrable_concrete_type.rs:9:23
-   |
-LL | fn bar(x: Foo) -> Foo { x }
-   |                       ^^^^^
-   = note: ...which again requires processing `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
-  --> $DIR/no_inferrable_concrete_type.rs:4:1
-   |
-LL | / #![feature(existential_type)]
-LL | |
-LL | | existential type Foo: Copy;
-LL | |
-...  |
-LL | |     let _: Foo = std::mem::transmute(0u8);
-LL | | }
-   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/suggestions/auxiliary/issue-61963-1.rs b/src/test/ui/suggestions/auxiliary/issue-61963-1.rs
new file mode 100644
index 00000000000..6c2df7e84e0
--- /dev/null
+++ b/src/test/ui/suggestions/auxiliary/issue-61963-1.rs
@@ -0,0 +1,40 @@
+// force-host
+// no-prefer-dynamic
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{Group, TokenStream, TokenTree};
+
+// This macro exists as part of a reproduction of #61963 but without using quote/syn/proc_macro2.
+
+#[proc_macro_derive(DomObject)]
+pub fn expand_token_stream(input: TokenStream) -> TokenStream {
+    // Construct a dummy span - `#0 bytes(0..0)` - which is present in the input because
+    // of the specially crafted generated tokens in the `attribute-crate` proc-macro.
+    let dummy_span = input.clone().into_iter().nth(0).unwrap().span();
+
+    // Define what the macro would output if constructed properly from the source using syn/quote.
+    let output: TokenStream = "impl Bar for ((), Qux<Qux<Baz> >) { }
+    impl Bar for ((), Box<Bar>) { }".parse().unwrap();
+
+    let mut tokens: Vec<_> = output.into_iter().collect();
+    // Adjust token spans to match the original crate (which would use `quote`). Some of the
+    // generated tokens point to the dummy span.
+    for token in tokens.iter_mut() {
+        if let TokenTree::Group(group) = token {
+            let mut tokens: Vec<_> = group.stream().into_iter().collect();
+            for token in tokens.iter_mut().skip(2) {
+                token.set_span(dummy_span);
+            }
+
+            let mut stream = TokenStream::new();
+            stream.extend(tokens);
+            *group = Group::new(group.delimiter(), stream);
+        }
+    }
+
+    let mut output = TokenStream::new();
+    output.extend(tokens);
+    output
+}
diff --git a/src/test/ui/suggestions/auxiliary/issue-61963.rs b/src/test/ui/suggestions/auxiliary/issue-61963.rs
new file mode 100644
index 00000000000..e86f1610ab0
--- /dev/null
+++ b/src/test/ui/suggestions/auxiliary/issue-61963.rs
@@ -0,0 +1,41 @@
+// force-host
+// no-prefer-dynamic
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{Group, Spacing, Punct, TokenTree, TokenStream};
+
+// This macro exists as part of a reproduction of #61963 but without using quote/syn/proc_macro2.
+
+#[proc_macro_attribute]
+pub fn dom_struct(_: TokenStream, input: TokenStream) -> TokenStream {
+    // Construct the expected output tokens - the input but with a `#[derive(DomObject)]` applied.
+    let attributes: TokenStream =
+        "#[derive(DomObject)]".to_string().parse().unwrap();
+    let output: TokenStream = attributes.into_iter()
+        .chain(input.into_iter()).collect();
+
+    let mut tokens: Vec<_> = output.into_iter().collect();
+    // Adjust the spacing of `>` tokens to match what `quote` would produce.
+    for token in tokens.iter_mut() {
+        if let TokenTree::Group(group) = token {
+            let mut tokens: Vec<_> = group.stream().into_iter().collect();
+            for token in tokens.iter_mut() {
+                if let TokenTree::Punct(p) = token {
+                    if p.as_char() == '>' {
+                        *p = Punct::new('>', Spacing::Alone);
+                    }
+                }
+            }
+
+            let mut stream = TokenStream::new();
+            stream.extend(tokens);
+            *group = Group::new(group.delimiter(), stream);
+        }
+    }
+
+    let mut output = TokenStream::new();
+    output.extend(tokens);
+    output
+}
diff --git a/src/test/ui/suggestions/issue-61963.rs b/src/test/ui/suggestions/issue-61963.rs
new file mode 100644
index 00000000000..c9d738f5a28
--- /dev/null
+++ b/src/test/ui/suggestions/issue-61963.rs
@@ -0,0 +1,24 @@
+// aux-build:issue-61963.rs
+// aux-build:issue-61963-1.rs
+#![deny(bare_trait_objects)]
+
+#[macro_use]
+extern crate issue_61963;
+#[macro_use]
+extern crate issue_61963_1;
+
+// This test checks that the bare trait object lint does not trigger on macro attributes that
+// generate code which would trigger the lint.
+
+pub struct Baz;
+pub trait Bar { }
+pub struct Qux<T>(T);
+
+#[dom_struct]
+pub struct Foo {
+    qux: Qux<Qux<Baz>>,
+    bar: Box<Bar>,
+    //~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-61963.stderr b/src/test/ui/suggestions/issue-61963.stderr
new file mode 100644
index 00000000000..46943f40066
--- /dev/null
+++ b/src/test/ui/suggestions/issue-61963.stderr
@@ -0,0 +1,14 @@
+error: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/issue-61963.rs:20:14
+   |
+LL |     bar: Box<Bar>,
+   |              ^^^ help: use `dyn`: `dyn Bar`
+   |
+note: lint level defined here
+  --> $DIR/issue-61963.rs:3:9
+   |
+LL | #![deny(bare_trait_objects)]
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+