about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-02-09 01:18:06 +0000
committerbors <bors@rust-lang.org>2022-02-09 01:18:06 +0000
commit9a5a961be97f405e751dd2cf966e1cdb80a612c2 (patch)
treebbecfb9fa61a950ea9bf47d0d7519591a6456985
parentcc38176793e9e13bb7b70dde4b951d9371017662 (diff)
parentff3324c1878c293b59b8e4711997e3422402726f (diff)
downloadrust-9a5a961be97f405e751dd2cf966e1cdb80a612c2.tar.gz
rust-9a5a961be97f405e751dd2cf966e1cdb80a612c2.zip
Auto merge of #93778 - matthiaskrgr:rollup-yfngdao, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #91950 (Point at type when a `static` `#[global_allocator]` doesn't `impl` `GlobalAlloc`)
 - #92715 (Do not suggest char literal for zero-length strings)
 - #92917 (Don't constrain projection predicates with inference vars in GAT substs)
 - #93206 (Use `NtCreateFile` instead of `NtOpenFile` to open a file)
 - #93732 (add fut/back compat tests for implied trait bounds)
 - #93764 (:arrow_up: rust-analyzer)
 - #93767 (deduplicate `lcnr` in mailmap)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--.mailmap2
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs22
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs10
-rw-r--r--library/std/src/fs.rs2
-rw-r--r--library/std/src/sys/windows/c.rs12
-rw-r--r--library/std/src/sys/windows/fs.rs11
-rw-r--r--src/test/ui/allocator/not-an-allocator.stderr16
-rw-r--r--src/test/ui/generic-associated-types/issue-74824.rs1
-rw-r--r--src/test/ui/generic-associated-types/issue-74824.stderr11
-rw-r--r--src/test/ui/generic-associated-types/issue-91762.rs30
-rw-r--r--src/test/ui/generic-associated-types/issue-91762.stderr9
-rw-r--r--src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs51
-rw-r--r--src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr12
-rw-r--r--src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs35
-rw-r--r--src/test/ui/inference/char-as-str-multi.rs3
-rw-r--r--src/test/ui/inference/char-as-str-multi.stderr10
m---------src/tools/rust-analyzer38
19 files changed, 230 insertions, 49 deletions
diff --git a/.mailmap b/.mailmap
index ac221fa3a60..d72e6ebcb65 100644
--- a/.mailmap
+++ b/.mailmap
@@ -173,7 +173,7 @@ Kyle J Strand <batmanaod@gmail.com> <kyle.j.strand@gmail.com>
 Kyle J Strand <batmanaod@gmail.com> <kyle.strand@pieinsurance.com>
 Kyle J Strand <batmanaod@gmail.com> <kyle.strand@rms.com>
 Laurențiu Nicola <lnicola@dend.ro>
-lcnr <bastian_kauschke@hotmail.de>
+lcnr <rust@lcnr.de> <bastian_kauschke@hotmail.de>
 Lee Jeffery <leejeffery@gmail.com> Lee Jeffery <lee@leejeffery.co.uk>
 Lee Wondong <wdlee91@gmail.com>
 Lennart Kudling <github@kudling.de>
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index a433876147f..36cfbba45da 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -26,14 +26,14 @@ pub fn expand(
 
     // Allow using `#[global_allocator]` on an item statement
     // FIXME - if we get deref patterns, use them to reduce duplication here
-    let (item, is_stmt) = match &item {
+    let (item, is_stmt, ty_span) = match &item {
         Annotatable::Item(item) => match item.kind {
-            ItemKind::Static(..) => (item, false),
+            ItemKind::Static(ref ty, ..) => (item, false, ecx.with_def_site_ctxt(ty.span)),
             _ => return not_static(),
         },
         Annotatable::Stmt(stmt) => match &stmt.kind {
             StmtKind::Item(item_) => match item_.kind {
-                ItemKind::Static(..) => (item_, true),
+                ItemKind::Static(ref ty, ..) => (item_, true, ecx.with_def_site_ctxt(ty.span)),
                 _ => return not_static(),
             },
             _ => return not_static(),
@@ -43,13 +43,14 @@ pub fn expand(
 
     // Generate a bunch of new items using the AllocFnFactory
     let span = ecx.with_def_site_ctxt(item.span);
-    let f = AllocFnFactory { span, kind: AllocatorKind::Global, global: item.ident, cx: ecx };
+    let f =
+        AllocFnFactory { span, ty_span, kind: AllocatorKind::Global, global: item.ident, cx: ecx };
 
     // Generate item statements for the allocator methods.
     let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect();
 
     // Generate anonymous constant serving as container for the allocator methods.
-    let const_ty = ecx.ty(span, TyKind::Tup(Vec::new()));
+    let const_ty = ecx.ty(ty_span, TyKind::Tup(Vec::new()));
     let const_body = ecx.expr_block(ecx.block(span, stmts));
     let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
     let const_item = if is_stmt {
@@ -64,6 +65,7 @@ pub fn expand(
 
 struct AllocFnFactory<'a, 'b> {
     span: Span,
+    ty_span: Span,
     kind: AllocatorKind,
     global: Ident,
     cx: &'b ExtCtxt<'a>,
@@ -97,18 +99,18 @@ impl AllocFnFactory<'_, '_> {
             self.attrs(),
             kind,
         );
-        self.cx.stmt_item(self.span, item)
+        self.cx.stmt_item(self.ty_span, item)
     }
 
     fn call_allocator(&self, method: Symbol, mut args: Vec<P<Expr>>) -> P<Expr> {
         let method = self.cx.std_path(&[sym::alloc, sym::GlobalAlloc, method]);
-        let method = self.cx.expr_path(self.cx.path(self.span, method));
-        let allocator = self.cx.path_ident(self.span, self.global);
+        let method = self.cx.expr_path(self.cx.path(self.ty_span, method));
+        let allocator = self.cx.path_ident(self.ty_span, self.global);
         let allocator = self.cx.expr_path(allocator);
-        let allocator = self.cx.expr_addr_of(self.span, allocator);
+        let allocator = self.cx.expr_addr_of(self.ty_span, allocator);
         args.insert(0, allocator);
 
-        self.cx.expr_call(self.span, method, args)
+        self.cx.expr_call(self.ty_span, method, args)
     }
 
     fn attrs(&self) -> Vec<Attribute> {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 6fdfc8e39f1..8d41497541a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2053,7 +2053,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                 if let Some(code) =
                                     code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
                                 {
-                                    if code.chars().nth(1).is_none() {
+                                    if code.chars().count() == 1 {
                                         err.span_suggestion(
                                             span,
                                             "if you meant to write a `char` literal, use single quotes",
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 51b8c9aca78..65a18897b39 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2473,7 +2473,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     // `T`
                     substs: self.tcx.mk_substs_trait(
                         trait_pred.self_ty().skip_binder(),
-                        self.fresh_substs_for_item(span, item_def_id),
+                        &self.fresh_substs_for_item(span, item_def_id)[1..],
                     ),
                     // `Future::Output`
                     item_def_id,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 5e7d4c8b415..36cc14610cb 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1073,6 +1073,16 @@ fn project<'cx, 'tcx>(
         return Ok(Projected::Progress(Progress::error(selcx.tcx())));
     }
 
+    // If the obligation contains any inference types or consts in associated
+    // type substs, then we don't assemble any candidates.
+    // This isn't really correct, but otherwise we can end up in a case where
+    // we constrain inference variables by selecting a single predicate, when
+    // we need to stay general. See issue #91762.
+    let (_, predicate_own_substs) = obligation.predicate.trait_ref_and_own_substs(selcx.tcx());
+    if predicate_own_substs.iter().any(|g| g.has_infer_types_or_consts()) {
+        return Err(ProjectionError::TooManyCandidates);
+    }
+
     let mut candidates = ProjectionCandidateSet::None;
 
     // Make sure that the following procedures are kept in order. ParamEnv
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 95e90644426..0b65336a5a7 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -2044,7 +2044,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 ///
 /// This function currently corresponds to `openat`, `fdopendir`, `unlinkat` and `lstat` functions
 /// on Unix (except for macOS before version 10.10 and REDOX) and the `CreateFileW`,
-/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtOpenFile` functions on
+/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile` functions on
 /// Windows. Note that, this [may change in the future][changes].
 ///
 /// [changes]: io#platform-specific-behavior
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 09d3661e4fd..dfcd6124454 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -88,6 +88,7 @@ pub const FILE_SHARE_DELETE: DWORD = 0x4;
 pub const FILE_SHARE_READ: DWORD = 0x1;
 pub const FILE_SHARE_WRITE: DWORD = 0x2;
 
+pub const FILE_OPEN: ULONG = 0x00000001;
 pub const FILE_OPEN_REPARSE_POINT: ULONG = 0x200000;
 pub const OBJ_DONT_REPARSE: ULONG = 0x1000;
 
@@ -1228,15 +1229,20 @@ compat_fn! {
 
 compat_fn! {
     "ntdll":
-    pub fn NtOpenFile(
+    pub fn NtCreateFile(
         FileHandle: *mut HANDLE,
         DesiredAccess: ACCESS_MASK,
         ObjectAttributes: *const OBJECT_ATTRIBUTES,
         IoStatusBlock: *mut IO_STATUS_BLOCK,
+        AllocationSize: *mut i64,
+        FileAttributes: ULONG,
         ShareAccess: ULONG,
-        OpenOptions: ULONG
+        CreateDisposition: ULONG,
+        CreateOptions: ULONG,
+        EaBuffer: *mut c_void,
+        EaLength: ULONG
     ) -> NTSTATUS {
-        panic!("`NtOpenFile` not available");
+        panic!("`NtCreateFile` not available");
     }
     pub fn RtlNtStatusToDosError(
         Status: NTSTATUS
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index fed655af87e..cb83ee2469a 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -712,11 +712,11 @@ impl<'a> Iterator for DirBuffIter<'a> {
 
 /// Open a link relative to the parent directory, ensure no symlinks are followed.
 fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result<File> {
-    // This is implemented using the lower level `NtOpenFile` function as
+    // This is implemented using the lower level `NtCreateFile` function as
     // unfortunately opening a file relative to a parent is not supported by
     // win32 functions. It is however a fundamental feature of the NT kernel.
     //
-    // See https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntopenfile
+    // See https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntcreatefile
     unsafe {
         let mut handle = ptr::null_mut();
         let mut io_status = c::IO_STATUS_BLOCK::default();
@@ -732,14 +732,19 @@ fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result<
             Attributes: ATTRIBUTES.load(Ordering::Relaxed),
             ..c::OBJECT_ATTRIBUTES::default()
         };
-        let status = c::NtOpenFile(
+        let status = c::NtCreateFile(
             &mut handle,
             access,
             &object,
             &mut io_status,
+            crate::ptr::null_mut(),
+            0,
             c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE,
+            c::FILE_OPEN,
             // If `name` is a symlink then open the link rather than the target.
             c::FILE_OPEN_REPARSE_POINT,
+            crate::ptr::null_mut(),
+            0,
         );
         // Convert an NTSTATUS to the more familiar Win32 error codes (aka "DosError")
         if c::nt_success(status) {
diff --git a/src/test/ui/allocator/not-an-allocator.stderr b/src/test/ui/allocator/not-an-allocator.stderr
index e7a9ce94af4..c0f6118a9f1 100644
--- a/src/test/ui/allocator/not-an-allocator.stderr
+++ b/src/test/ui/allocator/not-an-allocator.stderr
@@ -1,40 +1,40 @@
 error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
-  --> $DIR/not-an-allocator.rs:2:1
+  --> $DIR/not-an-allocator.rs:2:11
    |
 LL | #[global_allocator]
    | ------------------- in this procedural macro expansion
 LL | static A: usize = 0;
-   | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
+   |           ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
    |
    = note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
-  --> $DIR/not-an-allocator.rs:2:1
+  --> $DIR/not-an-allocator.rs:2:11
    |
 LL | #[global_allocator]
    | ------------------- in this procedural macro expansion
 LL | static A: usize = 0;
-   | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
+   |           ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
    |
    = note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
-  --> $DIR/not-an-allocator.rs:2:1
+  --> $DIR/not-an-allocator.rs:2:11
    |
 LL | #[global_allocator]
    | ------------------- in this procedural macro expansion
 LL | static A: usize = 0;
-   | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
+   |           ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
    |
    = note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
-  --> $DIR/not-an-allocator.rs:2:1
+  --> $DIR/not-an-allocator.rs:2:11
    |
 LL | #[global_allocator]
    | ------------------- in this procedural macro expansion
 LL | static A: usize = 0;
-   | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
+   |           ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
    |
    = note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/generic-associated-types/issue-74824.rs b/src/test/ui/generic-associated-types/issue-74824.rs
index 1bbf7aac5cd..01f99fa4487 100644
--- a/src/test/ui/generic-associated-types/issue-74824.rs
+++ b/src/test/ui/generic-associated-types/issue-74824.rs
@@ -17,6 +17,7 @@ impl<T> UnsafeCopy for T {}
 fn main() {
     let b = Box::new(42usize);
     let copy = <()>::copy(&b);
+    //~^ type annotations needed
 
     let raw_b = Box::deref(&b) as *const _;
     let raw_copy = Box::deref(&copy) as *const _;
diff --git a/src/test/ui/generic-associated-types/issue-74824.stderr b/src/test/ui/generic-associated-types/issue-74824.stderr
index 8517eb9fa21..e7ebf5964ba 100644
--- a/src/test/ui/generic-associated-types/issue-74824.stderr
+++ b/src/test/ui/generic-associated-types/issue-74824.stderr
@@ -27,6 +27,13 @@ help: consider restricting type parameter `T`
 LL |     type Copy<T: std::clone::Clone>: Copy = Box<T>;
    |                +++++++++++++++++++
 
-error: aborting due to 2 previous errors
+error[E0282]: type annotations needed
+  --> $DIR/issue-74824.rs:19:16
+   |
+LL |     let copy = <()>::copy(&b);
+   |                ^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `copy`
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0282.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/issue-91762.rs b/src/test/ui/generic-associated-types/issue-91762.rs
new file mode 100644
index 00000000000..b259a3c6e06
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-91762.rs
@@ -0,0 +1,30 @@
+// check-fail
+
+// FIXME(generic_associated_types): We almost certaintly want this to pass, but
+// it's particularly difficult currently, because we need a way of specifying
+// that `<Self::Base as Functor>::With<T> = Self` without using that when we have
+// a `U`. See `https://github.com/rust-lang/rust/pull/92728` for a (hacky)
+// solution. This might be better to just wait for Chalk.
+
+#![feature(generic_associated_types)]
+
+pub trait Functor {
+    type With<T>;
+
+    fn fmap<T, U>(this: Self::With<T>) -> Self::With<U>;
+}
+
+pub trait FunctorExt<T>: Sized {
+    type Base: Functor<With<T> = Self>;
+
+    fn fmap<U>(self) {
+        let arg: <Self::Base as Functor>::With<T>;
+        let ret: <Self::Base as Functor>::With<U>;
+
+        arg = self;
+        ret = <Self::Base as Functor>::fmap(arg);
+        //~^ type annotations needed
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-91762.stderr b/src/test/ui/generic-associated-types/issue-91762.stderr
new file mode 100644
index 00000000000..a9c465cdd7e
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-91762.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-91762.rs:25:15
+   |
+LL |         ret = <Self::Base as Functor>::fmap(arg);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `fmap`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs
new file mode 100644
index 00000000000..d9de73a38ef
--- /dev/null
+++ b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs
@@ -0,0 +1,51 @@
+// A test exploiting the bug behind #25860 except with
+// implied trait bounds which currently don't exist without `-Zchalk`.
+use std::marker::PhantomData;
+struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
+where
+    T: Convert<'a, 'b>;
+
+trait Convert<'a, 'b>: Sized {
+    fn cast(&'a self) -> &'b Self;
+}
+impl<'long: 'short, 'short, T> Convert<'long, 'short> for T {
+    fn cast(&'long self) -> &'short T {
+        self
+    }
+}
+
+// This function will compile once we add implied trait bounds.
+//
+// If we're not careful with our impl, the transformations
+// in `bad` would succeed, which is unsound ✨
+//
+// FIXME: the error is pretty bad, this should say
+//
+//     `T: Convert<'in_, 'out>` is not implemented
+//
+// help: needed by `Foo<'in_, 'out, T>`
+//
+// Please ping @lcnr if your changes end up causing `badboi` to compile.
+fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) -> &'out T {
+    //~^ ERROR lifetime mismatch
+    sadness.cast()
+}
+
+fn bad<'short, T>(value: &'short T) -> &'static T {
+    let x: for<'in_, 'out> fn(Foo<'in_, 'out, T>, &'in_ T) -> &'out T = badboi;
+    let x: for<'out> fn(Foo<'short, 'out, T>, &'short T) -> &'out T = x;
+    let x: for<'out> fn(Foo<'static, 'out, T>, &'short T) -> &'out T = x;
+    let x: fn(Foo<'static, 'static, T>, &'short T) -> &'static T = x;
+    x(Foo(PhantomData), value)
+}
+
+// Use `bad` to cause a segfault.
+fn main() {
+    let mut outer: Option<&'static u32> = Some(&3);
+    let static_ref: &'static &'static u32 = match outer {
+        Some(ref reference) => bad(reference),
+        None => unreachable!(),
+    };
+    outer = None;
+    println!("{}", static_ref);
+}
diff --git a/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr
new file mode 100644
index 00000000000..b020ea64bf4
--- /dev/null
+++ b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr
@@ -0,0 +1,12 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/hrlt-implied-trait-bounds-guard.rs:29:29
+   |
+LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) -> &'out T {
+   |                             ^^^^^^^^^^^^^^^^^^                       -------
+   |                             |
+   |                             this parameter and the return type are declared with different lifetimes...
+   |                             ...but data from `x` is returned here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs
new file mode 100644
index 00000000000..69847d6a8bb
--- /dev/null
+++ b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs
@@ -0,0 +1,35 @@
+// check-pass
+struct Foo<'a>(&'a ())
+where
+    (): Trait<'a>;
+
+trait Trait<'a> {
+    fn id<T>(value: &'a T) -> &'static T;
+}
+
+impl Trait<'static> for () {
+    fn id<T>(value: &'static T) -> &'static T {
+        value
+    }
+}
+
+fn could_use_implied_bounds<'a, T>(_: Foo<'a>, x: &'a T) -> &'static T
+where
+    (): Trait<'a>, // This could be an implied bound
+{
+    <()>::id(x)
+}
+
+fn main() {
+    let bar: for<'a, 'b> fn(Foo<'a>, &'b ()) = |_, _| {};
+
+    // If `could_use_implied_bounds` were to use implied bounds,
+    // keeping 'a late-bound, then we could assign that function
+    // to this variable.
+    let bar: for<'a> fn(Foo<'a>, &'a ()) = bar;
+
+    // In this case, the subtyping relation here would be unsound,
+    // allowing us to transmute lifetimes. This currently compiles
+    // because we incorrectly deal with implied bounds inside of binders.
+    let _bar: for<'a, 'b> fn(Foo<'a>, &'b ()) = bar;
+}
diff --git a/src/test/ui/inference/char-as-str-multi.rs b/src/test/ui/inference/char-as-str-multi.rs
index 21bbc6f20b2..c29a15025a9 100644
--- a/src/test/ui/inference/char-as-str-multi.rs
+++ b/src/test/ui/inference/char-as-str-multi.rs
@@ -1,6 +1,7 @@
-// When a MULTI-character string literal is used where a char should be,
+// When a MULTI/NO-character string literal is used where a char should be,
 // DO NOT suggest changing to single quotes.
 
 fn main() {
     let _: char = "foo"; //~ ERROR mismatched types
+    let _: char = ""; //~ ERROR mismatched types
 }
diff --git a/src/test/ui/inference/char-as-str-multi.stderr b/src/test/ui/inference/char-as-str-multi.stderr
index c3ba17a5579..297ca2b548f 100644
--- a/src/test/ui/inference/char-as-str-multi.stderr
+++ b/src/test/ui/inference/char-as-str-multi.stderr
@@ -6,6 +6,14 @@ LL |     let _: char = "foo";
    |            |
    |            expected due to this
 
-error: aborting due to previous error
+error[E0308]: mismatched types
+  --> $DIR/char-as-str-multi.rs:6:19
+   |
+LL |     let _: char = "";
+   |            ----   ^^ expected `char`, found `&str`
+   |            |
+   |            expected due to this
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject 9700addc82111200a2150b9a796f62dd8e600dd
+Subproject ba330548023607717295f0dfd61b72eda41aa9d