profile
viewpoint
Eduard-Mihai Burtescu eddyb @LykenSol Bucharest, Romania Senior Compiler/PL Engineer

alexcrichton/rustc-demangle 88

Rust symbol demangling

Centril/rfc-effects 8

Preparing an RFC on effect polymorphism in Rust with focus on 'const'

eddyb/cprep 5

C/C++ preprocessor.

eddyb/aoc 2

Advent of Code solutions in Rust

eddyb/bootstrap 2

HTML, CSS, and JS toolkit from Twitter

eddyb/hematite 2

A simple Minecraft written in Rust with the Piston game engine

eddyb/1ml 0

1ML prototype interpreter

eddyb/cargo 0

The Rust package manager

eddyb/clap-rs 0

A full featured, fast Command Line Argument Parser for Rust

pull request commentrust-lang/rust

Don't run `everybody_loops` for rustdoc; instead ignore resolution errors

@bors try @rust-timer queue

jyn514

comment created time in 3 hours

pull request commentrust-lang/rust

Don't run `everybody_loops` for rustdoc; instead ignore resolution errors

@rust-timer queue

jyn514

comment created time in 3 hours

issue commentrust-lang/rust

There's currently no way to specify bounds requiring constants in types to be well-formed

@newpavlov The plan is to replicate the expressions in the where clauses (shifting the burden on the user to check that the expressions const-evaluate successfully, just like trait bounds do today), we just haven't decided on a syntax for them.

This is one way I could see it working, although it's kind of messy (note that we need the type aliases due to lacking constant expression unification):

type ArrayMul<T, const N: usize, const M: usize> = [T; N*M];
fn foo<const N: usize>()
    where ArrayMul<u8, 2, N>:, ArrayMul<u8, 4, N>:,
{
    let a: ArrayMul<u8, 2, N> = ..;
    let b: ArrayMul<u8, 4, N>= ..;
}

There should probably be an "easy way" of doing this, where constant expressions in the fn signature are assumed to evaluate successfully, and the burden of checking that gets put on the caller (which could propagate up to a level where the constant expressions are fully known, thus requiring no where clauses).

But it's unclear how much it helps in general, compared to more explicit where clauses.

<hr/>

And the reason why we treat this differently from constants failing to evaluate elsewhere, is that it feeds into the typesystem. For constants used in runtime functions, we could just warn during monomorphization, and generate a runtime panic. It's not great, but it's also not exactly wrong either, since only runtime code actually relies on the value.

Whereas with constants in types, we're almost performing "post-monomorphization type-checking" (when triggering CTFE in types, from monomorphization) and we'd want to avoid exposing that aspect as much as possible.

One place where it could get really bad is functions which can fail instantiation with no outside indication of that possibility, simply due to the expressions they use in types, and the semver interactions there. But I'm not sure I'm the best person to explain that.

varkor

comment created time in 3 hours

pull request commentrust-lang/rust

Initialize default providers only once

Yeah you can generally ignore wall-time. The important thing to look at here is helloworld-check, which had no changes.

@bors r+

jyn514

comment created time in 4 hours

Pull request review commentrust-lang/rfcs

Add the partial-lambda-args RFC.

+- Feature Name: `partial_closure_args`+- Start Date: 2020-07-14+- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)+- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)++# Summary+[summary]: #summary++Pattern matching has this nice mechanism _partial pattern matching_: you can pattern match what you are+interested in, and then use the `..` syntax to _ignore everything else_. Example:++```rust+let (a, b, ..) = (1, true, "Hello, world!"); // here++struct Foo {+  x: u32,+  y: u32,+  id: String,+}++let foo = Foo { x: 0, y: 0, id: "Hello, world!".into() };+let Foo { id, .. } = foo; // here+```++The `..` syntax is also used to state “everything else” when constructing values (however, this is out+of scope of this RFC):++```rust+fn reset_foo(x: Foo) -> Foo {+  Foo { x: 0., y: 0., ..x }+}+```++This RFC suggests to provide the same `..` ergonomics syntax to ignore closures’ arguments in the+same way it works with tuples:++```rust+struct Point2D {+  x: f32,+  y: f32,+}++impl Point2D {+  fn map(self, f: impl FnOnce(f32, f32) -> (f32, f32)) -> Self {+    let (x, y) = f(self.x, self.y);+    Point2D { x, y }+  }+}++let x = Point2D { x: 123., y: -7. };+let a = x.map(|..| (0., 0.)); // here+```++As with tuples, it’s possible to pattern match up to the _nth_ argument, then ignore the rest:++```rust+|a, b, c, ..|+```++It is also possible to find `..` in the middle of the argument list, given all arguments are+provided at the beginning and the end of the list:++```rust+|a, .., z|+```++# Motivation+[motivation]: #motivation++Several functions / methods expect as argument another function, often expressed as a closure.+Sometimes, we want to ignore arguments and return a constant object whatever the arguments, or+simply are not interested in some of them. We are not often annoyed by this because the standard+library uses, most of the time, high-order unary functions, which means we can ignore the argument+with the simple `|_|` syntax — example: `Result::map_err`.++However, as we start building more complex applications, it happens that we have to provide n-ary+functions. In that case, for instance for a function with arity three (three arguments), the syntax+to ignore the arguments is `|_, _, _|`, which seems like a lot of noise to just express “ignore+everything”. Pattern matching tuples and structs has this mechanism, so it seems natural to extend+it to closure arguments as well.++# Guide-level explanation+[guide-level-explanation]: #guide-level-explanation++## Partially pattern match closure arguments++As with pattern matching tuples and structs, it is possible to _partially pattern match_ closure+arguments by using the `..` in the list of arguments (possibly none). Example:++```rust+// without argument+x.map(|| 123);+x.map(|..| 123); // same as above++// unary+x.map(|_| 123);+x.map(|..| 123); // same as above++// binary+x.map(|_, _| 123);+x.map(|..| 123); // same as above++// with five arguments+x.map(|_, _, _, _, _| 123);+x.map(|..| 123); // same as above+```++It is possible to mix underscores `_` with partial pattern matching as well with pattern matching+arguments you want in the same way you do with tuples and structs:++```rust+// with five arguments+x.map(|a, _, b, _, _| a + b);+x.map(|a, _, b, ..| a + b); // same as above+```++You can also use it in the middle of the arguments list, but that requires that all the arguments+to the right of `..` are filled until the end (without another `..` in the list):++```rust+x.map(|a, .., d, e| a + d + e);+x.map(|a, b, .., e| a + b + e);+```++The following, however, is not allowed:++```rust+x.map(|a, .., c, .., e| a + c + e); // error: cannot have two .. in a closure argument list+```++It is important to notice that `..` is not completely isomorphic to using `_` for all arguments. If+the arity of the function changes (for instance, it loses or gains arguments), the `..` syntax will+still compile while the `_` will obviously fail to match, which makes using `..` in lambda+arguments subject to breaking-changes if the type of the closure changes at the calling site.++## How we teach this++In the _Pattern Syntax_ section of the Rust book ([here](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html#ignoring-remaining-parts-of-a-value-with-),+some paragraphs should be added regarding pattern matching the arguments list by+using the `..` syntax.++The meaning of this syntax is equivalent to the tuple syntax:++```rust+let (a, b, ..) = (1, 2, 3, 4);+x.map(|a, b, ..| a + b);+```++The feature is not about [variadic functions](https://en.wikipedia.org/wiki/Variadic_function): the+arity is well-defined, so are the types of all of its arguments. Consider `..` as syntactic sugar for+ignoring zero to several arguments.++People should think of `..` as _“ignore everything else”_. So:++```rust+|a, ..|+```++is a closure that captures its first argument and ignore all the rest, whatever its arity. The+following:++```rust+|..|+```++Is a closure that will never read any of its arguments (if any). This:++```rust+|s, .., e|+```++Is a closure that captures its first `s` argument and its last `e` argument, and ignore all the+rest.++# Reference-level explanation+[reference-level-explanation]: #reference-level-explanation++## Interaction with type inference++A closure containing a `..` – as in `|a, b, .., x|` – is not type-inferable (there is no way to+detect which trait it implements). Closures with `..` can only be used in places where a type is+already constrained by one of the `FnOnce`, `Fn` or `FnMut` traits. The following is, thus, not+authorized:++```rust+let f = |a, b, ..| a + b;++println!("{}", f(1, 2)); // error: cannot deduce type of f+```

I'd like to express support for this, on the basis that we already do something simi for deducing HRTB (for<'a>) for closures, from the Fn trait bounds in the "expected type", which you can observe in examples like this (playground):

fn foo(_: impl Fn(&str)) {}

fn main() {
    foo(|_| {}); // works

    let f = |_| {};
    foo(f); // errors, cannot make the closure lifetime-polymorphic after-the-fact
}

cc @nikomatsakis

phaazon

comment created time in 5 hours

Pull request review commentrust-lang/rust

diagnostics: shorten paths of unique symbols

 macro_rules! p {     (@write($($data:expr),+)) => {         write!(scoped_cx!(), $($data),+)?     };+    (@write_full_path($($data:expr),+)) => {+        with_crate_prefix(|| {+            write!(scoped_cx!(), $($data),+)+        })?+    };     (@print($x:expr)) => {         scoped_cx!() = $x.print(scoped_cx!())?     };+    (@$method:ident(cond_full_path: $cond:expr, $($arg:expr),*)) => {+        let res = if $cond {+            with_crate_prefix(|| {+                scoped_cx!().$method($($arg),*)+            })+        } else {+            scoped_cx!().$method($($arg),*)+        };+        scoped_cx!() = res?+    };

Oh I think it's because of the closure nesting, that makes sense. You should be able to remove the users of this post-#74344, as per my other comments, thankfully.

da-x

comment created time in 6 hours

Pull request review commentrust-lang/rust

diagnostics: shorten paths of unique symbols

 impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> {         define_scoped_cx!(self);          if substs.is_empty() {+            if !SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {+                match self.try_print_unique_def(def_id)? {+                    (cx, true) => return Ok(cx),+                    (cx, false) => self = cx,+                }+            }+             match self.try_print_visible_def_path(def_id)? {

But "visible def path" is what you're doing, isn't it? Just not absolute. Maybe I'm overthinking things.

da-x

comment created time in 6 hours

Pull request review commentrust-lang/rust

diagnostics: shorten paths of unique symbols

 impl fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {  impl ty::TraitRef<'tcx> {     pub fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> {-        TraitRefPrintOnlyTraitPath(self)+        TraitRefPrintOnlyTraitPath(self, false)+    }+    pub fn print_only_trait_path_full(self) -> TraitRefPrintOnlyTraitPath<'tcx> {+        TraitRefPrintOnlyTraitPath(self, true)+    }+}++/// Wrapper type for `ty::TraitRef` to force printing the full path instead+/// of a possibly unique short path.+#[derive(Copy, Clone, TypeFoldable, Lift)]+pub struct TraitRefPrintFullPath<'tcx>(ty::TraitRef<'tcx>);++impl fmt::Debug for TraitRefPrintFullPath<'tcx> {+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {+        fmt::Display::fmt(self, f)+    }+}++impl ty::TraitRef<'tcx> {+    pub fn print_full_path(self) -> TraitRefPrintFullPath<'tcx> {+        TraitRefPrintFullPath(self)     } }  impl ty::Binder<ty::TraitRef<'tcx>> {     pub fn print_only_trait_path(self) -> ty::Binder<TraitRefPrintOnlyTraitPath<'tcx>> {         self.map_bound(|tr| tr.print_only_trait_path())     }+    pub fn print_only_trait_path_full(self) -> ty::Binder<TraitRefPrintOnlyTraitPath<'tcx>> {+        self.map_bound(|tr| tr.print_only_trait_path_full())+    }+    pub fn print_full_path(self) -> ty::Binder<TraitRefPrintFullPath<'tcx>> {+        self.map_bound(|tr| tr.print_full_path())+    }

Presumably that can be handled by "just" using the "include crate" mode that these internally use, directly?

da-x

comment created time in 6 hours

pull request commentrust-lang/rust

Use LocalDefId instead of HirId for reachable_set elements.

Mostly neutral, so this is more of a cleanup PR than an optimization one.

eddyb

comment created time in 6 hours

pull request commentrust-lang/rust

Support const args in type dependent paths (Take 2)

@bors r+ rollup=never :rocket:

lcnr

comment created time in 7 hours

issue commentrust-lang/rust

post const args in type dependent paths cleanup

Copying a couple of comments here:

  • https://github.com/rust-lang/rust/pull/74113#discussion_r454926268 (src/librustc_typeck/collect/type_of.rs / fn opt_const_param_of)

    I think you can make this cheaper incremental-wise by checking tcx.def_kind(def_id) first, because that won't add a dependency to the entire definition pointed to by def_id, just the simple DefKind enum (but feel free to file this under further experimentation).

  • https://github.com/rust-lang/rust/pull/74113#discussion_r454928692 (referring to the if ... { if let ... { return ... } } pattern)

    I just realized that this two-step process could probably be a helper method on WithOptConstParam (and do e.g. if let Some(def) = def.upgrade_with_const_param(tcx) or something like that, with the method documentation describing this kind of use pattern).

lcnr

comment created time in 7 hours

Pull request review commentrust-lang/rust

Support const args in type dependent paths (Take 2)

 use rustc_target::spec::PanicStrategy;  use super::lints; -crate fn mir_built(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::steal::Steal<Body<'_>> {-    tcx.alloc_steal_mir(mir_build(tcx, def_id))+crate fn mir_built<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> &'tcx ty::steal::Steal<Body<'tcx>> {+    if def.const_param_did.is_none() {+        if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {

I just realized that this two-step process could probably be a helper method on WithOptConstParam (e.g. if let Some(def) = def.upgrade_with_const_param(tcx) or something like that, with the method describing this kind of use pattern).

Again, you can file this under future improvements.

lcnr

comment created time in 8 hours

Pull request review commentrust-lang/rust

Support const args in type dependent paths (Take 2)

 use rustc_trait_selection::traits; use super::ItemCtxt; use super::{bad_placeholder_type, is_suggestable_infer_ty}; +/// Computes the relevant generic parameter for a potential generic const argument.+///+/// This should be called using the query `tcx.opt_const_param_of`.+pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {+    use hir::*;++    let hir_id = tcx.hir().as_local_hir_id(def_id);++    if let Node::AnonConst(_) = tcx.hir().get(hir_id) {

I think you can make this cheaper incremental-wise by checking tcx.def_kind(def_id) first, because that won't add a dependency to the entire definition pointed to by def_id, just the simple DefKind enum (but feel free to file this under further experimentation).

lcnr

comment created time in 8 hours

Pull request review commentrust-lang/rust

Support const args in type dependent paths (Take 2)

 rustc_queries! {             desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }         } +        /// Computes the `DefId` of the corresponding const parameter in case the `key` is a+        /// const argument and returns `None` otherwise.+        ///+        /// ```rust+        /// let a = foo::<7>();+        /// //            ^ Calling `opt_const_param_of` for this argument,+        ///+        /// fn foo<const N: usize>()+        /// //           ^ returns this `DefId`.+        ///+        /// fn bar() {+        /// // ^ While calling `opt_const_param_of` for other bodies returns `None`.+        /// }+        /// ```+        query opt_const_param_of(key: LocalDefId) -> Option<DefId> {+            desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) }+            // FIXME: consider storing this query on disk.

Can you open an issue and tag it here? I wonder if this will reduce some of the perf regressions?

lcnr

comment created time in 8 hours

Pull request review commentrust-lang/rust

Support const args in type dependent paths (Take 2)

 impl<'tcx> Instance<'tcx> {         tcx.resolve_instance(tcx.erase_regions(&param_env.and((def_id, substs))))     } +    // This should be kept up to date with `resolve`.+    pub fn resolve_const_arg(

Oops, I missed this one, could this be resolve_opt_const_arg? Maybe resolve could call into this with ty::WithOptConstParam::unknown(def_id), to avoid duplication?

lcnr

comment created time in 8 hours

pull request commentrust-lang/rust

Don't keep {Closure,Generator}Substs synthetics in an Instance.

Most of the wins are in some "patched incremental" benchmarks doing less codegen, I'm guessing something about a closure changes and it previously was treated as the identity of the closure instance changing, which was unnecessary and wasteful.

Do note that the numbers are all "patched incremental", with negligible effects on anything else. Maybe rustc-perf should emphasize that split more? Right now the use of only relative values can make it less clear what's going on. cc @Mark-Simulacrum

eddyb

comment created time in 10 hours

pull request commentrust-lang/rust

ClosureSubsts/GeneratorSubsts refactoring

@VFLashM Sorry, I didn't see this PR, you should've coordinated with @nikomatsakis. I believe as-is it's reverting a past change, which was probably done with Chalk integration in mind, but I don't know the details.

r? @nikomatsakis

VFLashM

comment created time in 10 hours

Pull request review commentrust-lang/rust

Add `TyCtxtAt::{ty_error, ty_error_with_message}`

 impl<'tcx> TyCtxt<'tcx> {     } } +impl TyCtxtAt<'tcx> {+    /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.+    #[track_caller]+    pub fn ty_error(self) -> Ty<'tcx> {+        self.tcx.ty_error_with_message(self.span, "TyKind::Error constructed but no error reported")+    }++    /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to+    /// ensure it gets used.+    #[track_caller]+    pub fn ty_error_with_message(self, msg: &str) -> Ty<'tcx> {+        self.sess.delay_span_bug(self.span, msg);+        self.mk_ty(Error(super::sty::DelaySpanBugEmitted(())))

@mark-i-m that's where it needs to be used, but it's a public type, you can use it from anywhere.

LeSeulArtichaut

comment created time in 10 hours

Pull request review commentrust-lang/rust

Don't visit foreign function bodies when lowering ast to hir

 impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {         }     } +    fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) {+        match fk {+            FnKind::Fn(FnCtxt::Foreign, _, sig, _, _) => {+                self.visit_fn_header(&sig.header);+                visit::walk_fn_decl(self, &sig.decl);+            }

Oh I forgot to ask, can you leave a comment that this is skipping visiting an extraneous body, which is an indication of a parse error?

ayazhafiz

comment created time in 10 hours

pull request commentrust-lang/rust

Change `SymbolName::name` to a `&str`.

@bors r+

nnethercote

comment created time in 10 hours

Pull request review commentrust-lang/rust

Change `SymbolName::name` to a `&str`.

 impl<'tcx> Value<'tcx> for &'_ TyS<'_> {     } } -impl<'tcx> Value<'tcx> for ty::SymbolName {-    fn from_cycle_error(_: TyCtxt<'tcx>) -> Self {-        ty::SymbolName { name: Symbol::intern("<error>") }+impl<'tcx> Value<'tcx> for ty::SymbolName<'_> {+    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {+        // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.+        // FIXME: Represent the above fact in the trait system somehow.

I hope @matthewjasper can come up with a better comment. Otherwise it's probably fine as-is. Although I kind of doubt this from_cycle_error implementation is needed at all.

nnethercote

comment created time in 10 hours

pull request commentrust-lang/rust

Don't run `everybody_loops` for rustdoc; instead ignore resolution errors

@Manishearth I'm fine with landing this by rebasing it on top of #74347, once the perf run there finishes.

jyn514

comment created time in 17 hours

pull request commentrust-lang/rust

Fix debug assertion in typeck

My initial thought was that we could apply the same way as #72019 but yeah, now, I'm not sure if it's always true. @eddyb could you confirm this?

@JohnTitor that change was in suggestion logic, whereas here it's for enforcing WF, and ICEs are preferred to unsoundness.

I left a comment with my suggestion (dummy -> bind) for making this work, I hope that works (since I didn't actually test it).

r? @nikomatsakis or @matthewjasper

JohnTitor

comment created time in 17 hours

Pull request review commentrust-lang/rust

Fix debug assertion in typeck

+// check-pass+// Regression test for #72410, this should be used with debug assertion enabled.++pub trait Foo {+    fn map()+    where+        Self: Sized,+        for<'a> &'a mut [u8]: ;

We should have a test for a type that is not WF, which this PR would allow compiling, but we'd never want to.

JohnTitor

comment created time in 17 hours

Pull request review commentrust-lang/rust

Fix debug assertion in typeck

 fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat                 // Keep the type around in a dummy predicate, in case of no bounds.                 // That way, `where Ty:` is not a complete noop (see #53696) and `Ty`                 // is still checked for WF.-                if bound_pred.bounds.is_empty() {+                if bound_pred.bounds.is_empty() && !ty.has_escaping_bound_vars() {

Huh, this was previously changed from a WF predicate, to an outlives one?

I suspect instead of changing the condition here (which would hide e.g. where for<'a> Foo<'a>:, from WF), you just need to change the ty::Binder::dummy to ty::Binder::bind.

JohnTitor

comment created time in 17 hours

pull request commentrust-lang/rust

Don't run `everybody_loops` for rustdoc; instead ignore resolution errors

Blocked on #74347.

jyn514

comment created time in 17 hours

Pull request review commentrust-lang/rust

Don't run `everybody_loops` for rustdoc; instead ignore resolution errors

 impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {         impl_items: &'ast [P<AssocItem>],     ) {         debug!("resolve_implementation");+        let old_ignore = self.in_func_body;+        // Never ignore errors in trait implementations.+        self.in_func_body = false;

@jyn514 I would expect this to set in_func_body to false for the duration of visit_item (and reset it back to the previous value afterwards).

jyn514

comment created time in 17 hours

pull request commentrust-lang/rust

disallow non-static lifetimes in const generics

r? @matthewjasper cc @nikomatsakis

yodaldevoid

comment created time in 17 hours

Pull request review commentrust-lang/rust

Don't visit foreign function bodies when lowering ast to hir

 impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {         }     } +    fn visit_fn(&mut self, fk: FnKind<'a>, _: Span, _: NodeId) {+        match fk {+            FnKind::Fn(FnCtxt::Foreign, _, sig, _, _) => {+                self.visit_fn_header(&sig.header);+                visit::walk_fn_decl(self, &sig.decl);+            }+            FnKind::Fn(_, _, sig, _, body) => {+                self.visit_fn_header(&sig.header);+                visit::walk_fn_decl(self, &sig.decl);+                walk_list!(self, visit_block, body);+            }+            FnKind::Closure(decl, body) => {+                visit::walk_fn_decl(self, decl);+                self.visit_expr(body);+            }

Can you use walk_fn for this part? So that it's clearer what's being overriden?

ayazhafiz

comment created time in 17 hours

pull request commentrust-lang/rust

Initialize default providers only once

LGTM, let's make sure this is a perf noop: @bors try @rust-timer queue

jyn514

comment created time in 17 hours

Pull request review commentrust-lang/rust

Rewrite the `Visitor` for `non_ssa_locals`

 pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(     let mir = fx.mir;     let mut analyzer = LocalAnalyzer::new(fx); -    analyzer.visit_body(&mir);+    for (block, data) in traversal::reverse_postorder(mir) {+        analyzer.visit_basic_block_data(block, data);+    }++    for debuginfo in mir.var_debug_info.iter() {+        analyzer.visit_var_debug_info(debuginfo);+    }      for (local, decl) in mir.local_decls.iter_enumerated() {         let ty = fx.monomorphize(&decl.ty);         debug!("local {:?} has type `{}`", local, ty);         let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);-        if fx.cx.is_backend_immediate(layout) {-            // These sorts of types are immediates that we can store-            // in an Value without an alloca.-        } else if fx.cx.is_backend_scalar_pair(layout) {-            // We allow pairs and uses of any of their 2 fields.-        } else {-            // These sorts of types require an alloca. Note that-            // is_llvm_immediate() may *still* be true, particularly-            // for newtypes, but we currently force some types-            // (e.g., structs) into an alloca unconditionally, just so-            // that we don't have to deal with having two pathways-            // (gep vs extractvalue etc).++        if ty_requires_alloca(&analyzer.fx, layout) {             analyzer.not_ssa(local);         }     }      analyzer.non_ssa_locals } +#[derive(Default, PartialEq, Eq)]+struct PlaceInfo {+    has_disqualifying_projection: bool,+    has_deref_projection: bool,+}+ struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {     fx: &'mir FunctionCx<'a, 'tcx, Bx>,     dominators: Dominators<mir::BasicBlock>,     non_ssa_locals: BitSet<mir::Local>,-    // The location of the first visited direct assignment to each-    // local, or an invalid location (out of bounds `block` index).-    first_assignment: IndexVec<mir::Local, Location>,++    /// The location of the first visited direct assignment to each local.+    first_assignment: IndexVec<mir::Local, Option<Location>>,++    place_info: PlaceInfo, }  impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {     fn new(fx: &'mir FunctionCx<'a, 'tcx, Bx>) -> Self {-        let invalid_location = mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location();         let dominators = fx.mir.dominators();         let mut analyzer = LocalAnalyzer {             fx,             dominators,             non_ssa_locals: BitSet::new_empty(fx.mir.local_decls.len()),-            first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls),+            first_assignment: IndexVec::from_elem(None, &fx.mir.local_decls),+            place_info: PlaceInfo::default(),         };          // Arguments get assigned to by means of the function being called         for arg in fx.mir.args_iter() {-            analyzer.first_assignment[arg] = mir::START_BLOCK.start_location();+            analyzer.assign(arg, mir::START_BLOCK.start_location());         }          analyzer     }      fn first_assignment(&self, local: mir::Local) -> Option<Location> {-        let location = self.first_assignment[local];-        if location.block.index() < self.fx.mir.basic_blocks().len() {-            Some(location)-        } else {-            None-        }+        self.first_assignment[local]

Can inline this, as it only existed to handle the invalid value encoding.

ecstatic-morse

comment created time in 18 hours

Pull request review commentrust-lang/rust

Rewrite the `Visitor` for `non_ssa_locals`

 impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>             }         }     }++    fn visit_projection_elem(+        &mut self,+        local: mir::Local,+        proj_base: &[mir::PlaceElem<'tcx>],+        elem: mir::PlaceElem<'tcx>,+        context: PlaceContext,+        location: Location,+    ) {+        self.super_projection_elem(local, proj_base, elem, context, location);++        // Projections like `(*x)[12]` are allowed but not `*(x[12])`.+        if let mir::PlaceElem::Deref = elem {+            self.place_info.has_disqualifying_projection = false;+            self.place_info.has_deref_projection = true;+            return;+        }++        if !is_consume(context) {+            self.place_info.has_disqualifying_projection = true;+            return;+        }++        if let mir::ProjectionElem::Field(..) = elem {+            let base_ty = mir::Place::ty_from(local, proj_base, self.fx.mir, self.fx.cx.tcx());+            let base_ty = self.fx.monomorphize(&base_ty);+            let span = self.fx.mir.local_decls[local].source_info.span;+            let layout = self.fx.cx.spanned_layout_of(base_ty.ty, span);+            if !ty_requires_alloca(self.fx, layout) {+                return;+            }+        }++        self.place_info.has_disqualifying_projection = true;+    }++    fn visit_var_debug_info(&mut self, var_debug_info: &mir::VarDebugInfo<'tcx>) {+        // Indirect debuginfo requires going through memory, that only+        // the debugger accesses, following our emitted DWARF pointer ops.+        //+        // FIXME(eddyb) Investigate the possibility of relaxing this, but+        // note that `llvm.dbg.declare` *must* be used for indirect places,+        // even if we start using `llvm.dbg.value` for all other cases,+        // as we don't necessarily know when the value changes, but only+        // where it lives in memory.+        //+        // It's possible `llvm.dbg.declare` could support starting from+        // a pointer that doesn't point to an `alloca`, but this would+        // only be useful if we know the pointer being `Deref`'d comes+        // from an immutable place, and if `llvm.dbg.declare` calls+        // must be at the very start of the function, then only function+        // arguments could contain such pointers.+        if var_debug_info.place.is_indirect() {+            self.not_ssa(var_debug_info.place.local);+        }+    }

I suspect you can remove this, since #68961. Any future changes would probably be done through rustc_codegen_ssa::mir::debuginfo itself checking whether there are any indirections in the place.

ecstatic-morse

comment created time in 18 hours

Pull request review commentrust-lang/rust

Rewrite the `Visitor` for `non_ssa_locals`

 impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>      fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {         debug!("visit_place(place={:?}, context={:?})", place, context);-        self.process_place(&place.as_ref(), context, location);++        // Except for `VarDebugInfo`, non-uses do not force locals onto the stack.+        //+        // `VarDebugInfo` is handled in `visit_var_debug_info`.+        if !context.is_use() {+            return;+        }++        let mir::Place { local, projection } = *place;++        // Reads from ZSTs do not require memory accesses.+        if is_consume(context) {+            let ty = place.ty(self.fx.mir, self.fx.cx.tcx()).ty;+            let ty = self.fx.monomorphize(&ty);+            let span = self.fx.mir.local_decls[local].source_info.span;+            if self.fx.cx.spanned_layout_of(ty, span).is_zst() {+                return;+            }+        }++        assert!(self.place_info == PlaceInfo::default(), "`visit_place` should not recurse");+        self.visit_projection(local, projection, context, location);

Can you use a loop instead? I'm hoping we won't need self.place_info that way.

ecstatic-morse

comment created time in 18 hours

issue commentrust-lang/rust

Refactor `non_ssa_locals` to remove `LocalAnalyzer::process_place`

Ah, the visit_local call could've been removed after/thanks to #68961 (specifically, this change) - somehow I forgot to do that.

And, wow, I can't believe we made the RPO mistake. That line has been the same since the start (https://github.com/rust-lang/rust/commit/6a5b263503dce838c2a09619171b409c9f11bb9f).

ecstatic-morse

comment created time in 18 hours

Pull request review commentrust-lang/rust

Rewrite the `Visitor` for `non_ssa_locals`

 pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi     debug!("cleanup_kinds: result={:?}", result);     result }++/// Returns `true` if locals of this type need to be allocated on the stack.+fn ty_requires_alloca<'a, 'tcx>(+    fx: &FunctionCx<'a, 'tcx, impl BuilderMethods<'a, 'tcx>>,+    ty: TyAndLayout<'tcx>,+) -> bool {+    // Currently, this returns `true` for ADTs that are otherwise small enough to qualify. For+    // example, `struct Newtype(i32)`. This way, every type has a single way to extract data+    // (gep, extractvalue, etc.).

This comment appears to be rewritten, but hasn't been true in ages, newtypes of immediates (scalars/vectors) and scalar pairs get "unpacked" automatically.

ecstatic-morse

comment created time in 18 hours

Pull request review commentrust-lang/rust

Change `SymbolName::name` to a `&str`.

 impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {                 // and/or monomorphization invalidates these assumptions.                 let coverageinfo = tcx.coverageinfo(caller_instance.def_id());                 let mangled_fn = tcx.symbol_name(caller_instance);-                let (mangled_fn_name, _len_val) = self.const_str(mangled_fn.name);+                let (mangled_fn_name, _len_val) = self.const_str(mangled_fn);

Is this why you changed the const_str API?

IMO const_str shouldn't care about this usecase, and if caching is desired, we probably want to cache the result of const_cstr (const_str is used here but the length is ignored anyway) once per FunctionCx, since the symbol name is that of the caller.

nnethercote

comment created time in 18 hours

Pull request review commentrust-lang/rust

Change `SymbolName::name` to a `&str`.

 impl<'tcx> Value<'tcx> for &'_ TyS<'_> {     } } -impl<'tcx> Value<'tcx> for ty::SymbolName {-    fn from_cycle_error(_: TyCtxt<'tcx>) -> Self {-        ty::SymbolName { name: Symbol::intern("<error>") }+impl<'tcx> Value<'tcx> for ty::SymbolName<'_> {+    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {+        // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.+        // FIXME: Represent the above fact in the trait system somehow.

Why can't you write ty::SymbolName<'tcx>? That's why Value has a 'tcx parameter.

Oh this is a specialization issue. IMO it should be noted as such rather then left as a vague FIXME (cc @matthewjasper).

nnethercote

comment created time in 18 hours

pull request commentrust-lang/rust

Remove string comparison and use diagnostic item instead

@bors r+ Thanks!

estebank

comment created time in 18 hours

pull request commentrust-lang/rust

Use LocalDefId instead of HirId for reachable_set elements.

@bors try @rust-timer queue

eddyb

comment created time in 18 hours

PR opened rust-lang/rust

Use LocalDefId instead of HirId for reachable_set elements.

The only HirIds being tracked there that don't have matching DefIds are local variables, and that's an accident from #44316 (where I preserved the old behavior, even if nothing relied on reachability tracking local variables).

+49 -53

0 comment

5 changed files

pr created time in 18 hours

Pull request review commentrust-lang/rust

Don't keep {Closure,Generator}Substs synthetics in an Instance.

 impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {         if let hir::ExprKind::Closure(..) = expr.kind {             let def_id = self.tcx.hir().local_def_id(expr.hir_id);             self.tcx.ensure().generics_of(def_id);-            self.tcx.ensure().type_of(def_id);

If they're because of having to return a value, I suspect using Result<T, ErrorReported> could work well.

eddyb

comment created time in 18 hours

create barncheddyb/rust

branch : reachable-defs

created branch time in 18 hours

issue commentrust-lang/rust

Consider merging `values` and `targets` fields on MIR `switchInt`?

@oli-obk isn't it the way it is today to optimize the space usage? (not saying that's a good reason, just that I thought it was intentional)

wesleywiser

comment created time in 20 hours

Pull request review commentrust-lang/rust

lint: use `transparent_newtype_field` to avoid ICE

 impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {         match ty.kind {             ty::FnPtr(_) => true,             ty::Ref(..) => true,-            ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => {-                for field in field_def.all_fields() {-                    let field_ty = self.cx.tcx.normalize_erasing_regions(-                        self.cx.param_env,-                        field.ty(self.cx.tcx, substs),-                    );-                    if field_ty.is_zst(self.cx.tcx, field.did) {

What does is_zst even do? I'm surprised to see that method on Ty, and suspicious of how it might be implemented.

davidtwco

comment created time in 20 hours

Pull request review commentrust-lang/rust

Support const args in type dependent paths (Take 2)

 rustc_queries! {     }      TypeChecking {-        /// The result of unsafety-checking this `DefId`.-        query unsafety_check_result(key: LocalDefId) -> mir::UnsafetyCheckResult {+        /// The result of unsafety-checking this `LocalDefId`.+        query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {             desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }             cache_on_disk_if { true }-            storage(ArenaCacheSelector<'tcx>)+        }+        query unsafety_check_result_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::UnsafetyCheckResult {

unsafety_check_result_for_const_arg

lcnr

comment created time in a day

Pull request review commentrust-lang/rust

Support const args in type dependent paths (Take 2)

 pub type PlaceholderType = Placeholder<BoundVar>;  pub type PlaceholderConst = Placeholder<BoundVar>; +/// A `DefId` which is potentially bundled with its corresponding generic parameter+/// in case `did` is a const argument.+///+/// This is used to prevent cycle errors during typeck+/// as `type_of(const_arg)` depends on `typeck_tables_of(owning_body)`+/// which once again requires the type of its generic arguments.+///+/// Luckily we only need to deal with const arguments once we+/// know their corresponding parameters. We (ab)use this by+/// calling `type_of(param_did)` for these arguments.+///+/// ```rust+/// #![feature(const_generics)]+///+/// struct A;+/// impl A {+///     fn foo<const N: usize>(&self) -> usize { N }+/// }+/// struct B;+/// impl B {+///     fn foo<const N: u8>(&self) -> usize { 42 }+/// }+///+/// fn main() {+///     let a = A;+///     a.foo::<7>();+/// }+/// ```+#[derive(Copy, Clone, Debug, TypeFoldable, Lift, RustcEncodable, RustcDecodable)]+#[derive(PartialEq, Eq, PartialOrd, Ord)]+#[derive(Hash, HashStable)]+pub struct WithOptParam<T> {+    pub did: T,

Btw, if you want to use a name for this that isn't def_id, I'd prefer id. Bonus: when you name the struct def, you get def.id, which reads better to me than def.did.

lcnr

comment created time in a day

Pull request review commentrust-lang/rust

Support const args in type dependent paths (Take 2)

 pub type PlaceholderType = Placeholder<BoundVar>;  pub type PlaceholderConst = Placeholder<BoundVar>; +/// A `DefId` which is potentially bundled with its corresponding generic parameter+/// in case `did` is a const argument.+///+/// This is used to prevent cycle errors during typeck+/// as `type_of(const_arg)` depends on `typeck_tables_of(owning_body)`+/// which once again requires the type of its generic arguments.+///+/// Luckily we only need to deal with const arguments once we+/// know their corresponding parameters. We (ab)use this by+/// calling `type_of(param_did)` for these arguments.+///+/// ```rust+/// #![feature(const_generics)]+///+/// struct A;+/// impl A {+///     fn foo<const N: usize>(&self) -> usize { N }+/// }+/// struct B;+/// impl B {+///     fn foo<const N: u8>(&self) -> usize { 42 }+/// }+///+/// fn main() {+///     let a = A;+///     a.foo::<7>();+/// }+/// ```+#[derive(Copy, Clone, Debug, TypeFoldable, Lift, RustcEncodable, RustcDecodable)]+#[derive(PartialEq, Eq, PartialOrd, Ord)]+#[derive(Hash, HashStable)]+pub struct WithOptParam<T> {+    pub did: T,+    /// The `DefId` of the corresponding generic paramter in case `did` is+    /// a const argument.+    ///+    /// Note that even if `did` is a const argument, this may still be `None`.+    /// All queries taking `WithOptParam` start by calling `tcx.opt_const_param_of(def.did)`+    /// to potentially update `param_did` in case it `None`.+    pub param_did: Option<DefId>,+}++impl<T> WithOptParam<T> {+    pub fn dummy(did: T) -> WithOptParam<T> {

Maybe unknown would be better than dummy? Since it means that something will potentially have to look up whether a const param DefId is needed.

lcnr

comment created time in a day

Pull request review commentrust-lang/rust

Support const args in type dependent paths (Take 2)

 impl<'tcx> Const<'tcx> {     /// Literals and const generic parameters are eagerly converted to a constant, everything else     /// becomes `Unevaluated`.     pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {-        debug!("Const::from_anon_const(id={:?})", def_id);+        Self::const_arg_from_anon_const(tcx, ty::WithOptParam::dummy(def_id))+    }++    pub fn const_arg_from_anon_const(

Okay you use opt_const_arg elsewhere, I think that would make sense here.

lcnr

comment created time in a day

Pull request review commentrust-lang/rust

Support const args in type dependent paths (Take 2)

 pub type PlaceholderType = Placeholder<BoundVar>;  pub type PlaceholderConst = Placeholder<BoundVar>; +/// A `DefId` which is potentially bundled with its corresponding generic parameter+/// in case `did` is a const argument.+///+/// This is used to prevent cycle errors during typeck+/// as `type_of(const_arg)` depends on `typeck_tables_of(owning_body)`+/// which once again requires the type of its generic arguments.+///+/// Luckily we only need to deal with const arguments once we+/// know their corresponding parameters. We (ab)use this by+/// calling `type_of(param_did)` for these arguments.+///+/// ```rust+/// #![feature(const_generics)]+///+/// struct A;+/// impl A {+///     fn foo<const N: usize>(&self) -> usize { N }+/// }+/// struct B;+/// impl B {+///     fn foo<const N: u8>(&self) -> usize { 42 }+/// }+///+/// fn main() {+///     let a = A;+///     a.foo::<7>();+/// }+/// ```+#[derive(Copy, Clone, Debug, TypeFoldable, Lift, RustcEncodable, RustcDecodable)]+#[derive(PartialEq, Eq, PartialOrd, Ord)]+#[derive(Hash, HashStable)]+pub struct WithOptParam<T> {+    pub did: T,+    /// The `DefId` of the corresponding generic paramter in case `did` is+    /// a const argument.+    ///+    /// Note that even if `did` is a const argument, this may still be `None`.+    /// All queries taking `WithOptParam` start by calling `tcx.opt_const_param_of(def.did)`+    /// to potentially update `param_did` in case it `None`.+    pub param_did: Option<DefId>,+}++impl<T> WithOptParam<T> {+    pub fn dummy(did: T) -> WithOptParam<T> {+        WithOptParam { did, param_did: None }+    }+}++impl WithOptParam<LocalDefId> {+    pub fn to_global(self) -> WithOptParam<DefId> {+        WithOptParam { did: self.did.to_def_id(), param_did: self.param_did }+    }++    pub fn ty_def_id(self) -> DefId {

This could be clearer, such as def_id_for_type_of.

lcnr

comment created time in a day

Pull request review commentrust-lang/rust

Support const args in type dependent paths (Take 2)

 impl<'tcx> Const<'tcx> {     /// Literals and const generic parameters are eagerly converted to a constant, everything else     /// becomes `Unevaluated`.     pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {-        debug!("Const::from_anon_const(id={:?})", def_id);+        Self::const_arg_from_anon_const(tcx, ty::WithOptParam::dummy(def_id))+    }++    pub fn const_arg_from_anon_const(

Should probably be named from_const_arg.

lcnr

comment created time in a day

Pull request review commentrust-lang/rust

Support const args in type dependent paths (Take 2)

 pub type PlaceholderType = Placeholder<BoundVar>;  pub type PlaceholderConst = Placeholder<BoundVar>; +/// A `DefId` which is potentially bundled with its corresponding generic parameter+/// in case `did` is a const argument.+///+/// This is used to prevent cycle errors during typeck+/// as `type_of(const_arg)` depends on `typeck_tables_of(owning_body)`+/// which once again requires the type of its generic arguments.+///+/// Luckily we only need to deal with const arguments once we+/// know their corresponding parameters. We (ab)use this by+/// calling `type_of(param_did)` for these arguments.+///+/// ```rust+/// #![feature(const_generics)]+///+/// struct A;+/// impl A {+///     fn foo<const N: usize>(&self) -> usize { N }+/// }+/// struct B;+/// impl B {+///     fn foo<const N: u8>(&self) -> usize { 42 }+/// }+///+/// fn main() {+///     let a = A;+///     a.foo::<7>();+/// }+/// ```+#[derive(Copy, Clone, Debug, TypeFoldable, Lift, RustcEncodable, RustcDecodable)]+#[derive(PartialEq, Eq, PartialOrd, Ord)]+#[derive(Hash, HashStable)]+pub struct WithOptParam<T> {+    pub did: T,+    /// The `DefId` of the corresponding generic paramter in case `did` is+    /// a const argument.+    ///+    /// Note that even if `did` is a const argument, this may still be `None`.+    /// All queries taking `WithOptParam` start by calling `tcx.opt_const_param_of(def.did)`+    /// to potentially update `param_did` in case it `None`.+    pub param_did: Option<DefId>,

So ignoring the use of did vs def_id, I believe that using the word "param" (as opposed to "const param") is too unclear reading the uses of this, without reading the definition. I'm hoping @nikomatsakis agrees with me, and renaming this to be clearer shouldn't be a lot of work.

lcnr

comment created time in a day

Pull request review commentrust-lang/rust

Don't keep {Closure,Generator}Substs synthetics in an Instance.

 impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {         if let hir::ExprKind::Closure(..) = expr.kind {             let def_id = self.tcx.hir().local_def_id(expr.hir_id);             self.tcx.ensure().generics_of(def_id);-            self.tcx.ensure().type_of(def_id);

I removed this line to make 29 UI tests pass - their only failure mode was missing some of the errors.

I believe what's happening is that this would now trigger type-checking the body of the closure, before bodies are normally type-checked, and so it trips on an "abort if any errors" check.

Can we start removing those "checkpoints" that turn regular errors into fatal ones, given how on-demand some of the various checks are nowadays? cc @estebank

eddyb

comment created time in a day

pull request commentrust-lang/rust

Don't keep {Closure,Generator}Substs synthetics in an Instance.

@bors try @rust-timer queue

eddyb

comment created time in a day

PR opened rust-lang/rust

Don't keep {Closure,Generator}Substs synthetics in an Instance.

Based on #74314, which removes the main use of synthetic type parameters in closure/generator ty::Generics

This PR keeps the "synthetics" (closure kind/signature/upvar types, or similar information for generators) only in the Ty (Closure/Generator) substitutions (used during inference and for type layout), but not in Instances which are used to refer to the MIR body of the closure during codegen (and the MIR body doesn't refer to the "synthetics" at all).

I originally started work on this to change the codegen behavior of closures with no type/const generics in scope (and have them not be deduplicated across crates), as per https://github.com/rust-lang/rust/pull/74283#issuecomment-657530357 - but have since given up on that line of experimentation.

It might still improve some performance or help with @davidtwco polymorphization work, but it's not clear that it will.

r? @nikomatsakis

+138 -115

0 comment

10 changed files

pr created time in a day

create barncheddyb/rust

branch : desynthesize

created branch time in a day

pull request commentrust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

@oli-obk Yes, that's typically a good idea because we want to inline closures. And it barely hurts rustc, presumably they just get less optimized in rustc_interface than they would in their original crate. AFAIK the only official way to avoid closures or generic functions from being codegen'd downstream is -Z share-generics, I don't know what the future of that is.

eddyb

comment created time in a day

pull request commentrust-lang/rust

rustc_typeck: construct {Closure,Generator}Substs more directly.

Yeah, it's neutral, no big surprise there.

eddyb

comment created time in a day

pull request commentrust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

The macro would be slightly nicer than today (and more declarative, so it would work with approaches other than "struct of fn pointers"), so I don't know why we would remove it, to be honest.

And the closure thing we'll likely not fix, as it's arguably largely not a bug: it's free devirtualization, it just happens to slightly regress performance in this very specific case.

eddyb

comment created time in a day

issue openedrust-dev-tools/rust-semverver

Concept: cargo publish automatically running this tool.

As long as we provide an opt-out, it should be possible for cargo publish to build the most recent semver-compatible version of a crate (as downloaded from crates.io), alongside the about-to-publish version (which I believe already always gets built), and compare them for incompatibilities.

cc @ehuss (I don't know where to suggest this on the Cargo side)

created time in a day

pull request commentrust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

@oli-obk In case it wasn't clear: the macro idea should make the current PR to work, by removing all closures (i.e. the macro can turn closure syntax into regular functions under the hook, which would not trigger the problematic behavior this PR stumbled onto).

eddyb

comment created time in a day

pull request commentrust-lang/rust

rustc_typeck: construct {Closure,Generator}Substs more directly.

@bors try @rust-timer queue

eddyb

comment created time in a day

PR opened rust-lang/rust

rustc_typeck: construct {Closure,Generator}Substs more directly.

We've previously not had a way to create {Closure,Generator}Substs other than instantiating all generics as inference variables and unifying the inference types (extracted using the regular {Closure,Generator}Substs accessors), with the actual types.

With this PR, those hacks, and assumptions about the order of closure/generator-specific components, are replaced with a simple API where the base Substs are combined with the additional information into a {Closure,Generator}Substs. This might also be faster than relying inference, although probably not by much.

r? @nikomatsakis cc #53488 @blitzerr

+123 -71

0 comment

3 changed files

pr created time in a day

create barncheddyb/rust

branch : closure-substs-direct

created branch time in a day

pull request commentrust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

I've played around with changing the closure codegen behavior (to fit this situation better), and I don't think it's worth it.

What's happening is arguably not a bug, but a feature, we just lose a bit of performance due to the closure-provided queries having duplicate codegen in rustc_interface, and whatever that implies for optimizations.

If we want to rely on CTFE I believe there's only one way: introduce a provide! macro that provides the ergonomics of using closures for queries (or better, really, since *providers = Providers { ..., ..*providers }; is not the nicest thing), but which avoids closures entirely (and instead relies on functions and grabbing the query input/output type from ty::query::queries using the query name, which is something rustc_metadata already employs successfully).

We could even use the same name: |tcx, input| {...}, syntax as today, so the main difference would be in indentation.

I'd appreciate feedback on that, but otherwise it'd be probably fine to just have a lazy_static! in rustc_interface for the default providers, so that custom drivers don't need to keep their own. And that should have no impact on performance either way.

<hr/>

While playing around with closures, I've come across a few things that I'll try to split into several PRs (aren't rabbit holes fun?).

eddyb

comment created time in a day

PR closed rust-lang/rust

Rollup of 18 pull requests S-waiting-on-review rollup

Successful merges:

  • #71237 (Add Ayu theme to rustdoc)
  • #72808 (Substantial refactor to the design of LineWriter)
  • #73354 (Update RELEASES.md for 1.45.0)
  • #73852 (rustdoc: insert newlines between attributes)
  • #73867 (Document the union keyword)
  • #73986 (add (unchecked) indexing methods to raw (and NonNull) slices)
  • #74046 (Fix caching issue when building tools.)
  • #74123 (clean up E0718 explanation)
  • #74147 (rustdoc: Allow linking from private items to private types)
  • #74173 (Detect tuple struct incorrectly used as struct pat)
  • #74227 (Remove an unwrap in layout computation)
  • #74239 (Update llvm-project to latest origin/rustc/10.0-2020-05-05 commit )
  • #74257 (don't mark linux kernel module targets as a unix environment)
  • #74263 (Slight reorganization of sys/(fast_)thread_local)
  • #74270 (typeck: report placeholder type error w/out span)
  • #74272 (pprust: support multiline comments within lines)
  • #74285 (#71669: add ui, codegen tests for volatile + nearby int intrinsics)
  • #74286 (Added detailed error code explanation for issue E0688 in Rust compiler.)

Failed merges:

r? @ghost

+2543 -556

10 comments

73 changed files

Manishearth

pr closed time in 2 days

pull request commentrust-lang/rust

Update llvm-project to latest origin/rustc/10.0-2020-05-05 commit

@bors rollup (trying to clear the "iffy", since it did work on wasm)

AdrianCX

comment created time in 2 days

pull request commentrust-lang/rust

Update llvm-project to latest origin/rustc/10.0-2020-05-05 commit

@bors p=0

AdrianCX

comment created time in 2 days

pull request commentrust-lang/rust

Rollup of 18 pull requests

LLVM update PR (#74239) seems to have succeeded the CI / auto (wasm32, ubuntu-latest-xl) (push) step, so it's not it? No clue what could be causing the wasm failure then.

Manishearth

comment created time in 2 days

pull request commentrust-lang/rust

Update llvm-project to latest origin/rustc/10.0-2020-05-05 commit

@bors rollup=iffy p=5 (checking if this is the cause of wasm failures, should take only half an hour)

AdrianCX

comment created time in 2 days

pull request commentrust-lang/rust

Rollup of 18 pull requests

Attempting the LLVM PR in isolation (should only take half an hour to find out if it introduces the test failure).

Manishearth

comment created time in 2 days

pull request commentrust-lang/rust

Rollup of 18 pull requests

I'm worried it's #74239 (the LLVM update), which did change wasm codegen (but the change I backported will be in LLVM 11 AFAICT so it should be fine?)

Anyway, recommend trying a rollup w/o LLVM.

Manishearth

comment created time in 2 days

pull request commentrust-lang/rust

Teach bootstrap about target files vs target triples

@Manishearth I'm no so sure this PR broke wasm, the test fails w/o it: https://github.com/rust-lang/rust/pull/74309#issuecomment-657917670

shepmaster

comment created time in 2 days

pull request commentrust-lang/rust

Rollup of 18 pull requests

The test is // ignore-wasm32-bare but the test fails on wasm32-unknown-emscripten.

So I'm not even sure the PR you took out had any effect on the rollup.

Manishearth

comment created time in 2 days

pull request commentrust-lang/rust

Rollup of 18 pull requests

Uhh, ui/rfcs/rfc-1014.rs failed again on wasm, did you take the PR out?

Manishearth

comment created time in 2 days

pull request commentrust-lang/rust

Don't panic if the lhs of a div by zero is not statically known

@Manishearth this PR had already failed PR CI by the time the rollup was created, could we have bors gate on PR, and r- on failure?

oli-obk

comment created time in 2 days

pull request commentrust-lang/rust

Rollup of 17 pull requests

Huh, this is what ended up on the PR CI, although this passed on the wasm builder (which failed for an unrelated reason):

---- [ui] ui/const_prop/ice-assert-fail-div-by-zero.rs stdout ----
diff of stderr:

-	warning: this operation will panic at runtime
-	  --> $DIR/ice-assert-fail-div-by-zero.rs:10:5
-	   |
-	LL |     f.0 / 0;
-	   |     ^^^^^^^ attempt to divide _ by zero
-	   |
-	note: the lint level is defined here
-	  --> $DIR/ice-assert-fail-div-by-zero.rs:5:9
-	   |
-	LL | #![warn(unconditional_panic)]
-	   |         ^^^^^^^^^^^^^^^^^^^
-	
-	warning: 1 warning emitted
-	
-	
Manishearth

comment created time in 2 days

pull request commentrust-lang/rust

Rollup of 17 pull requests

@bors retry

Manishearth

comment created time in 2 days

pull request commentrust-lang/rust

[beta] next

@bors retry

Mark-Simulacrum

comment created time in 2 days

pull request commentrust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

It looks like closures are considered generic functions, due to substs.non_erasable_generics() always returning true, thanks to the "generic parameters" they keep around (to track certain properties, including e.g. captures' types, during type inference).

(-Z share-generics might do something, but I haven't done a full build with it on to see what happens)

I can try and fix the closure monomorphization behavior, although we might want to land it separately, there's clearly some risk of it limiting some optimizations, although not for all the cases in which a closure is found within a generic function, and the only other case would have to be #[inline] functions with closures inside, which we could maybe account for?

eddyb

comment created time in 2 days

pull request commentrust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

@lcnr compare with the old code, which also kept Providers on the stack.

<hr/>

One thing I wasn't aware of was that LLVM can actually optimize the *providers = Providers { foo, ..*providers }; to a single field write.

So the difference is that before we were writing every field twice, once by Providers::default(), and once by the relevant fn provide, potentially copying the Providers once (keep in mind e.g. Providers::default() couldn't be inlined into rustc_interface, but maybe we do great codegen for that now?), whereas now there's just one copy from .rodata.

<hr/>

Nevermind, I think I found the problem, it's something I was worried might happen but didn't think it could. Instantiating DEFAULT_QUERY_PROVIDERS results in 14493 instances of define (pre-optimizations).

So a const Providers results in massive amounts of codegen, in the wrong crate (rustc_interface instead of the original). Presumably most of the functions involved remain in the original crate, so the copies in rustc_interface are less optimized?

eddyb

comment created time in 2 days

pull request commentrust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

Okay, that's weird, I was expecting a speed-up. Since all it needs to do now is memcpy the Providers onto the stack. Surely there were more copies in the old configuration? I guess I could try to perf diff the compilation of an empty #![no_std] library crate, before and after this PR.

eddyb

comment created time in 2 days

Pull request review commentrust-lang/rust

diagnostics: shorten paths of unique symbols

 impl fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {  impl ty::TraitRef<'tcx> {     pub fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> {-        TraitRefPrintOnlyTraitPath(self)+        TraitRefPrintOnlyTraitPath(self, false)+    }+    pub fn print_only_trait_path_full(self) -> TraitRefPrintOnlyTraitPath<'tcx> {+        TraitRefPrintOnlyTraitPath(self, true)+    }+}++/// Wrapper type for `ty::TraitRef` to force printing the full path instead+/// of a possibly unique short path.+#[derive(Copy, Clone, TypeFoldable, Lift)]+pub struct TraitRefPrintFullPath<'tcx>(ty::TraitRef<'tcx>);++impl fmt::Debug for TraitRefPrintFullPath<'tcx> {+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {+        fmt::Display::fmt(self, f)+    }+}++impl ty::TraitRef<'tcx> {+    pub fn print_full_path(self) -> TraitRefPrintFullPath<'tcx> {+        TraitRefPrintFullPath(self)     } }  impl ty::Binder<ty::TraitRef<'tcx>> {     pub fn print_only_trait_path(self) -> ty::Binder<TraitRefPrintOnlyTraitPath<'tcx>> {         self.map_bound(|tr| tr.print_only_trait_path())     }+    pub fn print_only_trait_path_full(self) -> ty::Binder<TraitRefPrintOnlyTraitPath<'tcx>> {+        self.map_bound(|tr| tr.print_only_trait_path_full())+    }+    pub fn print_full_path(self) -> ty::Binder<TraitRefPrintFullPath<'tcx>> {+        self.map_bound(|tr| tr.print_full_path())+    }

These changes shouldn't be necessary once we stop using string matching for diagnostics, AFAICT.

da-x

comment created time in 2 days

Pull request review commentrust-lang/rust

diagnostics: shorten paths of unique symbols

 impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {                         );                          let should_convert_option_to_result =-                            format!("{}", trait_ref.print_only_trait_path())+                            format!("{}", trait_ref.print_only_trait_path_full())                                 .starts_with("std::convert::From<std::option::NoneError");-                        let should_convert_result_to_option = format!("{}", trait_ref)-                            .starts_with("<std::option::NoneError as std::convert::From<");+                        let should_convert_result_to_option =+                            format!("{}", trait_ref.print_full_path())+                                .starts_with("<std::option::NoneError as std::convert::From<");

NoneError should be a diagnostic item, instead of string matching.

da-x

comment created time in 2 days

Pull request review commentrust-lang/rust

diagnostics: shorten paths of unique symbols

 impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {                             .span_to_snippet(span)                             .map(|s| &s == "?")                             .unwrap_or(false);-                        let is_from = format!("{}", trait_ref.print_only_trait_path())+                        let is_from = format!("{}", trait_ref.print_only_trait_path_full())                             .starts_with("std::convert::From<");

String manipulation is really hacky, and code like this should instead check trait_ref.def_id for a lang item (if one exists) or a diagnostic item otherwise.

da-x

comment created time in 2 days

Pull request review commentrust-lang/rust

diagnostics: shorten paths of unique symbols

 pub trait PrettyPrinter<'tcx>:         self.try_print_visible_def_path_recur(def_id, &mut callers)     } +    /// Try to see if this is a unique symbol, meaning there's no other definition with+    /// the same name.+    fn try_print_unique_def(mut self, def_id: DefId) -> Result<(Self::Path, bool), Self::Error> {+        let unique_symbols = &self.tcx().unique_symbols;++        match unique_symbols.get(&def_id) {+            None => return Ok((self, false)),+            Some(symbol) => {+                write!(&mut self, "{}", symbol)?;

Is this used (as opposed to write_str) elsewhere? I forget.

da-x

comment created time in 2 days

Pull request review commentrust-lang/rust

diagnostics: shorten paths of unique symbols

 impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> {         define_scoped_cx!(self);          if substs.is_empty() {+            if !SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {+                match self.try_print_unique_def(def_id)? {+                    (cx, true) => return Ok(cx),+                    (cx, false) => self = cx,+                }+            }+             match self.try_print_visible_def_path(def_id)? {

I wonder if it might be useful to move the logic into try_print_visible_def_path.

da-x

comment created time in 2 days

Pull request review commentrust-lang/rust

diagnostics: shorten paths of unique symbols

 macro_rules! p {     (@write($($data:expr),+)) => {         write!(scoped_cx!(), $($data),+)?     };+    (@write_full_path($($data:expr),+)) => {+        with_crate_prefix(|| {+            write!(scoped_cx!(), $($data),+)+        })?+    };     (@print($x:expr)) => {         scoped_cx!() = $x.print(scoped_cx!())?     };+    (@$method:ident(cond_full_path: $cond:expr, $($arg:expr),*)) => {+        let res = if $cond {+            with_crate_prefix(|| {+                scoped_cx!().$method($($arg),*)+            })+        } else {+            scoped_cx!().$method($($arg),*)+        };+        scoped_cx!() = res?+    };

I believe you can do these manually around p! calls and avoid changing the macro.

da-x

comment created time in 2 days

issue commentrust-lang/rust

The compiler should report publicly exported type names if possible

There was an idea I noted down in a pull request: https://github.com/rust-lang/rust/pull/70911#issuecomment-611102912. In short, it involves shortening paths to a name that is unique to them (e.g. if there's only one Vec ever), and potentially doing some prelude-specific logic (but not necessarily, I guess?).

I don't know if #73996 is based on that comment or not, but it's really cool that it's happening, and I'm sorry I didn't leave a comment here when I suggested the idea in the str librarification PR.

pcwalton

comment created time in 2 days

pull request commentrust-lang/rust

[beta] next

@bors retry

Mark-Simulacrum

comment created time in 2 days

Pull request review commentrust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

 pub fn prepare_outputs(     Ok(outputs) } -pub fn default_provide(providers: &mut ty::query::Providers) {-    providers.analysis = analysis;-    proc_macro_decls::provide(providers);-    plugin::build::provide(providers);-    rustc_middle::hir::provide(providers);-    mir::provide(providers);-    mir_build::provide(providers);-    rustc_privacy::provide(providers);-    typeck::provide(providers);-    ty::provide(providers);-    traits::provide(providers);-    rustc_passes::provide(providers);-    rustc_resolve::provide(providers);-    rustc_traits::provide(providers);-    rustc_ty::provide(providers);-    rustc_metadata::provide(providers);-    rustc_lint::provide(providers);-    rustc_symbol_mangling::provide(providers);-    rustc_codegen_ssa::provide(providers);-}+pub const DEFAULT_QUERY_PROVIDERS: Providers = {+    // FIXME(eddyb) the `const fn` shouldn't be needed, but mutable references

Indeed, maybe I should say "separate function" or something like that.

eddyb

comment created time in 2 days

pull request commentrust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

@bors try @rust-timer queue

eddyb

comment created time in 3 days

push eventeddyb/rust

Eduard-Mihai Burtescu

commit sha f0141eb89f43b24bfc78697201b190a2a4624677

Compute `query::Providers` almost entirely at compile-time.

view details

push time in 3 days

pull request commentrust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

Oh I was worried about this, but didn't realize it changed in this release cycle:

error[E0764]: mutable references are not allowed in constants
   --> src/librustc_interface/passes.rs:724:25
    |
724 |     let mut providers = &mut Providers::EMPTY;
    |                         ^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`

error[E0764]: mutable references are not allowed in constants
   --> src/librustc_interface/passes.rs:749:21
    |
749 |     let providers = &mut DEFAULT_QUERY_PROVIDERS;
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`
eddyb

comment created time in 3 days

pull request commentrust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

@bors try @rust-timer queue

eddyb

comment created time in 3 days

pull request commentrust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

@bors rollup=never (in case this breaks some tool or fulldeps test, and for perf)

eddyb

comment created time in 3 days

PR opened rust-lang/rust

Compute `query::Providers` almost entirely at compile-time.

Background

Query "providers" are the functions which actually implement the computation of a query, when the result wasn't already cached.

To allow queries to be implemented "downstream" from the definition of the query system, and even crates using the query, their providers are kept as fn pointers in a struct Providers, which is filled at runtime:

pub struct Providers {
    pub generics_of: fn(TyCtxt<'_>, DefId) -> ty::Generics,
    pub type_of: for<'tcx> fn(TyCtxt<'tcx>, DefId) -> Ty<'tcx>,
    // ... all other queries ...
}

To further make filling the Providers struct ergonomic, and hide implementation details, fn provide functions are used, which mutate one or more fn pointer fields, in order to "provide" query implementations:

pub fn provide(providers: &mut Providers) {
    *providers = Providers {
        // These refer to `fn generics_of` and `fn type_of` in the same module, which can remain private.
        generics_of,
        type_of,
        // ... other queries implemented in the same module ...
        ..*providers
    };
}

rustc_interface ties all of this together, by calling each crate's top-level fn provide functions, to create a complete Providers, which is then immutably stored within the query system (which ends up inside/referenced by TyCtxt).

Motivation

rustc_interface's API allows custom drivers to override query providers, to customize the behavior of certain queries. E.g.: @jyn514 used this in #73566 to prevent rustdoc from doing too much work (and producing unwanted errors).

However, if executing the original provider (also called "default", although not in the sense of Providers implementing Default, but rather the result of rustc_interface combining all the fn provide together) is desired, there is no nice way to do so.

The main approach today is to use a lazy_static! / thread_local! to cache one or more providers, by running one or more fn provide, and then extracting some of the fn pointer fields, or even preserving the entire resulting Providers.

Sometimes the actual provider function is publicly exposed, but ideally it should remain hidden, to avoid accidental calls (which would bypass the query cache), or dead code remaining around even when it's no longer used through the query system.

It's also possible that there's some startup cost to constructing the Providers at runtime, but likely not enough to matter.

This PR

All fn provide are now const fn, and they're ran at compile-time to produce const DEFAULT_QUERY_PROVIDERS. (The one exception is the codegen backend, due to it potentially varying at runtime, but e.g. rustc_codegen_llvm only installs a grand total of 2 providers, so it likely does not matter much)

The effect of this is that the following snippet optimizes to returning a constant fn pointer:

pub fn default_type_of() -> for<'tcx> fn(TyCtxt<'tcx>, DefId) -> Ty<'tcx> {
    rustc_interface::DEFAULT_QUERY_PROVIDERS.type_of
}

Probably the best way to grab one of the default providers, however, is this:

const DEFAULT_TYPE_OF: for<'tcx> fn(TyCtxt<'tcx>, DefId) -> Ty<'tcx> =
    rustc_interface::DEFAULT_QUERY_PROVIDERS.type_of;

As DEFAULT_TYPE_OF is computed entirely at compile-time, any use of it will directly refer to the (private) function which implements the type_of query, even with no LLVM optimizations involved. (And you can directly use it to call that function, e.g. DEFAULT_TYPE_OF(tcx, def_id))

r? @nikomatsakis cc @nnethercote (also cc @rust-lang/wg-const-eval because of the feature(const_mut_refs) dogfooding involved)

+130 -90

0 comment

77 changed files

pr created time in 3 days

push eventeddyb/rust

Eduard-Mihai Burtescu

commit sha 77e4bef6bc791bc166021050f8e5d5b618645ea1

Compute `query::Providers` almost entirely at compile-time.

view details

push time in 3 days

issue commentrust-lang/rust

consider disallowing setting target_family if target_os=none

@alex was #74257 meant to point to this issue? It points to #72314 instead which I don't see how it's related.

ehuss

comment created time in 3 days

Pull request review commentrust-lang/rust

Add build support for Cargo's build-std feature.

 cfg_if::cfg_if! {     if #[cfg(target_os = "emscripten")] {         #[path = "emcc.rs"]         mod real_imp;-    } else if #[cfg(target_arch = "wasm32")] {-        #[path = "dummy.rs"]-        mod real_imp;     } else if #[cfg(target_os = "hermit")] {         #[path = "hermit.rs"]         mod real_imp;     } else if #[cfg(target_env = "msvc")] {         #[path = "seh.rs"]         mod real_imp;-    } else {+    } else if #[cfg(any(+        all(target_family = "windows", target_env = "gnu"),+        target_os = "cloudabi",+        target_family = "unix",

Not sure if it was related or coincidental but I just saw #74257 being open.

ehuss

comment created time in 3 days

create barncheddyb/rust

branch : const-fn-provide

created branch time in 3 days

more