diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index e6d26240e242e..5a1670f06fc64 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -276,10 +276,12 @@ E0509: include_str!("./error_codes/E0509.md"),
E0510: include_str!("./error_codes/E0510.md"),
E0511: include_str!("./error_codes/E0511.md"),
E0512: include_str!("./error_codes/E0512.md"),
+E0514: include_str!("./error_codes/E0514.md"),
E0515: include_str!("./error_codes/E0515.md"),
E0516: include_str!("./error_codes/E0516.md"),
E0517: include_str!("./error_codes/E0517.md"),
E0518: include_str!("./error_codes/E0518.md"),
+E0519: include_str!("./error_codes/E0519.md"),
E0520: include_str!("./error_codes/E0520.md"),
E0521: include_str!("./error_codes/E0521.md"),
E0522: include_str!("./error_codes/E0522.md"),
@@ -615,8 +617,6 @@ E0791: include_str!("./error_codes/E0791.md"),
// E0488, // lifetime of variable does not enclose its declaration
// E0489, // type/lifetime parameter not in scope here
E0490, // a value of type `..` is borrowed for too long
- E0514, // metadata version mismatch
- E0519, // local crate and dependency have same (crate-name, disambiguator)
E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
// E0526, // shuffle indices are not constant
// E0540, // multiple rustc_deprecated attributes
diff --git a/compiler/rustc_error_codes/src/error_codes/E0514.md b/compiler/rustc_error_codes/src/error_codes/E0514.md
new file mode 100644
index 0000000000000..ce2bbc5c5056c
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0514.md
@@ -0,0 +1,33 @@
+Dependency compiled with different version of `rustc`.
+
+Example of erroneous code:
+
+`a.rs`
+```ignore (cannot-link-with-other-tests)
+// compiled with stable `rustc`
+
+#[crate_type = "lib"]
+```
+
+`b.rs`
+```ignore (cannot-link-with-other-tests)
+// compiled with nightly `rustc`
+
+#[crate_type = "lib"]
+
+extern crate a; // error: found crate `a` compiled by an incompatible version
+ // of rustc
+```
+
+This error is caused when the version of `rustc` used to compile a crate, as
+stored in the binary's metadata, differs from the version of one of its
+dependencies. Many parts of Rust binaries are considered unstable. For
+instance, the Rust ABI is not stable between compiler versions. This means that
+the compiler cannot be sure about *how* to call a function between compiler
+versions, and therefore this error occurs.
+
+This error can be fixed by:
+ * Using [Cargo](../cargo/index.html), the Rust package manager and
+ [Rustup](https://rust-lang.github.io/rustup/), the Rust toolchain installer,
+ automatically fixing this issue.
+ * Recompiling the crates with a uniform `rustc` version.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0519.md b/compiler/rustc_error_codes/src/error_codes/E0519.md
new file mode 100644
index 0000000000000..12876e2ad75fc
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0519.md
@@ -0,0 +1,40 @@
+The current crate is indistinguishable from one of its dependencies, in terms
+of metadata.
+
+Example of erroneous code:
+
+`a.rs`
+```ignore (cannot-link-with-other-tests)
+#![crate_name = "a"]
+#![crate_type = "lib"]
+
+pub fn foo() {}
+```
+
+`b.rs`
+```ignore (cannot-link-with-other-tests)
+#![crate_name = "a"]
+#![crate_type = "lib"]
+
+// error: the current crate is indistinguishable from one of its dependencies:
+// it has the same crate-name `a` and was compiled with the same
+// `-C metadata` arguments. This will result in symbol conflicts between
+// the two.
+extern crate a;
+
+pub fn foo() {}
+
+fn bar() {
+ a::foo(); // is this calling the local crate or the dependency?
+}
+```
+
+The above example compiles two crates with exactly the same name and
+`crate_type` (plus any other metadata). This causes an error because it becomes
+impossible for the compiler to distinguish between symbols (`pub` item names).
+
+This error can be fixed by:
+ * Using [Cargo](../cargo/index.html), the Rust package manager, automatically
+ fixing this issue.
+ * Recompiling the crate with different metadata (different name/
+ `crate_type`).
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index e2a0e436fd5e2..0ca200abe19fb 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -845,7 +845,10 @@ impl EmitterWriter {
// 3 | |
// 4 | | }
// | |_^ test
- if let [ann] = &line.annotations[..] {
+ let mut buffer_ops = vec![];
+ let mut annotations = vec![];
+ let mut short_start = true;
+ for ann in &line.annotations {
if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) {
let style = if ann.is_primary {
@@ -853,10 +856,23 @@ impl EmitterWriter {
} else {
Style::UnderlineSecondary
};
- buffer.putc(line_offset, width_offset + depth - 1, '/', style);
- return vec![(depth, style)];
+ annotations.push((depth, style));
+ buffer_ops.push((line_offset, width_offset + depth - 1, '/', style));
+ } else {
+ short_start = false;
+ break;
}
+ } else if let AnnotationType::MultilineLine(_) = ann.annotation_type {
+ } else {
+ short_start = false;
+ break;
+ }
+ }
+ if short_start {
+ for (y, x, c, s) in buffer_ops {
+ buffer.putc(y, x, c, s);
}
+ return annotations;
}
// We want to display like this:
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index e1ced2eb9656c..265c03e40b7f0 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2423,7 +2423,7 @@ impl<'a> Parser<'a> {
}
/// Parses the parameter list of a function, including the `(` and `)` delimiters.
- fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec> {
+ pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec> {
let mut first_param = true;
// Parse the arguments, starting out with `self` being allowed...
let (mut params, _) = self.parse_paren_comma_seq(|p| {
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 8661e9ca16b8d..fb5dea457e1d1 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -933,8 +933,8 @@ impl<'a> Parser<'a> {
has_parens: bool,
modifiers: BoundModifiers,
) -> PResult<'a, GenericBound> {
- let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
- let path = if self.token.is_keyword(kw::Fn)
+ let mut lifetime_defs = self.parse_late_bound_lifetime_defs()?;
+ let mut path = if self.token.is_keyword(kw::Fn)
&& self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
&& let Some(path) = self.recover_path_from_fn()
{
@@ -942,6 +942,11 @@ impl<'a> Parser<'a> {
} else {
self.parse_path(PathStyle::Type)?
};
+
+ if self.may_recover() && self.token == TokenKind::OpenDelim(Delimiter::Parenthesis) {
+ self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?;
+ }
+
if has_parens {
if self.token.is_like_plus() {
// Someone has written something like `&dyn (Trait + Other)`. The correct code
@@ -1016,6 +1021,92 @@ impl<'a> Parser<'a> {
}
}
+ /// Recover from `Fn`-family traits (Fn, FnMut, FnOnce) with lifetime arguments
+ /// (e.g. `FnOnce<'a>(&'a str) -> bool`). Up to generic arguments have already
+ /// been eaten.
+ fn recover_fn_trait_with_lifetime_params(
+ &mut self,
+ fn_path: &mut ast::Path,
+ lifetime_defs: &mut Vec,
+ ) -> PResult<'a, ()> {
+ let fn_path_segment = fn_path.segments.last_mut().unwrap();
+ let generic_args = if let Some(p_args) = &fn_path_segment.args {
+ p_args.clone().into_inner()
+ } else {
+ // Normally it wouldn't come here because the upstream should have parsed
+ // generic parameters (otherwise it's impossible to call this function).
+ return Ok(());
+ };
+ let lifetimes =
+ if let ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { span: _, args }) =
+ &generic_args
+ {
+ args.into_iter()
+ .filter_map(|arg| {
+ if let ast::AngleBracketedArg::Arg(generic_arg) = arg
+ && let ast::GenericArg::Lifetime(lifetime) = generic_arg {
+ Some(lifetime)
+ } else {
+ None
+ }
+ })
+ .collect()
+ } else {
+ Vec::new()
+ };
+ // Only try to recover if the trait has lifetime params.
+ if lifetimes.is_empty() {
+ return Ok(());
+ }
+
+ // Parse `(T, U) -> R`.
+ let inputs_lo = self.token.span;
+ let inputs: Vec<_> =
+ self.parse_fn_params(|_| false)?.into_iter().map(|input| input.ty).collect();
+ let inputs_span = inputs_lo.to(self.prev_token.span);
+ let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?;
+ let args = ast::ParenthesizedArgs {
+ span: fn_path_segment.span().to(self.prev_token.span),
+ inputs,
+ inputs_span,
+ output,
+ }
+ .into();
+ *fn_path_segment =
+ ast::PathSegment { ident: fn_path_segment.ident, args, id: ast::DUMMY_NODE_ID };
+
+ // Convert parsed `<'a>` in `Fn<'a>` into `for<'a>`.
+ let mut generic_params = lifetimes
+ .iter()
+ .map(|lt| GenericParam {
+ id: lt.id,
+ ident: lt.ident,
+ attrs: ast::AttrVec::new(),
+ bounds: Vec::new(),
+ is_placeholder: false,
+ kind: ast::GenericParamKind::Lifetime,
+ colon_span: None,
+ })
+ .collect::>();
+ lifetime_defs.append(&mut generic_params);
+
+ let generic_args_span = generic_args.span();
+ let mut err =
+ self.struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters");
+ let snippet = format!(
+ "for<{}> ",
+ lifetimes.iter().map(|lt| lt.ident.as_str()).intersperse(", ").collect::(),
+ );
+ let before_fn_path = fn_path.span.shrink_to_lo();
+ err.multipart_suggestion(
+ "consider using a higher-ranked trait bound instead",
+ vec![(generic_args_span, "".to_owned()), (before_fn_path, snippet)],
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ Ok(())
+ }
+
pub(super) fn check_lifetime(&mut self) -> bool {
self.expected_tokens.push(TokenType::Lifetime);
self.token.is_lifetime()
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 472086eca8feb..d3274cc829e34 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2683,7 +2683,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Don't print the tuple of capture types
'print: {
if !is_upvar_tys_infer_tuple {
- let msg = format!("required because it appears within the type `{}`", ty);
+ let msg = with_forced_trimmed_paths!(format!(
+ "required because it appears within the type `{ty}`",
+ ));
match ty.kind() {
ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) {
Some(ident) => err.span_note(ident.span, &msg),
@@ -2724,7 +2726,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut msg =
"required because it captures the following types: ".to_owned();
for ty in bound_tys.skip_binder() {
- write!(msg, "`{}`, ", ty).unwrap();
+ with_forced_trimmed_paths!(write!(msg, "`{}`, ", ty).unwrap());
}
err.note(msg.trim_end_matches(", "))
}
@@ -2735,7 +2737,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let kind = tcx.generator_kind(def_id).unwrap().descr();
err.span_note(
sp,
- &format!("required because it's used within this {}", kind),
+ with_forced_trimmed_paths!(&format!(
+ "required because it's used within this {kind}",
+ )),
)
}
ty::Closure(def_id, _) => err.span_note(
@@ -2959,7 +2963,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let expr_ty = with_forced_trimmed_paths!(self.ty_to_string(expr_ty));
err.span_label(
expr_span,
- format!("return type was inferred to be `{expr_ty}` here"),
+ with_forced_trimmed_paths!(format!(
+ "return type was inferred to be `{expr_ty}` here",
+ )),
);
}
}
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 5838049aa5c79..3f43c68d2e082 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -506,7 +506,11 @@ impl Step for Std {
// Look for library/std, library/core etc in the `x.py doc` arguments and
// open the corresponding rendered docs.
for requested_crate in requested_crates {
- if STD_PUBLIC_CRATES.iter().any(|k| *k == requested_crate.as_str()) {
+ if requested_crate == "library" {
+ // For `x.py doc library --open`, open `std` by default.
+ let index = out.join("std").join("index.html");
+ builder.open_in_browser(index);
+ } else if STD_PUBLIC_CRATES.iter().any(|&k| k == requested_crate) {
let index = out.join(requested_crate).join("index.html");
builder.open_in_browser(index);
}
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index b49322e3c028f..1d57c6ecbbb8d 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -74,11 +74,11 @@ fn update_rustfmt_version(build: &Builder<'_>) {
t!(std::fs::write(stamp_file, version))
}
-/// Returns the files modified between the `merge-base` of HEAD and
+/// Returns the Rust files modified between the `merge-base` of HEAD and
/// rust-lang/master and what is now on the disk.
///
/// Returns `None` if all files should be formatted.
-fn get_modified_files(build: &Builder<'_>) -> Option> {
+fn get_modified_rs_files(build: &Builder<'_>) -> Option> {
let Ok(remote) = get_rust_lang_rust_remote() else {return None;};
if !verify_rustfmt_version(build) {
return None;
@@ -95,6 +95,7 @@ fn get_modified_files(build: &Builder<'_>) -> Option> {
)
.lines()
.map(|s| s.trim().to_owned())
+ .filter(|f| Path::new(f).extension().map_or(false, |ext| ext == "rs"))
.collect(),
)
}
@@ -195,7 +196,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
ignore_fmt.add(&format!("!/{}", untracked_path)).expect(&untracked_path);
}
if !check && paths.is_empty() {
- if let Some(files) = get_modified_files(build) {
+ if let Some(files) = get_modified_rs_files(build) {
for file in files {
println!("formatting modified file {file}");
ignore_fmt.add(&format!("/{file}")).expect(&file);
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 7a13e7e36d169..62217df8de79c 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1740,7 +1740,7 @@ impl Type {
fn inner_def_id(&self, cache: Option<&Cache>) -> Option {
let t: PrimitiveType = match *self {
Type::Path { ref path } => return Some(path.def_id()),
- DynTrait(ref bounds, _) => return Some(bounds[0].trait_.def_id()),
+ DynTrait(ref bounds, _) => return bounds.get(0).map(|b| b.trait_.def_id()),
Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 8eb9c07f8a796..2d61519d6c908 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -322,8 +322,7 @@ fn get_index_type_id(clean_type: &clean::Type) -> Option {
match *clean_type {
clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())),
clean::DynTrait(ref bounds, _) => {
- let path = &bounds[0].trait_;
- Some(RenderTypeId::DefId(path.def_id()))
+ bounds.get(0).map(|b| RenderTypeId::DefId(b.trait_.def_id()))
}
clean::Primitive(p) => Some(RenderTypeId::Primitive(p)),
clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => {
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 2a41d3579e1d8..d4a0e93b1e6bf 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1318,15 +1318,11 @@ a.test-arrow:hover {
-webkit-appearance: none;
opacity: 1;
}
+
#settings-menu, #help-button {
margin-left: 4px;
display: flex;
}
-
-#settings-menu > a, #help-button > a, #copy-path {
- width: 33px;
-}
-
#settings-menu > a, #help-button > a {
display: flex;
align-items: center;
@@ -1338,6 +1334,7 @@ a.test-arrow:hover {
/* Rare exception to specifying font sizes in rem. Since this is acting
as an icon, it's okay to specify their sizes in pixels. */
font-size: 20px;
+ width: 33px;
}
#settings-menu > a:hover, #settings-menu > a:focus,
@@ -1353,6 +1350,7 @@ a.test-arrow:hover {
padding: 0;
padding-left: 2px;
border: 0;
+ width: 33px;
}
#copy-path > img {
filter: var(--copy-path-img-filter);
diff --git a/src/test/rustdoc-ui/issue-106213.rs b/src/test/rustdoc-ui/issue-106213.rs
new file mode 100644
index 0000000000000..6d51846b7d0c0
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-106213.rs
@@ -0,0 +1,7 @@
+// compile-flags: --document-private-items
+// edition:2021
+
+fn use_avx() -> dyn {
+ //~^ ERROR at least one trait is required for an object type
+ !( ident_error )
+}
diff --git a/src/test/rustdoc-ui/issue-106213.stderr b/src/test/rustdoc-ui/issue-106213.stderr
new file mode 100644
index 0000000000000..0a4ff69bafb34
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-106213.stderr
@@ -0,0 +1,9 @@
+error[E0224]: at least one trait is required for an object type
+ --> $DIR/issue-106213.rs:4:17
+ |
+LL | fn use_avx() -> dyn {
+ | ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0224`.
diff --git a/src/test/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr b/src/test/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr
index dd3665f22ac78..59192a1ecc3f4 100644
--- a/src/test/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr
+++ b/src/test/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr
@@ -3,10 +3,7 @@ error[E0308]: mismatched types
|
LL | #[alloc_error_handler]
| ---------------------- in this procedural macro expansion
-LL | fn oom(
- | __^
- | | _|
- | ||
+LL | // fn oom(
LL | || info: &Layout,
LL | || ) -> ()
| ||_______- arguments to this function are incorrect
@@ -29,10 +26,7 @@ error[E0308]: mismatched types
|
LL | #[alloc_error_handler]
| ---------------------- in this procedural macro expansion
-LL | fn oom(
- | __^
- | | _|
- | ||
+LL | // fn oom(
LL | || info: &Layout,
LL | || ) -> ()
| ||_______^ expected `!`, found `()`
diff --git a/src/test/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr b/src/test/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr
index 2673ee9f937fb..7d23c2fc05ac3 100644
--- a/src/test/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr
+++ b/src/test/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr
@@ -3,10 +3,7 @@ error[E0308]: mismatched types
|
LL | #[alloc_error_handler]
| ---------------------- in this procedural macro expansion
-LL | fn oom(
- | __^
- | | _|
- | ||
+LL | // fn oom(
LL | || info: Layout,
LL | || ) {
| ||_- arguments to this function are incorrect
@@ -36,10 +33,7 @@ error[E0308]: mismatched types
|
LL | #[alloc_error_handler]
| ---------------------- in this procedural macro expansion
-LL | fn oom(
- | __^
- | | _|
- | ||
+LL | // fn oom(
LL | || info: Layout,
LL | || ) {
| ||_^ expected `!`, found `()`
diff --git a/src/test/ui/asm/aarch64/interpolated-idents.stderr b/src/test/ui/asm/aarch64/interpolated-idents.stderr
index 2df17f2e03620..f6c50c2e1fdd0 100644
--- a/src/test/ui/asm/aarch64/interpolated-idents.stderr
+++ b/src/test/ui/asm/aarch64/interpolated-idents.stderr
@@ -30,12 +30,7 @@ error: asm outputs are not allowed with the `noreturn` option
LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
| ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^
...
-LL | m!(in out lateout inout inlateout const sym
- | _____-
- | |_____|
- | |_____|
- | |_____|
- | |
+LL | / m!(in out lateout inout inlateout const sym
LL | | pure nomem readonly preserves_flags
LL | | noreturn nostack options);
| | -
diff --git a/src/test/ui/asm/x86_64/interpolated-idents.stderr b/src/test/ui/asm/x86_64/interpolated-idents.stderr
index 6ac2ac5a77914..80a8c8c77cfec 100644
--- a/src/test/ui/asm/x86_64/interpolated-idents.stderr
+++ b/src/test/ui/asm/x86_64/interpolated-idents.stderr
@@ -30,12 +30,7 @@ error: asm outputs are not allowed with the `noreturn` option
LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
| ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^
...
-LL | m!(in out lateout inout inlateout const sym
- | _____-
- | |_____|
- | |_____|
- | |_____|
- | |
+LL | / m!(in out lateout inout inlateout const sym
LL | | pure nomem readonly preserves_flags
LL | | noreturn nostack att_syntax options);
| | -
diff --git a/src/test/ui/error-codes/E0519.rs b/src/test/ui/error-codes/E0519.rs
new file mode 100644
index 0000000000000..269ffd6320d9e
--- /dev/null
+++ b/src/test/ui/error-codes/E0519.rs
@@ -0,0 +1,8 @@
+// no need to create a new aux file, we can use an existing.
+// aux-build: crateresolve1-1.rs
+
+// set same metadata as `crateresolve1`
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+extern crate crateresolve1; //~ ERROR E0519
diff --git a/src/test/ui/error-codes/E0519.stderr b/src/test/ui/error-codes/E0519.stderr
new file mode 100644
index 0000000000000..e24fc4aaa70fb
--- /dev/null
+++ b/src/test/ui/error-codes/E0519.stderr
@@ -0,0 +1,9 @@
+error[E0519]: the current crate is indistinguishable from one of its dependencies: it has the same crate-name `crateresolve1` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two.
+ --> $DIR/E0519.rs:8:1
+ |
+LL | extern crate crateresolve1;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0519`.
diff --git a/src/test/ui/function-pointer/unsized-ret.stderr b/src/test/ui/function-pointer/unsized-ret.stderr
index 40bf7a3898acc..6f430687e6d6e 100644
--- a/src/test/ui/function-pointer/unsized-ret.stderr
+++ b/src/test/ui/function-pointer/unsized-ret.stderr
@@ -23,7 +23,7 @@ LL | foo:: fn(&'a ()) -> (dyn std::fmt::Display + 'a), _>(None, (&()
| required by a bound introduced by this call
|
= help: within `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`, the trait `for<'a> Sized` is not implemented for `(dyn std::fmt::Display + 'a)`
- = note: required because it appears within the type `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`
+ = note: required because it appears within the type `for<'a> fn(&'a ()) -> (dyn Display + 'a)`
note: required by a bound in `foo`
--> $DIR/unsized-ret.rs:5:11
|
diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr
index ed0628bbbc3cc..ebf35be581c60 100644
--- a/src/test/ui/generator/print/generator-print-verbose-1.stderr
+++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr
@@ -35,7 +35,7 @@ note: required because it's used within this generator
|
LL | || {
| ^^
-note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [std::sync::Arc>])`
+note: required because it appears within the type `Opaque(DefId(0:35 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [Arc>])`
--> $DIR/generator-print-verbose-1.rs:41:30
|
LL | pub fn make_gen2(t: T) -> impl Generator {
diff --git a/src/test/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs
new file mode 100644
index 0000000000000..4b096be591a04
--- /dev/null
+++ b/src/test/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs
@@ -0,0 +1,20 @@
+// Test that Fn-family traits with lifetime parameters shouldn't compile and
+// we suggest the usage of higher-rank trait bounds instead.
+
+fn fa(_: impl Fn<'a>(&'a str) -> bool) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+use std::ops::Fn as AliasedFn;
+fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn fe(_: F) where F: Fn<'a>(&'a str) -> bool {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr
new file mode 100644
index 0000000000000..e8f6d63b5ab8a
--- /dev/null
+++ b/src/test/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr
@@ -0,0 +1,62 @@
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:4:17
+ |
+LL | fn fa(_: impl Fn<'a>(&'a str) -> bool) {}
+ | ^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fa(_: impl Fn<'a>(&'a str) -> bool) {}
+LL + fn fa(_: impl for<'a> Fn(&'a str) -> bool) {}
+ |
+
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:7:20
+ |
+LL | fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {}
+ | ^^^^^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {}
+LL + fn fb(_: impl for<'a, 'b> FnMut(&'a str, &'b str) -> bool) {}
+ |
+
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:10:41
+ |
+LL | fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {}
+ | ^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {}
+LL + fn fc(_: impl std::fmt::Display + for<'a> FnOnce(&'a str) -> bool + std::fmt::Debug) {}
+ |
+
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:14:24
+ |
+LL | fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {}
+ | ^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {}
+LL + fn fd(_: impl for<'a> AliasedFn(&'a str) -> bool) {}
+ |
+
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:17:27
+ |
+LL | fn fe(_: F) where F: Fn<'a>(&'a str) -> bool {}
+ | ^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fe(_: F) where F: Fn<'a>(&'a str) -> bool {}
+LL + fn fe(_: F) where F: for<'a> Fn(&'a str) -> bool {}
+ |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/issues/issue-13497-2.stderr b/src/test/ui/issues/issue-13497-2.stderr
index 3abeadf9e4bbe..a365e24e27e27 100644
--- a/src/test/ui/issues/issue-13497-2.stderr
+++ b/src/test/ui/issues/issue-13497-2.stderr
@@ -1,10 +1,7 @@
error[E0515]: cannot return value referencing local variable `rawLines`
--> $DIR/issue-13497-2.rs:3:5
|
-LL | rawLines
- | ______^
- | | _____|
- | ||
+LL | // rawLines
LL | || .iter().map(|l| l.trim()).collect()
| ||_______________-___________________________^ returns a value referencing data owned by the current function
| |_______________|
diff --git a/src/test/ui/issues/issue-21763.stderr b/src/test/ui/issues/issue-21763.stderr
index 72c65029746ad..04379f07ba0f7 100644
--- a/src/test/ui/issues/issue-21763.stderr
+++ b/src/test/ui/issues/issue-21763.stderr
@@ -7,7 +7,7 @@ LL | foo::, Rc<()>>>();
= help: within `(Rc<()>, Rc<()>)`, the trait `Send` is not implemented for `Rc<()>`
= note: required because it appears within the type `(Rc<()>, Rc<()>)`
= note: required for `hashbrown::raw::RawTable<(Rc<()>, Rc<()>)>` to implement `Send`
- = note: required because it appears within the type `hashbrown::map::HashMap, Rc<()>, RandomState>`
+ = note: required because it appears within the type `HashMap, Rc<()>, RandomState>`
= note: required because it appears within the type `HashMap, Rc<()>>`
note: required by a bound in `foo`
--> $DIR/issue-21763.rs:6:11
diff --git a/src/test/ui/suggestions/issue-99240-2.stderr b/src/test/ui/suggestions/issue-99240-2.stderr
index 260df85653b15..a2b5597847846 100644
--- a/src/test/ui/suggestions/issue-99240-2.stderr
+++ b/src/test/ui/suggestions/issue-99240-2.stderr
@@ -4,10 +4,7 @@ error[E0618]: expected function, found enum variant `Alias::Unit`
LL | Unit,
| ---- enum variant `Alias::Unit` defined here
...
-LL | Alias::
- | ______^
- | | _____|
- | ||
+LL | // Alias::
LL | || Unit();
| ||________^_- call expression requires function
| |________|
diff --git a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr
index 41fc3600fcd54..30cc76b2e1aad 100644
--- a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr
+++ b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr
@@ -50,7 +50,7 @@ LL | is_send((8, TestType));
| required by a bound introduced by this call
|
= help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType`
- = note: required because it appears within the type `({integer}, dummy1c::TestType)`
+ = note: required because it appears within the type `({integer}, TestType)`
note: required by a bound in `is_send`
--> $DIR/negated-auto-traits-error.rs:16:15
|
@@ -67,7 +67,7 @@ LL | is_send(Box::new(TestType));
|
= note: the trait bound `Unique: Send` is not satisfied
= note: required for `Unique` to implement `Send`
- = note: required because it appears within the type `Box`
+ = note: required because it appears within the type `Box`
note: required by a bound in `is_send`
--> $DIR/negated-auto-traits-error.rs:16:15
|
@@ -87,13 +87,13 @@ LL | is_send(Box::new(Outer2(TestType)));
| required by a bound introduced by this call
|
= help: within `Outer2`, the trait `Send` is not implemented for `dummy3::TestType`
-note: required because it appears within the type `Outer2`
+note: required because it appears within the type `Outer2`
--> $DIR/negated-auto-traits-error.rs:12:8
|
LL | struct Outer2(T);
| ^^^^^^
= note: required for `Unique>` to implement `Send`
- = note: required because it appears within the type `Box>`
+ = note: required because it appears within the type `Box>`
note: required by a bound in `is_send`
--> $DIR/negated-auto-traits-error.rs:16:15
|
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 903ee938d9d2d..02f3188f8be08 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -4203,6 +4203,7 @@ Released 2018-09-13
[`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
[`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs
[`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
+[`fn_null_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_null_check
[`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
[`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
[`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
@@ -4460,6 +4461,7 @@ Released 2018-09-13
[`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
+[`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false
[`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
@@ -4545,6 +4547,7 @@ Released 2018-09-13
[`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
[`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
[`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count
+[`size_of_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_ref
[`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
[`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
[`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
@@ -4590,6 +4593,7 @@ Released 2018-09-13
[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
+[`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn
[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
[`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
index e862f13e69fc7..c8e54d7b8e0c3 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv
diag.span_suggestion(
expr.span,
- &format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
+ format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
sugg,
rustc_errors::Applicability::HasPlaceholders,
);
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 3cd7d1d7e7228..2982460c9cfa4 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -161,6 +161,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO,
crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO,
+ crate::fn_null_check::FN_NULL_CHECK_INFO,
crate::format::USELESS_FORMAT_INFO,
crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO,
crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO,
@@ -494,6 +495,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO,
crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO,
crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO,
+ crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO,
crate::precedence::PRECEDENCE_INFO,
crate::ptr::CMP_NULL_INFO,
crate::ptr::INVALID_NULL_PTR_USAGE_INFO,
@@ -535,6 +537,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
+ crate::size_of_ref::SIZE_OF_REF_INFO,
crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO,
crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO,
crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO,
@@ -568,6 +571,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
+ crate::transmute::TRANSMUTE_NULL_TO_FN_INFO,
crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
crate::transmute::TRANSMUTE_PTR_TO_REF_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 7b43d8ccc67d1..728941b8b3d9a 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1282,10 +1282,10 @@ fn referent_used_exactly_once<'tcx>(
possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
}
let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
- // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
- // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
- // itself. See the comment in that method for an explanation as to why.
- possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
+ // If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The
+ // reason is that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible
+ // borrower of itself. See the comment in that method for an explanation as to why.
+ possible_borrower.at_most_borrowers(cx, &[local, place.local], place.local, location)
&& used_exactly_once(mir, place.local).unwrap_or(false)
} else {
false
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 0ed301964758e..f95b628e6c31e 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -324,7 +324,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
let maybe_neg_sugg = |expr, hir_id| {
let sugg = Sugg::hir(cx, expr, "..");
if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id {
- format!("-{sugg}")
+ format!("-{}", sugg.maybe_par())
} else {
sugg.to_string()
}
diff --git a/src/tools/clippy/clippy_lints/src/fn_null_check.rs b/src/tools/clippy/clippy_lints/src/fn_null_check.rs
new file mode 100644
index 0000000000000..91c8c340ce28f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/fn_null_check.rs
@@ -0,0 +1,106 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
+use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for comparing a function pointer to null.
+ ///
+ /// ### Why is this bad?
+ /// Function pointers are assumed to not be null.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */
+ ///
+ /// if (fn_ptr as *const ()).is_null() { ... }
+ /// ```
+ /// Use instead:
+ /// ```rust,ignore
+ /// let fn_ptr: Option = /* somehow obtained nullable function pointer */
+ ///
+ /// if fn_ptr.is_none() { ... }
+ /// ```
+ #[clippy::version = "1.67.0"]
+ pub FN_NULL_CHECK,
+ correctness,
+ "`fn()` type assumed to be nullable"
+}
+declare_lint_pass!(FnNullCheck => [FN_NULL_CHECK]);
+
+fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ span_lint_and_help(
+ cx,
+ FN_NULL_CHECK,
+ expr.span,
+ "function pointer assumed to be nullable, even though it isn't",
+ None,
+ "try wrapping your function pointer type in `Option` instead, and using `is_none` to check for null pointer value",
+ );
+}
+
+fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ if let ExprKind::Cast(cast_expr, cast_ty) = expr.kind
+ && let TyKind::Ptr(_) = cast_ty.kind
+ {
+ cx.typeck_results().expr_ty_adjusted(cast_expr).is_fn()
+ } else {
+ false
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for FnNullCheck {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ match expr.kind {
+ // Catching:
+ // (fn_ptr as * ).is_null()
+ ExprKind::MethodCall(method_name, receiver, _, _)
+ if method_name.ident.as_str() == "is_null" && is_fn_ptr_cast(cx, receiver) =>
+ {
+ lint_expr(cx, expr);
+ },
+
+ ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => {
+ let to_check: &Expr<'_>;
+ if is_fn_ptr_cast(cx, left) {
+ to_check = right;
+ } else if is_fn_ptr_cast(cx, right) {
+ to_check = left;
+ } else {
+ return;
+ }
+
+ match to_check.kind {
+ // Catching:
+ // (fn_ptr as * ) == (0 as )
+ ExprKind::Cast(cast_expr, _) if is_integer_literal(cast_expr, 0) => {
+ lint_expr(cx, expr);
+ },
+
+ // Catching:
+ // (fn_ptr as * ) == std::ptr::null()
+ ExprKind::Call(func, []) if is_path_diagnostic_item(cx, func, sym::ptr_null) => {
+ lint_expr(cx, expr);
+ },
+
+ // Catching:
+ // (fn_ptr as * ) ==
+ _ if matches!(
+ constant(cx, cx.typeck_results(), to_check),
+ Some((Constant::RawPtr(0), _))
+ ) =>
+ {
+ lint_expr(cx, expr);
+ },
+
+ _ => {},
+ }
+ },
+ _ => {},
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 69f7c152fc4af..043112bbc9596 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -382,7 +382,7 @@ fn check_format_in_format_args(
call_site,
&format!("`format!` in `{name}!` args"),
|diag| {
- diag.help(&format!(
+ diag.help(format!(
"combine the `format!(..)` arguments with the outer `{name}!(..)` call"
));
diag.help("or consider changing `format!` to `format_args!`");
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index 91e6ffe644790..9dbce3f889bef 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -63,23 +63,40 @@ declare_clippy_lint! {
/// arguments but are not marked `unsafe`.
///
/// ### Why is this bad?
- /// The function should probably be marked `unsafe`, since
- /// for an arbitrary raw pointer, there is no way of telling for sure if it is
- /// valid.
+ /// The function should almost definitely be marked `unsafe`, since for an
+ /// arbitrary raw pointer, there is no way of telling for sure if it is valid.
+ ///
+ /// In general, this lint should **never be disabled** unless it is definitely a
+ /// false positive (please submit an issue if so) since it breaks Rust's
+ /// soundness guarantees, directly exposing API users to potentially dangerous
+ /// program behavior. This is also true for internal APIs, as it is easy to leak
+ /// unsoundness.
+ ///
+ /// ### Context
+ /// In Rust, an `unsafe {...}` block is used to indicate that the code in that
+ /// section has been verified in some way that the compiler can not. For a
+ /// function that accepts a raw pointer then accesses the pointer's data, this is
+ /// generally impossible as the incoming pointer could point anywhere, valid or
+ /// not. So, the signature should be marked `unsafe fn`: this indicates that the
+ /// function's caller must provide some verification that the arguments it sends
+ /// are valid (and then call the function within an `unsafe` block).
///
/// ### Known problems
/// * It does not check functions recursively so if the pointer is passed to a
/// private non-`unsafe` function which does the dereferencing, the lint won't
- /// trigger.
+ /// trigger (false negative).
/// * It only checks for arguments whose type are raw pointers, not raw pointers
/// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
- /// `some_argument.get_raw_ptr()`).
+ /// `some_argument.get_raw_ptr()`) (false negative).
///
/// ### Example
/// ```rust,ignore
/// pub fn foo(x: *const u8) {
/// println!("{}", unsafe { *x });
/// }
+ ///
+ /// // this call "looks" safe but will segfault or worse!
+ /// // foo(invalid_ptr);
/// ```
///
/// Use instead:
@@ -87,6 +104,12 @@ declare_clippy_lint! {
/// pub unsafe fn foo(x: *const u8) {
/// println!("{}", unsafe { *x });
/// }
+ ///
+ /// // this would cause a compiler error for calling without `unsafe`
+ /// // foo(invalid_ptr);
+ ///
+ /// // sound call if the caller knows the pointer is valid
+ /// unsafe { foo(valid_ptr); }
/// ```
#[clippy::version = "pre 1.29.0"]
pub NOT_UNSAFE_PTR_ARG_DEREF,
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index 76c83ab47d095..db637dfc068d4 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -34,12 +34,12 @@ declare_clippy_lint! {
}
pub struct LargeConstArrays {
- maximum_allowed_size: u64,
+ maximum_allowed_size: u128,
}
impl LargeConstArrays {
#[must_use]
- pub fn new(maximum_allowed_size: u64) -> Self {
+ pub fn new(maximum_allowed_size: u128) -> Self {
Self { maximum_allowed_size }
}
}
@@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind();
if let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx);
if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes());
- if self.maximum_allowed_size < element_count * element_size;
+ if self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size);
then {
let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index b18456ee52340..b8d4abdbb781a 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
);
diag.span_label(
def.variants[variants_size[1].ind].span,
- &if variants_size[1].fields_size.is_empty() {
+ if variants_size[1].fields_size.is_empty() {
"the second-largest variant carries no data at all".to_owned()
} else {
format!(
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
index 5857d81ab1f20..89ae83d48f536 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
@@ -24,12 +24,12 @@ declare_clippy_lint! {
}
pub struct LargeStackArrays {
- maximum_allowed_size: u64,
+ maximum_allowed_size: u128,
}
impl LargeStackArrays {
#[must_use]
- pub fn new(maximum_allowed_size: u64) -> Self {
+ pub fn new(maximum_allowed_size: u128) -> Self {
Self { maximum_allowed_size }
}
}
@@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
&& let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
&& !cx.tcx.hir().parent_iter(expr.hir_id)
.any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. })))
- && self.maximum_allowed_size < element_count * element_size {
+ && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) {
span_lint_and_help(
cx,
LARGE_STACK_ARRAYS,
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index e88d1764a2489..9eba46756299c 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -361,7 +361,7 @@ fn check_for_is_empty<'tcx>(
db.span_note(span, "`is_empty` defined here");
}
if let Some(self_kind) = self_kind {
- db.note(&output.expected_sig(self_kind));
+ db.note(output.expected_sig(self_kind));
}
});
}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 39850d598038f..dcd8ca81ae872 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -125,6 +125,7 @@ mod explicit_write;
mod fallible_impl_from;
mod float_literal;
mod floating_point_arithmetic;
+mod fn_null_check;
mod format;
mod format_args;
mod format_impl;
@@ -234,6 +235,7 @@ mod partialeq_ne_impl;
mod partialeq_to_none;
mod pass_by_ref_or_value;
mod pattern_type_mismatch;
+mod permissions_set_readonly_false;
mod precedence;
mod ptr;
mod ptr_offset_with_cast;
@@ -263,6 +265,7 @@ mod shadow;
mod single_char_lifetime_names;
mod single_component_path_imports;
mod size_of_in_element_count;
+mod size_of_ref;
mod slow_vector_initialization;
mod std_instead_of_core;
mod strings;
@@ -334,7 +337,7 @@ pub fn read_conf(sess: &Session, path: &io::Result