Skip to content

Commit

Permalink
Auto merge of #95702 - Dylan-DPC:rollup-793rz6v, r=Dylan-DPC
Browse files Browse the repository at this point in the history
Rollup of 8 pull requests

Successful merges:

 - #88025 (ScmCredentials netbsd implementation.)
 - #95473 (track individual proc-macro expansions in the self-profiler)
 - #95547 (caution against ptr-to-int transmutes)
 - #95585 (Explain why `&T` is cloned when `T` is not `Clone`)
 - #95591 (Use revisions to track NLL test output (part 1))
 - #95663 (diagnostics: give a special note for unsafe fn / Fn/FnOnce/FnMut)
 - #95673 (:arrow_up: rust-analyzer)
 - #95681 (resolve: Fix resolution of empty paths passed from rustdoc)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Apr 5, 2022
2 parents 306ba83 + 728f263 commit bbe9d27
Show file tree
Hide file tree
Showing 132 changed files with 877 additions and 369 deletions.
6 changes: 6 additions & 0 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,12 @@ impl<'a> ExtCtxt<'a> {
self.current_expansion.id.expn_data().call_site
}

/// Returns the current expansion kind's description.
pub(crate) fn expansion_descr(&self) -> String {
let expn_data = self.current_expansion.id.expn_data();
expn_data.kind.descr()
}

/// Equivalent of `Span::def_site` from the proc macro API,
/// except that the location is taken from the span passed as an argument.
pub fn with_def_site_ctxt(&self, span: Span) -> Span {
Expand Down
28 changes: 18 additions & 10 deletions compiler/rustc_expand/src/proc_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ impl base::ProcMacro for BangProcMacro {
span: Span,
input: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
let _timer =
ecx.sess.prof.generic_activity_with_arg("expand_proc_macro", ecx.expansion_descr());
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace).map_err(|e| {
Expand All @@ -48,6 +50,8 @@ impl base::AttrProcMacro for AttrProcMacro {
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
let _timer =
ecx.sess.prof.generic_activity_with_arg("expand_proc_macro", ecx.expansion_descr());
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
self.client
Expand Down Expand Up @@ -97,17 +101,21 @@ impl MultiItemModifier for ProcMacroDerive {
nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::No)
};

let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
let stream = match self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace) {
Ok(stream) => stream,
Err(e) => {
let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
if let Some(s) = e.as_str() {
err.help(&format!("message: {}", s));
let stream = {
let _timer =
ecx.sess.prof.generic_activity_with_arg("expand_proc_macro", ecx.expansion_descr());
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
match self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace) {
Ok(stream) => stream,
Err(e) => {
let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
if let Some(s) = e.as_str() {
err.help(&format!("message: {}", s));
}
err.emit();
return ExpandResult::Ready(vec![]);
}
err.emit();
return ExpandResult::Ready(vec![]);
}
};

Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3298,7 +3298,9 @@ impl<'a> Resolver<'a> {
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
Some(path_res.base_res())
}
PathResult::NonModule(..) | PathResult::Failed { .. } => None,
PathResult::Module(ModuleOrUniformRoot::ExternPrelude)
| PathResult::NonModule(..)
| PathResult::Failed { .. } => None,
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
flags.push((sym::_Self, Some("&[]".to_owned())));
}

if self_ty.is_fn() {
let fn_sig = self_ty.fn_sig(self.tcx);
let shortname = match fn_sig.unsafety() {
hir::Unsafety::Normal => "fn",
hir::Unsafety::Unsafe => "unsafe fn",
};
flags.push((sym::_Self, Some(shortname.to_owned())));
}

if let ty::Array(aty, len) = self_ty.kind() {
flags.push((sym::_Self, Some("[]".to_owned())));
flags.push((sym::_Self, Some(format!("[{}]", aty))));
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
self.suggest_missing_parentheses(err, expr);
self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
self.report_closure_inferred_return_type(err, expected);
Expand Down Expand Up @@ -630,7 +631,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MachineApplicable,
true,
));

}
}
_ => {}
Expand Down
59 changes: 54 additions & 5 deletions compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ use super::FnCtxt;
use crate::astconv::AstConv;

use rustc_ast::util::parser::ExprPrecedence;
use rustc_span::{self, Span};

use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind};
Expand All @@ -13,12 +11,14 @@ use rustc_hir::{
WherePredicate,
};
use rustc_infer::infer::{self, TyCtxtInferExt};

use rustc_infer::traits;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Binder, Ty};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Binder, ToPredicate, Ty};
use rustc_span::symbol::{kw, sym};
use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;

use rustc_middle::ty::subst::GenericArgKind;
use std::iter;

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Expand Down Expand Up @@ -846,4 +846,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let node = self.tcx.hir().get(id);
matches!(node, Node::Stmt(Stmt { kind: StmtKind::Local(..), .. }))
}

/// Suggest that `&T` was cloned instead of `T` because `T` does not implement `Clone`,
/// which is a side-effect of autoref.
pub(crate) fn note_type_is_not_clone(
&self,
diag: &mut Diagnostic,
expected_ty: Ty<'tcx>,
found_ty: Ty<'tcx>,
expr: &hir::Expr<'_>,
) {
let hir::ExprKind::MethodCall(segment, &[ref callee_expr], _) = expr.kind else { return; };
let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; };
let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return };
let results = self.typeck_results.borrow();
// First, look for a `Clone::clone` call
if segment.ident.name == sym::clone
&& results.type_dependent_def_id(expr.hir_id).map_or(
false,
|did| {
self.tcx.associated_item(did).container
== ty::AssocItemContainer::TraitContainer(clone_trait_did)
},
)
// If that clone call hasn't already dereferenced the self type (i.e. don't give this
// diagnostic in cases where we have `(&&T).clone()` and we expect `T`).
&& !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
// Check that we're in fact trying to clone into the expected type
&& self.can_coerce(*pointee_ty, expected_ty)
// And the expected type doesn't implement `Clone`
&& !self.predicate_must_hold_considering_regions(&traits::Obligation {
cause: traits::ObligationCause::dummy(),
param_env: self.param_env,
recursion_depth: 0,
predicate: ty::Binder::dummy(ty::TraitRef {
def_id: clone_trait_did,
substs: self.tcx.mk_substs([expected_ty.into()].iter()),
})
.without_const()
.to_predicate(self.tcx),
})
{
diag.span_note(
callee_expr.span,
&format!(
"`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
),
);
}
}
}
10 changes: 10 additions & 0 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,16 @@ extern "rust-intrinsic" {
/// let ptr_num_cast = ptr as *const i32 as usize;
/// ```
///
/// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined
/// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave
/// as expected -- this is touching on many unspecified aspects of the Rust memory model.
/// Depending on what the code is doing, the following alternatives are preferrable to
/// pointer-to-integer transmutation:
/// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a
/// type for that buffer, it can use [`MaybeUninit`][mem::MaybeUninit].
/// - If the code actually wants to work on the address the pointer points to, it can use `as`
/// casts or [`ptr.addr()`][pointer::addr].
///
/// Turning a `*mut T` into an `&mut T`:
///
/// ```
Expand Down
18 changes: 18 additions & 0 deletions library/core/src/ops/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@
Args = "()",
note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
),
on(
_Self = "unsafe fn",
note = "unsafe function cannot be called generically without an unsafe block",
// SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
),
message = "expected a `{Fn}<{Args}>` closure, found `{Self}`",
label = "expected an `Fn<{Args}>` closure, found `{Self}`"
)]
Expand Down Expand Up @@ -141,6 +147,12 @@ pub trait Fn<Args>: FnMut<Args> {
Args = "()",
note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
),
on(
_Self = "unsafe fn",
note = "unsafe function cannot be called generically without an unsafe block",
// SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
),
message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`",
label = "expected an `FnMut<{Args}>` closure, found `{Self}`"
)]
Expand Down Expand Up @@ -214,6 +226,12 @@ pub trait FnMut<Args>: FnOnce<Args> {
Args = "()",
note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
),
on(
_Self = "unsafe fn",
note = "unsafe function cannot be called generically without an unsafe block",
// SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
),
message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`",
label = "expected an `FnOnce<{Args}>` closure, found `{Self}`"
)]
Expand Down
Loading

0 comments on commit bbe9d27

Please sign in to comment.