about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-10-12 05:42:23 +0000
committerbors <bors@rust-lang.org>2024-10-12 05:42:23 +0000
commit763ad520cc6b831ec98e20f8a8fe85b160ad859d (patch)
tree30c855c33c3ce962a0f2e166a32ff088b0225c83
parent6a3b69c6b0529151da5fb4568961519a80adccf9 (diff)
parent1439844faaa86a593c5e20fe22dd72f1332b1dbc (diff)
downloadrust-763ad520cc6b831ec98e20f8a8fe85b160ad859d.tar.gz
rust-763ad520cc6b831ec98e20f8a8fe85b160ad859d.zip
Auto merge of #131423 - cuviper:beta-next, r=cuviper
[beta] backports

- Only add an automatic SONAME for Rust dylibs #130960
- Reject leading unsafe in `cfg!(...)` and `--check-cfg` #131057, resolving https://github.com/rust-lang/rust/issues/131055
- Disable jump threading `UnOp::Not` for non-bool #131201
- Update LLVM submodule #131448
- Split x86_64-msvc-ext into two jobs #130072
- Use a small runner for msvc-ext2 job #130151

r? ghost
-rw-r--r--.gitmodules2
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs83
-rw-r--r--compiler/rustc_interface/src/interface.rs2
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs8
-rwxr-xr-xsrc/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh15
-rw-r--r--src/ci/github-actions/jobs.yml16
m---------src/llvm-project0
-rw-r--r--tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff46
-rw-r--r--tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff46
-rw-r--r--tests/mir-opt/jump_threading.rs11
-rw-r--r--tests/run-make/dylib-soname/rmake.rs16
-rw-r--r--tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs6
-rw-r--r--tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr20
-rw-r--r--tests/ui/check-cfg/invalid-arguments.rs3
-rw-r--r--tests/ui/check-cfg/invalid-arguments.unsafe_attr.stderr5
17 files changed, 251 insertions, 32 deletions
diff --git a/.gitmodules b/.gitmodules
index b5250d49386..b549282fd89 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -33,7 +33,7 @@
 [submodule "src/llvm-project"]
 	path = src/llvm-project
 	url = https://github.com/rust-lang/llvm-project.git
-	branch = rustc/19.1-2024-07-30
+	branch = rustc/19.1-2024-09-17
 	shallow = true
 [submodule "src/doc/embedded-book"]
 	path = src/doc/embedded-book
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index de198115fa0..cf1d5c68ead 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -43,7 +43,7 @@ fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a,
         return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
     }
 
-    let cfg = p.parse_meta_item(AllowLeadingUnsafe::Yes)?;
+    let cfg = p.parse_meta_item(AllowLeadingUnsafe::No)?;
 
     let _ = p.eat(&token::Comma);
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index e8143b9a5f3..1518e45f16f 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2493,7 +2493,7 @@ fn add_order_independent_options(
         }
     }
 
-    cmd.set_output_kind(link_output_kind, out_filename);
+    cmd.set_output_kind(link_output_kind, crate_type, out_filename);
 
     add_relro_args(cmd, sess);
 
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index cb266247e0d..8274ff17d8e 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -266,7 +266,12 @@ pub trait Linker {
     fn is_cc(&self) -> bool {
         false
     }
-    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
+    fn set_output_kind(
+        &mut self,
+        output_kind: LinkOutputKind,
+        crate_type: CrateType,
+        out_filename: &Path,
+    );
     fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
         bug!("dylib linked with unsupported linker")
     }
@@ -387,7 +392,7 @@ impl<'a> GccLinker<'a> {
         ]);
     }
 
-    fn build_dylib(&mut self, out_filename: &Path) {
+    fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) {
         // On mac we need to tell the linker to let this library be rpathed
         if self.sess.target.is_like_osx {
             if !self.is_ld {
@@ -418,7 +423,7 @@ impl<'a> GccLinker<'a> {
                     let mut out_implib = OsString::from("--out-implib=");
                     out_implib.push(out_filename.with_file_name(implib_name));
                     self.link_arg(out_implib);
-                } else {
+                } else if crate_type == CrateType::Dylib {
                     // When dylibs are linked by a full path this value will get into `DT_NEEDED`
                     // instead of the full path, so the library can be later found in some other
                     // location than that specific path.
@@ -465,7 +470,12 @@ impl<'a> Linker for GccLinker<'a> {
         !self.is_ld
     }
 
-    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
+    fn set_output_kind(
+        &mut self,
+        output_kind: LinkOutputKind,
+        crate_type: CrateType,
+        out_filename: &Path,
+    ) {
         match output_kind {
             LinkOutputKind::DynamicNoPicExe => {
                 if !self.is_ld && self.is_gnu {
@@ -500,10 +510,10 @@ impl<'a> Linker for GccLinker<'a> {
                     self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
                 }
             }
-            LinkOutputKind::DynamicDylib => self.build_dylib(out_filename),
+            LinkOutputKind::DynamicDylib => self.build_dylib(crate_type, out_filename),
             LinkOutputKind::StaticDylib => {
                 self.link_or_cc_arg("-static");
-                self.build_dylib(out_filename);
+                self.build_dylib(crate_type, out_filename);
             }
             LinkOutputKind::WasiReactorExe => {
                 self.link_args(&["--entry", "_initialize"]);
@@ -859,7 +869,12 @@ impl<'a> Linker for MsvcLinker<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
+    fn set_output_kind(
+        &mut self,
+        output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        out_filename: &Path,
+    ) {
         match output_kind {
             LinkOutputKind::DynamicNoPicExe
             | LinkOutputKind::DynamicPicExe
@@ -1111,7 +1126,13 @@ impl<'a> Linker for EmLinker<'a> {
         true
     }
 
-    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+    fn set_output_kind(
+        &mut self,
+        _output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        _out_filename: &Path,
+    ) {
+    }
 
     fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
         // Emscripten always links statically
@@ -1260,7 +1281,12 @@ impl<'a> Linker for WasmLd<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) {
+    fn set_output_kind(
+        &mut self,
+        output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        _out_filename: &Path,
+    ) {
         match output_kind {
             LinkOutputKind::DynamicNoPicExe
             | LinkOutputKind::DynamicPicExe
@@ -1409,7 +1435,13 @@ impl<'a> Linker for L4Bender<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+    fn set_output_kind(
+        &mut self,
+        _output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        _out_filename: &Path,
+    ) {
+    }
 
     fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
         self.hint_static();
@@ -1556,7 +1588,12 @@ impl<'a> Linker for AixLinker<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
+    fn set_output_kind(
+        &mut self,
+        output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        out_filename: &Path,
+    ) {
         match output_kind {
             LinkOutputKind::DynamicDylib => {
                 self.hint_dynamic();
@@ -1763,7 +1800,13 @@ impl<'a> Linker for PtxLinker<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+    fn set_output_kind(
+        &mut self,
+        _output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        _out_filename: &Path,
+    ) {
+    }
 
     fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
         panic!("staticlibs not supported")
@@ -1829,7 +1872,13 @@ impl<'a> Linker for LlbcLinker<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+    fn set_output_kind(
+        &mut self,
+        _output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        _out_filename: &Path,
+    ) {
+    }
 
     fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
         panic!("staticlibs not supported")
@@ -1900,7 +1949,13 @@ impl<'a> Linker for BpfLinker<'a> {
         &mut self.cmd
     }
 
-    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+    fn set_output_kind(
+        &mut self,
+        _output_kind: LinkOutputKind,
+        _crate_type: CrateType,
+        _out_filename: &Path,
+    ) {
+    }
 
     fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
         panic!("staticlibs not supported")
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 04e2b7d45dc..3f29d1d3cbc 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -174,7 +174,7 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
             }
         };
 
-        let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::Yes) {
+        let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::No) {
             Ok(meta_item) if parser.token == token::Eof => meta_item,
             Ok(..) => expected_error(),
             Err(err) => {
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 435b6a01163..7ef566720e0 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -492,8 +492,16 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
             }
             // Transfer the conditions on the copy rhs, after inversing polarity.
             Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => {
+                if !place.ty(self.body, self.tcx).ty.is_bool() {
+                    // Constructing the conditions by inverting the polarity
+                    // of equality is only correct for bools. That is to say,
+                    // `!a == b` is not `a != b` for integers greater than 1 bit.
+                    return;
+                }
                 let Some(conditions) = state.try_get_idx(lhs, self.map) else { return };
                 let Some(place) = self.map.find(place.as_ref()) else { return };
+                // FIXME: I think This could be generalized to not bool if we
+                // actually perform a logical not on the condition's value.
                 let conds = conditions.map(self.arena, Condition::inv);
                 state.insert_value_idx(place, conds, self.map);
             }
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
index a5a5acc333b..303a2f26c0f 100755
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh
@@ -58,8 +58,9 @@ case $HOST_TARGET in
     # Strangely, Linux targets do not work here. cargo always says
     # "error: cannot produce cdylib for ... as the target ... does not support these crate types".
     # Only run "pass" tests, which is quite a bit faster.
-    python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass
-    python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-gnu --test-args pass
+    #FIXME: Re-enable this once CI issues are fixed
+    #python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass
+    #python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-gnu --test-args pass
     ;;
   *)
     echo "FATAL: unexpected host $HOST_TARGET"
@@ -68,6 +69,10 @@ case $HOST_TARGET in
 esac
 # Also smoke-test `x.py miri`. This doesn't run any actual tests (that would take too long),
 # but it ensures that the crates build properly when tested with Miri.
-python3 "$X_PY" miri --stage 2 library/core --test-args notest
-python3 "$X_PY" miri --stage 2 library/alloc --test-args notest
-python3 "$X_PY" miri --stage 2 library/std --test-args notest
+
+#FIXME: Re-enable this for msvc once CI issues are fixed
+if [ "$HOST_TARGET" != "x86_64-pc-windows-msvc" ]; then
+  python3 "$X_PY" miri --stage 2 library/core --test-args notest
+  python3 "$X_PY" miri --stage 2 library/alloc --test-args notest
+  python3 "$X_PY" miri --stage 2 library/std --test-args notest
+fi
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 4de44c6dd39..04ea1bdc082 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -24,6 +24,10 @@ runners:
     os: macos-14
     <<: *base-job
 
+  - &job-windows
+    os: windows-2022
+    <<: *base-job
+
   - &job-windows-8c
     os: windows-2022-8core-32gb
     <<: *base-job
@@ -373,6 +377,18 @@ auto:
       DEPLOY_TOOLSTATES_JSON: toolstates-windows.json
     <<: *job-windows-8c
 
+  # Temporary builder to workaround CI issues
+  - image: x86_64-msvc-ext2
+    env:
+      SCRIPT: >
+        python x.py test --stage 2 src/tools/miri --target aarch64-apple-darwin --test-args pass &&
+        python x.py test --stage 2 src/tools/miri --target i686-pc-windows-gnu --test-args pass &&
+        python x.py miri --stage 2 library/core --test-args notest &&
+        python x.py miri --stage 2 library/alloc --test-args notest &&
+        python x.py miri --stage 2 library/std --test-args notest
+      RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld
+    <<: *job-windows
+
   # 32/64-bit MinGW builds.
   #
   # We are using MinGW with POSIX threads since LLVM requires
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 4b8d29c585687084bbcf21471e04f279d1eddc0
+Subproject 3a17f74904a74565c54cfac0d67026362d03869
diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff
new file mode 100644
index 00000000000..047441e6099
--- /dev/null
+++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff
@@ -0,0 +1,46 @@
+- // MIR for `bitwise_not` before JumpThreading
++ // MIR for `bitwise_not` after JumpThreading
+  
+  fn bitwise_not() -> i32 {
+      let mut _0: i32;
+      let mut _1: i32;
+      let mut _2: bool;
+      let mut _3: i32;
+      let mut _4: i32;
+      scope 1 {
+          debug a => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = const 0_i32;
+          _1 = const 1_i32;
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = copy _1;
+          _3 = Not(move _4);
+          StorageDead(_4);
+          _2 = Eq(move _3, const 0_i32);
+          switchInt(move _2) -> [0: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          StorageDead(_3);
+          _0 = const 1_i32;
+          goto -> bb3;
+      }
+  
+      bb2: {
+          StorageDead(_3);
+          _0 = const 0_i32;
+          goto -> bb3;
+      }
+  
+      bb3: {
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff
new file mode 100644
index 00000000000..047441e6099
--- /dev/null
+++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff
@@ -0,0 +1,46 @@
+- // MIR for `bitwise_not` before JumpThreading
++ // MIR for `bitwise_not` after JumpThreading
+  
+  fn bitwise_not() -> i32 {
+      let mut _0: i32;
+      let mut _1: i32;
+      let mut _2: bool;
+      let mut _3: i32;
+      let mut _4: i32;
+      scope 1 {
+          debug a => _1;
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = const 0_i32;
+          _1 = const 1_i32;
+          StorageLive(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = copy _1;
+          _3 = Not(move _4);
+          StorageDead(_4);
+          _2 = Eq(move _3, const 0_i32);
+          switchInt(move _2) -> [0: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          StorageDead(_3);
+          _0 = const 1_i32;
+          goto -> bb3;
+      }
+  
+      bb2: {
+          StorageDead(_3);
+          _0 = const 0_i32;
+          goto -> bb3;
+      }
+  
+      bb3: {
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs
index 9487a4e7e5f..4094dec0cbf 100644
--- a/tests/mir-opt/jump_threading.rs
+++ b/tests/mir-opt/jump_threading.rs
@@ -531,6 +531,16 @@ fn floats() -> u32 {
     if x == 0.0 { 0 } else { 1 }
 }
 
+pub fn bitwise_not() -> i32 {
+    // CHECK-LABEL: fn bitwise_not(
+    // CHECK: switchInt(
+
+    // Test for #131195, which was optimizing `!a == b` into `a != b`.
+    let mut a: i32 = 0;
+    a = 1;
+    if !a == 0 { 1 } else { 0 }
+}
+
 fn main() {
     // CHECK-LABEL: fn main(
     too_complex(Ok(0));
@@ -562,3 +572,4 @@ fn main() {
 // EMIT_MIR jump_threading.assume.JumpThreading.diff
 // EMIT_MIR jump_threading.aggregate_copy.JumpThreading.diff
 // EMIT_MIR jump_threading.floats.JumpThreading.diff
+// EMIT_MIR jump_threading.bitwise_not.JumpThreading.diff
diff --git a/tests/run-make/dylib-soname/rmake.rs b/tests/run-make/dylib-soname/rmake.rs
index cec0d463842..714997cbc1a 100644
--- a/tests/run-make/dylib-soname/rmake.rs
+++ b/tests/run-make/dylib-soname/rmake.rs
@@ -7,12 +7,16 @@
 use run_make_support::{cmd, run_in_tmpdir, rustc};
 
 fn main() {
+    let check = |ty: &str| {
+        rustc().crate_name("foo").crate_type(ty).input("foo.rs").run();
+        cmd("readelf").arg("-d").arg("libfoo.so").run()
+    };
     run_in_tmpdir(|| {
-        rustc().crate_name("foo").crate_type("dylib").input("foo.rs").run();
-        cmd("readelf")
-            .arg("-d")
-            .arg("libfoo.so")
-            .run()
-            .assert_stdout_contains("Library soname: [libfoo.so]");
+        // Rust dylibs should get a relative SONAME
+        check("dylib").assert_stdout_contains("Library soname: [libfoo.so]");
+    });
+    run_in_tmpdir(|| {
+        // C dylibs should not implicitly get any SONAME
+        check("cdylib").assert_stdout_not_contains("Library soname:");
     });
 }
diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
index b561550c198..273b127bf9c 100644
--- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
@@ -27,4 +27,8 @@ mod inner {
 #[unsafe(used)] //~ ERROR: is not an unsafe attribute
 static FOO: usize = 0;
 
-fn main() {}
+fn main() {
+    let _a = cfg!(unsafe(foo));
+    //~^ ERROR: expected identifier, found keyword `unsafe`
+    //~^^ ERROR: invalid predicate `r#unsafe`
+}
diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr
index 9fb7f062b91..445d239d867 100644
--- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr
@@ -22,6 +22,23 @@ LL | #[unsafe(test)]
    |
    = note: extraneous unsafe is not allowed in attributes
 
+error: expected identifier, found keyword `unsafe`
+  --> $DIR/extraneous-unsafe-attributes.rs:31:19
+   |
+LL |     let _a = cfg!(unsafe(foo));
+   |                   ^^^^^^ expected identifier, found keyword
+   |
+help: escape `unsafe` to use it as an identifier
+   |
+LL |     let _a = cfg!(r#unsafe(foo));
+   |                   ++
+
+error[E0537]: invalid predicate `r#unsafe`
+  --> $DIR/extraneous-unsafe-attributes.rs:31:19
+   |
+LL |     let _a = cfg!(unsafe(foo));
+   |                   ^^^^^^^^^^^
+
 error: `ignore` is not an unsafe attribute
   --> $DIR/extraneous-unsafe-attributes.rs:13:3
    |
@@ -62,5 +79,6 @@ LL | #[unsafe(used)]
    |
    = note: extraneous unsafe is not allowed in attributes
 
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
 
+For more information about this error, try `rustc --explain E0537`.
diff --git a/tests/ui/check-cfg/invalid-arguments.rs b/tests/ui/check-cfg/invalid-arguments.rs
index b8588ecb4ff..c6b1218ce27 100644
--- a/tests/ui/check-cfg/invalid-arguments.rs
+++ b/tests/ui/check-cfg/invalid-arguments.rs
@@ -8,7 +8,7 @@
 //@ revisions: values_any_missing_values values_any_before_ident ident_in_values_1
 //@ revisions: ident_in_values_2 unknown_meta_item_1 unknown_meta_item_2 unknown_meta_item_3
 //@ revisions: mixed_values_any mixed_any any_values giberich unterminated
-//@ revisions: none_not_empty cfg_none
+//@ revisions: none_not_empty cfg_none unsafe_attr
 //
 //@ [anything_else]compile-flags: --check-cfg=anything_else(...)
 //@ [boolean]compile-flags: --check-cfg=cfg(true)
@@ -33,5 +33,6 @@
 //@ [cfg_none]compile-flags: --check-cfg=cfg(none())
 //@ [giberich]compile-flags: --check-cfg=cfg(...)
 //@ [unterminated]compile-flags: --check-cfg=cfg(
+//@ [unsafe_attr]compile-flags: --check-cfg=unsafe(cfg(foo))
 
 fn main() {}
diff --git a/tests/ui/check-cfg/invalid-arguments.unsafe_attr.stderr b/tests/ui/check-cfg/invalid-arguments.unsafe_attr.stderr
new file mode 100644
index 00000000000..5236ed6f605
--- /dev/null
+++ b/tests/ui/check-cfg/invalid-arguments.unsafe_attr.stderr
@@ -0,0 +1,5 @@
+error: invalid `--check-cfg` argument: `unsafe(cfg(foo))`
+   |
+   = note: expected `cfg(name, values("value1", "value2", ... "valueN"))`
+   = note: visit <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more details
+