Skip to content

Rollup of 8 pull requests #98904

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jul 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/constraint_generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
fn visit_ascribe_user_ty(
&mut self,
_place: &Place<'tcx>,
_variance: &ty::Variance,
_variance: ty::Variance,
_user_ty: &UserTypeProjection,
_location: Location,
) {
Expand Down
17 changes: 13 additions & 4 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ pub enum StatementKind<'tcx> {

/// Describes what kind of retag is to be performed.
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)]
#[rustc_pass_by_value]
pub enum RetagKind {
/// The initial retag when entering a function.
FnEntry,
Expand Down Expand Up @@ -990,11 +991,19 @@ pub enum Rvalue<'tcx> {
/// matching types and return a value of that type.
BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),

/// Same as `BinaryOp`, but yields `(T, bool)` instead of `T`. In addition to performing the
/// same computation as the matching `BinaryOp`, checks if the infinite precison result would be
/// unequal to the actual result and sets the `bool` if this is the case.
/// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
///
/// This only supports addition, subtraction, multiplication, and shift operations on integers.
/// When overflow checking is disabled, the error condition is false. Otherwise, the error
/// condition is determined as described below.
///
/// For addition, subtraction, and multiplication on integers the error condition is set when
/// the infinite precision result would be unequal to the actual result.
///
/// For shift operations on integers the error condition is set when the value of right-hand
/// side is greater than or equal to the number of bits in the type of the left-hand side, or
/// when the value of right-hand side is negative.
///
/// Other combinations of types and operators are unsupported.
CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),

/// Computes a value as described by the operation.
Expand Down
25 changes: 12 additions & 13 deletions compiler/rustc_middle/src/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ macro_rules! make_mir_visitor {
fn visit_ascribe_user_ty(
&mut self,
place: & $($mutability)? Place<'tcx>,
variance: & $($mutability)? ty::Variance,
variance: $(& $mutability)? ty::Variance,
user_ty: & $($mutability)? UserTypeProjection,
location: Location,
) {
Expand All @@ -164,7 +164,7 @@ macro_rules! make_mir_visitor {

fn visit_retag(
&mut self,
kind: & $($mutability)? RetagKind,
kind: $(& $mutability)? RetagKind,
place: & $($mutability)? Place<'tcx>,
location: Location,
) {
Expand Down Expand Up @@ -425,7 +425,7 @@ macro_rules! make_mir_visitor {
self.visit_source_info(source_info);
match kind {
StatementKind::Assign(
box(ref $($mutability)? place, ref $($mutability)? rvalue)
box (place, rvalue)
) => {
self.visit_assign(place, rvalue, location);
}
Expand Down Expand Up @@ -465,13 +465,13 @@ macro_rules! make_mir_visitor {
);
}
StatementKind::Retag(kind, place) => {
self.visit_retag(kind, place, location);
self.visit_retag($(& $mutability)? *kind, place, location);
}
StatementKind::AscribeUserType(
box(ref $($mutability)? place, ref $($mutability)? user_ty),
box (place, user_ty),
variance
) => {
self.visit_ascribe_user_ty(place, variance, user_ty, location);
self.visit_ascribe_user_ty(place, $(& $mutability)? *variance, user_ty, location);
}
StatementKind::Coverage(coverage) => {
self.visit_coverage(
Expand All @@ -480,9 +480,9 @@ macro_rules! make_mir_visitor {
)
}
StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{
ref $($mutability)? src,
ref $($mutability)? dst,
ref $($mutability)? count,
src,
dst,
count,
}) => {
self.visit_operand(src, location);
self.visit_operand(dst, location);
Expand Down Expand Up @@ -517,8 +517,7 @@ macro_rules! make_mir_visitor {
TerminatorKind::GeneratorDrop |
TerminatorKind::Unreachable |
TerminatorKind::FalseEdge { .. } |
TerminatorKind::FalseUnwind { .. } => {
}
TerminatorKind::FalseUnwind { .. } => {}

TerminatorKind::Return => {
// `return` logically moves from the return place `_0`. Note that the place
Expand Down Expand Up @@ -830,7 +829,7 @@ macro_rules! make_mir_visitor {

fn super_ascribe_user_ty(&mut self,
place: & $($mutability)? Place<'tcx>,
_variance: & $($mutability)? ty::Variance,
_variance: $(& $mutability)? ty::Variance,
user_ty: & $($mutability)? UserTypeProjection,
location: Location) {
self.visit_place(
Expand All @@ -847,7 +846,7 @@ macro_rules! make_mir_visitor {
}

fn super_retag(&mut self,
_kind: & $($mutability)? RetagKind,
_kind: $(& $mutability)? RetagKind,
place: & $($mutability)? Place<'tcx>,
location: Location) {
self.visit_place(
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2724,8 +2724,8 @@ pub(crate) mod dep_tracking {
use super::{
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
SymbolManglingVersion, TrimmedDefPaths,
OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
};
use crate::lint;
use crate::options::WasiExecModel;
Expand Down Expand Up @@ -2812,6 +2812,7 @@ pub(crate) mod dep_tracking {
Edition,
LinkerPluginLto,
SplitDebuginfo,
SplitDwarfKind,
StackProtector,
SwitchWithOptPath,
SymbolManglingVersion,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1496,15 +1496,15 @@ options! {
"control if mem::uninitialized and mem::zeroed panic on more UB"),
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [UNTRACKED],
split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED],
"split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
(default: `split`)

`split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
file which is ignored by the linker
`single`: sections which do not require relocation are written into object file but ignored
by the linker"),
split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
split_dwarf_inlining: bool = (true, parse_bool, [TRACKED],
"provide minimal debug info in the object/executable to facilitate online \
symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
symbol_mangling_version: Option<SymbolManglingVersion> = (None,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_type_ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,7 @@ impl UnifyKey for FloatVid {
}

#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash)]
#[rustc_pass_by_value]
pub enum Variance {
Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
Expand Down
27 changes: 24 additions & 3 deletions compiler/rustc_typeck/src/check/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,15 +280,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
callee_node: &hir::ExprKind<'_>,
callee_span: Span,
) {
let hir_id = self.tcx.hir().get_parent_node(hir_id);
let parent_node = self.tcx.hir().get(hir_id);
let hir = self.tcx.hir();
let parent_hir_id = hir.get_parent_node(hir_id);
let parent_node = hir.get(parent_hir_id);
if let (
hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure { fn_decl_span, .. }, ..
kind: hir::ExprKind::Closure { fn_decl_span, body, .. },
..
}),
hir::ExprKind::Block(..),
) = (parent_node, callee_node)
{
let fn_decl_span = if hir.body(*body).generator_kind
== Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure))
{
// Actually need to unwrap a few more layers of HIR to get to
// the _real_ closure...
let async_closure = hir.get_parent_node(hir.get_parent_node(parent_hir_id));
if let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure { fn_decl_span, .. },
..
}) = hir.get(async_closure)
{
*fn_decl_span
} else {
return;
}
} else {
*fn_decl_span
};

let start = fn_decl_span.shrink_to_lo();
let end = callee_span.shrink_to_hi();
err.multipart_suggestion(
Expand Down
27 changes: 20 additions & 7 deletions compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,16 @@ fn check_predicates<'tcx>(
span: Span,
) {
let tcx = infcx.tcx;
let impl1_predicates: Vec<_> = traits::elaborate_predicates(
let instantiated = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
let impl1_predicates: Vec<_> = traits::elaborate_predicates_with_span(
tcx,
tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).predicates.into_iter(),
std::iter::zip(
instantiated.predicates,
// Don't drop predicates (unsound!) because `spans` is too short
instantiated.spans.into_iter().chain(std::iter::repeat(span)),
),
)
.map(|obligation| obligation.predicate)
.map(|obligation| (obligation.predicate, obligation.cause.span))
.collect();

let mut impl2_predicates = if impl2_node.is_from_trait() {
Expand Down Expand Up @@ -321,7 +326,7 @@ fn check_predicates<'tcx>(
// which is sound because we forbid impls like the following
//
// impl<D: Debug> AlwaysApplicable for D { }
let always_applicable_traits = impl1_predicates.iter().copied().filter(|&predicate| {
let always_applicable_traits = impl1_predicates.iter().copied().filter(|&(predicate, _)| {
matches!(
trait_predicate_kind(tcx, predicate),
Some(TraitSpecializationKind::AlwaysApplicable)
Expand All @@ -345,11 +350,11 @@ fn check_predicates<'tcx>(
}
}
impl2_predicates.extend(
traits::elaborate_predicates(tcx, always_applicable_traits)
traits::elaborate_predicates_with_span(tcx, always_applicable_traits)
.map(|obligation| obligation.predicate),
);

for predicate in impl1_predicates {
for (predicate, span) in impl1_predicates {
if !impl2_predicates.contains(&predicate) {
check_specialization_on(tcx, predicate, span)
}
Expand Down Expand Up @@ -384,9 +389,17 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
.emit();
}
}
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
tcx.sess
.struct_span_err(
span,
&format!("cannot specialize on associated type `{projection_ty} == {term}`",),
)
.emit();
}
_ => {
tcx.sess
.struct_span_err(span, &format!("cannot specialize on `{:?}`", predicate))
.struct_span_err(span, &format!("cannot specialize on predicate `{}`", predicate))
.emit();
}
}
Expand Down
93 changes: 87 additions & 6 deletions src/librustdoc/clean/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,17 +340,98 @@ pub(crate) fn is_literal_expr(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
false
}

/// Build a textual representation of an unevaluated constant expression.
///
/// If the const expression is too complex, an underscore `_` is returned.
/// For const arguments, it's `{ _ }` to be precise.
/// This means that the output is not necessarily valid Rust code.
///
/// Currently, only
///
/// * literals (optionally with a leading `-`)
/// * unit `()`
/// * blocks (`{ … }`) around simple expressions and
/// * paths without arguments
///
/// are considered simple enough. Simple blocks are included since they are
/// necessary to disambiguate unit from the unit type.
/// This list might get extended in the future.
///
/// Without this censoring, in a lot of cases the output would get too large
/// and verbose. Consider `match` expressions, blocks and deeply nested ADTs.
/// Further, private and `doc(hidden)` fields of structs would get leaked
/// since HIR datatypes like the `body` parameter do not contain enough
/// semantic information for this function to be able to hide them –
/// at least not without significant performance overhead.
///
/// Whenever possible, prefer to evaluate the constant first and try to
/// use a different method for pretty-printing. Ideally this function
/// should only ever be used as a fallback.
pub(crate) fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String {
let hir = tcx.hir();
let value = &hir.body(body).value;

let snippet = if !value.span.from_expansion() {
tcx.sess.source_map().span_to_snippet(value.span).ok()
} else {
None
};
#[derive(PartialEq, Eq)]
enum Classification {
Literal,
Simple,
Complex,
}

snippet.unwrap_or_else(|| rustc_hir_pretty::id_to_string(&hir, body.hir_id))
use Classification::*;

fn classify(expr: &hir::Expr<'_>) -> Classification {
match &expr.kind {
hir::ExprKind::Unary(hir::UnOp::Neg, expr) => {
if matches!(expr.kind, hir::ExprKind::Lit(_)) { Literal } else { Complex }
}
hir::ExprKind::Lit(_) => Literal,
hir::ExprKind::Tup([]) => Simple,
hir::ExprKind::Block(hir::Block { stmts: [], expr: Some(expr), .. }, _) => {
if classify(expr) == Complex { Complex } else { Simple }
}
// Paths with a self-type or arguments are too “complex” following our measure since
// they may leak private fields of structs (with feature `adt_const_params`).
// Consider: `<Self as Trait<{ Struct { private: () } }>>::CONSTANT`.
// Paths without arguments are definitely harmless though.
hir::ExprKind::Path(hir::QPath::Resolved(_, hir::Path { segments, .. })) => {
if segments.iter().all(|segment| segment.args.is_none()) { Simple } else { Complex }
}
// FIXME: Claiming that those kinds of QPaths are simple is probably not true if the Ty
// contains const arguments. Is there a *concise* way to check for this?
hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => Simple,
// FIXME: Can they contain const arguments and thus leak private struct fields?
hir::ExprKind::Path(hir::QPath::LangItem(..)) => Simple,
_ => Complex,
}
}

let classification = classify(value);

if classification == Literal
&& !value.span.from_expansion()
&& let Ok(snippet) = tcx.sess.source_map().span_to_snippet(value.span) {
// For literals, we avoid invoking the pretty-printer and use the source snippet instead to
// preserve certain stylistic choices the user likely made for the sake legibility like
//
// * hexadecimal notation
// * underscores
// * character escapes
//
// FIXME: This passes through `-/*spacer*/0` verbatim.
snippet
} else if classification == Simple {
// Otherwise we prefer pretty-printing to get rid of extraneous whitespace, comments and
// other formatting artifacts.
rustc_hir_pretty::id_to_string(&hir, body.hir_id)
} else if tcx.def_kind(hir.body_owner_def_id(body).to_def_id()) == DefKind::AnonConst {
// FIXME: Omit the curly braces if the enclosing expression is an array literal
// with a repeated element (an `ExprKind::Repeat`) as in such case it
// would not actually need any disambiguation.
"{ _ }".to_owned()
} else {
"_".to_owned()
}
}

/// Given a type Path, resolve it to a Type using the TyCtxt
Expand Down
4 changes: 3 additions & 1 deletion src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -716,12 +716,14 @@ fn assoc_const(
ty = ty.print(cx),
);
if let Some(default) = default {
write!(w, " = ");

// FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
// hood which adds noisy underscores and a type suffix to number literals.
// This hurts readability in this context especially when more complex expressions
// are involved and it doesn't add much of value.
// Find a way to print constants here without all that jazz.
write!(w, " = {}", default.value(cx.tcx()).unwrap_or_else(|| default.expr(cx.tcx())));
write!(w, "{}", Escape(&default.value(cx.tcx()).unwrap_or_else(|| default.expr(cx.tcx()))));
}
}

Expand Down
Loading