diff options
Diffstat (limited to 'compiler')
254 files changed, 3385 insertions, 2527 deletions
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index a8522547666..b76e1e7ce65 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -228,7 +228,7 @@ impl<T> TypedArena<T> { // bytes, then this chunk will be least double the previous // chunk's size. new_cap = last_chunk.storage.len().min(HUGE_PAGE / elem_size / 2); - new_cap = new_cap * 2; + new_cap *= 2; } else { new_cap = PAGE / elem_size; } @@ -346,7 +346,7 @@ impl DroplessArena { // bytes, then this chunk will be least double the previous // chunk's size. new_cap = last_chunk.storage.len().min(HUGE_PAGE / 2); - new_cap = new_cap * 2; + new_cap *= 2; } else { new_cap = PAGE; } @@ -562,10 +562,8 @@ impl DropArena { // Record the destructors after doing the allocation as that may panic // and would cause `object`'s destructor to run twice if it was recorded before for i in 0..len { - destructors.push(DropType { - drop_fn: drop_for_type::<T>, - obj: start_ptr.offset(i as isize) as *mut u8, - }); + destructors + .push(DropType { drop_fn: drop_for_type::<T>, obj: start_ptr.add(i) as *mut u8 }); } slice::from_raw_parts_mut(start_ptr, len) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7d5e235c885..f13d67b9c15 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -905,6 +905,13 @@ pub struct Stmt { } impl Stmt { + pub fn has_trailing_semicolon(&self) -> bool { + match &self.kind { + StmtKind::Semi(_) => true, + StmtKind::MacCall(mac) => matches!(mac.style, MacStmtStyle::Semicolon), + _ => false, + } + } pub fn add_trailing_semicolon(mut self) -> Self { self.kind = match self.kind { StmtKind::Expr(expr) => StmtKind::Semi(expr), diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 70ad43ecad2..ec87a88f4ab 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -360,7 +360,7 @@ pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { impl MetaItem { fn token_trees_and_spacings(&self) -> Vec<TreeAndSpacing> { let mut idents = vec![]; - let mut last_pos = BytePos(0 as u32); + let mut last_pos = BytePos(0_u32); for (i, segment) in self.path.segments.iter().enumerate() { let is_first = i == 0; if !is_first { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 166d36ce424..fe9ad58c9ac 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -34,6 +34,13 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> { } pub trait MutVisitor: Sized { + /// Mutable token visiting only exists for the `macro_rules` token marker and should not be + /// used otherwise. Token visitor would be entirely separate from the regular visitor if + /// the marker didn't have to visit AST fragments in nonterminal tokens. + fn token_visiting_enabled(&self) -> bool { + false + } + // Methods in this trait have one of three forms: // // fn visit_t(&mut self, t: &mut T); // common @@ -246,22 +253,6 @@ pub trait MutVisitor: Sized { noop_flat_map_generic_param(param, self) } - fn visit_tt(&mut self, tt: &mut TokenTree) { - noop_visit_tt(tt, self); - } - - fn visit_tts(&mut self, tts: &mut TokenStream) { - noop_visit_tts(tts, self); - } - - fn visit_token(&mut self, t: &mut Token) { - noop_visit_token(t, self); - } - - fn visit_interpolated(&mut self, nt: &mut token::Nonterminal) { - noop_visit_interpolated(nt, self); - } - fn visit_param_bound(&mut self, tpb: &mut GenericBound) { noop_visit_param_bound(tpb, self); } @@ -375,11 +366,30 @@ pub fn visit_mac_args<T: MutVisitor>(args: &mut MacArgs, vis: &mut T) { MacArgs::Empty => {} MacArgs::Delimited(dspan, _delim, tokens) => { visit_delim_span(dspan, vis); - vis.visit_tts(tokens); + visit_tts(tokens, vis); } MacArgs::Eq(eq_span, tokens) => { vis.visit_span(eq_span); - vis.visit_tts(tokens); + visit_tts(tokens, vis); + // The value in `#[key = VALUE]` must be visited as an expression for backward + // compatibility, so that macros can be expanded in that position. + if !vis.token_visiting_enabled() { + if let Some(TokenTree::Token(token)) = tokens.trees_ref().next() { + if let token::Interpolated(..) = token.kind { + // ^^ Do not `make_mut` unless we have to. + match Lrc::make_mut(&mut tokens.0).get_mut(0) { + Some((TokenTree::Token(token), _spacing)) => match &mut token.kind { + token::Interpolated(nt) => match Lrc::make_mut(nt) { + token::NtExpr(expr) => vis.visit_expr(expr), + t => panic!("unexpected token in key-value attribute: {:?}", t), + }, + t => panic!("unexpected token in key-value attribute: {:?}", t), + }, + t => panic!("unexpected token in key-value attribute: {:?}", t), + } + } + } + } } } } @@ -626,28 +636,33 @@ pub fn noop_flat_map_param<T: MutVisitor>(mut param: Param, vis: &mut T) -> Smal smallvec![param] } -pub fn noop_visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) { +// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. +pub fn visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) { match tt { TokenTree::Token(token) => { - vis.visit_token(token); + visit_token(token, vis); } TokenTree::Delimited(DelimSpan { open, close }, _delim, tts) => { vis.visit_span(open); vis.visit_span(close); - vis.visit_tts(tts); + visit_tts(tts, vis); } } } -pub fn noop_visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) { - let tts = Lrc::make_mut(tts); - visit_vec(tts, |(tree, _is_joint)| vis.visit_tt(tree)); +// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. +pub fn visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) { + if vis.token_visiting_enabled() { + let tts = Lrc::make_mut(tts); + visit_vec(tts, |(tree, _is_joint)| visit_tt(tree, vis)); + } } +// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. // Applies ident visitor if it's an ident; applies other visits to interpolated nodes. // In practice the ident part is not actually used by specific visitors right now, // but there's a test below checking that it works. -pub fn noop_visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) { +pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) { let Token { kind, span } = t; match kind { token::Ident(name, _) | token::Lifetime(name) => { @@ -659,13 +674,14 @@ pub fn noop_visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) { } token::Interpolated(nt) => { let mut nt = Lrc::make_mut(nt); - vis.visit_interpolated(&mut nt); + visit_interpolated(&mut nt, vis); } _ => {} } vis.visit_span(span); } +// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. /// Applies the visitor to elements of interpolated nodes. // // N.B., this can occur only when applying a visitor to partially expanded @@ -689,7 +705,7 @@ pub fn noop_visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) { // contain multiple items, but decided against it when I looked at // `parse_item_or_view_item` and tried to figure out what I would do with // multiple items there.... -pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) { +pub fn visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) { match nt { token::NtItem(item) => visit_clobber(item, |item| { // This is probably okay, because the only visitors likely to @@ -714,7 +730,7 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: visit_mac_args(args, vis); } token::NtPath(path) => vis.visit_path(path), - token::NtTT(tt) => vis.visit_tt(tt), + token::NtTT(tt) => visit_tt(tt, vis), token::NtVis(visib) => vis.visit_vis(visib), } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index cb419b6362c..1e7001c2b23 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -22,7 +22,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; -use std::{iter, mem}; +use std::{fmt, iter, mem}; /// When the main rust parser encounters a syntax-extension invocation, it /// parses the arguments to the invocation as a token-tree. This is a very @@ -120,72 +120,52 @@ where } } -// A cloneable callback which produces a `TokenStream`. Each clone -// of this should produce the same `TokenStream` -pub trait CreateTokenStream: sync::Send + sync::Sync + FnOnce() -> TokenStream { - // Workaround for the fact that `Clone` is not object-safe - fn clone_it(&self) -> Box<dyn CreateTokenStream>; +pub trait CreateTokenStream: sync::Send + sync::Sync { + fn create_token_stream(&self) -> TokenStream; } -impl<F: 'static + Clone + sync::Send + sync::Sync + FnOnce() -> TokenStream> CreateTokenStream - for F -{ - fn clone_it(&self) -> Box<dyn CreateTokenStream> { - Box::new(self.clone()) - } -} - -impl Clone for Box<dyn CreateTokenStream> { - fn clone(&self) -> Self { - let val: &(dyn CreateTokenStream) = &**self; - val.clone_it() +impl CreateTokenStream for TokenStream { + fn create_token_stream(&self) -> TokenStream { + self.clone() } } -/// A lazy version of `TokenStream`, which may defer creation +/// A lazy version of `TokenStream`, which defers creation /// of an actual `TokenStream` until it is needed. -pub type LazyTokenStream = Lrc<LazyTokenStreamInner>; - +/// `Box` is here only to reduce the structure size. #[derive(Clone)] -pub enum LazyTokenStreamInner { - Lazy(Box<dyn CreateTokenStream>), - Ready(TokenStream), -} +pub struct LazyTokenStream(Lrc<Box<dyn CreateTokenStream>>); -impl std::fmt::Debug for LazyTokenStreamInner { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - LazyTokenStreamInner::Lazy(..) => f.debug_struct("LazyTokenStream::Lazy").finish(), - LazyTokenStreamInner::Ready(..) => f.debug_struct("LazyTokenStream::Ready").finish(), - } +impl LazyTokenStream { + pub fn new(inner: impl CreateTokenStream + 'static) -> LazyTokenStream { + LazyTokenStream(Lrc::new(Box::new(inner))) + } + + pub fn create_token_stream(&self) -> TokenStream { + self.0.create_token_stream() } } -impl LazyTokenStreamInner { - pub fn into_token_stream(&self) -> TokenStream { - match self { - // Note that we do not cache this. If this ever becomes a performance - // problem, we should investigate wrapping `LazyTokenStreamInner` - // in a lock - LazyTokenStreamInner::Lazy(cb) => (cb.clone())(), - LazyTokenStreamInner::Ready(stream) => stream.clone(), - } +impl fmt::Debug for LazyTokenStream { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt("LazyTokenStream", f) } } -impl<S: Encoder> Encodable<S> for LazyTokenStreamInner { - fn encode(&self, _s: &mut S) -> Result<(), S::Error> { - panic!("Attempted to encode LazyTokenStream"); +impl<S: Encoder> Encodable<S> for LazyTokenStream { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + // Used by AST json printing. + Encodable::encode(&self.create_token_stream(), s) } } -impl<D: Decoder> Decodable<D> for LazyTokenStreamInner { +impl<D: Decoder> Decodable<D> for LazyTokenStream { fn decode(_d: &mut D) -> Result<Self, D::Error> { panic!("Attempted to decode LazyTokenStream"); } } -impl<CTX> HashStable<CTX> for LazyTokenStreamInner { +impl<CTX> HashStable<CTX> for LazyTokenStream { fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) { panic!("Attempted to compute stable hash for LazyTokenStream"); } @@ -338,6 +318,10 @@ impl TokenStream { } } + pub fn trees_ref(&self) -> CursorRef<'_> { + CursorRef::new(self) + } + pub fn trees(&self) -> Cursor { self.clone().into_trees() } @@ -428,6 +412,36 @@ impl TokenStreamBuilder { } } +/// By-reference iterator over a `TokenStream`. +#[derive(Clone)] +pub struct CursorRef<'t> { + stream: &'t TokenStream, + index: usize, +} + +impl<'t> CursorRef<'t> { + fn new(stream: &TokenStream) -> CursorRef<'_> { + CursorRef { stream, index: 0 } + } + + fn next_with_spacing(&mut self) -> Option<&'t TreeAndSpacing> { + self.stream.0.get(self.index).map(|tree| { + self.index += 1; + tree + }) + } +} + +impl<'t> Iterator for CursorRef<'t> { + type Item = &'t TokenTree; + + fn next(&mut self) -> Option<&'t TokenTree> { + self.next_with_spacing().map(|(tree, _)| tree) + } +} + +/// Owning by-value iterator over a `TokenStream`. +/// FIXME: Many uses of this can be replaced with by-reference iterator to avoid clones. #[derive(Clone)] pub struct Cursor { pub stream: TokenStream, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 507b49616ea..2ab6667ac3c 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -14,8 +14,8 @@ //! those that are created by the expansion of a macro. use crate::ast::*; -use crate::token::Token; -use crate::tokenstream::{TokenStream, TokenTree}; +use crate::token; +use crate::tokenstream::TokenTree; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -208,14 +208,6 @@ pub trait Visitor<'ast>: Sized { fn visit_attribute(&mut self, attr: &'ast Attribute) { walk_attribute(self, attr) } - fn visit_tt(&mut self, tt: TokenTree) { - walk_tt(self, tt) - } - fn visit_tts(&mut self, tts: TokenStream) { - walk_tts(self, tts) - } - fn visit_token(&mut self, _t: Token) {} - // FIXME: add `visit_interpolated` and `walk_interpolated` fn visit_vis(&mut self, vis: &'ast Visibility) { walk_vis(self, vis) } @@ -902,20 +894,19 @@ pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) { match args { MacArgs::Empty => {} - MacArgs::Delimited(_dspan, _delim, tokens) => visitor.visit_tts(tokens.clone()), - MacArgs::Eq(_eq_span, tokens) => visitor.visit_tts(tokens.clone()), - } -} - -pub fn walk_tt<'a, V: Visitor<'a>>(visitor: &mut V, tt: TokenTree) { - match tt { - TokenTree::Token(token) => visitor.visit_token(token), - TokenTree::Delimited(_, _, tts) => visitor.visit_tts(tts), - } -} - -pub fn walk_tts<'a, V: Visitor<'a>>(visitor: &mut V, tts: TokenStream) { - for tt in tts.trees() { - visitor.visit_tt(tt); + MacArgs::Delimited(_dspan, _delim, _tokens) => {} + // The value in `#[key = VALUE]` must be visited as an expression for backward + // compatibility, so that macros can be expanded in that position. + MacArgs::Eq(_eq_span, tokens) => match tokens.trees_ref().next() { + Some(TokenTree::Token(token)) => match &token.kind { + token::Interpolated(nt) => match &**nt { + token::NtExpr(expr) => visitor.visit_expr(expr), + t => panic!("unexpected token in key-value attribute: {:?}", t), + }, + token::Literal(..) | token::Ident(..) => {} + t => panic!("unexpected token in key-value attribute: {:?}", t), + }, + t => panic!("unexpected token in key-value attribute: {:?}", t), + }, } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 269811053a0..599599f415f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -490,10 +490,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let count = generics .params .iter() - .filter(|param| match param.kind { - ast::GenericParamKind::Lifetime { .. } => true, - _ => false, - }) + .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime { .. })) .count(); self.lctx.type_def_lifetime_params.insert(def_id.to_def_id(), count); } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index cf68dfb9ae1..6afed355dc3 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -262,10 +262,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx) }; - let has_lifetimes = generic_args.args.iter().any(|arg| match arg { - GenericArg::Lifetime(_) => true, - _ => false, - }); + let has_lifetimes = + generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))); let first_generic_span = generic_args .args .iter() @@ -310,8 +308,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { E0726, "implicit elided lifetime not allowed here" ); - rustc_session::lint::add_elided_lifetime_in_path_suggestion( - &self.sess, + rustc_errors::add_elided_lifetime_in_path_suggestion( + &self.sess.source_map(), &mut err, expected_lifetimes, path_span, diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 029a6cb664d..9fcba902443 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -156,24 +156,13 @@ fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { } } match tt { - TokenTree::Token(token) => match token.kind { - token::Comma => false, - _ => true, - }, - TokenTree::Delimited(_, DelimToken::Paren, _) => match prev { - TokenTree::Token(token) => match token.kind { - token::Ident(_, _) => false, - _ => true, - }, - _ => true, - }, - TokenTree::Delimited(_, DelimToken::Bracket, _) => match prev { - TokenTree::Token(token) => match token.kind { - token::Pound => false, - _ => true, - }, - _ => true, - }, + TokenTree::Token(token) => token.kind != token::Comma, + TokenTree::Delimited(_, DelimToken::Paren, _) => { + !matches!(prev, TokenTree::Token(Token { kind: token::Ident(..), .. })) + } + TokenTree::Delimited(_, DelimToken::Bracket, _) => { + !matches!(prev, TokenTree::Token(Token { kind: token::Pound, .. })) + } TokenTree::Delimited(..) => true, } } @@ -650,13 +639,11 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere fn break_offset_if_not_bol(&mut self, n: usize, off: isize) { if !self.is_beginning_of_line() { self.break_offset(n, off) - } else { - if off != 0 && self.last_token().is_hardbreak_tok() { - // We do something pretty sketchy here: tuck the nonzero - // offset-adjustment we were going to deposit along with the - // break into the previous hardbreak. - self.replace_last_token(pp::Printer::hardbreak_tok_offset(off)); - } + } else if off != 0 && self.last_token().is_hardbreak_tok() { + // We do something pretty sketchy here: tuck the nonzero + // offset-adjustment we were going to deposit along with the + // break into the previous hardbreak. + self.replace_last_token(pp::Printer::hardbreak_tok_offset(off)); } } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 218a9b229e0..2fd625c2a6c 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -637,19 +637,15 @@ pub struct Deprecation { } /// Finds the deprecation attribute. `None` if none exists. -pub fn find_deprecation(sess: &Session, attrs: &[Attribute], item_sp: Span) -> Option<Deprecation> { - find_deprecation_generic(sess, attrs.iter(), item_sp) +pub fn find_deprecation(sess: &Session, attrs: &[Attribute]) -> Option<(Deprecation, Span)> { + find_deprecation_generic(sess, attrs.iter()) } -fn find_deprecation_generic<'a, I>( - sess: &Session, - attrs_iter: I, - item_sp: Span, -) -> Option<Deprecation> +fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(Deprecation, Span)> where I: Iterator<Item = &'a Attribute>, { - let mut depr: Option<Deprecation> = None; + let mut depr: Option<(Deprecation, Span)> = None; let diagnostic = &sess.parse_sess.span_diagnostic; 'outer: for attr in attrs_iter { @@ -658,8 +654,11 @@ where continue; } - if depr.is_some() { - struct_span_err!(diagnostic, item_sp, E0550, "multiple deprecated attributes").emit(); + if let Some((_, span)) = &depr { + struct_span_err!(diagnostic, attr.span, E0550, "multiple deprecated attributes") + .span_label(attr.span, "repeated deprecation attribute") + .span_label(*span, "first deprecation attribute") + .emit(); break; } @@ -780,7 +779,7 @@ where sess.mark_attr_used(&attr); let is_since_rustc_version = sess.check_name(attr, sym::rustc_deprecated); - depr = Some(Deprecation { since, note, suggestion, is_since_rustc_version }); + depr = Some((Deprecation { since, note, suggestion, is_since_rustc_version }, attr.span)); } depr @@ -901,38 +900,36 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { ) .emit(); } - } else { - if let Some(meta_item) = item.meta_item() { - if meta_item.has_name(sym::align) { - if let MetaItemKind::NameValue(ref value) = meta_item.kind { - recognised = true; - let mut err = struct_span_err!( - diagnostic, - item.span(), - E0693, - "incorrect `repr(align)` attribute format" - ); - match value.kind { - ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { - err.span_suggestion( - item.span(), - "use parentheses instead", - format!("align({})", int), - Applicability::MachineApplicable, - ); - } - ast::LitKind::Str(s, _) => { - err.span_suggestion( - item.span(), - "use parentheses instead", - format!("align({})", s), - Applicability::MachineApplicable, - ); - } - _ => {} + } else if let Some(meta_item) = item.meta_item() { + if meta_item.has_name(sym::align) { + if let MetaItemKind::NameValue(ref value) = meta_item.kind { + recognised = true; + let mut err = struct_span_err!( + diagnostic, + item.span(), + E0693, + "incorrect `repr(align)` attribute format" + ); + match value.kind { + ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { + err.span_suggestion( + item.span(), + "use parentheses instead", + format!("align({})", int), + Applicability::MachineApplicable, + ); + } + ast::LitKind::Str(s, _) => { + err.span_suggestion( + item.span(), + "use parentheses instead", + format!("align({})", s), + Applicability::MachineApplicable, + ); } - err.emit(); + _ => {} } + err.emit(); } } } diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/bootstrap_rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/bootstrap_rustc.yml new file mode 100644 index 00000000000..8c94a0aa5e6 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/.github/workflows/bootstrap_rustc.yml @@ -0,0 +1,44 @@ +name: Bootstrap rustc using cg_clif + +on: + - push + +jobs: + bootstrap_rustc: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Cache cargo installed crates + uses: actions/cache@v2 + with: + path: ~/.cargo/bin + key: ${{ runner.os }}-cargo-installed-crates + + - name: Cache cargo registry and index + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo target dir + uses: actions/cache@v2 + with: + path: target + key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + + - name: Prepare dependencies + run: | + git config --global user.email "user@example.com" + git config --global user.name "User" + ./prepare.sh + + - name: Test + run: | + # Enable backtraces for easier debugging + export RUST_BACKTRACE=1 + + ./scripts/test_bootstrap.sh diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 841e1a0870e..e6d3375fb1b 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -51,4 +51,13 @@ jobs: export COMPILE_RUNS=2 export RUN_RUNS=2 - ./test.sh --release + ./test.sh + + - name: Package prebuilt cg_clif + run: tar cvfJ cg_clif.tar.xz build + + - name: Upload prebuilt cg_clif + uses: actions/upload-artifact@v2 + with: + name: cg_clif-${{ runner.os }} + path: cg_clif.tar.xz diff --git a/compiler/rustc_codegen_cranelift/.gitignore b/compiler/rustc_codegen_cranelift/.gitignore index 0da9927b479..18196bce009 100644 --- a/compiler/rustc_codegen_cranelift/.gitignore +++ b/compiler/rustc_codegen_cranelift/.gitignore @@ -6,7 +6,7 @@ perf.data perf.data.old *.events *.string* -/build_sysroot/sysroot +/build /build_sysroot/sysroot_src /rust /rand diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 6cfbed0a5e4..2889fac77f6 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -44,7 +44,7 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cranelift-bforest" version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4fd90dccabb266e983740e1f5daf8bde9266b286" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" dependencies = [ "cranelift-entity", ] @@ -52,7 +52,7 @@ dependencies = [ [[package]] name = "cranelift-codegen" version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4fd90dccabb266e983740e1f5daf8bde9266b286" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" dependencies = [ "byteorder", "cranelift-bforest", @@ -70,7 +70,7 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4fd90dccabb266e983740e1f5daf8bde9266b286" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -79,17 +79,17 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4fd90dccabb266e983740e1f5daf8bde9266b286" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" [[package]] name = "cranelift-entity" version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4fd90dccabb266e983740e1f5daf8bde9266b286" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" [[package]] name = "cranelift-frontend" version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4fd90dccabb266e983740e1f5daf8bde9266b286" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" dependencies = [ "cranelift-codegen", "log", @@ -100,7 +100,7 @@ dependencies = [ [[package]] name = "cranelift-module" version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4fd90dccabb266e983740e1f5daf8bde9266b286" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" dependencies = [ "anyhow", "cranelift-codegen", @@ -112,7 +112,7 @@ dependencies = [ [[package]] name = "cranelift-native" version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4fd90dccabb266e983740e1f5daf8bde9266b286" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" dependencies = [ "cranelift-codegen", "raw-cpuid", @@ -122,7 +122,7 @@ dependencies = [ [[package]] name = "cranelift-object" version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4fd90dccabb266e983740e1f5daf8bde9266b286" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" dependencies = [ "anyhow", "cranelift-codegen", @@ -135,7 +135,7 @@ dependencies = [ [[package]] name = "cranelift-simplejit" version = "0.67.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#4fd90dccabb266e983740e1f5daf8bde9266b286" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#44cbdecea03c360ea82e6482f0cf6c614effef21" dependencies = [ "cranelift-codegen", "cranelift-entity", diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index 680ff877656..f8a5e13ed54 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -2,41 +2,56 @@ > ⚠⚠⚠Certain kinds of FFI don't work yet. ⚠⚠⚠-The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/master/cranelift). This has the potential to improve compilation times in debug mode. If your project doesn't use any of the things listed under "Not yet supported", it should work fine. If not please open an issue. +The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/master/cranelift). +This has the potential to improve compilation times in debug mode. +If your project doesn't use any of the things listed under "Not yet supported", it should work fine. +If not please open an issue. -## Building +## Building and testing ```bash $ git clone https://github.com/bjorn3/rustc_codegen_cranelift.git $ cd rustc_codegen_cranelift $ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking -$ ./test.sh --release +$ ./build.sh ``` +To run the test suite replace the last command with: + +```bash +$ ./test.sh +``` + +This will implicitly build cg_clif too. Both `build.sh` and `test.sh` accept a `--debug` argument to +build in debug mode. + +Alternatively you can download a pre built version from [GHA]. It is listed in the artifacts section +of workflow runs. Unfortunately due to GHA restrictions you need to be logged in to access it. + +[GHA]: https://github.com/bjorn3/rustc_codegen_cranelift/actions?query=branch%3Amaster+event%3Apush+is%3Asuccess + ## Usage rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects. -Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`prepare.sh` and `test.sh`). +Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`prepare.sh` and `build.sh` or `test.sh`). ### Cargo In the directory with your project (where you can do the usual `cargo build`), run: ```bash -$ $cg_clif_dir/cargo.sh run +$ $cg_clif_dir/build/cargo.sh run ``` This should build and run your project with rustc_codegen_cranelift instead of the usual LLVM backend. -If you compiled cg_clif in debug mode (aka you didn't pass `--release` to `./test.sh`) you should set `CHANNEL="debug"`. - ### Rustc > You should prefer using the Cargo method. ```bash -$ $cg_clif_dir/target/release/cg_clif my_crate.rs +$ $cg_clif_dir/build/cg_clif my_crate.rs ``` ### Jit mode @@ -47,13 +62,13 @@ In jit mode cg_clif will immediately execute your code without creating an execu > The jit mode will probably need cargo integration to make this possible. ```bash -$ $cg_clif_dir/cargo.sh jit +$ $cg_clif_dir/build/cargo.sh jit ``` or ```bash -$ $cg_clif_dir/target/release/cg_clif --jit my_crate.rs +$ $cg_clif_dir/build/cg_clif --jit my_crate.rs ``` ### Shell @@ -62,7 +77,7 @@ These are a few functions that allow you to easily run rust code from the shell ```bash function jit_naked() { - echo "$@" | $cg_clif_dir/target/release/cg_clif - --jit + echo "$@" | $cg_clif_dir/build/cg_clif - --jit } function jit() { diff --git a/compiler/rustc_codegen_cranelift/build.sh b/compiler/rustc_codegen_cranelift/build.sh new file mode 100755 index 00000000000..f9a87e68a04 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/build.sh @@ -0,0 +1,47 @@ +#!/bin/bash +set -e + +# Settings +export CHANNEL="release" +build_sysroot=1 +target_dir='build' +while [[ $# != 0 ]]; do + case $1 in + "--debug") + export CHANNEL="debug" + ;; + "--without-sysroot") + build_sysroot=0 + ;; + "--target-dir") + target_dir=$2 + shift + ;; + *) + echo "Unknown flag '$1'" + echo "Usage: ./build.sh [--debug] [--without-sysroot] [--target-dir DIR]" + ;; + esac + shift +done + +# Build cg_clif +export RUSTFLAGS="-Zrun_dsymutil=no" +if [[ "$CHANNEL" == "release" ]]; then + cargo build --release +else + cargo build +fi + +rm -rf $target_dir +mkdir $target_dir +cp -a target/$CHANNEL/cg_clif{,_build_sysroot} target/$CHANNEL/*rustc_codegen_cranelift* $target_dir/ +cp -a rust-toolchain scripts/config.sh scripts/cargo.sh $target_dir + +if [[ "$build_sysroot" == "1" ]]; then + echo "[BUILD] sysroot" + export CG_CLIF_INCR_CACHE_DISABLED=1 + dir=$(pwd) + cd $target_dir + time $dir/build_sysroot/build_sysroot.sh +fi diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh b/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh index 04c82ca2a51..eba15c0dd43 100755 --- a/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh +++ b/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh @@ -3,25 +3,28 @@ # Requires the CHANNEL env var to be set to `debug` or `release.` set -e -cd $(dirname "$0") -pushd ../ >/dev/null -source ./scripts/config.sh -popd >/dev/null +source ./config.sh -# Cleanup for previous run -# v Clean target dir except for build scripts and incremental cache -rm -r target/*/{debug,release}/{build,deps,examples,libsysroot*,native} 2>/dev/null || true -rm -r sysroot/ 2>/dev/null || true +dir=$(pwd) # Use rustc with cg_clif as hotpluggable backend instead of the custom cg_clif driver so that # build scripts are still compiled using cg_llvm. -export RUSTC=$(pwd)/../"target/"$CHANNEL"/cg_clif_build_sysroot" +export RUSTC=$dir"/cg_clif_build_sysroot" export RUSTFLAGS=$RUSTFLAGS" --clif" +cd $(dirname "$0") + +# Cleanup for previous run +# v Clean target dir except for build scripts and incremental cache +rm -r target/*/{debug,release}/{build,deps,examples,libsysroot*,native} 2>/dev/null || true + +# We expect the target dir in the default location. Guard against the user changing it. +export CARGO_TARGET_DIR=target + # Build libs export RUSTFLAGS="$RUSTFLAGS -Zforce-unstable-if-unmarked -Cpanic=abort" -if [[ "$1" == "--release" ]]; then +if [[ "$1" != "--debug" ]]; then sysroot_channel='release' # FIXME Enable incremental again once rust-lang/rust#74946 is fixed # FIXME Enable -Zmir-opt-level=2 again once it doesn't ice anymore @@ -32,5 +35,5 @@ else fi # Copy files to sysroot -mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ -cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ +mkdir -p $dir/sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ +cp -a target/$TARGET_TRIPLE/$sysroot_channel/deps/* $dir/sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh index 14aa77478f5..d0fb09ce745 100755 --- a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh +++ b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh @@ -12,7 +12,7 @@ fi rm -rf $DST_DIR mkdir -p $DST_DIR/library -cp -r $SRC_DIR/library $DST_DIR/ +cp -a $SRC_DIR/library $DST_DIR/ pushd $DST_DIR echo "[GIT] init" diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh index 3003a0ea2d1..5a69c862d01 100755 --- a/compiler/rustc_codegen_cranelift/clean_all.sh +++ b/compiler/rustc_codegen_cranelift/clean_all.sh @@ -1,5 +1,5 @@ #!/bin/bash --verbose set -e -rm -rf target/ build_sysroot/{sysroot/,sysroot_src/,target/} perf.data{,.old} +rm -rf target/ build/ build_sysroot/{sysroot_src/,target/} perf.data{,.old} rm -rf rand/ regex/ simple-raytracer/ diff --git a/compiler/rustc_codegen_cranelift/docs/env_vars.md b/compiler/rustc_codegen_cranelift/docs/env_vars.md index 07b75622a58..f0a0a6ad42e 100644 --- a/compiler/rustc_codegen_cranelift/docs/env_vars.md +++ b/compiler/rustc_codegen_cranelift/docs/env_vars.md @@ -9,7 +9,4 @@ object files when their content should have been changed by a change to cg_clif.</dd> <dt>CG_CLIF_DISPLAY_CG_TIME</dt> <dd>If "1", display the time it took to perform codegen for a crate</dd> - <dt>CG_CLIF_FUNCTION_SECTIONS</dt> - <dd>Use a single section for each function. This will often reduce the executable size at the - cost of making linking significantly slower.</dd> </dl> diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index a972beedaa3..ce07fe83df1 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -48,6 +48,7 @@ unsafe impl Copy for u8 {} unsafe impl Copy for u16 {} unsafe impl Copy for u32 {} unsafe impl Copy for u64 {} +unsafe impl Copy for u128 {} unsafe impl Copy for usize {} unsafe impl Copy for i8 {} unsafe impl Copy for i16 {} @@ -283,6 +284,15 @@ impl PartialEq for u64 { } } +impl PartialEq for u128 { + fn eq(&self, other: &u128) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u128) -> bool { + (*self) != (*other) + } +} + impl PartialEq for usize { fn eq(&self, other: &usize) -> bool { (*self) == (*other) diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 376056e1938..4a8375afac3 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -287,6 +287,8 @@ fn main() { assert_eq!(repeat[0], Some(42)); assert_eq!(repeat[1], Some(42)); + from_decimal_string(); + #[cfg(not(jit))] test_tls(); @@ -446,3 +448,23 @@ fn check_niche_behavior () { intrinsics::abort(); } } + +fn from_decimal_string() { + loop { + let multiplier = 1; + + take_multiplier_ref(&multiplier); + + if multiplier == 1 { + break; + } + + unreachable(); + } +} + +fn take_multiplier_ref(_multiplier: &u128) {} + +fn unreachable() -> ! { + panic("unreachable") +} diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 079b4299049..cb512a4aa33 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -315,13 +315,13 @@ fn test_checked_mul() { assert_eq!(1i8.checked_mul(-128i8), Some(-128i8)); assert_eq!((-128i8).checked_mul(-128i8), None); - assert_eq!(1u64.checked_mul(u64::max_value()), Some(u64::max_value())); - assert_eq!(u64::max_value().checked_mul(u64::max_value()), None); - assert_eq!(1i64.checked_mul(i64::max_value()), Some(i64::max_value())); - assert_eq!(i64::max_value().checked_mul(i64::max_value()), None); - assert_eq!((-1i64).checked_mul(i64::min_value() + 1), Some(i64::max_value())); - assert_eq!(1i64.checked_mul(i64::min_value()), Some(i64::min_value())); - assert_eq!(i64::min_value().checked_mul(i64::min_value()), None); + assert_eq!(1u64.checked_mul(u64::MAX), Some(u64::MAX)); + assert_eq!(u64::MAX.checked_mul(u64::MAX), None); + assert_eq!(1i64.checked_mul(i64::MAX), Some(i64::MAX)); + assert_eq!(i64::MAX.checked_mul(i64::MAX), None); + assert_eq!((-1i64).checked_mul(i64::MIN + 1), Some(i64::MAX)); + assert_eq!(1i64.checked_mul(i64::MIN), Some(i64::MIN)); + assert_eq!(i64::MIN.checked_mul(i64::MIN), None); } #[derive(PartialEq)] diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 87e54719fdc..0ca96be9ae7 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1 +1 @@ -nightly-2020-10-26 +nightly-2020-10-31 diff --git a/compiler/rustc_codegen_cranelift/cargo.sh b/compiler/rustc_codegen_cranelift/scripts/cargo.sh index cebc3e67363..e63daa40f35 100755 --- a/compiler/rustc_codegen_cranelift/cargo.sh +++ b/compiler/rustc_codegen_cranelift/scripts/cargo.sh @@ -1,19 +1,13 @@ #!/bin/bash -if [ -z $CHANNEL ]; then -export CHANNEL='release' -fi - -pushd $(dirname "$0") >/dev/null -source scripts/config.sh +dir=$(dirname "$0") +source $dir/config.sh # read nightly compiler from rust-toolchain file -TOOLCHAIN=$(cat rust-toolchain) - -popd >/dev/null +TOOLCHAIN=$(cat $dir/rust-toolchain) cmd=$1 -shift +shift || true if [[ "$cmd" = "jit" ]]; then cargo +${TOOLCHAIN} rustc $@ -- --jit diff --git a/compiler/rustc_codegen_cranelift/scripts/config.sh b/compiler/rustc_codegen_cranelift/scripts/config.sh index 530b7f242a0..af181f4f724 100644 --- a/compiler/rustc_codegen_cranelift/scripts/config.sh +++ b/compiler/rustc_codegen_cranelift/scripts/config.sh @@ -39,18 +39,19 @@ echo export RUSTC_WRAPPER= fi -export RUSTC=$(pwd)/"target/"$CHANNEL"/cg_clif" +dir=$(cd $(dirname "$BASH_SOURCE"); pwd) + +export RUSTC=$dir"/cg_clif" export RUSTFLAGS=$linker export RUSTDOCFLAGS=$linker' -Ztrim-diagnostic-paths=no -Cpanic=abort -Zpanic-abort-tests '\ -'-Zcodegen-backend='$(pwd)'/target/'$CHANNEL'/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$(pwd)'/build_sysroot/sysroot' +'-Zcodegen-backend='$dir'/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$dir'/sysroot' # FIXME remove once the atomic shim is gone if [[ `uname` == 'Darwin' ]]; then export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup" fi -export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/"$TARGET_TRIPLE"/lib:\ -$(pwd)/target/"$CHANNEL":$(rustc --print sysroot)/lib" +export LD_LIBRARY_PATH="$dir:$(rustc --print sysroot)/lib:$dir/target/out:$dir/sysroot/lib/rustlib/"$TARGET_TRIPLE"/lib" export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH export CG_CLIF_DISPLAY_CG_TIME=1 diff --git a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs index c70c3ec47f3..3327c10089d 100755 --- a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs +++ b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs @@ -1,9 +1,8 @@ #!/bin/bash #![forbid(unsafe_code)]/* This line is ignored by bash # This block is ignored by rustc -CHANNEL="release" pushd $(dirname "$0")/../ -source scripts/config.sh +source build/config.sh popd PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS --jit $0 #*/ diff --git a/compiler/rustc_codegen_cranelift/scripts/rustup.sh b/compiler/rustc_codegen_cranelift/scripts/rustup.sh index 38991d6d47d..541b3c6563b 100755 --- a/compiler/rustc_codegen_cranelift/scripts/rustup.sh +++ b/compiler/rustc_codegen_cranelift/scripts/rustup.sh @@ -26,6 +26,15 @@ case $1 in git add rust-toolchain build_sysroot/Cargo.lock git commit -m "Rustup to $(rustc -V)" ;; + "push") + cg_clif=$(pwd) + pushd ../rust + branch=update_cg_clif-$(date +%Y-%m-%d) + git checkout -b $branch + git subtree pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/bjorn3/rustc_codegen_cranelift.git master + git push -u my $branch + popd + ;; *) echo "Unknown command '$1'" echo "Usage: ./rustup.sh prepare|commit" diff --git a/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh b/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh new file mode 100755 index 00000000000..7f43f81a6cd --- /dev/null +++ b/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh @@ -0,0 +1,65 @@ +#!/bin/bash +set -e + +cd $(dirname "$0")/../ + +./build.sh +source build/config.sh + +echo "[TEST] Bootstrap of rustc" +git clone https://github.com/rust-lang/rust.git || true +pushd rust +git fetch +git checkout -- . +git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') + +git apply - <<EOF +diff --git a/.gitmodules b/.gitmodules +index 984113151de..c1e9d960d56 100644 +--- a/.gitmodules ++++ b/.gitmodules +@@ -34,10 +34,6 @@ + [submodule "src/doc/edition-guide"] + path = src/doc/edition-guide + url = https://github.com/rust-lang/edition-guide.git +-[submodule "src/llvm-project"] +- path = src/llvm-project +- url = https://github.com/rust-lang/llvm-project.git +- branch = rustc/11.0-2020-10-12 + [submodule "src/doc/embedded-book"] + path = src/doc/embedded-book + url = https://github.com/rust-embedded/book.git +diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml +index 23e689fcae7..5f077b765b6 100644 +--- a/compiler/rustc_data_structures/Cargo.toml ++++ b/compiler/rustc_data_structures/Cargo.toml +@@ -32,7 +32,6 @@ tempfile = "3.0.5" + + [dependencies.parking_lot] + version = "0.11" +-features = ["nightly"] + + [target.'cfg(windows)'.dependencies] + winapi = { version = "0.3", features = ["fileapi", "psapi"] } +EOF + +cat > config.toml <<EOF +[llvm] +ninja = false + +[build] +rustc = "$(pwd)/../build/cg_clif" +cargo = "$(rustup which cargo)" +full-bootstrap = true +local-rebuild = true + +[rust] +codegen-backends = ["cranelift"] +EOF + +rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src} +cp ../Cargo.* compiler/rustc_codegen_cranelift/ +cp -r ../src compiler/rustc_codegen_cranelift/src + +./x.py build --stage 1 library/std +popd diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh new file mode 100755 index 00000000000..d941b73c81b --- /dev/null +++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh @@ -0,0 +1,123 @@ +#!/bin/bash + +set -e + +source build/config.sh +export CG_CLIF_INCR_CACHE_DISABLED=1 +MY_RUSTC=$RUSTC" "$RUSTFLAGS" -L crate=target/out --out-dir target/out -Cdebuginfo=2" + +function no_sysroot_tests() { + echo "[BUILD] mini_core" + $MY_RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib --target $TARGET_TRIPLE + + echo "[BUILD] example" + $MY_RUSTC example/example.rs --crate-type lib --target $TARGET_TRIPLE + + if [[ "$JIT_SUPPORTED" = "1" ]]; then + echo "[JIT] mini_core_hello_world" + CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC --jit example/mini_core_hello_world.rs --cfg jit --target $HOST_TRIPLE + else + echo "[JIT] mini_core_hello_world (skipped)" + fi + + echo "[AOT] mini_core_hello_world" + $MY_RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/mini_core_hello_world abc bcd + # (echo "break set -n main"; echo "run"; sleep 1; echo "si -c 10"; sleep 1; echo "frame variable") | lldb -- ./target/out/mini_core_hello_world abc bcd + + echo "[AOT] arbitrary_self_types_pointers_and_wrappers" + $MY_RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/arbitrary_self_types_pointers_and_wrappers +} + +function base_sysroot_tests() { + echo "[AOT] alloc_example" + $MY_RUSTC example/alloc_example.rs --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/alloc_example + + if [[ "$JIT_SUPPORTED" = "1" ]]; then + echo "[JIT] std_example" + $MY_RUSTC --jit example/std_example.rs --target $HOST_TRIPLE + else + echo "[JIT] std_example (skipped)" + fi + + echo "[AOT] dst_field_align" + # FIXME Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed. + $MY_RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false) + + echo "[AOT] std_example" + $MY_RUSTC example/std_example.rs --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/std_example arg + + echo "[AOT] subslice-patterns-const-eval" + $MY_RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/subslice-patterns-const-eval + + echo "[AOT] track-caller-attribute" + $MY_RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/track-caller-attribute + + echo "[AOT] mod_bench" + $MY_RUSTC example/mod_bench.rs --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/mod_bench + + pushd rand + rm -r ./target || true + ../build/cargo.sh test --workspace + popd +} + +function extended_sysroot_tests() { + pushd simple-raytracer + if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then + echo "[BENCH COMPILE] ebobby/simple-raytracer" + hyperfine --runs ${RUN_RUNS:-10} --warmup 1 --prepare "cargo clean" \ + "RUSTC=rustc RUSTFLAGS='' cargo build" \ + "../build/cargo.sh build" + + echo "[BENCH RUN] ebobby/simple-raytracer" + cp ./target/debug/main ./raytracer_cg_clif + hyperfine --runs ${RUN_RUNS:-10} ./raytracer_cg_llvm ./raytracer_cg_clif + else + echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)" + echo "[COMPILE] ebobby/simple-raytracer" + ../cargo.sh build + echo "[BENCH RUN] ebobby/simple-raytracer (skipped)" + fi + popd + + pushd build_sysroot/sysroot_src/library/core/tests + echo "[TEST] libcore" + rm -r ./target || true + ../../../../../build/cargo.sh test + popd + + pushd regex + echo "[TEST] rust-lang/regex example shootout-regex-dna" + ../build/cargo.sh clean + # Make sure `[codegen mono items] start` doesn't poison the diff + ../build/cargo.sh build --example shootout-regex-dna + cat examples/regexdna-input.txt | ../build/cargo.sh run --example shootout-regex-dna | grep -v "Spawned thread" > res.txt + diff -u res.txt examples/regexdna-output.txt + + echo "[TEST] rust-lang/regex tests" + ../build/cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q + popd +} + +case "$1" in + "no_sysroot") + no_sysroot_tests + ;; + "base_sysroot") + base_sysroot_tests + ;; + "extended_sysroot") + extended_sysroot_tests + ;; + *) + echo "unknown test suite" + ;; +esac diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index 7bb00c8d46a..01073d26e83 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -11,9 +11,9 @@ use crate::abi::pass_mode::*; use crate::prelude::*; pub(super) fn add_args_header_comment(fx: &mut FunctionCx<'_, '_, impl Module>) { - fx.add_global_comment(format!( - "kind loc.idx param pass mode ty" - )); + fx.add_global_comment( + "kind loc.idx param pass mode ty".to_string(), + ); } pub(super) fn add_arg_comment<'tcx>( @@ -56,9 +56,9 @@ pub(super) fn add_arg_comment<'tcx>( pub(super) fn add_locals_header_comment(fx: &mut FunctionCx<'_, '_, impl Module>) { fx.add_global_comment(String::new()); - fx.add_global_comment(format!( - "kind local ty size align (abi,pref)" - )); + fx.add_global_comment( + "kind local ty size align (abi,pref)".to_string(), + ); } pub(super) fn add_local_place_comments<'tcx>( diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 80169122843..81091728692 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -300,7 +300,7 @@ impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> { return_ty: Ty<'tcx>, ) -> CValue<'tcx> { let (input_tys, args): (Vec<_>, Vec<_>) = args - .into_iter() + .iter() .map(|arg| { ( self.clif_type(arg.layout().ty).unwrap(), @@ -421,34 +421,31 @@ pub(crate) fn codegen_fn_prelude<'tcx>( // While this is normally an optimization to prevent an unnecessary copy when an argument is // not mutated by the current function, this is necessary to support unsized arguments. - match arg_kind { - ArgKind::Normal(Some(val)) => { - if let Some((addr, meta)) = val.try_to_ptr() { - let local_decl = &fx.mir.local_decls[local]; - // v this ! is important - let internally_mutable = !val.layout().ty.is_freeze( - fx.tcx.at(local_decl.source_info.span), - ParamEnv::reveal_all(), - ); - if local_decl.mutability == mir::Mutability::Not && !internally_mutable { - // We wont mutate this argument, so it is fine to borrow the backing storage - // of this argument, to prevent a copy. - - let place = if let Some(meta) = meta { - CPlace::for_ptr_with_extra(addr, meta, val.layout()) - } else { - CPlace::for_ptr(addr, val.layout()) - }; - - #[cfg(debug_assertions)] - self::comments::add_local_place_comments(fx, place, local); - - assert_eq!(fx.local_map.push(place), local); - continue; - } + if let ArgKind::Normal(Some(val)) = arg_kind { + if let Some((addr, meta)) = val.try_to_ptr() { + let local_decl = &fx.mir.local_decls[local]; + // v this ! is important + let internally_mutable = !val.layout().ty.is_freeze( + fx.tcx.at(local_decl.source_info.span), + ParamEnv::reveal_all(), + ); + if local_decl.mutability == mir::Mutability::Not && !internally_mutable { + // We wont mutate this argument, so it is fine to borrow the backing storage + // of this argument, to prevent a copy. + + let place = if let Some(meta) = meta { + CPlace::for_ptr_with_extra(addr, meta, val.layout()) + } else { + CPlace::for_ptr(addr, val.layout()) + }; + + #[cfg(debug_assertions)] + self::comments::add_local_place_comments(fx, place, local); + + assert_eq!(fx.local_map.push(place), local); + continue; } } - _ => {} } let place = make_local_place(fx, local, layout, is_ssa); @@ -500,7 +497,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( .tcx .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &fn_ty.fn_sig(fx.tcx)); - let destination = destination.map(|(place, bb)| (trans_place(fx, place), bb)); + let destination = destination.map(|(place, bb)| (codegen_place(fx, place), bb)); // Handle special calls like instrinsics and empty drop glue. let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() { @@ -553,8 +550,8 @@ pub(crate) fn codegen_terminator_call<'tcx>( // Unpack arguments tuple for closures let args = if fn_sig.abi == Abi::RustCall { assert_eq!(args.len(), 2, "rust-call abi requires two arguments"); - let self_arg = trans_operand(fx, &args[0]); - let pack_arg = trans_operand(fx, &args[1]); + let self_arg = codegen_operand(fx, &args[0]); + let pack_arg = codegen_operand(fx, &args[1]); let tupled_arguments = match pack_arg.layout().ty.kind() { ty::Tuple(ref tupled_arguments) => tupled_arguments, @@ -568,8 +565,8 @@ pub(crate) fn codegen_terminator_call<'tcx>( } args } else { - args.into_iter() - .map(|arg| trans_operand(fx, arg)) + args.iter() + .map(|arg| codegen_operand(fx, arg)) .collect::<Vec<_>>() }; @@ -613,7 +610,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( let nop_inst = fx.bcx.ins().nop(); fx.add_comment(nop_inst, "indirect call"); } - let func = trans_operand(fx, func).load_scalar(fx); + let func = codegen_operand(fx, func).load_scalar(fx); ( Some(func), args.get(0) diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index 0735ad6f832..6c5916550ff 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -123,7 +123,7 @@ fn codegen_inner( .unwrap(); let mut ctx = Context::new(); - ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig.clone()); + ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig); { let mut func_ctx = FunctionBuilderContext::new(); let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); @@ -131,7 +131,7 @@ fn codegen_inner( let block = bcx.create_block(); bcx.switch_to_block(block); let args = (&[usize_ty, usize_ty]) - .into_iter() + .iter() .map(|&ty| bcx.append_block_param(block, ty)) .collect::<Vec<Value>>(); diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index 6382f8df344..9a970efbcfd 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -132,7 +132,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { } // ok, don't skip this - return false; + false }) } diff --git a/compiler/rustc_codegen_cranelift/src/atomic_shim.rs b/compiler/rustc_codegen_cranelift/src/atomic_shim.rs index 92281fdacc9..2f0157c257b 100644 --- a/compiler/rustc_codegen_cranelift/src/atomic_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/atomic_shim.rs @@ -7,7 +7,7 @@ use crate::prelude::*; #[cfg(all(feature = "jit", unix))] #[no_mangle] -pub static mut __cg_clif_global_atomic_mutex: libc::pthread_mutex_t = +static mut __cg_clif_global_atomic_mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; pub(crate) fn init_global_lock( diff --git a/compiler/rustc_codegen_cranelift/src/backend.rs b/compiler/rustc_codegen_cranelift/src/backend.rs index 8b900fd0dd0..9e32259716f 100644 --- a/compiler/rustc_codegen_cranelift/src/backend.rs +++ b/compiler/rustc_codegen_cranelift/src/backend.rs @@ -73,7 +73,7 @@ impl WriteDebugInfo for ObjectProduct { // FIXME use SHT_X86_64_UNWIND for .eh_frame let section_id = self.object.add_section( segment, - name.clone(), + name, if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { @@ -198,9 +198,9 @@ pub(crate) fn make_module(sess: &Session, name: String) -> ObjectModule { cranelift_module::default_libcall_names(), ) .unwrap(); - if std::env::var("CG_CLIF_FUNCTION_SECTIONS").is_ok() { - builder.per_function_section(true); - } - let module = ObjectModule::new(builder); - module + // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size + // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections + // can easily double the amount of time necessary to perform linking. + builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false)); + ObjectModule::new(builder) } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index fa9b8853d39..bfe5514b6d3 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::adjustment::PointerCast; use crate::prelude::*; -pub(crate) fn trans_fn<'tcx>( +pub(crate) fn codegen_fn<'tcx>( cx: &mut crate::CodegenCx<'tcx, impl Module>, instance: Instance<'tcx>, linkage: Linkage, @@ -202,7 +202,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) { fx.bcx.ins().nop(); for stmt in &bb_data.statements { fx.set_debug_loc(stmt.source_info); - trans_stmt(fx, block, stmt); + codegen_stmt(fx, block, stmt); } #[cfg(debug_assertions)] @@ -258,7 +258,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) { continue; } } - let cond = trans_operand(fx, cond).load_scalar(fx); + let cond = codegen_operand(fx, cond).load_scalar(fx); let target = fx.get_block(*target); let failure = fx.bcx.create_block(); @@ -276,8 +276,8 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) { match msg { AssertKind::BoundsCheck { ref len, ref index } => { - let len = trans_operand(fx, len).load_scalar(fx); - let index = trans_operand(fx, index).load_scalar(fx); + let len = codegen_operand(fx, len).load_scalar(fx); + let index = codegen_operand(fx, index).load_scalar(fx); let location = fx .get_caller_location(bb_data.terminator().source_info.span) .load_scalar(fx); @@ -301,7 +301,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) { switch_ty, targets, } => { - let discr = trans_operand(fx, discr).load_scalar(fx); + let discr = codegen_operand(fx, discr).load_scalar(fx); if switch_ty.kind() == fx.tcx.types.bool.kind() { assert_eq!(targets.iter().count(), 1); @@ -396,14 +396,14 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) { | TerminatorKind::FalseUnwind { .. } | TerminatorKind::DropAndReplace { .. } | TerminatorKind::GeneratorDrop => { - bug!("shouldn't exist at trans {:?}", bb_data.terminator()); + bug!("shouldn't exist at codegen {:?}", bb_data.terminator()); } TerminatorKind::Drop { place, target, unwind: _, } => { - let drop_place = trans_place(fx, *place); + let drop_place = codegen_place(fx, *place); crate::abi::codegen_drop(fx, bb_data.terminator().source_info.span, drop_place); let target_block = fx.get_block(*target); @@ -416,7 +416,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Module>) { fx.bcx.finalize(); } -fn trans_stmt<'tcx>( +fn codegen_stmt<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, #[allow(unused_variables)] cur_block: Block, stmt: &Statement<'tcx>, @@ -439,19 +439,19 @@ fn trans_stmt<'tcx>( place, variant_index, } => { - let place = trans_place(fx, **place); + let place = codegen_place(fx, **place); crate::discriminant::codegen_set_discriminant(fx, place, *variant_index); } StatementKind::Assign(to_place_and_rval) => { - let lval = trans_place(fx, to_place_and_rval.0); + let lval = codegen_place(fx, to_place_and_rval.0); let dest_layout = lval.layout(); match &to_place_and_rval.1 { Rvalue::Use(operand) => { - let val = trans_operand(fx, operand); + let val = codegen_operand(fx, operand); lval.write_cvalue(fx, val); } Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - let place = trans_place(fx, *place); + let place = codegen_place(fx, *place); let ref_ = place.place_ref(fx, lval.layout()); lval.write_cvalue(fx, ref_); } @@ -460,29 +460,29 @@ fn trans_stmt<'tcx>( lval.write_cvalue(fx, val); } Rvalue::BinaryOp(bin_op, lhs, rhs) => { - let lhs = trans_operand(fx, lhs); - let rhs = trans_operand(fx, rhs); + let lhs = codegen_operand(fx, lhs); + let rhs = codegen_operand(fx, rhs); let res = crate::num::codegen_binop(fx, *bin_op, lhs, rhs); lval.write_cvalue(fx, res); } Rvalue::CheckedBinaryOp(bin_op, lhs, rhs) => { - let lhs = trans_operand(fx, lhs); - let rhs = trans_operand(fx, rhs); + let lhs = codegen_operand(fx, lhs); + let rhs = codegen_operand(fx, rhs); let res = if !fx.tcx.sess.overflow_checks() { let val = - crate::num::trans_int_binop(fx, *bin_op, lhs, rhs).load_scalar(fx); + crate::num::codegen_int_binop(fx, *bin_op, lhs, rhs).load_scalar(fx); let is_overflow = fx.bcx.ins().iconst(types::I8, 0); CValue::by_val_pair(val, is_overflow, lval.layout()) } else { - crate::num::trans_checked_int_binop(fx, *bin_op, lhs, rhs) + crate::num::codegen_checked_int_binop(fx, *bin_op, lhs, rhs) }; lval.write_cvalue(fx, res); } Rvalue::UnaryOp(un_op, operand) => { - let operand = trans_operand(fx, operand); + let operand = codegen_operand(fx, operand); let layout = operand.layout(); let val = operand.load_scalar(fx); let res = match un_op { @@ -499,8 +499,8 @@ fn trans_stmt<'tcx>( UnOp::Neg => match layout.ty.kind() { ty::Int(IntTy::I128) => { // FIXME remove this case once ineg.i128 works - let zero = CValue::const_val(fx, layout, 0); - crate::num::trans_int_binop(fx, BinOp::Sub, zero, operand) + let zero = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size)); + crate::num::codegen_int_binop(fx, BinOp::Sub, zero, operand) } ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout), ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout), @@ -534,11 +534,11 @@ fn trans_stmt<'tcx>( | Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, to_ty) | Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), operand, to_ty) => { let to_layout = fx.layout_of(fx.monomorphize(to_ty)); - let operand = trans_operand(fx, operand); + let operand = codegen_operand(fx, operand); lval.write_cvalue(fx, operand.cast_pointer_to(to_layout)); } Rvalue::Cast(CastKind::Misc, operand, to_ty) => { - let operand = trans_operand(fx, operand); + let operand = codegen_operand(fx, operand); let from_ty = operand.layout().ty; let to_ty = fx.monomorphize(to_ty); @@ -585,13 +585,11 @@ fn trans_stmt<'tcx>( .discriminant_for_variant(fx.tcx, *index) .unwrap(); let discr = if discr.ty.is_signed() { - rustc_middle::mir::interpret::sign_extend( - discr.val, - fx.layout_of(discr.ty).size, - ) + fx.layout_of(discr.ty).size.sign_extend(discr.val) } else { discr.val }; + let discr = discr.into(); let discr = CValue::const_val(fx, fx.layout_of(to_ty), discr); lval.write_cvalue(fx, discr); @@ -639,7 +637,7 @@ fn trans_stmt<'tcx>( operand, _to_ty, ) => { - let operand = trans_operand(fx, operand); + let operand = codegen_operand(fx, operand); match *operand.layout().ty.kind() { ty::Closure(def_id, substs) => { let instance = Instance::resolve_closure( @@ -657,18 +655,18 @@ fn trans_stmt<'tcx>( } } Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), operand, _to_ty) => { - let operand = trans_operand(fx, operand); + let operand = codegen_operand(fx, operand); operand.unsize_value(fx, lval); } Rvalue::Discriminant(place) => { - let place = trans_place(fx, *place); + let place = codegen_place(fx, *place); let value = place.to_cvalue(fx); let discr = crate::discriminant::codegen_get_discriminant(fx, value, dest_layout); lval.write_cvalue(fx, discr); } Rvalue::Repeat(operand, times) => { - let operand = trans_operand(fx, operand); + let operand = codegen_operand(fx, operand); let times = fx .monomorphize(times) .eval(fx.tcx, ParamEnv::reveal_all()) @@ -706,7 +704,7 @@ fn trans_stmt<'tcx>( } } Rvalue::Len(place) => { - let place = trans_place(fx, *place); + let place = codegen_place(fx, *place); let usize_layout = fx.layout_of(fx.tcx.types.usize); let len = codegen_array_len(fx, place); lval.write_cvalue(fx, CValue::by_val(len, usize_layout)); @@ -753,14 +751,14 @@ fn trans_stmt<'tcx>( } Rvalue::Aggregate(kind, operands) => match **kind { AggregateKind::Array(_ty) => { - for (i, operand) in operands.into_iter().enumerate() { - let operand = trans_operand(fx, operand); + for (i, operand) in operands.iter().enumerate() { + let operand = codegen_operand(fx, operand); let index = fx.bcx.ins().iconst(fx.pointer_type, i as i64); let to = lval.place_index(fx, index); to.write_cvalue(fx, operand); } } - _ => unreachable!("shouldn't exist at trans {:?}", to_place_and_rval.1), + _ => unreachable!("shouldn't exist at codegen {:?}", to_place_and_rval.1), }, } } @@ -813,20 +811,20 @@ fn trans_stmt<'tcx>( assert!(!alignstack); assert_eq!(inputs.len(), 2); - let leaf = trans_operand(fx, &inputs[0].1).load_scalar(fx); // %eax - let subleaf = trans_operand(fx, &inputs[1].1).load_scalar(fx); // %ecx + let leaf = codegen_operand(fx, &inputs[0].1).load_scalar(fx); // %eax + let subleaf = codegen_operand(fx, &inputs[1].1).load_scalar(fx); // %ecx let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, subleaf); assert_eq!(outputs.len(), 4); - trans_place(fx, outputs[0]) + codegen_place(fx, outputs[0]) .write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32))); - trans_place(fx, outputs[1]) + codegen_place(fx, outputs[1]) .write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32))); - trans_place(fx, outputs[2]) + codegen_place(fx, outputs[2]) .write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32))); - trans_place(fx, outputs[3]) + codegen_place(fx, outputs[3]) .write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32))); } "xgetbv" => { @@ -892,7 +890,7 @@ fn codegen_array_len<'tcx>( } } -pub(crate) fn trans_place<'tcx>( +pub(crate) fn codegen_place<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, place: Place<'tcx>, ) -> CPlace<'tcx> { @@ -938,7 +936,7 @@ pub(crate) fn trans_place<'tcx>( let ptr = cplace.to_ptr(); cplace = CPlace::for_ptr( ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)), - fx.layout_of(fx.tcx.mk_array(elem_ty, u64::from(to) - u64::from(from))), + fx.layout_of(fx.tcx.mk_array(elem_ty, to - from)), ); } ty::Slice(elem_ty) => { @@ -964,16 +962,16 @@ pub(crate) fn trans_place<'tcx>( cplace } -pub(crate) fn trans_operand<'tcx>( +pub(crate) fn codegen_operand<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, operand: &Operand<'tcx>, ) -> CValue<'tcx> { match operand { Operand::Move(place) | Operand::Copy(place) => { - let cplace = trans_place(fx, *place); + let cplace = codegen_place(fx, *place); cplace.to_cvalue(fx) } - Operand::Constant(const_) => crate::constant::trans_constant(fx, const_), + Operand::Constant(const_) => crate::constant::codegen_constant(fx, const_), } } diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs index 590c9ef0ce1..71ef4d22673 100644 --- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs @@ -24,22 +24,16 @@ impl rustc_driver::Callbacks for CraneliftPassesCallbacks { self.time_passes = config.opts.prints.is_empty() && (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time); - // FIXME workaround for an ICE - config.opts.debugging_opts.trim_diagnostic_paths = false; - config.opts.cg.panic = Some(PanicStrategy::Abort); config.opts.debugging_opts.panic_abort_tests = true; config.opts.maybe_sysroot = Some( - std::env::current_exe() - .unwrap() - .parent() - .unwrap() - .parent() - .unwrap() - .parent() - .unwrap() - .join("build_sysroot") - .join("sysroot"), + config.opts.maybe_sysroot.clone().unwrap_or( + std::env::current_exe() + .unwrap() + .parent() + .unwrap() + .join("sysroot"), + ), ); } } diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs index c207d98d6c1..165d33dcfb5 100644 --- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs @@ -44,9 +44,6 @@ impl rustc_driver::Callbacks for CraneliftPassesCallbacks { return; } - // FIXME workaround for an ICE - config.opts.debugging_opts.trim_diagnostic_paths = false; - config.opts.cg.panic = Some(PanicStrategy::Abort); config.opts.debugging_opts.panic_abort_tests = true; config.opts.maybe_sysroot = Some( diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs index 122a36b5bf7..57204de1135 100644 --- a/compiler/rustc_codegen_cranelift/src/cast.rs +++ b/compiler/rustc_codegen_cranelift/src/cast.rs @@ -181,12 +181,10 @@ pub(crate) fn clif_int_or_float_cast( fx.bcx.ins().select(has_overflow, max_val, val) }; fx.bcx.ins().ireduce(to_ty, val) + } else if to_signed { + fx.bcx.ins().fcvt_to_sint_sat(to_ty, from) } else { - if to_signed { - fx.bcx.ins().fcvt_to_sint_sat(to_ty, from) - } else { - fx.bcx.ins().fcvt_to_uint_sat(to_ty, from) - } + fx.bcx.ins().fcvt_to_uint_sat(to_ty, from) } } else if from_ty.is_float() && to_ty.is_float() { // float -> float diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs index e998403dea6..d6a38bdafc9 100644 --- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs +++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs @@ -21,9 +21,9 @@ pub(crate) fn maybe_codegen<'tcx>( match bin_op { BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => { assert!(!checked); - return None; + None } - BinOp::Add | BinOp::Sub if !checked => return None, + BinOp::Add | BinOp::Sub if !checked => None, BinOp::Add => { let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); return Some(if is_signed { @@ -57,7 +57,7 @@ pub(crate) fn maybe_codegen<'tcx>( }; fx.easy_call("__multi3", &[lhs, rhs], val_ty) }; - return Some(res); + Some(res) } BinOp::Div => { assert!(!checked); @@ -77,7 +77,7 @@ pub(crate) fn maybe_codegen<'tcx>( } BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => { assert!(!checked); - return None; + None } BinOp::Shl | BinOp::Shr => { let is_overflow = if checked { diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 13c62add41a..eda77bf19d3 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -406,7 +406,7 @@ impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> { caller.line as u32, caller.col_display as u32 + 1, )); - crate::constant::trans_const_value(self, const_loc, self.tcx.caller_location_ty()) + crate::constant::codegen_const_value(self, const_loc, self.tcx.caller_location_ty()) } pub(crate) fn triple(&self) -> &target_lexicon::Triple { diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 1b514958a48..41cfae4ca6e 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -106,7 +106,7 @@ fn codegen_static_ref<'tcx>( CPlace::for_ptr(crate::pointer::Pointer::new(global_ptr), layout) } -pub(crate) fn trans_constant<'tcx>( +pub(crate) fn codegen_constant<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, constant: &Constant<'tcx>, ) -> CValue<'tcx> { @@ -151,10 +151,10 @@ pub(crate) fn trans_constant<'tcx>( | ConstKind::Error(_) => unreachable!("{:?}", const_), }; - trans_const_value(fx, const_val, const_.ty) + codegen_const_value(fx, const_val, const_.ty) } -pub(crate) fn trans_const_value<'tcx>( +pub(crate) fn codegen_const_value<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, const_val: ConstValue<'tcx>, ty: Ty<'tcx>, @@ -164,7 +164,7 @@ pub(crate) fn trans_const_value<'tcx>( if layout.is_zst() { return CValue::by_ref( - crate::Pointer::const_addr(fx, i64::try_from(layout.align.pref.bytes()).unwrap()), + crate::Pointer::dangling(layout.align.pref), layout, ); } @@ -186,9 +186,8 @@ pub(crate) fn trans_const_value<'tcx>( } match x { - Scalar::Raw { data, size } => { - assert_eq!(u64::from(size), layout.size.bytes()); - return CValue::const_val(fx, layout, data); + Scalar::Int(int) => { + CValue::const_val(fx, layout, int) } Scalar::Ptr(ptr) => { let alloc_kind = fx.tcx.get_global_alloc(ptr.alloc_id); @@ -232,7 +231,7 @@ pub(crate) fn trans_const_value<'tcx>( } else { base_addr }; - return CValue::by_val(val, layout); + CValue::by_val(val, layout) } } } @@ -276,7 +275,7 @@ fn data_id_for_alloc_id( ) -> DataId { module .declare_data( - &format!("__alloc_{:x}", alloc_id.0), + &format!(".L__alloc_{:x}", alloc_id.0), Linkage::Local, mutability == rustc_hir::Mutability::Mut, false, @@ -293,14 +292,12 @@ fn data_id_for_static( let rlinkage = tcx.codegen_fn_attrs(def_id).linkage; let linkage = if definition { crate::linkage::get_static_linkage(tcx, def_id) + } else if rlinkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak) + || rlinkage == Some(rustc_middle::mir::mono::Linkage::WeakAny) + { + Linkage::Preemptible } else { - if rlinkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak) - || rlinkage == Some(rustc_middle::mir::mono::Linkage::WeakAny) - { - Linkage::Preemptible - } else { - Linkage::Import - } + Linkage::Import }; let instance = Instance::mono(tcx, def_id).polymorphize(tcx); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs index cf8fee2b1d1..f6f795e4561 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs @@ -195,9 +195,7 @@ impl Writer for WriterRelocate { }); self.write_udata(0, size) } - _ => { - return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)); - } + _ => Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)), }, } } diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 4de84855328..d226755d85d 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -49,7 +49,7 @@ fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] { pub(crate) const MD5_LEN: usize = 16; -pub fn make_file_info(hash: SourceFileHash) -> Option<FileInfo> { +pub(crate) fn make_file_info(hash: SourceFileHash) -> Option<FileInfo> { if hash.kind == SourceFileHashAlgorithm::Md5 { let mut buf = [0u8; MD5_LEN]; buf.copy_from_slice(hash.hash_bytes()); @@ -190,7 +190,7 @@ impl<'tcx> DebugContext<'tcx> { if current_file_changed { let file_id = line_program_add_file(line_program, line_strings, &file); line_program.row().file = file_id; - last_file = Some(file.clone()); + last_file = Some(file); } line_program.row().line = line; diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index 61ebd931d2f..68138404c24 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -55,6 +55,7 @@ impl<'tcx> UnwindContext<'tcx> { UnwindInfo::WindowsX64(_) => { // FIXME implement this } + unwind_info => unimplemented!("{:?}", unwind_info), } } diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index d15bc36ad05..6c9fb8e051b 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -30,7 +30,8 @@ pub(crate) fn codegen_set_discriminant<'tcx>( .ty .discriminant_for_variant(fx.tcx, variant_index) .unwrap() - .val; + .val + .into(); let discr = CValue::const_val(fx, ptr.layout(), to); ptr.write_cvalue(fx, discr); } @@ -49,7 +50,7 @@ pub(crate) fn codegen_set_discriminant<'tcx>( let niche = place.place_field(fx, mir::Field::new(tag_field)); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = u128::from(niche_value).wrapping_add(niche_start); - let niche_llval = CValue::const_val(fx, niche.layout(), niche_value); + let niche_llval = CValue::const_val(fx, niche.layout(), niche_value.into()); niche.write_cvalue(fx, niche_llval); } } @@ -77,7 +78,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>( .ty .discriminant_for_variant(fx.tcx, *index) .map_or(u128::from(index.as_u32()), |discr| discr.val); - return CValue::const_val(fx, dest_layout, discr_val); + return CValue::const_val(fx, dest_layout, discr_val.into()); } Variants::Multiple { tag, diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index b5bab3d9e1e..3f47df7d844 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -94,7 +94,7 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! { let args = ::std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new()); let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string()) - .chain(args.split(" ")) + .chain(args.split(' ')) .map(|arg| CString::new(arg).unwrap()) .collect::<Vec<_>>(); let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>(); @@ -151,7 +151,7 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> { } let dlsym_name = if cfg!(target_os = "macos") { // On macOS `dlsym` expects the name without leading `_`. - assert!(name.starts_with("_"), "{:?}", name); + assert!(name.starts_with('_'), "{:?}", name); &name[1..] } else { &name diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs index 2fb353ca162..a11dc57ee64 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs @@ -64,11 +64,11 @@ fn codegen_mono_items<'tcx>( for (mono_item, (linkage, visibility)) in mono_items { let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); - trans_mono_item(cx, mono_item, linkage); + codegen_mono_item(cx, mono_item, linkage); } } -fn trans_mono_item<'tcx, M: Module>( +fn codegen_mono_item<'tcx, M: Module>( cx: &mut crate::CodegenCx<'tcx, M>, mono_item: MonoItem<'tcx>, linkage: Linkage, @@ -80,7 +80,7 @@ fn trans_mono_item<'tcx, M: Module>( crate::PrintOnPanic(|| format!("{:?} {}", inst, tcx.symbol_name(inst).name)); debug_assert!(!inst.substs.needs_infer()); tcx.sess - .time("codegen fn", || crate::base::trans_fn(cx, inst, linkage)); + .time("codegen fn", || crate::base::codegen_fn(cx, inst, linkage)); } MonoItem::Static(def_id) => { crate::constant::codegen_static(&mut cx.constants_cx, def_id); diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index aa2edb2dfd4..04aac780125 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -50,7 +50,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( inputs.push(( reg, new_slot(reg.reg_class()), - crate::base::trans_operand(fx, value).load_scalar(fx), + crate::base::codegen_operand(fx, value).load_scalar(fx), )); } InlineAsmOperand::Out { @@ -64,7 +64,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( outputs.push(( reg, new_slot(reg.reg_class()), - crate::base::trans_place(fx, place), + crate::base::codegen_place(fx, place), )); } } @@ -79,13 +79,13 @@ pub(crate) fn codegen_inline_asm<'tcx>( inputs.push(( reg, new_slot(reg.reg_class()), - crate::base::trans_operand(fx, in_value).load_scalar(fx), + crate::base::codegen_operand(fx, in_value).load_scalar(fx), )); if let Some(out_place) = out_place { outputs.push(( reg, new_slot(reg.reg_class()), - crate::base::trans_place(fx, out_place), + crate::base::codegen_place(fx, out_place), )); } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 18d86f0c5f9..171445f2d71 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -53,7 +53,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( }; llvm.x86.sse2.cmp.ps | llvm.x86.sse2.cmp.pd, (c x, c y, o kind) { let kind_const = crate::constant::mir_operand_get_const_val(fx, kind).expect("llvm.x86.sse2.cmp.* kind not const"); - let flt_cc = match kind_const.val.try_to_bits(Size::from_bytes(1)).expect(&format!("kind not scalar: {:?}", kind_const)) { + let flt_cc = match kind_const.val.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind_const)) { 0 => FloatCC::Equal, 1 => FloatCC::LessThan, 2 => FloatCC::LessThanOrEqual, @@ -84,7 +84,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( llvm.x86.sse2.psrli.d, (c a, o imm8) { let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const"); simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| { - let res_lane = match imm8.val.try_to_bits(Size::from_bytes(4)).expect(&format!("imm8 not scalar: {:?}", imm8)) { + let res_lane = match imm8.val.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)), _ => fx.bcx.ins().iconst(types::I32, 0), }; @@ -94,7 +94,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( llvm.x86.sse2.pslli.d, (c a, o imm8) { let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const"); simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| { - let res_lane = match imm8.val.try_to_bits(Size::from_bytes(4)).expect(&format!("imm8 not scalar: {:?}", imm8)) { + let res_lane = match imm8.val.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)), _ => fx.bcx.ins().iconst(types::I32, 0), }; diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 9a3e4c7b56e..ab16fabd348 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -9,6 +9,7 @@ pub(crate) use cpuid::codegen_cpuid_call; pub(crate) use llvm::codegen_llvm_intrinsic_call; use crate::prelude::*; +use rustc_middle::ty::print::with_no_trimmed_paths; macro intrinsic_pat { (_) => { @@ -30,10 +31,10 @@ macro intrinsic_arg { $arg }, (c $fx:expr, $arg:ident) => { - trans_operand($fx, $arg) + codegen_operand($fx, $arg) }, (v $fx:expr, $arg:ident) => { - trans_operand($fx, $arg).load_scalar($fx) + codegen_operand($fx, $arg).load_scalar($fx) } } @@ -89,7 +90,7 @@ macro call_intrinsic_match { assert!($substs.is_noop()); if let [$(ref $arg),*] = *$args { let ($($arg,)*) = ( - $(trans_operand($fx, $arg),)* + $(codegen_operand($fx, $arg),)* ); let res = $fx.easy_call(stringify!($func), &[$($arg),*], $fx.tcx.types.$ty); $ret.write_cvalue($fx, res); @@ -576,7 +577,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( "unchecked_shr" => BinOp::Shr, _ => unreachable!("intrinsic {}", intrinsic), }; - let res = crate::num::trans_int_binop(fx, bin_op, x, y); + let res = crate::num::codegen_int_binop(fx, bin_op, x, y); ret.write_cvalue(fx, res); }; _ if intrinsic.ends_with("_with_overflow"), (c x, c y) { @@ -588,7 +589,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( _ => unreachable!("intrinsic {}", intrinsic), }; - let res = crate::num::trans_checked_int_binop( + let res = crate::num::codegen_checked_int_binop( fx, bin_op, x, @@ -604,7 +605,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( "wrapping_mul" => BinOp::Mul, _ => unreachable!("intrinsic {}", intrinsic), }; - let res = crate::num::trans_int_binop( + let res = crate::num::codegen_int_binop( fx, bin_op, x, @@ -622,7 +623,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let signed = type_sign(T); - let checked_res = crate::num::trans_checked_int_binop( + let checked_res = crate::num::codegen_checked_int_binop( fx, bin_op, lhs, @@ -819,29 +820,29 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( assert_inhabited | assert_zero_valid | assert_uninit_valid, <T> () { let layout = fx.layout_of(T); if layout.abi.is_uninhabited() { - crate::base::codegen_panic( + with_no_trimmed_paths(|| crate::base::codegen_panic( fx, &format!("attempted to instantiate uninhabited type `{}`", T), span, - ); + )); return; } if intrinsic == "assert_zero_valid" && !layout.might_permit_raw_init(fx, /*zero:*/ true).unwrap() { - crate::base::codegen_panic( + with_no_trimmed_paths(|| crate::base::codegen_panic( fx, &format!("attempted to zero-initialize type `{}`, which is invalid", T), span, - ); + )); return; } if intrinsic == "assert_uninit_valid" && !layout.might_permit_raw_init(fx, /*zero:*/ false).unwrap() { - crate::base::codegen_panic( + with_no_trimmed_paths(|| crate::base::codegen_panic( fx, &format!("attempted to leave type `{}` uninitialized, which is invalid", T), span, - ); + )); return; } }; @@ -866,7 +867,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( size_of | pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () { let const_val = fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap(); - let val = crate::constant::trans_const_value( + let val = crate::constant::codegen_const_value( fx, const_val, ret.layout().ty, @@ -885,12 +886,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( }; ptr_guaranteed_eq, (c a, c b) { - let val = crate::num::trans_ptr_binop(fx, BinOp::Eq, a, b); + let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b); ret.write_cvalue(fx, val); }; ptr_guaranteed_ne, (c a, c b) { - let val = crate::num::trans_ptr_binop(fx, BinOp::Ne, a, b); + let val = crate::num::codegen_ptr_binop(fx, BinOp::Ne, a, b); ret.write_cvalue(fx, val); }; @@ -1063,12 +1064,13 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( fx.bcx.ins().call_indirect(f_sig, f, &[data]); - let ret_val = CValue::const_val(fx, ret.layout(), 0); + let layout = ret.layout(); + let ret_val = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size)); ret.write_cvalue(fx, ret_val); }; fadd_fast | fsub_fast | fmul_fast | fdiv_fast | frem_fast, (c x, c y) { - let res = crate::num::trans_float_binop(fx, match intrinsic { + let res = crate::num::codegen_float_binop(fx, match intrinsic { "fadd_fast" => BinOp::Add, "fsub_fast" => BinOp::Sub, "fmul_fast" => BinOp::Mul, diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index b4269f4fafa..2e31c4669e2 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -127,7 +127,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ); }; - let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).expect(&format!("kind not scalar: {:?}", idx_const)); + let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, base.layout()); if idx >= lane_count.into() { fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count)); @@ -149,7 +149,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ); }; - let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).expect(&format!("kind not scalar: {:?}", idx_const)); + let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, v.layout()); if idx >= lane_count.into() { fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count)); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index fd00a2e00a6..ba9ee0d450e 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -9,6 +9,7 @@ )] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] +#![warn(unreachable_pub)] #[cfg(feature = "jit")] extern crate libc; @@ -110,7 +111,7 @@ mod prelude { pub(crate) use cranelift_module::{self, DataContext, DataId, FuncId, Linkage, Module}; pub(crate) use crate::abi::*; - pub(crate) use crate::base::{trans_operand, trans_place}; + pub(crate) use crate::base::{codegen_operand, codegen_place}; pub(crate) use crate::cast::*; pub(crate) use crate::common::*; pub(crate) use crate::debuginfo::{DebugContext, UnwindContext}; diff --git a/compiler/rustc_codegen_cranelift/src/linkage.rs b/compiler/rustc_codegen_cranelift/src/linkage.rs index fe5d1d64443..dc1e2107ce7 100644 --- a/compiler/rustc_codegen_cranelift/src/linkage.rs +++ b/compiler/rustc_codegen_cranelift/src/linkage.rs @@ -25,11 +25,9 @@ pub(crate) fn get_static_linkage(tcx: TyCtxt<'_>, def_id: DefId) -> Linkage { RLinkage::ExternalWeak | RLinkage::WeakAny => Linkage::Preemptible, _ => panic!("{:?}", linkage), } + } else if tcx.is_reachable_non_generic(def_id) { + Linkage::Export } else { - if tcx.is_reachable_non_generic(def_id) { - Linkage::Export - } else { - Linkage::Hidden - } + Linkage::Hidden } } diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index db34d89fe2b..10f515e38ea 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -76,7 +76,7 @@ pub(crate) fn maybe_create_entry_wrapper( .unwrap(); let mut ctx = Context::new(); - ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig.clone()); + ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig); { let mut func_ctx = FunctionBuilderContext::new(); let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); diff --git a/compiler/rustc_codegen_cranelift/src/metadata.rs b/compiler/rustc_codegen_cranelift/src/metadata.rs index 04369bf89fd..cda2a187ff9 100644 --- a/compiler/rustc_codegen_cranelift/src/metadata.rs +++ b/compiler/rustc_codegen_cranelift/src/metadata.rs @@ -29,7 +29,7 @@ impl MetadataLoader for CraneliftMetadataLoader { .expect("Rlib metadata file too big to load into memory."), ); ::std::io::copy(&mut entry, &mut buf).map_err(|e| format!("{:?}", e))?; - let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf).into(); + let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf); return Ok(rustc_erase_owner!(buf.map_owner_box())); } } @@ -47,7 +47,7 @@ impl MetadataLoader for CraneliftMetadataLoader { .data() .map_err(|e| format!("failed to read .rustc section: {:?}", e))? .to_owned(); - let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf).into(); + let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf); Ok(rustc_erase_owner!(buf.map_owner_box())) } } diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index b37826d71f4..41f4a9b9662 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -89,10 +89,10 @@ pub(crate) fn codegen_binop<'tcx>( } match in_lhs.layout().ty.kind() { - ty::Bool => crate::num::trans_bool_binop(fx, bin_op, in_lhs, in_rhs), - ty::Uint(_) | ty::Int(_) => crate::num::trans_int_binop(fx, bin_op, in_lhs, in_rhs), - ty::Float(_) => crate::num::trans_float_binop(fx, bin_op, in_lhs, in_rhs), - ty::RawPtr(..) | ty::FnPtr(..) => crate::num::trans_ptr_binop(fx, bin_op, in_lhs, in_rhs), + ty::Bool => crate::num::codegen_bool_binop(fx, bin_op, in_lhs, in_rhs), + ty::Uint(_) | ty::Int(_) => crate::num::codegen_int_binop(fx, bin_op, in_lhs, in_rhs), + ty::Float(_) => crate::num::codegen_float_binop(fx, bin_op, in_lhs, in_rhs), + ty::RawPtr(..) | ty::FnPtr(..) => crate::num::codegen_ptr_binop(fx, bin_op, in_lhs, in_rhs), _ => unreachable!( "{:?}({:?}, {:?})", bin_op, @@ -102,7 +102,7 @@ pub(crate) fn codegen_binop<'tcx>( } } -pub(crate) fn trans_bool_binop<'tcx>( +pub(crate) fn codegen_bool_binop<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, bin_op: BinOp, in_lhs: CValue<'tcx>, @@ -123,7 +123,7 @@ pub(crate) fn trans_bool_binop<'tcx>( CValue::by_val(res, fx.layout_of(fx.tcx.types.bool)) } -pub(crate) fn trans_int_binop<'tcx>( +pub(crate) fn codegen_int_binop<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, bin_op: BinOp, in_lhs: CValue<'tcx>, @@ -196,7 +196,7 @@ pub(crate) fn trans_int_binop<'tcx>( CValue::by_val(val, in_lhs.layout()) } -pub(crate) fn trans_checked_int_binop<'tcx>( +pub(crate) fn codegen_checked_int_binop<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, bin_op: BinOp, in_lhs: CValue<'tcx>, @@ -357,7 +357,7 @@ pub(crate) fn trans_checked_int_binop<'tcx>( out_place.to_cvalue(fx) } -pub(crate) fn trans_float_binop<'tcx>( +pub(crate) fn codegen_float_binop<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, bin_op: BinOp, in_lhs: CValue<'tcx>, @@ -402,7 +402,7 @@ pub(crate) fn trans_float_binop<'tcx>( CValue::by_val(res, in_lhs.layout()) } -pub(crate) fn trans_ptr_binop<'tcx>( +pub(crate) fn codegen_ptr_binop<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, bin_op: BinOp, in_lhs: CValue<'tcx>, diff --git a/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs b/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs index f368d65f7f8..3c939d5a586 100644 --- a/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs +++ b/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs @@ -228,7 +228,8 @@ pub(super) fn optimize_function( match *potential_stores { [] => { #[cfg(debug_assertions)] - clif_comments.add_comment(load, format!("[BUG?] Reading uninitialized memory")); + clif_comments + .add_comment(load, "[BUG?] Reading uninitialized memory".to_string()); } [store] if spatial_overlap(&opt_ctx.ctx.func, store, load) == SpatialOverlap::Full diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs index 7f8ab953d71..ff878af7f5e 100644 --- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs @@ -131,11 +131,11 @@ impl FuncWriter for &'_ CommentWriter { if !comment.is_empty() { writeln!(w, "; {}", comment)?; } else { - writeln!(w, "")?; + writeln!(w)?; } } if !self.global_comments.is_empty() { - writeln!(w, "")?; + writeln!(w)?; } self.super_preamble(w, func, reg_info) @@ -153,7 +153,7 @@ impl FuncWriter for &'_ CommentWriter { if let Some(comment) = self.entity_comments.get(&entity) { writeln!(w, " ; {}", comment.replace('\n', "\n; ")) } else { - writeln!(w, "") + writeln!(w) } } @@ -261,7 +261,7 @@ pub(crate) fn write_clif_file<'tcx>( writeln!(file, "set is_pic")?; writeln!(file, "set enable_simd")?; writeln!(file, "target {} haswell", target_triple)?; - writeln!(file, "")?; + writeln!(file)?; file.write_all(clif.as_bytes())?; }; if let Err(err) = res { diff --git a/compiler/rustc_codegen_cranelift/src/trap.rs b/compiler/rustc_codegen_cranelift/src/trap.rs index 37dca77bdbd..690d96764a8 100644 --- a/compiler/rustc_codegen_cranelift/src/trap.rs +++ b/compiler/rustc_codegen_cranelift/src/trap.rs @@ -67,4 +67,3 @@ pub(crate) fn trap_unimplemented(fx: &mut FunctionCx<'_, '_, impl Module>, msg: let true_ = fx.bcx.ins().iconst(types::I32, 1); fx.bcx.ins().trapnz(true_, TrapCode::User(!0)); } - diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 5d513cb3ea0..0000866c4f6 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -27,10 +27,10 @@ fn codegen_field<'tcx>( return simple(fx); } match field_layout.ty.kind() { - ty::Slice(..) | ty::Str | ty::Foreign(..) => return simple(fx), + ty::Slice(..) | ty::Str | ty::Foreign(..) => simple(fx), ty::Adt(def, _) if def.repr.packed() => { assert_eq!(layout.align.abi.bytes(), 1); - return simple(fx); + simple(fx) } _ => { // We have to align the offset for DST's @@ -231,25 +231,24 @@ impl<'tcx> CValue<'tcx> { pub(crate) fn const_val( fx: &mut FunctionCx<'_, 'tcx, impl Module>, layout: TyAndLayout<'tcx>, - const_val: u128, + const_val: ty::ScalarInt, ) -> CValue<'tcx> { + assert_eq!(const_val.size(), layout.size); use cranelift_codegen::ir::immediates::{Ieee32, Ieee64}; let clif_ty = fx.clif_type(layout.ty).unwrap(); - match layout.ty.kind() { - ty::Bool => { - assert!( - const_val == 0 || const_val == 1, - "Invalid bool 0x{:032X}", - const_val - ); - } - _ => {} + if let ty::Bool = layout.ty.kind() { + assert!( + const_val == ty::ScalarInt::FALSE || const_val == ty::ScalarInt::TRUE, + "Invalid bool 0x{:032X}", + const_val + ); } let val = match layout.ty.kind() { ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => { + let const_val = const_val.to_bits(layout.size).unwrap(); let lsb = fx.bcx.ins().iconst(types::I64, const_val as u64 as i64); let msb = fx .bcx @@ -262,7 +261,7 @@ impl<'tcx> CValue<'tcx> { fx .bcx .ins() - .iconst(clif_ty, u64::try_from(const_val).expect("uint") as i64) + .iconst(clif_ty, const_val.to_bits(layout.size).unwrap() as i64) } ty::Float(FloatTy::F32) => { fx.bcx.ins().f32const(Ieee32::with_bits(u32::try_from(const_val).unwrap())) @@ -335,7 +334,7 @@ impl<'tcx> CPlace<'tcx> { let stack_slot = fx.bcx.create_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, - size: layout.size.bytes() as u32, + size: u32::try_from(layout.size.bytes()).unwrap(), offset: None, }); CPlace { @@ -533,6 +532,13 @@ impl<'tcx> CPlace<'tcx> { dst_ty: Type, ) { let src_ty = fx.bcx.func.dfg.value_type(data); + assert_eq!( + src_ty.bytes(), + dst_ty.bytes(), + "write_cvalue_transmute: {:?} -> {:?}", + src_ty, + dst_ty, + ); let data = match (src_ty, dst_ty) { (_, _) if src_ty == dst_ty => data, @@ -544,6 +550,17 @@ impl<'tcx> CPlace<'tcx> { _ if src_ty.is_vector() && dst_ty.is_vector() => { fx.bcx.ins().raw_bitcast(dst_ty, data) } + _ if src_ty.is_vector() || dst_ty.is_vector() => { + // FIXME do something more efficient for transmutes between vectors and integers. + let stack_slot = fx.bcx.create_stack_slot(StackSlotData { + kind: StackSlotKind::ExplicitSlot, + size: src_ty.bytes(), + offset: None, + }); + let ptr = Pointer::stack_slot(stack_slot); + ptr.store(fx, data, MemFlags::trusted()); + ptr.load(fx, dst_ty, MemFlags::trusted()) + } _ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty, dst_ty), }; fx.bcx diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index bb3cf8b3f3a..238abc0d8bd 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -108,14 +108,14 @@ fn build_vtable<'tcx>( (&[]).iter() }; let methods = methods.cloned().map(|opt_mth| { - opt_mth.map_or(None, |(def_id, substs)| { - Some(import_function( + opt_mth.map(|(def_id, substs)| { + import_function( tcx, &mut fx.cx.module, Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs) .unwrap() .polymorphize(fx.tcx), - )) + ) }) }); components.extend(methods); @@ -137,15 +137,7 @@ fn build_vtable<'tcx>( } } - data_ctx.set_align( - fx.tcx - .data_layout - .pointer_align - .pref - .bytes() - .try_into() - .unwrap(), - ); + data_ctx.set_align(fx.tcx.data_layout.pointer_align.pref.bytes()); let data_id = fx .cx diff --git a/compiler/rustc_codegen_cranelift/test.sh b/compiler/rustc_codegen_cranelift/test.sh index a1c4d9f2872..3cdd4119d79 100755 --- a/compiler/rustc_codegen_cranelift/test.sh +++ b/compiler/rustc_codegen_cranelift/test.sh @@ -1,119 +1,15 @@ #!/bin/bash set -e -# Build cg_clif export RUSTFLAGS="-Zrun_dsymutil=no" -if [[ "$1" == "--release" ]]; then - export CHANNEL='release' - cargo build --release -else - export CHANNEL='debug' - cargo build --bin cg_clif -fi -# Config -source scripts/config.sh -export CG_CLIF_INCR_CACHE_DISABLED=1 -RUSTC=$RUSTC" "$RUSTFLAGS" -L crate=target/out --out-dir target/out -Cdebuginfo=2" +./build.sh --without-sysroot $@ -# Cleanup rm -r target/out || true -# Perform all tests -echo "[BUILD] mini_core" -$RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib --target $TARGET_TRIPLE +scripts/tests.sh no_sysroot -echo "[BUILD] example" -$RUSTC example/example.rs --crate-type lib --target $TARGET_TRIPLE +./build.sh $@ -if [[ "$JIT_SUPPORTED" = "1" ]]; then - echo "[JIT] mini_core_hello_world" - CG_CLIF_JIT_ARGS="abc bcd" $RUSTC --jit example/mini_core_hello_world.rs --cfg jit --target $HOST_TRIPLE -else - echo "[JIT] mini_core_hello_world (skipped)" -fi - -echo "[AOT] mini_core_hello_world" -$RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target $TARGET_TRIPLE -$RUN_WRAPPER ./target/out/mini_core_hello_world abc bcd -# (echo "break set -n main"; echo "run"; sleep 1; echo "si -c 10"; sleep 1; echo "frame variable") | lldb -- ./target/out/mini_core_hello_world abc bcd - -echo "[AOT] arbitrary_self_types_pointers_and_wrappers" -$RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target $TARGET_TRIPLE -$RUN_WRAPPER ./target/out/arbitrary_self_types_pointers_and_wrappers - -echo "[BUILD] sysroot" -time ./build_sysroot/build_sysroot.sh --release - -echo "[AOT] alloc_example" -$RUSTC example/alloc_example.rs --crate-type bin --target $TARGET_TRIPLE -$RUN_WRAPPER ./target/out/alloc_example - -if [[ "$JIT_SUPPORTED" = "1" ]]; then - echo "[JIT] std_example" - $RUSTC --jit example/std_example.rs --target $HOST_TRIPLE -else - echo "[JIT] std_example (skipped)" -fi - -echo "[AOT] dst_field_align" -# FIXME Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed. -$RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target $TARGET_TRIPLE -$RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false) - -echo "[AOT] std_example" -$RUSTC example/std_example.rs --crate-type bin --target $TARGET_TRIPLE -$RUN_WRAPPER ./target/out/std_example arg - -echo "[AOT] subslice-patterns-const-eval" -$RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE -$RUN_WRAPPER ./target/out/subslice-patterns-const-eval - -echo "[AOT] track-caller-attribute" -$RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE -$RUN_WRAPPER ./target/out/track-caller-attribute - -echo "[AOT] mod_bench" -$RUSTC example/mod_bench.rs --crate-type bin --target $TARGET_TRIPLE -$RUN_WRAPPER ./target/out/mod_bench - -pushd rand -rm -r ./target || true -../cargo.sh test --workspace -popd - -pushd simple-raytracer -if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then - echo "[BENCH COMPILE] ebobby/simple-raytracer" - hyperfine --runs ${RUN_RUNS:-10} --warmup 1 --prepare "cargo clean" \ - "RUSTC=rustc RUSTFLAGS='' cargo build" \ - "../cargo.sh build" - - echo "[BENCH RUN] ebobby/simple-raytracer" - cp ./target/debug/main ./raytracer_cg_clif - hyperfine --runs ${RUN_RUNS:-10} ./raytracer_cg_llvm ./raytracer_cg_clif -else - echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)" - echo "[COMPILE] ebobby/simple-raytracer" - ../cargo.sh build - echo "[BENCH RUN] ebobby/simple-raytracer (skipped)" -fi -popd - -pushd build_sysroot/sysroot_src/library/core/tests -echo "[TEST] libcore" -rm -r ./target || true -../../../../../cargo.sh test -popd - -pushd regex -echo "[TEST] rust-lang/regex example shootout-regex-dna" -../cargo.sh clean -# Make sure `[codegen mono items] start` doesn't poison the diff -../cargo.sh build --example shootout-regex-dna -cat examples/regexdna-input.txt | ../cargo.sh run --example shootout-regex-dna | grep -v "Spawned thread" > res.txt -diff -u res.txt examples/regexdna-output.txt - -echo "[TEST] rust-lang/regex tests" -../cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -popd +scripts/tests.sh base_sysroot +scripts/tests.sh extended_sysroot diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index d02bc41f4af..f7d82ff78fa 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -93,7 +93,7 @@ pub(crate) unsafe fn codegen( let args = [usize, usize]; // size, align let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False); - let name = format!("__rust_alloc_error_handler"); + let name = "__rust_alloc_error_handler".to_string(); let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty); // -> ! DIFlagNoReturn llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn); diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index b096664bc74..d856280158f 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -302,13 +302,11 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { } else if options.contains(InlineAsmOptions::READONLY) { llvm::Attribute::ReadOnly.apply_callsite(llvm::AttributePlace::Function, result); } + } else if options.contains(InlineAsmOptions::NOMEM) { + llvm::Attribute::InaccessibleMemOnly + .apply_callsite(llvm::AttributePlace::Function, result); } else { - if options.contains(InlineAsmOptions::NOMEM) { - llvm::Attribute::InaccessibleMemOnly - .apply_callsite(llvm::AttributePlace::Function, result); - } else { - // LLVM doesn't have an attribute to represent ReadOnly + SideEffect - } + // LLVM doesn't have an attribute to represent ReadOnly + SideEffect } // Write results to outputs diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 2075c2e1911..d4872aedd70 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -378,8 +378,8 @@ pub fn provide_both(providers: &mut Providers) { .collect::<FxHashMap<_, _>>(); let mut ret = FxHashMap::default(); - for lib in tcx.foreign_modules(cnum).iter() { - let module = def_id_to_native_lib.get(&lib.def_id).and_then(|s| s.wasm_import_module); + for (def_id, lib) in tcx.foreign_modules(cnum).iter() { + let module = def_id_to_native_lib.get(&def_id).and_then(|s| s.wasm_import_module); let module = match module { Some(s) => s, None => continue, diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index ff312bade25..64fd1d09cc2 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -900,7 +900,7 @@ impl ThinLTOKeysMap { let file = File::open(path)?; for line in io::BufReader::new(file).lines() { let line = line?; - let mut split = line.split(" "); + let mut split = line.split(' '); let module = split.next().unwrap(); let key = split.next().unwrap(); assert_eq!(split.next(), None, "Expected two space-separated values, found {:?}", line); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 3902df8a7ca..f13c2d312df 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -156,7 +156,11 @@ pub fn target_machine_factory( let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes; let asm_comments = sess.asm_comments(); - let relax_elf_relocations = sess.target.options.relax_elf_relocations; + let relax_elf_relocations = sess + .opts + .debugging_opts + .relax_elf_relocations + .unwrap_or(sess.target.options.relax_elf_relocations); let use_init_array = !sess .opts diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 978ad37c0f3..f122fa14e70 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -732,10 +732,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let src_ty = self.cx.val_ty(val); let float_width = self.cx.float_width(src_ty); let int_width = self.cx.int_width(dest_ty); - match (int_width, float_width) { - (32, 32) | (32, 64) | (64, 32) | (64, 64) => true, - _ => false, - } + matches!((int_width, float_width), (32, 32) | (32, 64) | (64, 32) | (64, 64)) } fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 7633dd0600d..34e1b7a6045 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -12,7 +12,7 @@ use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; use rustc_middle::bug; use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar}; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::{layout::TyAndLayout, ScalarInt}; use rustc_span::symbol::Symbol; use rustc_target::abi::{self, AddressSpace, HasDataLayout, LayoutOf, Pointer, Size}; @@ -230,12 +230,12 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn scalar_to_backend(&self, cv: Scalar, layout: &abi::Scalar, llty: &'ll Type) -> &'ll Value { let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() }; match cv { - Scalar::Raw { size: 0, .. } => { + Scalar::Int(ScalarInt::ZST) => { assert_eq!(0, layout.value.size(self).bytes()); self.const_undef(self.type_ix(0)) } - Scalar::Raw { data, size } => { - assert_eq!(size as u64, layout.value.size(self).bytes()); + Scalar::Int(int) => { + let data = int.assert_bits(layout.value.size(self)); let llval = self.const_uint_big(self.type_ix(bitsize), data); if layout.value == Pointer { unsafe { llvm::LLVMConstIntToPtr(llval, llty) } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index b57a23328b6..90a51f75e0e 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -19,7 +19,6 @@ use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::sym; -use rustc_span::Span; use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size}; use tracing::debug; @@ -110,7 +109,7 @@ fn check_and_apply_linkage( attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str, - span: Span, + span_def_id: DefId, ) -> &'ll Value { let llty = cx.layout_of(ty).llvm_type(cx); if let Some(linkage) = attrs.linkage { @@ -125,7 +124,7 @@ fn check_and_apply_linkage( cx.layout_of(mt.ty).llvm_type(cx) } else { cx.sess().span_fatal( - span, + cx.tcx.def_span(span_def_id), "must have type `*const T` or `*mut T` due to `#[linkage]` attribute", ) }; @@ -143,7 +142,10 @@ fn check_and_apply_linkage( let mut real_name = "_rust_extern_with_linkage_".to_string(); real_name.push_str(&sym); let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| { - cx.sess().span_fatal(span, &format!("symbol `{}` is already defined", &sym)) + cx.sess().span_fatal( + cx.tcx.def_span(span_def_id), + &format!("symbol `{}` is already defined", &sym), + ) }); llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); @@ -210,21 +212,21 @@ impl CodegenCx<'ll, 'tcx> { debug!("get_static: sym={} instance={:?}", sym, instance); - let g = if let Some(def_id) = def_id.as_local() { - let id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let g = if let Some(local_def_id) = def_id.as_local() { + let id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); let llty = self.layout_of(ty).llvm_type(self); // FIXME: refactor this to work without accessing the HIR let (g, attrs) = match self.tcx.hir().get(id) { - Node::Item(&hir::Item { attrs, span, kind: hir::ItemKind::Static(..), .. }) => { + Node::Item(&hir::Item { attrs, kind: hir::ItemKind::Static(..), .. }) => { if let Some(g) = self.get_declared_value(sym) { if self.val_ty(g) != self.type_ptr_to(llty) { - span_bug!(span, "Conflicting types for static"); + span_bug!(self.tcx.def_span(def_id), "Conflicting types for static"); } } let g = self.declare_global(sym, llty); - if !self.tcx.is_reachable_non_generic(def_id) { + if !self.tcx.is_reachable_non_generic(local_def_id) { unsafe { llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden); } @@ -235,12 +237,11 @@ impl CodegenCx<'ll, 'tcx> { Node::ForeignItem(&hir::ForeignItem { ref attrs, - span, kind: hir::ForeignItemKind::Static(..), .. }) => { - let fn_attrs = self.tcx.codegen_fn_attrs(def_id); - (check_and_apply_linkage(&self, &fn_attrs, ty, sym, span), &**attrs) + let fn_attrs = self.tcx.codegen_fn_attrs(local_def_id); + (check_and_apply_linkage(&self, &fn_attrs, ty, sym, def_id), &**attrs) } item => bug!("get_static: expected static, found {:?}", item), @@ -260,8 +261,7 @@ impl CodegenCx<'ll, 'tcx> { debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id)); let attrs = self.tcx.codegen_fn_attrs(def_id); - let span = self.tcx.def_span(def_id); - let g = check_and_apply_linkage(&self, &attrs, ty, sym, span); + let g = check_and_apply_linkage(&self, &attrs, ty, sym, def_id); // Thread-local statics in some other crate need to *always* be linked // against in a thread-local fashion, so we need to be sure to apply the @@ -397,10 +397,8 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { // As an optimization, all shared statics which do not have interior // mutability are placed into read-only memory. - if !is_mutable { - if self.type_is_freeze(ty) { - llvm::LLVMSetGlobalConstant(g, llvm::True); - } + if !is_mutable && self.type_is_freeze(ty) { + llvm::LLVMSetGlobalConstant(g, llvm::True); } debuginfo::create_global_var_metadata(&self, def_id, g); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 56ff580b43b..253e02bd082 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -122,10 +122,10 @@ pub unsafe fn create_module( if llvm_util::get_major_version() < 9 { target_data_layout = strip_function_ptr_alignment(target_data_layout); } - if llvm_util::get_major_version() < 10 { - if sess.target.arch == "x86" || sess.target.arch == "x86_64" { - target_data_layout = strip_x86_address_spaces(target_data_layout); - } + if llvm_util::get_major_version() < 10 + && (sess.target.arch == "x86" || sess.target.arch == "x86_64") + { + target_data_layout = strip_x86_address_spaces(target_data_layout); } // Ensure the data-layout values hardcoded remain the defaults. @@ -864,7 +864,7 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> { // user defined names let mut name = String::with_capacity(prefix.len() + 6); name.push_str(prefix); - name.push_str("."); + name.push('.'); base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name); name } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 73c1f73ec7f..454d43fd4e7 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -29,7 +29,6 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::ich::NodeIdHashingMode; -use rustc_middle::mir::interpret::truncate; use rustc_middle::mir::{self, Field, GeneratorLayout}; use rustc_middle::ty::layout::{self, IntegerExt, PrimitiveExt, TyAndLayout}; use rustc_middle::ty::subst::GenericArgKind; @@ -801,6 +800,7 @@ fn file_metadata_raw( let kind = match hash.kind { rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5, rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1, + rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256, }; (kind, hex_encode(hash.hash_bytes())) } @@ -1692,7 +1692,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { let value = (i.as_u32() as u128) .wrapping_sub(niche_variants.start().as_u32() as u128) .wrapping_add(niche_start); - let value = truncate(value, tag.value.size(cx)); + let value = tag.value.size(cx).truncate(value); // NOTE(eddyb) do *NOT* remove this assert, until // we pass the full 128-bit value to LLVM, otherwise // truncation will be silent and remain undetected. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index beaea49874e..6bb93857d71 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -435,7 +435,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { name_to_append_suffix_to.push('<'); for (i, actual_type) in substs.types().enumerate() { if i != 0 { - name_to_append_suffix_to.push_str(","); + name_to_append_suffix_to.push(','); } let actual_type = diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index daceda20097..8b15c8b0eb6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -558,6 +558,7 @@ pub enum ChecksumKind { None, MD5, SHA1, + SHA256, } extern "C" { diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 4d937609132..afb407b35be 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -46,7 +46,6 @@ use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, EntryFnType}; use rustc_session::utils::NativeLibKind; use rustc_session::Session; -use rustc_span::Span; use rustc_symbol_mangling::test as symbol_names_test; use rustc_target::abi::{Align, LayoutOf, VariantIdx}; @@ -364,11 +363,7 @@ pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, ) -> Option<Bx::Function> { - let (main_def_id, span) = match cx.tcx().entry_fn(LOCAL_CRATE) { - Some((def_id, _)) => (def_id, cx.tcx().def_span(def_id)), - None => return None, - }; - + let main_def_id = cx.tcx().entry_fn(LOCAL_CRATE).map(|(def_id, _)| def_id)?; let instance = Instance::mono(cx.tcx(), main_def_id.to_def_id()); if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) { @@ -381,12 +376,11 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( return cx.tcx().entry_fn(LOCAL_CRATE).map(|(_, et)| { let use_start_lang_item = EntryFnType::Start != et; - create_entry_fn::<Bx>(cx, span, main_llfn, main_def_id, use_start_lang_item) + create_entry_fn::<Bx>(cx, main_llfn, main_def_id, use_start_lang_item) }); fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, - sp: Span, rust_main: Bx::Value, rust_main_def_id: LocalDefId, use_start_lang_item: bool, @@ -411,8 +405,9 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( Some(llfn) => llfn, None => { // FIXME: We should be smart and show a better diagnostic here. + let span = cx.tcx().def_span(rust_main_def_id); cx.sess() - .struct_span_err(sp, "entry symbol `main` declared multiple times") + .struct_span_err(span, "entry symbol `main` declared multiple times") .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead") .emit(); cx.sess().abort_if_errors(); @@ -860,8 +855,6 @@ pub fn provide_both(providers: &mut Providers) { providers.dllimport_foreign_items = |tcx, krate| { let module_map = tcx.foreign_modules(krate); - let module_map = - module_map.iter().map(|lib| (lib.def_id, lib)).collect::<FxHashMap<_, _>>(); let dllimports = tcx .native_libraries(krate) diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 5f42d46e285..1634c586316 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -33,16 +33,31 @@ fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>( result: &mut Vec<G::Node>, visited: &mut IndexVec<G::Node, bool>, ) { + struct PostOrderFrame<Node, Iter> { + node: Node, + iter: Iter, + } + if visited[node] { return; } - visited[node] = true; - for successor in graph.successors(node) { - post_order_walk(graph, successor, result, visited); - } + let mut stack = vec![PostOrderFrame { node, iter: graph.successors(node) }]; + + 'recurse: while let Some(frame) = stack.last_mut() { + let node = frame.node; + visited[node] = true; - result.push(node); + while let Some(successor) = frame.iter.next() { + if !visited[successor] { + stack.push(PostOrderFrame { node: successor, iter: graph.successors(successor) }); + continue 'recurse; + } + } + + let _ = stack.pop(); + result.push(node); + } } pub fn reverse_post_order<G: DirectedGraph + WithSuccessors + WithNumNodes>( diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index 2db8e466e11..486a9ba77b7 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -307,10 +307,7 @@ where fn walk_unvisited_node(&mut self, depth: usize, node: G::Node) -> WalkReturn<S> { debug!("walk_unvisited_node(depth = {:?}, node = {:?})", depth, node); - debug_assert!(match self.node_states[node] { - NodeState::NotVisited => true, - _ => false, - }); + debug_assert!(matches!(self.node_states[node], NodeState::NotVisited)); // Push `node` onto the stack. self.node_states[node] = NodeState::BeingVisited { depth }; diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index fa510e58314..fe8ae7abf98 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -395,7 +395,7 @@ where V: Copy, { fn extend<T: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: T) { - self.extend(iter.into_iter().map(|(k, v)| (k.clone(), v.clone()))) + self.extend(iter.into_iter().map(|(k, v)| (*k, *v))) } #[inline] @@ -451,7 +451,7 @@ impl<'a, K, V> IntoIterator for &'a SsoHashMap<K, V> { fn into_iter(self) -> Self::IntoIter { match self { SsoHashMap::Array(array) => EitherIter::Left(array.into_iter().map(adapt_array_ref_it)), - SsoHashMap::Map(map) => EitherIter::Right(map.into_iter()), + SsoHashMap::Map(map) => EitherIter::Right(map.iter()), } } } @@ -469,7 +469,7 @@ impl<'a, K, V> IntoIterator for &'a mut SsoHashMap<K, V> { fn into_iter(self) -> Self::IntoIter { match self { SsoHashMap::Array(array) => EitherIter::Left(array.into_iter().map(adapt_array_mut_it)), - SsoHashMap::Map(map) => EitherIter::Right(map.into_iter()), + SsoHashMap::Map(map) => EitherIter::Right(map.iter_mut()), } } } diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index d22f3adfb01..26706cd2b1b 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -512,7 +512,7 @@ impl<T: Clone> Clone for Lock<T> { } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct RwLock<T>(InnerRwLock<T>); impl<T> RwLock<T> { diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 29771bee9ae..f434673c39e 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -716,7 +716,7 @@ impl RustcDefaultCalls { TargetList => { let mut targets = rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>(); - targets.sort(); + targets.sort_unstable(); println!("{}", targets.join("\n")); } Sysroot => println!("{}", sess.sysroot.display()), diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index e4dbb8db381..5d8ff601e79 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -13,6 +13,7 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_macros = { path = "../rustc_macros" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_lint_defs = { path = "../rustc_lint_defs" } unicode-width = "0.1.4" atty = "0.2" termcolor = "1.0" diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 265ba59cccb..6f365c07f6d 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -72,6 +72,7 @@ fn annotation_type_for_level(level: Level) -> AnnotationType { Level::Help => AnnotationType::Help, // FIXME(#59346): Not sure how to map these two levels Level::Cancelled | Level::FailureNote => AnnotationType::Error, + Level::Allow => panic!("Should not call with Allow"), } } @@ -143,7 +144,8 @@ impl AnnotateSnippetEmitterWriter { title: Some(Annotation { label: Some(&message), id: code.as_ref().map(|c| match c { - DiagnosticId::Error(val) | DiagnosticId::Lint(val) => val.as_str(), + DiagnosticId::Error(val) + | DiagnosticId::Lint { name: val, has_future_breakage: _ } => val.as_str(), }), annotation_type: annotation_type_for_level(*level), }), diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 91bfc6296b1..decbf03b9de 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,10 +1,10 @@ use crate::snippet::Style; -use crate::Applicability; use crate::CodeSuggestion; use crate::Level; use crate::Substitution; use crate::SubstitutionPart; use crate::SuggestionStyle; +use rustc_lint_defs::Applicability; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use std::fmt; @@ -27,7 +27,7 @@ pub struct Diagnostic { #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] pub enum DiagnosticId { Error(String), - Lint(String), + Lint { name: String, has_future_breakage: bool }, } /// For example a note attached to an error. @@ -107,7 +107,14 @@ impl Diagnostic { match self.level { Level::Bug | Level::Fatal | Level::Error | Level::FailureNote => true, - Level::Warning | Level::Note | Level::Help | Level::Cancelled => false, + Level::Warning | Level::Note | Level::Help | Level::Cancelled | Level::Allow => false, + } + } + + pub fn has_future_breakage(&self) -> bool { + match self.code { + Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage, + _ => false, } } diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index d1ff6f721c4..56acdf699ef 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -1,5 +1,6 @@ -use crate::{Applicability, Handler, Level, StashKey}; use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString}; +use crate::{Handler, Level, StashKey}; +use rustc_lint_defs::Applicability; use rustc_span::{MultiSpan, Span}; use std::fmt::{self, Debug}; diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 08e9bdf3087..302713a21db 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -9,14 +9,15 @@ use Destination::*; +use rustc_lint_defs::FutureBreakage; use rustc_span::source_map::SourceMap; use rustc_span::{MultiSpan, SourceFile, Span}; use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString}; use crate::styled_buffer::StyledBuffer; -use crate::{ - pluralize, CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SuggestionStyle, -}; +use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SuggestionStyle}; + +use rustc_lint_defs::pluralize; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; @@ -192,6 +193,8 @@ pub trait Emitter { /// other formats can, and will, simply ignore it. fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {} + fn emit_future_breakage_report(&mut self, _diags: Vec<(FutureBreakage, Diagnostic)>) {} + /// Checks if should show explanations about "rustc --explain" fn should_show_explain(&self) -> bool { true @@ -296,7 +299,7 @@ pub trait Emitter { // Skip past non-macro entries, just in case there // are some which do actually involve macros. - ExpnKind::Desugaring(..) | ExpnKind::AstPass(..) => None, + ExpnKind::Inlined | ExpnKind::Desugaring(..) | ExpnKind::AstPass(..) => None, ExpnKind::Macro(macro_kind, _) => Some(macro_kind), } @@ -356,7 +359,10 @@ pub trait Emitter { continue; } - if always_backtrace { + if matches!(trace.kind, ExpnKind::Inlined) { + new_labels + .push((trace.call_site, "in the inlined copy of this code".to_string())); + } else if always_backtrace { new_labels.push(( trace.def_site, format!( diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 750d36d3d89..d57beb1148a 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -13,8 +13,9 @@ use rustc_span::source_map::{FilePathMapping, SourceMap}; use crate::emitter::{Emitter, HumanReadableErrorType}; use crate::registry::Registry; -use crate::{Applicability, DiagnosticId}; +use crate::DiagnosticId; use crate::{CodeSuggestion, SubDiagnostic}; +use rustc_lint_defs::{Applicability, FutureBreakage}; use rustc_data_structures::sync::Lrc; use rustc_span::hygiene::ExpnData; @@ -131,15 +132,37 @@ impl Emitter for JsonEmitter { } } + fn emit_future_breakage_report(&mut self, diags: Vec<(FutureBreakage, crate::Diagnostic)>) { + let data: Vec<FutureBreakageItem> = diags + .into_iter() + .map(|(breakage, mut diag)| { + if diag.level == crate::Level::Allow { + diag.level = crate::Level::Warning; + } + FutureBreakageItem { + future_breakage_date: breakage.date, + diagnostic: Diagnostic::from_errors_diagnostic(&diag, self), + } + }) + .collect(); + let report = FutureIncompatReport { future_incompat_report: data }; + let result = if self.pretty { + writeln!(&mut self.dst, "{}", as_pretty_json(&report)) + } else { + writeln!(&mut self.dst, "{}", as_json(&report)) + } + .and_then(|_| self.dst.flush()); + if let Err(e) = result { + panic!("failed to print future breakage report: {:?}", e); + } + } + fn source_map(&self) -> Option<&Lrc<SourceMap>> { Some(&self.sm) } fn should_show_explain(&self) -> bool { - match self.json_rendered { - HumanReadableErrorType::Short(_) => false, - _ => true, - } + !matches!(self.json_rendered, HumanReadableErrorType::Short(_)) } } @@ -226,6 +249,17 @@ struct ArtifactNotification<'a> { emit: &'a str, } +#[derive(Encodable)] +struct FutureBreakageItem { + future_breakage_date: Option<&'static str>, + diagnostic: Diagnostic, +} + +#[derive(Encodable)] +struct FutureIncompatReport { + future_incompat_report: Vec<FutureBreakageItem>, +} + impl Diagnostic { fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic { let sugg = diag.suggestions.iter().map(|sugg| Diagnostic { @@ -435,7 +469,7 @@ impl DiagnosticCode { s.map(|s| { let s = match s { DiagnosticId::Error(s) => s, - DiagnosticId::Lint(s) => s, + DiagnosticId::Lint { name, has_future_breakage: _ } => name, }; let je_result = je.registry.as_ref().map(|registry| registry.try_find_description(&s)).unwrap(); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 2e8a4ef327a..593e0d92031 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -21,6 +21,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::{self, Lock, Lrc}; use rustc_data_structures::AtomicRef; +use rustc_lint_defs::FutureBreakage; +pub use rustc_lint_defs::{pluralize, Applicability}; use rustc_span::source_map::SourceMap; use rustc_span::{Loc, MultiSpan, Span}; @@ -49,30 +51,6 @@ pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>; #[cfg(target_arch = "x86_64")] rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16); -/// Indicates the confidence in the correctness of a suggestion. -/// -/// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion -/// to determine whether it should be automatically applied or if the user should be consulted -/// before applying the suggestion. -#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)] -pub enum Applicability { - /// The suggestion is definitely what the user intended. This suggestion should be - /// automatically applied. - MachineApplicable, - - /// The suggestion may be what the user intended, but it is uncertain. The suggestion should - /// result in valid Rust code if it is applied. - MaybeIncorrect, - - /// The suggestion contains placeholders like `(...)` or `{ /* fields */ }`. The suggestion - /// cannot be applied automatically because it will not result in valid Rust code. The user - /// will need to fill in the placeholders. - HasPlaceholders, - - /// The applicability of the suggestion is unknown. - Unspecified, -} - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)] pub enum SuggestionStyle { /// Hide the suggested code when displaying this suggestion inline. @@ -91,10 +69,7 @@ pub enum SuggestionStyle { impl SuggestionStyle { fn hide_inline(&self) -> bool { - match *self { - SuggestionStyle::ShowCode => false, - _ => true, - } + !matches!(*self, SuggestionStyle::ShowCode) } } @@ -324,6 +299,8 @@ struct HandlerInner { /// The warning count, used for a recap upon finishing deduplicated_warn_count: usize, + + future_breakage_diagnostics: Vec<Diagnostic>, } /// A key denoting where from a diagnostic was stashed. @@ -437,6 +414,7 @@ impl Handler { emitted_diagnostic_codes: Default::default(), emitted_diagnostics: Default::default(), stashed_diagnostics: Default::default(), + future_breakage_diagnostics: Vec::new(), }), } } @@ -506,6 +484,17 @@ impl Handler { result } + /// Construct a builder at the `Allow` level at the given `span` and with the `msg`. + pub fn struct_span_allow( + &self, + span: impl Into<MultiSpan>, + msg: &str, + ) -> DiagnosticBuilder<'_> { + let mut result = self.struct_allow(msg); + result.set_span(span); + result + } + /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. /// Also include a code. pub fn struct_span_warn_with_code( @@ -528,6 +517,11 @@ impl Handler { result } + /// Construct a builder at the `Allow` level with the `msg`. + pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_> { + DiagnosticBuilder::new(self, Level::Allow, msg) + } + /// Construct a builder at the `Error` level at the given `span` and with the `msg`. pub fn struct_span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> { let mut result = self.struct_err(msg); @@ -696,6 +690,10 @@ impl Handler { self.inner.borrow_mut().print_error_count(registry) } + pub fn take_future_breakage_diagnostics(&self) -> Vec<Diagnostic> { + std::mem::take(&mut self.inner.borrow_mut().future_breakage_diagnostics) + } + pub fn abort_if_errors(&self) { self.inner.borrow_mut().abort_if_errors() } @@ -726,6 +724,10 @@ impl Handler { self.inner.borrow_mut().emit_artifact_notification(path, artifact_type) } + pub fn emit_future_breakage_report(&self, diags: Vec<(FutureBreakage, Diagnostic)>) { + self.inner.borrow_mut().emitter.emit_future_breakage_report(diags) + } + pub fn delay_as_bug(&self, diagnostic: Diagnostic) { self.inner.borrow_mut().delay_as_bug(diagnostic) } @@ -751,12 +753,23 @@ impl HandlerInner { return; } + if diagnostic.has_future_breakage() { + self.future_breakage_diagnostics.push(diagnostic.clone()); + } + if diagnostic.level == Warning && !self.flags.can_emit_warnings { + if diagnostic.has_future_breakage() { + (*TRACK_DIAGNOSTICS)(diagnostic); + } return; } (*TRACK_DIAGNOSTICS)(diagnostic); + if diagnostic.level == Allow { + return; + } + if let Some(ref code) = diagnostic.code { self.emitted_diagnostic_codes.insert(code.clone()); } @@ -995,6 +1008,7 @@ pub enum Level { Help, Cancelled, FailureNote, + Allow, } impl fmt::Display for Level { @@ -1020,7 +1034,7 @@ impl Level { spec.set_fg(Some(Color::Cyan)).set_intense(true); } FailureNote => {} - Cancelled => unreachable!(), + Allow | Cancelled => unreachable!(), } spec } @@ -1034,22 +1048,55 @@ impl Level { Help => "help", FailureNote => "failure-note", Cancelled => panic!("Shouldn't call on cancelled error"), + Allow => panic!("Shouldn't call on allowed error"), } } pub fn is_failure_note(&self) -> bool { - match *self { - FailureNote => true, - _ => false, - } + matches!(*self, FailureNote) } } -#[macro_export] -macro_rules! pluralize { - ($x:expr) => { - if $x != 1 { "s" } else { "" } +pub fn add_elided_lifetime_in_path_suggestion( + source_map: &SourceMap, + db: &mut DiagnosticBuilder<'_>, + n: usize, + path_span: Span, + incl_angl_brckt: bool, + insertion_span: Span, + anon_lts: String, +) { + let (replace_span, suggestion) = if incl_angl_brckt { + (insertion_span, anon_lts) + } else { + // When possible, prefer a suggestion that replaces the whole + // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, ` + // at a point (which makes for an ugly/confusing label) + if let Ok(snippet) = source_map.span_to_snippet(path_span) { + // But our spans can get out of whack due to macros; if the place we think + // we want to insert `'_` isn't even within the path expression's span, we + // should bail out of making any suggestion rather than panicking on a + // subtract-with-overflow or string-slice-out-out-bounds (!) + // FIXME: can we do better? + if insertion_span.lo().0 < path_span.lo().0 { + return; + } + let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize; + if insertion_index > snippet.len() { + return; + } + let (before, after) = snippet.split_at(insertion_index); + (path_span, format!("{}{}{}", before, anon_lts, after)) + } else { + (insertion_span, anon_lts) + } }; + db.span_suggestion( + replace_span, + &format!("indicate the anonymous lifetime{}", pluralize!(n)), + suggestion, + Applicability::MachineApplicable, + ); } // Useful type to use with `Result<>` indicate that an error has already diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs index fae5b94b3a8..dbb2523f286 100644 --- a/compiler/rustc_errors/src/snippet.rs +++ b/compiler/rustc_errors/src/snippet.rs @@ -158,10 +158,7 @@ impl Annotation { pub fn takes_space(&self) -> bool { // Multiline annotations always have to keep vertical space. - match self.annotation_type { - AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_) => true, - _ => false, - } + matches!(self.annotation_type, AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_)) } } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b0e43a260e9..b435def87ac 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -793,7 +793,7 @@ impl SyntaxExtension { allow_internal_unsafe: sess.contains_name(attrs, sym::allow_internal_unsafe), local_inner_macros, stability, - deprecation: attr::find_deprecation(&sess, attrs, span), + deprecation: attr::find_deprecation(&sess, attrs).map(|(d, _)| d), helper_attrs, edition, is_builtin, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 3551b92967c..c124ab64218 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -4,12 +4,11 @@ use rustc_ast::attr::HasAttrs; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::token::{DelimToken, Token, TokenKind}; -use rustc_ast::tokenstream::{DelimSpan, LazyTokenStreamInner, Spacing, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{DelimSpan, LazyTokenStream, Spacing, TokenStream, TokenTree}; use rustc_ast::{self as ast, AttrItem, Attribute, MetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::map_in_place::MapInPlace; -use rustc_data_structures::sync::Lrc; use rustc_errors::{error_code, struct_span_err, Applicability, Handler}; use rustc_feature::{Feature, Features, State as FeatureState}; use rustc_feature::{ @@ -303,7 +302,7 @@ impl<'a> StripUnconfigured<'a> { // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token // for `attr` when we expand it to `#[attr]` - let pound_token = orig_tokens.into_token_stream().trees().next().unwrap(); + let pound_token = orig_tokens.create_token_stream().trees().next().unwrap(); if !matches!(pound_token, TokenTree::Token(Token { kind: TokenKind::Pound, .. })) { panic!("Bad tokens for attribute {:?}", attr); } @@ -313,16 +312,16 @@ impl<'a> StripUnconfigured<'a> { DelimSpan::from_single(pound_token.span()), DelimToken::Bracket, item.tokens - .clone() + .as_ref() .unwrap_or_else(|| panic!("Missing tokens for {:?}", item)) - .into_token_stream(), + .create_token_stream(), ); let mut attr = attr::mk_attr_from_item(attr.style, item, span); - attr.tokens = Some(Lrc::new(LazyTokenStreamInner::Ready(TokenStream::new(vec![ + attr.tokens = Some(LazyTokenStream::new(TokenStream::new(vec![ (pound_token, Spacing::Alone), (bracket_group, Spacing::Alone), - ])))); + ]))); self.process_cfg_attr(attr) }) .collect() diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs index 9aed307ec93..eb4aab116f0 100644 --- a/compiler/rustc_expand/src/mbe.rs +++ b/compiler/rustc_expand/src/mbe.rs @@ -102,10 +102,7 @@ impl TokenTree { /// Returns `true` if the given token tree is delimited. fn is_delimited(&self) -> bool { - match *self { - TokenTree::Delimited(..) => true, - _ => false, - } + matches!(*self, TokenTree::Delimited(..)) } /// Returns `true` if the given token tree is a token of the given kind. diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 6b419dae3f6..91add4f9218 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -134,10 +134,7 @@ enum Stack<'a, T> { impl<'a, T> Stack<'a, T> { /// Returns whether a stack is empty. fn is_empty(&self) -> bool { - match *self { - Stack::Empty => true, - _ => false, - } + matches!(*self, Stack::Empty) } /// Returns a new stack with an element of top. diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 791d2686cb5..a074af0189a 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -1036,17 +1036,16 @@ fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool { /// a fragment specifier (indeed, these fragments can be followed by /// ANYTHING without fear of future compatibility hazards). fn frag_can_be_followed_by_any(kind: NonterminalKind) -> bool { - match kind { + matches!( + kind, NonterminalKind::Item // always terminated by `}` or `;` | NonterminalKind::Block // exactly one token tree | NonterminalKind::Ident // exactly one token tree | NonterminalKind::Literal // exactly one token tree | NonterminalKind::Meta // exactly one token tree | NonterminalKind::Lifetime // exactly one token tree - | NonterminalKind::TT => true, // exactly one token tree - - _ => false, - } + | NonterminalKind::TT // exactly one token tree + ) } enum IsInFollow { diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 0e5c5fe4d44..629e0e702b6 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -20,6 +20,10 @@ use std::mem; struct Marker(ExpnId, Transparency); impl MutVisitor for Marker { + fn token_visiting_enabled(&self) -> bool { + true + } + fn visit_span(&mut self, span: &mut Span) { *span = span.apply_mark(self.0, self.1) } @@ -232,17 +236,19 @@ pub(super) fn transcribe<'a>( // the meta-var. let ident = MacroRulesNormalizedIdent::new(orignal_ident); if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { - if let MatchedNonterminal(ref nt) = cur_matched { - // FIXME #2887: why do we apply a mark when matching a token tree meta-var - // (e.g. `$x:tt`), but not when we are matching any other type of token - // tree? - if let NtTT(ref tt) = **nt { - result.push(tt.clone().into()); + if let MatchedNonterminal(nt) = cur_matched { + let token = if let NtTT(tt) = &**nt { + // `tt`s are emitted into the output stream directly as "raw tokens", + // without wrapping them into groups. + tt.clone() } else { + // Other variables are emitted into the output stream as groups with + // `Delimiter::None` to maintain parsing priorities. + // `Interpolated` is currenty used for such groups in rustc parser. marker.visit_span(&mut sp); - let token = TokenTree::token(token::Interpolated(nt.clone()), sp); - result.push(token.into()); - } + TokenTree::token(token::Interpolated(nt.clone()), sp) + }; + result.push(token.into()); } else { // We were unable to descend far enough. This is an error. return Err(cx.struct_span_err( @@ -275,7 +281,7 @@ pub(super) fn transcribe<'a>( // preserve syntax context. mbe::TokenTree::Token(token) => { let mut tt = TokenTree::Token(token); - marker.visit_tt(&mut tt); + mut_visit::visit_tt(&mut tt, &mut marker); result.push(tt.into()); } diff --git a/compiler/rustc_expand/src/mut_visit/tests.rs b/compiler/rustc_expand/src/mut_visit/tests.rs index 38ff594b6e9..9e65fc2eca7 100644 --- a/compiler/rustc_expand/src/mut_visit/tests.rs +++ b/compiler/rustc_expand/src/mut_visit/tests.rs @@ -15,6 +15,9 @@ fn fake_print_crate(s: &mut pprust::State<'_>, krate: &ast::Crate) { struct ToZzIdentMutVisitor; impl MutVisitor for ToZzIdentMutVisitor { + fn token_visiting_enabled(&self) -> bool { + true + } fn visit_ident(&mut self, ident: &mut Ident) { *ident = Ident::from_str("zz"); } diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 4c9271a58df..0cffca17271 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -310,8 +310,44 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { }; if style == ast::MacStmtStyle::Semicolon { + // Implement the proposal described in + // https://github.com/rust-lang/rust/issues/61733#issuecomment-509626449 + // + // The macro invocation expands to the list of statements. + // If the list of statements is empty, then 'parse' + // the trailing semicolon on the original invocation + // as an empty statement. That is: + // + // `empty();` is parsed as a single `StmtKind::Empty` + // + // If the list of statements is non-empty, see if the + // final statement alreayd has a trailing semicolon. + // + // If it doesn't have a semicolon, then 'parse' the trailing semicolon + // from the invocation as part of the final statement, + // using `stmt.add_trailing_semicolon()` + // + // If it does have a semicolon, then 'parse' the trailing semicolon + // from the invocation as a new StmtKind::Empty + + // FIXME: We will need to preserve the original + // semicolon token and span as part of #15701 + let empty_stmt = ast::Stmt { + id: ast::DUMMY_NODE_ID, + kind: ast::StmtKind::Empty, + span: DUMMY_SP, + tokens: None, + }; + if let Some(stmt) = stmts.pop() { - stmts.push(stmt.add_trailing_semicolon()); + if stmt.has_trailing_semicolon() { + stmts.push(stmt); + stmts.push(empty_stmt); + } else { + stmts.push(stmt.add_trailing_semicolon()); + } + } else { + stmts.push(empty_stmt); } } @@ -345,10 +381,10 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { fn visit_mod(&mut self, module: &mut ast::Mod) { noop_visit_mod(module, self); - module.items.retain(|item| match item.kind { - ast::ItemKind::MacCall(_) if !self.cx.ecfg.keep_macs => false, // remove macro definitions - _ => true, - }); + // remove macro definitions + module.items.retain( + |item| !matches!(item.kind, ast::ItemKind::MacCall(_) if !self.cx.ecfg.keep_macs), + ); } fn visit_mac(&mut self, _mac: &mut ast::MacCall) { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index f73363cbccc..57ae534590d 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -83,10 +83,7 @@ impl std::fmt::Debug for AttributeGate { impl AttributeGate { fn is_deprecated(&self) -> bool { - match *self { - Self::Gated(Stability::Deprecated(_, _), ..) => true, - _ => false, - } + matches!(*self, Self::Gated(Stability::Deprecated(_, _), ..)) } } diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 76e33bed97f..d332466160c 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -653,13 +653,13 @@ where writeln!(w, r#" edge[{}];"#, content_attrs_str)?; } + let mut text = Vec::new(); for n in g.nodes().iter() { write!(w, " ")?; let id = g.node_id(n); let escaped = &g.node_label(n).to_dot_string(); - let mut text = Vec::new(); write!(text, "{}", id.as_slice()).unwrap(); if !options.contains(&RenderOption::NoNodeLabels) { @@ -677,6 +677,8 @@ where writeln!(text, ";").unwrap(); w.write_all(&text[..])?; + + text.clear(); } for e in g.edges().iter() { @@ -687,7 +689,6 @@ where let source_id = g.node_id(&source); let target_id = g.node_id(&target); - let mut text = Vec::new(); write!(text, "{} -> {}", source_id.as_slice(), target_id.as_slice()).unwrap(); if !options.contains(&RenderOption::NoEdgeLabels) { @@ -701,6 +702,8 @@ where writeln!(text, ";").unwrap(); w.write_all(&text[..])?; + + text.clear(); } writeln!(w, "}}") diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index fc15bb324c1..b9ec18688c5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -272,10 +272,7 @@ impl GenericArg<'_> { } pub fn is_const(&self) -> bool { - match self { - GenericArg::Const(_) => true, - _ => false, - } + matches!(self, GenericArg::Const(_)) } pub fn descr(&self) -> &'static str { @@ -980,17 +977,11 @@ impl BinOpKind { } pub fn is_lazy(self) -> bool { - match self { - BinOpKind::And | BinOpKind::Or => true, - _ => false, - } + matches!(self, BinOpKind::And | BinOpKind::Or) } pub fn is_shift(self) -> bool { - match self { - BinOpKind::Shl | BinOpKind::Shr => true, - _ => false, - } + matches!(self, BinOpKind::Shl | BinOpKind::Shr) } pub fn is_comparison(self) -> bool { @@ -1070,10 +1061,7 @@ impl UnOp { /// Returns `true` if the unary operator takes its argument by value. pub fn is_by_value(self) -> bool { - match self { - Self::UnNeg | Self::UnNot => true, - _ => false, - } + matches!(self, Self::UnNeg | Self::UnNot) } } @@ -1409,10 +1397,9 @@ impl Expr<'_> { /// on the given expression should be considered a place expression. pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool { match self.kind { - ExprKind::Path(QPath::Resolved(_, ref path)) => match path.res { - Res::Local(..) | Res::Def(DefKind::Static, _) | Res::Err => true, - _ => false, - }, + ExprKind::Path(QPath::Resolved(_, ref path)) => { + matches!(path.res, Res::Local(..) | Res::Def(DefKind::Static, _) | Res::Err) + } // Type ascription inherits its place expression kind from its // operand. See: @@ -2204,10 +2191,7 @@ pub enum ImplicitSelfKind { impl ImplicitSelfKind { /// Does this represent an implicit self? pub fn has_implicit_self(&self) -> bool { - match *self { - ImplicitSelfKind::None => false, - _ => true, - } + !matches!(*self, ImplicitSelfKind::None) } } @@ -2237,10 +2221,7 @@ impl Defaultness { } pub fn is_default(&self) -> bool { - match *self { - Defaultness::Default { .. } => true, - _ => false, - } + matches!(*self, Defaultness::Default { .. }) } } @@ -2371,10 +2352,7 @@ pub enum VisibilityKind<'hir> { impl VisibilityKind<'_> { pub fn is_pub(&self) -> bool { - match *self { - VisibilityKind::Public => true, - _ => false, - } + matches!(*self, VisibilityKind::Public) } pub fn is_pub_restricted(&self) -> bool { @@ -2502,10 +2480,7 @@ pub struct FnHeader { impl FnHeader { pub fn is_const(&self) -> bool { - match &self.constness { - Constness::Const => true, - _ => false, - } + matches!(&self.constness, Constness::Const) } } diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index c05d3e44423..9e0a6aae242 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -92,10 +92,7 @@ impl hir::Pat<'_> { /// Checks if the pattern contains any patterns that bind something to /// an ident, e.g., `foo`, or `Foo(foo)` or `foo @ Bar(..)`. pub fn contains_bindings(&self) -> bool { - self.satisfies(|p| match p.kind { - PatKind::Binding(..) => true, - _ => false, - }) + self.satisfies(|p| matches!(p.kind, PatKind::Binding(..))) } /// Checks if the pattern satisfies the given predicate on some sub-pattern. diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 1cd4ddad578..f7018ae62aa 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -299,13 +299,11 @@ impl<'a> State<'a> { pub fn break_offset_if_not_bol(&mut self, n: usize, off: isize) { if !self.s.is_beginning_of_line() { self.s.break_offset(n, off) - } else { - if off != 0 && self.s.last_token().is_hardbreak_tok() { - // We do something pretty sketchy here: tuck the nonzero - // offset-adjustment we were going to deposit along with the - // break into the previous hardbreak. - self.s.replace_last_token(pp::Printer::hardbreak_tok_offset(off)); - } + } else if off != 0 && self.s.last_token().is_hardbreak_tok() { + // We do something pretty sketchy here: tuck the nonzero + // offset-adjustment we were going to deposit along with the + // break into the previous hardbreak. + self.s.replace_last_token(pp::Printer::hardbreak_tok_offset(off)); } } @@ -1921,10 +1919,7 @@ impl<'a> State<'a> { self.pclose(); } PatKind::Box(ref inner) => { - let is_range_inner = match inner.kind { - PatKind::Range(..) => true, - _ => false, - }; + let is_range_inner = matches!(inner.kind, PatKind::Range(..)); self.s.word("box "); if is_range_inner { self.popen(); @@ -1935,10 +1930,7 @@ impl<'a> State<'a> { } } PatKind::Ref(ref inner, mutbl) => { - let is_range_inner = match inner.kind { - PatKind::Range(..) => true, - _ => false, - }; + let is_range_inner = matches!(inner.kind, PatKind::Range(..)); self.s.word("&"); self.s.word(mutbl.prefix_str()); if is_range_inner { @@ -2435,10 +2427,7 @@ impl<'a> State<'a> { // // Duplicated from `parse::classify`, but adapted for the HIR. fn expr_requires_semi_to_be_stmt(e: &hir::Expr<'_>) -> bool { - match e.kind { - hir::ExprKind::Match(..) | hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) => false, - _ => true, - } + !matches!(e.kind, hir::ExprKind::Match(..) | hir::ExprKind::Block(..) | hir::ExprKind::Loop(..)) } /// This statement requires a semicolon after it. diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs index 80448c01a26..17d8ac9c882 100644 --- a/compiler/rustc_incremental/src/assert_module_sources.rs +++ b/compiler/rustc_incremental/src/assert_module_sources.rs @@ -111,10 +111,12 @@ impl AssertModuleSource<'tcx> { (&user_path[..], None) }; - let mut cgu_path_components = user_path.split('-').collect::<Vec<_>>(); + let mut iter = user_path.split('-'); // Remove the crate name - assert_eq!(cgu_path_components.remove(0), crate_name); + assert_eq!(iter.next().unwrap(), crate_name); + + let cgu_path_components = iter.collect::<Vec<_>>(); let cgu_name_builder = &mut CodegenUnitNameBuilder::new(self.tcx); let cgu_name = diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index f0a10885550..d55813f4cc5 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -160,7 +160,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { let mut all_attrs = FindAllAttrs { tcx, - attr_names: vec![sym::rustc_dirty, sym::rustc_clean], + attr_names: &[sym::rustc_dirty, sym::rustc_clean], found_attrs: vec![], }; intravisit::walk_crate(&mut all_attrs, krate); @@ -299,7 +299,7 @@ impl DirtyCleanVisitor<'tcx> { // Represents a Trait Declaration // FIXME(michaelwoerister): trait declaration is buggy because sometimes some of - // the depnodes don't exist (because they legitametely didn't need to be + // the depnodes don't exist (because they legitimately didn't need to be // calculated) // // michaelwoerister and vitiral came up with a possible solution, @@ -512,17 +512,17 @@ fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol { } // A visitor that collects all #[rustc_dirty]/#[rustc_clean] attributes from -// the HIR. It is used to verfiy that we really ran checks for all annotated +// the HIR. It is used to verify that we really ran checks for all annotated // nodes. -pub struct FindAllAttrs<'tcx> { +pub struct FindAllAttrs<'a, 'tcx> { tcx: TyCtxt<'tcx>, - attr_names: Vec<Symbol>, + attr_names: &'a [Symbol], found_attrs: Vec<&'tcx Attribute>, } -impl FindAllAttrs<'tcx> { +impl FindAllAttrs<'_, 'tcx> { fn is_active_attr(&mut self, attr: &Attribute) -> bool { - for attr_name in &self.attr_names { + for attr_name in self.attr_names { if self.tcx.sess.check_name(attr, *attr_name) && check_config(self.tcx, attr) { return true; } @@ -543,7 +543,7 @@ impl FindAllAttrs<'tcx> { } } -impl intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> { +impl intravisit::Visitor<'tcx> for FindAllAttrs<'_, 'tcx> { type Map = Map<'tcx>; fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> { diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 4926f726f35..9fdf0a56d9d 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -765,7 +765,6 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { // Now garbage collect the valid session directories. let mut deletion_candidates = vec![]; - let mut definitely_delete = vec![]; for (lock_file_name, directory_name) in &lock_file_to_session_dir { debug!("garbage_collect_session_directories() - inspecting: {}", directory_name); @@ -842,8 +841,11 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { successfully acquired lock" ); - // Note that we are holding on to the lock - definitely_delete.push((crate_directory.join(directory_name), Some(lock))); + delete_old(sess, &crate_directory.join(directory_name)); + + // Let's make it explicit that the file lock is released at this point, + // or rather, that we held on to it until here + mem::drop(lock); } Err(_) => { debug!( @@ -880,26 +882,21 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { mem::drop(lock); } - for (path, lock) in definitely_delete { - debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); + Ok(()) +} - if let Err(err) = safe_remove_dir_all(&path) { - sess.warn(&format!( - "Failed to garbage collect incremental \ - compilation session directory `{}`: {}", - path.display(), - err - )); - } else { - delete_session_dir_lock_file(sess, &lock_file_path(&path)); - } +fn delete_old(sess: &Session, path: &Path) { + debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); - // Let's make it explicit that the file lock is released at this point, - // or rather, that we held on to it until here - mem::drop(lock); + if let Err(err) = safe_remove_dir_all(&path) { + sess.warn(&format!( + "Failed to garbage collect incremental compilation session directory `{}`: {}", + path.display(), + err + )); + } else { + delete_session_dir_lock_file(sess, &lock_file_path(&path)); } - - Ok(()) } fn all_except_most_recent( diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index c43d4ad4049..45cef479a4f 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -153,7 +153,8 @@ fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) { let total_node_count = serialized_graph.nodes.len(); let total_edge_count = serialized_graph.edge_list_data.len(); - let mut counts: FxHashMap<_, Stat> = FxHashMap::default(); + let mut counts: FxHashMap<_, Stat> = + FxHashMap::with_capacity_and_hasher(total_node_count, Default::default()); for (i, &node) in serialized_graph.nodes.iter_enumerated() { let stat = counts.entry(node.kind).or_insert(Stat { @@ -170,14 +171,6 @@ fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) { let mut counts: Vec<_> = counts.values().cloned().collect(); counts.sort_by_key(|s| -(s.node_counter as i64)); - let percentage_of_all_nodes: Vec<f64> = counts - .iter() - .map(|s| (100.0 * (s.node_counter as f64)) / (total_node_count as f64)) - .collect(); - - let average_edges_per_kind: Vec<f64> = - counts.iter().map(|s| (s.edge_counter as f64) / (s.node_counter as f64)).collect(); - println!("[incremental]"); println!("[incremental] DepGraph Statistics"); @@ -207,13 +200,13 @@ fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) { |------------------|" ); - for (i, stat) in counts.iter().enumerate() { + for stat in counts.iter() { println!( "[incremental] {:<36}|{:>16.1}% |{:>12} |{:>17.1} |", format!("{:?}", stat.kind), - percentage_of_all_nodes[i], + (100.0 * (stat.node_counter as f64)) / (total_node_count as f64), // percentage of all nodes stat.node_counter, - average_edges_per_kind[i] + (stat.edge_counter as f64) / (stat.node_counter as f64), // average edges per kind ); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 1402f70c220..524efd04cfc 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -71,6 +71,7 @@ use rustc_middle::ty::{ }; use rustc_span::{BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; +use std::ops::ControlFlow; use std::{cmp, fmt}; mod note; @@ -1497,7 +1498,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { if let Some((kind, def_id)) = TyCategory::from_ty(t) { let span = self.tcx.def_span(def_id); // Avoid cluttering the output when the "found" and error span overlap: diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 21023a06bb2..868989539d4 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -739,7 +739,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "cannot infer {} {} {} `{}`{}", kind_str, preposition, descr, type_name, parent_desc ) - .into() } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index e9d5ebad7de..df3dbfca01d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -15,6 +15,8 @@ use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, T use rustc_span::symbol::Ident; use rustc_span::{MultiSpan, Span}; +use std::ops::ControlFlow; + impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the return type is a static `impl Trait`, /// `dyn Trait` or if a method call on a trait object introduces a static requirement. @@ -472,13 +474,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { struct TraitObjectVisitor(Vec<DefId>); impl TypeVisitor<'_> for TraitObjectVisitor { - fn visit_ty(&mut self, t: Ty<'_>) -> bool { + fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<()> { match t.kind() { ty::Dynamic(preds, RegionKind::ReStatic) => { if let Some(def_id) = preds.principal_def_id() { self.0.push(def_id); } - false + ControlFlow::CONTINUE } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index abdd6edea90..9b2ffc7a920 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -30,6 +30,7 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use std::fmt::Debug; +use std::ops::ControlFlow; #[derive(PartialEq)] pub enum NormalizationStrategy { @@ -740,15 +741,15 @@ struct ScopeInstantiator<'me, 'tcx> { } impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool { + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ControlFlow<()> { self.target_index.shift_in(1); t.super_visit_with(self); self.target_index.shift_out(1); - false + ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { let ScopeInstantiator { bound_region_scope, next_region, .. } = self; match r { @@ -759,7 +760,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { _ => {} } - false + ControlFlow::CONTINUE } } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 337772d70b8..fe4ba5aa4e8 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -3,6 +3,8 @@ use super::{FixupError, FixupResult, InferCtxt, Span}; use rustc_middle::ty::fold::{TypeFolder, TypeVisitor}; use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; +use std::ops::ControlFlow; + /////////////////////////////////////////////////////////////////////////// // OPPORTUNISTIC VAR RESOLVER @@ -121,7 +123,7 @@ impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { if let ty::Infer(infer_ty) = *t.kind() { @@ -143,7 +145,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { None }; self.first_unresolved = Some((t, ty_var_span)); - true // Halt visiting. + ControlFlow::BREAK } else { // Otherwise, visit its contents. t.super_visit_with(self) @@ -151,7 +153,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { } else { // All type variables in inference types must already be resolved, // - no need to visit the contents, continue visiting. - false + ControlFlow::CONTINUE } } } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index ea9a4661348..3690a88c0d9 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -22,6 +22,7 @@ #![feature(never_type)] #![feature(or_patterns)] #![feature(in_band_lifetimes)] +#![feature(control_flow_enum)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index c48e58c0482..1a1c2637a6f 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -4,6 +4,7 @@ use rustc_middle::ty; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use std::fmt; +use std::ops::ControlFlow; // Structural impls for the structs in `traits`. @@ -68,7 +69,7 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { self.predicate.visit_with(visitor) } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 9dbd59506b1..548b6c03daa 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -2,9 +2,8 @@ use crate::interface::{Compiler, Result}; use crate::proc_macro_decls; use crate::util; -use rustc_ast::mut_visit::{self, MutVisitor}; -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, token, visit}; +use rustc_ast::mut_visit::MutVisitor; +use rustc_ast::{self as ast, visit}; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal}; @@ -37,7 +36,6 @@ use rustc_span::symbol::Symbol; use rustc_span::{FileName, RealFileName}; use rustc_trait_selection::traits; use rustc_typeck as typeck; -use smallvec::SmallVec; use tracing::{info, warn}; use rustc_serialize::json; @@ -52,71 +50,6 @@ use std::path::PathBuf; use std::rc::Rc; use std::{env, fs, iter, mem}; -/// Remove alls `LazyTokenStreams` from an AST struct -/// Normally, this is done during AST lowering. However, -/// printing the AST JSON requires us to serialize -/// the entire AST, and we don't want to serialize -/// a `LazyTokenStream`. -struct TokenStripper; -impl mut_visit::MutVisitor for TokenStripper { - fn flat_map_item(&mut self, mut i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> { - i.tokens = None; - mut_visit::noop_flat_map_item(i, self) - } - fn flat_map_foreign_item( - &mut self, - mut i: P<ast::ForeignItem>, - ) -> SmallVec<[P<ast::ForeignItem>; 1]> { - i.tokens = None; - mut_visit::noop_flat_map_foreign_item(i, self) - } - fn visit_block(&mut self, b: &mut P<ast::Block>) { - b.tokens = None; - mut_visit::noop_visit_block(b, self); - } - fn flat_map_stmt(&mut self, mut stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { - stmt.tokens = None; - mut_visit::noop_flat_map_stmt(stmt, self) - } - fn visit_pat(&mut self, p: &mut P<ast::Pat>) { - p.tokens = None; - mut_visit::noop_visit_pat(p, self); - } - fn visit_ty(&mut self, ty: &mut P<ast::Ty>) { - ty.tokens = None; - mut_visit::noop_visit_ty(ty, self); - } - fn visit_attribute(&mut self, attr: &mut ast::Attribute) { - attr.tokens = None; - if let ast::AttrKind::Normal(ast::AttrItem { tokens, .. }) = &mut attr.kind { - *tokens = None; - } - mut_visit::noop_visit_attribute(attr, self); - } - - fn visit_interpolated(&mut self, nt: &mut token::Nonterminal) { - if let token::Nonterminal::NtMeta(meta) = nt { - meta.tokens = None; - } - // Handles all of the other cases - mut_visit::noop_visit_interpolated(nt, self); - } - - fn visit_path(&mut self, p: &mut ast::Path) { - p.tokens = None; - mut_visit::noop_visit_path(p, self); - } - fn visit_vis(&mut self, vis: &mut ast::Visibility) { - vis.tokens = None; - mut_visit::noop_visit_vis(vis, self); - } - fn visit_expr(&mut self, e: &mut P<ast::Expr>) { - e.tokens = None; - mut_visit::noop_visit_expr(e, self); - } - fn visit_mac(&mut self, _mac: &mut ast::MacCall) {} -} - pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { let krate = sess.time("parse_crate", || match input { Input::File(file) => parse_crate_from_file(file, &sess.parse_sess), @@ -126,10 +59,6 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { })?; if sess.opts.debugging_opts.ast_json_noexpand { - // Set any `token` fields to `None` before - // we display the AST. - let mut krate = krate.clone(); - TokenStripper.visit_crate(&mut krate); println!("{}", json::as_json(&krate)); } @@ -275,7 +204,10 @@ pub fn register_plugins<'a>( } }); - Ok((krate, Lrc::new(lint_store))) + let lint_store = Lrc::new(lint_store); + sess.init_lint_store(lint_store.clone()); + + Ok((krate, lint_store)) } fn pre_expansion_lint(sess: &Session, lint_store: &LintStore, krate: &ast::Crate) { @@ -450,10 +382,6 @@ fn configure_and_expand_inner<'a>( } if sess.opts.debugging_opts.ast_json { - // Set any `token` fields to `None` before - // we display the AST. - let mut krate = krate.clone(); - TokenStripper.visit_crate(&mut krate); println!("{}", json::as_json(&krate)); } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 235e049c3f5..dfc6f691457 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -477,6 +477,7 @@ fn test_debugging_options_tracking_hash() { untracked!(dump_mir_dir, String::from("abc")); untracked!(dump_mir_exclude_pass_number, true); untracked!(dump_mir_graphviz, true); + untracked!(emit_future_incompat_report, true); untracked!(emit_stack_sizes, true); untracked!(hir_stats, true); untracked!(identify_regions, true); @@ -573,6 +574,7 @@ fn test_debugging_options_tracking_hash() { tracked!(print_fuel, Some("abc".to_string())); tracked!(profile, true); tracked!(profile_emit, Some(PathBuf::from("abc"))); + tracked!(relax_elf_relocations, Some(true)); tracked!(relro_level, Some(RelroLevel::Full)); tracked!(report_delayed_bugs, true); tracked!(run_dsymutil, false); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 46a6c5861d5..3ed7d20ae45 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -246,10 +246,10 @@ pub fn get_codegen_backend(sopts: &config::Options) -> Box<dyn CodegenBackend> { INIT.call_once(|| { #[cfg(feature = "llvm")] - const DEFAULT_CODEGEN_BACKEND: &'static str = "llvm"; + const DEFAULT_CODEGEN_BACKEND: &str = "llvm"; #[cfg(not(feature = "llvm"))] - const DEFAULT_CODEGEN_BACKEND: &'static str = "cranelift"; + const DEFAULT_CODEGEN_BACKEND: &str = "cranelift"; let codegen_name = sopts .debugging_opts @@ -414,11 +414,10 @@ pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<dyn CodegenBackend let libdir = filesearch::relative_target_lib_path(&sysroot, &target); sysroot.join(libdir).with_file_name("codegen-backends") }) - .filter(|f| { + .find(|f| { info!("codegen backend candidate: {}", f.display()); f.exists() - }) - .next(); + }); let sysroot = sysroot.unwrap_or_else(|| { let candidates = sysroot_candidates .iter() diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index c5b59a041ab..6539419aefb 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -238,9 +238,10 @@ pub fn is_whitespace(c: char) -> bool { // Note that this set is stable (ie, it doesn't change with different // Unicode versions), so it's ok to just hard-code the values. - match c { + matches!( + c, // Usual ASCII suspects - | '\u{0009}' // \t + '\u{0009}' // \t | '\u{000A}' // \n | '\u{000B}' // vertical tab | '\u{000C}' // form feed @@ -257,9 +258,7 @@ pub fn is_whitespace(c: char) -> bool { // Dedicated whitespace characters from Unicode | '\u{2028}' // LINE SEPARATOR | '\u{2029}' // PARAGRAPH SEPARATOR - => true, - _ => false, - } + ) } /// True if `c` is valid as a first character of an identifier. diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index e6be082da0e..0b5bd39f7f9 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -3,7 +3,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_middle::ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; -use rustc_session::lint::FutureIncompatibleInfo; +use rustc_session::lint::FutureBreakage; use rustc_span::symbol::sym; declare_lint! { @@ -38,6 +38,9 @@ declare_lint! { @future_incompatible = FutureIncompatibleInfo { reference: "issue #66145 <https://github.com/rust-lang/rust/issues/66145>", edition: None, + future_breakage: Some(FutureBreakage { + date: None + }) }; } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index e5f66611d0f..c65cf65b1c7 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -44,7 +44,6 @@ use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, Subst}; use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt}; -use rustc_session::lint::FutureIncompatibleInfo; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; @@ -1369,10 +1368,9 @@ impl TypeAliasBounds { hir::QPath::TypeRelative(ref ty, _) => { // If this is a type variable, we found a `T::Assoc`. match ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => match path.res { - Res::Def(DefKind::TyParam, _) => true, - _ => false, - }, + hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { + matches!(path.res, Res::Def(DefKind::TyParam, _)) + } _ => false, } } @@ -2381,10 +2379,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { return Some(InitKind::Zeroed); } else if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, def_id) { return Some(InitKind::Uninit); - } else if cx.tcx.is_diagnostic_item(sym::transmute, def_id) { - if is_zero(&args[0]) { - return Some(InitKind::Zeroed); - } + } else if cx.tcx.is_diagnostic_item(sym::transmute, def_id) && is_zero(&args[0]) + { + return Some(InitKind::Zeroed); } } } else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind { @@ -2880,7 +2877,7 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignItem<'_>) { trace!("ClashingExternDeclarations: check_foreign_item: {:?}", this_fi); if let ForeignItemKind::Fn(..) = this_fi.kind { - let tcx = *&cx.tcx; + let tcx = cx.tcx; if let Some(existing_hid) = self.insert(tcx, this_fi) { let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid)); let this_decl_ty = tcx.type_of(tcx.hir().local_def_id(this_fi.hir_id)); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 48270eb59a0..4cfeb0d968b 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -22,7 +22,7 @@ use rustc_ast as ast; use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; @@ -33,9 +33,10 @@ use rustc_middle::middle::stability; use rustc_middle::ty::layout::{LayoutError, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; -use rustc_session::lint::{add_elided_lifetime_in_path_suggestion, BuiltinLintDiagnostics}; +use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::Session; +use rustc_session::SessionLintStore; use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP}; use rustc_target::abi::LayoutOf; @@ -69,6 +70,20 @@ pub struct LintStore { lint_groups: FxHashMap<&'static str, LintGroup>, } +impl SessionLintStore for LintStore { + fn name_to_lint(&self, lint_name: &str) -> LintId { + let lints = self + .find_lints(lint_name) + .unwrap_or_else(|_| panic!("Failed to find lint with name `{}`", lint_name)); + + if let &[lint] = lints.as_slice() { + return lint; + } else { + panic!("Found mutliple lints with name `{}`: {:?}", lint_name, lints); + } + } +} + /// The target of the `by_name` map, which accounts for renaming/deprecation. enum TargetLint { /// A direct lint target @@ -543,7 +558,7 @@ pub trait LintContext: Sized { anon_lts, ) => { add_elided_lifetime_in_path_suggestion( - sess, + sess.source_map(), &mut db, n, path_span, diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index f36f598ade2..aca28988364 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -74,6 +74,7 @@ impl<'s> LintLevelsBuilder<'s> { for &(ref lint_name, level) in &sess.opts.lint_opts { store.check_lint_name_cmdline(sess, &lint_name, level); + let orig_level = level; // If the cap is less than this specified level, e.g., if we've got // `--cap-lints allow` but we've also got `-D foo` then we ignore @@ -88,7 +89,7 @@ impl<'s> LintLevelsBuilder<'s> { }; for id in ids { self.check_gated_lint(id, DUMMY_SP); - let src = LintSource::CommandLine(lint_flag_val); + let src = LintSource::CommandLine(lint_flag_val, orig_level); specs.insert(id, (level, src)); } } @@ -123,7 +124,7 @@ impl<'s> LintLevelsBuilder<'s> { diag_builder.note(&rationale.as_str()); } } - LintSource::CommandLine(_) => { + LintSource::CommandLine(_, _) => { diag_builder.note("`forbid` lint level was set on command line"); } } @@ -422,7 +423,7 @@ impl<'s> LintLevelsBuilder<'s> { let forbidden_lint_name = match forbid_src { LintSource::Default => id.to_string(), LintSource::Node(name, _, _) => name.to_string(), - LintSource::CommandLine(name) => name.to_string(), + LintSource::CommandLine(name, _) => name.to_string(), }; let (lint_attr_name, lint_attr_span) = match *src { LintSource::Node(name, span, _) => (name, span), @@ -446,7 +447,7 @@ impl<'s> LintLevelsBuilder<'s> { diag_builder.note(&rationale.as_str()); } } - LintSource::CommandLine(_) => { + LintSource::CommandLine(_, _) => { diag_builder.note("`forbid` lint level was set on command line"); } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 2ecdff1a18d..7297a6de420 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -37,6 +37,7 @@ #![feature(or_patterns)] #![feature(half_open_range_patterns)] #![feature(exclusive_range_pattern)] +#![feature(control_flow_enum)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index b3125f55d4d..f117ce1f805 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -320,7 +320,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { .with_hi(lit.span.hi() - BytePos(right as u32)), ) }) - .unwrap_or_else(|| lit.span); + .unwrap_or(lit.span); Some(Ident::new(name, sp)) } else { diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index a31deb87ff0..84cc7b68d4c 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -42,6 +42,11 @@ impl EarlyLintPass for RedundantSemicolons { fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) { if let Some((span, multiple)) = seq.take() { + // FIXME: Find a better way of ignoring the trailing + // semicolon from macro expansion + if span == rustc_span::DUMMY_SP { + return; + } cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| { let (msg, rem) = if multiple { ("unnecessary trailing semicolons", "remove these semicolons") diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index bd025030567..467a3a42590 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -6,7 +6,6 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{is_range_literal, ExprKind, Node}; use rustc_index::vec::Idx; -use rustc_middle::mir::interpret::{sign_extend, truncate}; use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; @@ -18,6 +17,7 @@ use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants}; use rustc_target::spec::abi::Abi as SpecAbi; use std::cmp; +use std::ops::ControlFlow; use tracing::debug; declare_lint! { @@ -217,11 +217,11 @@ fn report_bin_hex_error( cx.struct_span_lint(OVERFLOWING_LITERALS, expr.span, |lint| { let (t, actually) = match ty { attr::IntType::SignedInt(t) => { - let actually = sign_extend(val, size) as i128; + let actually = size.sign_extend(val) as i128; (t.name_str(), actually.to_string()) } attr::IntType::UnsignedInt(t) => { - let actually = truncate(val, size); + let actually = size.truncate(val); (t.name_str(), actually.to_string()) } }; @@ -544,15 +544,15 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { } fn is_comparison(binop: hir::BinOp) -> bool { - match binop.node { + matches!( + binop.node, hir::BinOpKind::Eq - | hir::BinOpKind::Lt - | hir::BinOpKind::Le - | hir::BinOpKind::Ne - | hir::BinOpKind::Ge - | hir::BinOpKind::Gt => true, - _ => false, - } + | hir::BinOpKind::Lt + | hir::BinOpKind::Le + | hir::BinOpKind::Ne + | hir::BinOpKind::Ge + | hir::BinOpKind::Gt + ) } } } @@ -1135,11 +1135,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { match ty.kind() { ty::Opaque(..) => { self.ty = Some(ty); - true + ControlFlow::BREAK } // Consider opaque types within projections FFI-safe if they do not normalize // to more opaque types. @@ -1148,7 +1148,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // If `ty` is a opaque type directly then `super_visit_with` won't invoke // this function again. - if ty.has_opaque_types() { self.visit_ty(ty) } else { false } + if ty.has_opaque_types() { + self.visit_ty(ty) + } else { + ControlFlow::CONTINUE + } } _ => ty.super_visit_with(self), } @@ -1233,15 +1237,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } fn is_internal_abi(&self, abi: SpecAbi) -> bool { - if let SpecAbi::Rust - | SpecAbi::RustCall - | SpecAbi::RustIntrinsic - | SpecAbi::PlatformIntrinsic = abi - { - true - } else { - false - } + matches!( + abi, + SpecAbi::Rust | SpecAbi::RustCall | SpecAbi::RustIntrinsic | SpecAbi::PlatformIntrinsic + ) } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 17f0d5632e6..4bbc180b226 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -752,14 +752,11 @@ impl UnusedDelimLint for UnusedParens { && value.attrs.is_empty() && !value.span.from_expansion() && (ctx != UnusedDelimsCtx::LetScrutineeExpr - || match inner.kind { - ast::ExprKind::Binary( + || !matches!(inner.kind, ast::ExprKind::Binary( rustc_span::source_map::Spanned { node, .. }, _, _, - ) if node.lazy() => false, - _ => true, - }) + ) if node.lazy())) { self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos) } diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml new file mode 100644 index 00000000000..7f908088cf5 --- /dev/null +++ b/compiler/rustc_lint_defs/Cargo.toml @@ -0,0 +1,13 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_lint_defs" +version = "0.0.0" +edition = "2018" + +[dependencies] +log = { package = "tracing", version = "0.1" } +rustc_ast = { path = "../rustc_ast" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_span = { path = "../rustc_span" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b8826a548b8..a1b7c13e4c0 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4,7 +4,6 @@ //! compiler code, rather than using their own custom pass. Those //! lints are all available in `rustc_lint::builtin`. -use crate::lint::FutureIncompatibleInfo; use crate::{declare_lint, declare_lint_pass, declare_tool_lint}; use rustc_span::edition::Edition; use rustc_span::symbol::sym; @@ -2706,6 +2705,32 @@ declare_lint! { }; } +declare_lint! { + /// The `useless_deprecated` lint detects deprecation attributes with no effect. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// struct X; + /// + /// #[deprecated = "message"] + /// impl Default for X { + /// fn default() -> Self { + /// X + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Deprecation attributes have no effect on trait implementations. + pub USELESS_DEPRECATED, + Deny, + "detects deprecation attributes with no effect", +} + declare_tool_lint! { pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL, Deny, @@ -2793,6 +2818,7 @@ declare_lint_pass! { INEFFECTIVE_UNSTABLE_TRAIT_IMPL, UNINHABITED_STATIC, FUNCTION_ITEM_REFERENCES, + USELESS_DEPRECATED, ] } diff --git a/compiler/rustc_session/src/lint.rs b/compiler/rustc_lint_defs/src/lib.rs index 62e021d5e45..25a7bfcabb7 100644 --- a/compiler/rustc_session/src/lint.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -1,12 +1,45 @@ +#[macro_use] +extern crate rustc_macros; + pub use self::Level::*; use rustc_ast::node_id::{NodeId, NodeMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; -use rustc_errors::{pluralize, Applicability, DiagnosticBuilder}; use rustc_span::edition::Edition; use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol}; pub mod builtin; +#[macro_export] +macro_rules! pluralize { + ($x:expr) => { + if $x != 1 { "s" } else { "" } + }; +} + +/// Indicates the confidence in the correctness of a suggestion. +/// +/// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion +/// to determine whether it should be automatically applied or if the user should be consulted +/// before applying the suggestion. +#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)] +pub enum Applicability { + /// The suggestion is definitely what the user intended. This suggestion should be + /// automatically applied. + MachineApplicable, + + /// The suggestion may be what the user intended, but it is uncertain. The suggestion should + /// result in valid Rust code if it is applied. + MaybeIncorrect, + + /// The suggestion contains placeholders like `(...)` or `{ /* fields */ }`. The suggestion + /// cannot be applied automatically because it will not result in valid Rust code. The user + /// will need to fill in the placeholders. + HasPlaceholders, + + /// The applicability of the suggestion is unknown. + Unspecified, +} + /// Setting for how to handle a lint. #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] pub enum Level { @@ -106,6 +139,21 @@ pub struct FutureIncompatibleInfo { /// If this is an edition fixing lint, the edition in which /// this lint becomes obsolete pub edition: Option<Edition>, + /// Information about a future breakage, which will + /// be emitted in JSON messages to be displayed by Cargo + /// for upstream deps + pub future_breakage: Option<FutureBreakage>, +} + +#[derive(Copy, Clone, Debug)] +pub struct FutureBreakage { + pub date: Option<&'static str>, +} + +impl FutureIncompatibleInfo { + pub const fn default_fields_for_macro() -> Self { + FutureIncompatibleInfo { reference: "", edition: None, future_breakage: None } + } } impl Lint { @@ -331,31 +379,34 @@ macro_rules! declare_lint { ); ); ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, - $(@future_incompatible = $fi:expr;)? $(@feature_gate = $gate:expr;)? + $(@future_incompatible = FutureIncompatibleInfo { $($field:ident : $val:expr),* $(,)* }; )? $($v:ident),*) => ( $(#[$attr])* - $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { + $vis static $NAME: &$crate::Lint = &$crate::Lint { name: stringify!($NAME), - default_level: $crate::lint::$Level, + default_level: $crate::$Level, desc: $desc, edition_lint_opts: None, is_plugin: false, $($v: true,)* - $(future_incompatible: Some($fi),)* $(feature_gate: Some($gate),)* - ..$crate::lint::Lint::default_fields_for_macro() + $(future_incompatible: Some($crate::FutureIncompatibleInfo { + $($field: $val,)* + ..$crate::FutureIncompatibleInfo::default_fields_for_macro() + }),)* + ..$crate::Lint::default_fields_for_macro() }; ); ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, $lint_edition: expr => $edition_level: ident ) => ( $(#[$attr])* - $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { + $vis static $NAME: &$crate::Lint = &$crate::Lint { name: stringify!($NAME), - default_level: $crate::lint::$Level, + default_level: $crate::$Level, desc: $desc, - edition_lint_opts: Some(($lint_edition, $crate::lint::Level::$edition_level)), + edition_lint_opts: Some(($lint_edition, $crate::Level::$edition_level)), report_in_external_macro: false, is_plugin: false, }; @@ -380,9 +431,9 @@ macro_rules! declare_tool_lint { $external:expr ) => ( $(#[$attr])* - $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { + $vis static $NAME: &$crate::Lint = &$crate::Lint { name: &concat!(stringify!($tool), "::", stringify!($NAME)), - default_level: $crate::lint::$Level, + default_level: $crate::$Level, desc: $desc, edition_lint_opts: None, report_in_external_macro: $external, @@ -413,11 +464,11 @@ pub trait LintPass { #[macro_export] macro_rules! impl_lint_pass { ($ty:ty => [$($lint:expr),* $(,)?]) => { - impl $crate::lint::LintPass for $ty { + impl $crate::LintPass for $ty { fn name(&self) -> &'static str { stringify!($ty) } } impl $ty { - pub fn get_lints() -> $crate::lint::LintArray { $crate::lint_array!($($lint),*) } + pub fn get_lints() -> $crate::LintArray { $crate::lint_array!($($lint),*) } } }; } @@ -431,45 +482,3 @@ macro_rules! declare_lint_pass { $crate::impl_lint_pass!($name => [$($lint),*]); }; } - -pub fn add_elided_lifetime_in_path_suggestion( - sess: &crate::Session, - db: &mut DiagnosticBuilder<'_>, - n: usize, - path_span: Span, - incl_angl_brckt: bool, - insertion_span: Span, - anon_lts: String, -) { - let (replace_span, suggestion) = if incl_angl_brckt { - (insertion_span, anon_lts) - } else { - // When possible, prefer a suggestion that replaces the whole - // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, ` - // at a point (which makes for an ugly/confusing label) - if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) { - // But our spans can get out of whack due to macros; if the place we think - // we want to insert `'_` isn't even within the path expression's span, we - // should bail out of making any suggestion rather than panicking on a - // subtract-with-overflow or string-slice-out-out-bounds (!) - // FIXME: can we do better? - if insertion_span.lo().0 < path_span.lo().0 { - return; - } - let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize; - if insertion_index > snippet.len() { - return; - } - let (before, after) = snippet.split_at(insertion_index); - (path_span, format!("{}{}{}", before, anon_lts, after)) - } else { - (insertion_span, anon_lts) - } - }; - db.span_suggestion( - replace_span, - &format!("indicate the anonymous lifetime{}", pluralize!(n)), - suggestion, - Applicability::MachineApplicable, - ); -} diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 869aaa569ca..938eb19faef 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -648,6 +648,7 @@ enum class LLVMRustChecksumKind { None, MD5, SHA1, + SHA256, }; static Optional<DIFile::ChecksumKind> fromRust(LLVMRustChecksumKind Kind) { @@ -658,6 +659,10 @@ static Optional<DIFile::ChecksumKind> fromRust(LLVMRustChecksumKind Kind) { return DIFile::ChecksumKind::CSK_MD5; case LLVMRustChecksumKind::SHA1: return DIFile::ChecksumKind::CSK_SHA1; +#if (LLVM_VERSION_MAJOR >= 11) + case LLVMRustChecksumKind::SHA256: + return DIFile::ChecksumKind::CSK_SHA256; +#endif default: report_fatal_error("bad ChecksumKind."); } @@ -936,7 +941,7 @@ extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( return wrap(Builder->insertDeclare( unwrap(V), unwrap<DILocalVariable>(VarInfo), Builder->createExpression(llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)), - DebugLoc(cast<MDNode>(DL)), + DebugLoc(cast<MDNode>(unwrap(DL))), unwrap(InsertAtEnd))); } diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index 6931e6552ad..b16e22e8d77 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -15,8 +15,12 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: } }) }); - let body_visit = s.fold(false, |acc, bind| { - quote! { #acc || ::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder) } + + let body_visit = s.fold(quote!(), |acc, bind| { + quote! { + #acc + ::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder)?; + } }); s.bound_impl( @@ -32,8 +36,9 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:: fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>( &self, __folder: &mut __F - ) -> bool { + ) -> ::std::ops::ControlFlow<()> { match *self { #body_visit } + ::std::ops::ControlFlow::CONTINUE } }, ) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 7562da6d782..33cbf0fb234 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -752,10 +752,7 @@ impl<'a> CrateLoader<'a> { // At this point we've determined that we need an allocator. Let's see // if our compilation session actually needs an allocator based on what // we're emitting. - let all_rlib = self.sess.crate_types().iter().all(|ct| match *ct { - CrateType::Rlib => true, - _ => false, - }); + let all_rlib = self.sess.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib)); if all_rlib { return; } diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index f225f8acc89..d16985b9c2b 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -633,11 +633,9 @@ impl<'a> CrateLocator<'a> { } } - if self.exact_paths.is_empty() { - if self.crate_name != root.name() { - info!("Rejecting via crate name"); - return None; - } + if self.exact_paths.is_empty() && self.crate_name != root.name() { + info!("Rejecting via crate name"); + return None; } if root.triple() != &self.triple { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index b01a55b48da..c031e0e2e19 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1414,12 +1414,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ForeignModule] { + fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> Lrc<FxHashMap<DefId, ForeignModule>> { if self.root.is_proc_macro_crate() { // Proc macro crates do not have any *target* foreign modules. - &[] + Lrc::new(FxHashMap::default()) } else { - tcx.arena.alloc_from_iter(self.root.foreign_modules.decode((self, tcx.sess))) + let modules: FxHashMap<DefId, ForeignModule> = + self.root.foreign_modules.decode((self, tcx.sess)).map(|m| (m.def_id, m)).collect(); + Lrc::new(modules) } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 68faf9c7a62..ddd85ab7aaa 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -6,12 +6,14 @@ use crate::rmeta::{self, encoder}; use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; +use rustc_data_structures::stable_map::FxHashMap; use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::hir::exports::Export; +use rustc_middle::middle::cstore::ForeignModule; use rustc_middle::middle::cstore::{CrateSource, CrateStore, EncodedMetadata}; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::stability::DeprecationEntry; @@ -220,10 +222,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, missing_lang_items => { cdata.get_missing_lang_items(tcx) } missing_extern_crate_item => { - let r = match *cdata.extern_crate.borrow() { - Some(extern_crate) if !extern_crate.is_direct() => true, - _ => false, - }; + let r = matches!(*cdata.extern_crate.borrow(), Some(extern_crate) if !extern_crate.is_direct()); r } @@ -254,9 +253,11 @@ pub fn provide(providers: &mut Providers) { } _ => false, }, - is_statically_included_foreign_item: |tcx, id| match tcx.native_library_kind(id) { - Some(NativeLibKind::StaticBundle | NativeLibKind::StaticNoBundle) => true, - _ => false, + is_statically_included_foreign_item: |tcx, id| { + matches!( + tcx.native_library_kind(id), + Some(NativeLibKind::StaticBundle | NativeLibKind::StaticNoBundle) + ) }, native_library_kind: |tcx, id| { tcx.native_libraries(id.krate) @@ -267,9 +268,8 @@ pub fn provide(providers: &mut Providers) { Some(id) => id, None => return false, }; - tcx.foreign_modules(id.krate) - .iter() - .find(|m| m.def_id == fm_id) + let map = tcx.foreign_modules(id.krate); + map.get(&fm_id) .expect("failed to find foreign module") .foreign_items .contains(&id) @@ -282,7 +282,9 @@ pub fn provide(providers: &mut Providers) { }, foreign_modules: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - &tcx.arena.alloc(foreign_modules::collect(tcx))[..] + let modules: FxHashMap<DefId, ForeignModule> = + foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect(); + Lrc::new(modules) }, link_args: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 7e33a479228..a7cf1079b8f 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1502,7 +1502,7 @@ impl EncodeContext<'a, 'tcx> { fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> { empty_proc_macro!(self); let foreign_modules = self.tcx.foreign_modules(LOCAL_CRATE); - self.lazy(foreign_modules.iter().cloned()) + self.lazy(foreign_modules.iter().map(|(_, m)| m).cloned()) } fn encode_hygiene(&mut self) -> (SyntaxContextTable, ExpnDataTable) { @@ -2042,6 +2042,10 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { encoder.emit_raw_bytes(&[0, 0, 0, 0]); let source_map_files = tcx.sess.source_map().files(); + let source_file_cache = (source_map_files[0].clone(), 0); + let required_source_files = Some(GrowableBitSet::with_capacity(source_map_files.len())); + drop(source_map_files); + let hygiene_ctxt = HygieneEncodeContext::default(); let mut ecx = EncodeContext { @@ -2052,13 +2056,12 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { lazy_state: LazyState::NoNode, type_shorthands: Default::default(), predicate_shorthands: Default::default(), - source_file_cache: (source_map_files[0].clone(), 0), + source_file_cache, interpret_allocs: Default::default(), - required_source_files: Some(GrowableBitSet::with_capacity(source_map_files.len())), + required_source_files, is_proc_macro: tcx.sess.crate_types().contains(&CrateType::ProcMacro), hygiene_ctxt: &hygiene_ctxt, }; - drop(source_map_files); // Encode the rustc version string in a predictable location. rustc_version().encode(&mut ecx).unwrap(); diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 5ccadb7e660..4a1d5459d1e 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -24,6 +24,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] +#![feature(assoc_char_funcs)] #![feature(backtrace)] #![feature(bool_to_option)] #![feature(box_patterns)] @@ -49,6 +50,7 @@ #![feature(int_error_matching)] #![feature(half_open_range_patterns)] #![feature(exclusive_range_pattern)] +#![feature(control_flow_enum)] #![recursion_limit = "512"] #[macro_use] diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 91e1d6e0b0b..a61d37cc90e 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -22,7 +22,9 @@ pub enum LintSource { Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */), /// Lint level was set by a command-line flag. - CommandLine(Symbol), + /// The provided `Level` is the level specified on the command line - + /// the actual level may be lower due to `--cap-lints` + CommandLine(Symbol, Level), } impl LintSource { @@ -30,7 +32,7 @@ impl LintSource { match *self { LintSource::Default => symbol::kw::Default, LintSource::Node(name, _, _) => name, - LintSource::CommandLine(name) => name, + LintSource::CommandLine(name, _) => name, } } @@ -38,7 +40,7 @@ impl LintSource { match *self { LintSource::Default => DUMMY_SP, LintSource::Node(_, span, _) => span, - LintSource::CommandLine(_) => DUMMY_SP, + LintSource::CommandLine(_, _) => DUMMY_SP, } } } @@ -225,9 +227,24 @@ pub fn struct_lint_level<'s, 'd>( span: Option<MultiSpan>, decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>, ) { + // Check for future incompatibility lints and issue a stronger warning. + let lint_id = LintId::of(lint); + let future_incompatible = lint.future_incompatible; + + let has_future_breakage = + future_incompatible.map_or(false, |incompat| incompat.future_breakage.is_some()); + let mut err = match (level, span) { - (Level::Allow, _) => { - return; + (Level::Allow, span) => { + if has_future_breakage { + if let Some(span) = span { + sess.struct_span_allow(span, "") + } else { + sess.struct_allow("") + } + } else { + return; + } } (Level::Warn, Some(span)) => sess.struct_span_warn(span, ""), (Level::Warn, None) => sess.struct_warn(""), @@ -235,10 +252,6 @@ pub fn struct_lint_level<'s, 'd>( (Level::Deny | Level::Forbid, None) => sess.struct_err(""), }; - // Check for future incompatibility lints and issue a stronger warning. - let lint_id = LintId::of(lint); - let future_incompatible = lint.future_incompatible; - // If this code originates in a foreign macro, aka something that this crate // did not itself author, then it's likely that there's nothing this crate // can do about it. We probably want to skip the lint entirely. @@ -268,12 +281,12 @@ pub fn struct_lint_level<'s, 'd>( &format!("`#[{}({})]` on by default", level.as_str(), name), ); } - LintSource::CommandLine(lint_flag_val) => { - let flag = match level { + LintSource::CommandLine(lint_flag_val, orig_level) => { + let flag = match orig_level { Level::Warn => "-W", Level::Deny => "-D", Level::Forbid => "-F", - Level::Allow => panic!(), + Level::Allow => "-A", }; let hyphen_case_lint_name = name.replace("_", "-"); if lint_flag_val.as_str() == name { @@ -321,7 +334,7 @@ pub fn struct_lint_level<'s, 'd>( } } - err.code(DiagnosticId::Lint(name)); + err.code(DiagnosticId::Lint { name, has_future_breakage }); if let Some(future_incompatible) = future_incompatible { const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \ @@ -358,7 +371,9 @@ pub fn struct_lint_level<'s, 'd>( pub fn in_external_macro(sess: &Session, span: Span) -> bool { let expn_data = span.ctxt().outer_expn_data(); match expn_data.kind { - ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => false, + ExpnKind::Inlined | ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => { + false + } ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" ExpnKind::Macro(MacroKind::Bang, _) => { // Dummy span for the `def_site` means it's an external macro. diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 6ff0a94ebf3..921086366be 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -62,9 +62,9 @@ macro_rules! CloneTypeFoldableImpls { fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>( &self, _: &mut F) - -> bool + -> ::std::ops::ControlFlow<()> { - false + ::std::ops::ControlFlow::CONTINUE } } )+ @@ -105,7 +105,7 @@ macro_rules! EnumTypeFoldableImpl { fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>( &self, visitor: &mut V, - ) -> bool { + ) -> ::std::ops::ControlFlow<()> { EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output()) } } @@ -179,9 +179,10 @@ macro_rules! EnumTypeFoldableImpl { input($($input)*) output( $variant ( $($variant_arg),* ) => { - false $(|| $crate::ty::fold::TypeFoldable::visit_with( + $($crate::ty::fold::TypeFoldable::visit_with( $variant_arg, $visitor - ))* + )?;)* + ::std::ops::ControlFlow::CONTINUE } $($output)* ) @@ -196,9 +197,10 @@ macro_rules! EnumTypeFoldableImpl { input($($input)*) output( $variant { $($variant_arg),* } => { - false $(|| $crate::ty::fold::TypeFoldable::visit_with( + $($crate::ty::fold::TypeFoldable::visit_with( $variant_arg, $visitor - ))* + )?;)* + ::std::ops::ControlFlow::CONTINUE } $($output)* ) @@ -212,7 +214,7 @@ macro_rules! EnumTypeFoldableImpl { @VisitVariants($this, $visitor) input($($input)*) output( - $variant => { false } + $variant => { ::std::ops::ControlFlow::CONTINUE } $($output)* ) ) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 1a206b245d3..978f08927c6 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -399,7 +399,7 @@ impl<'tcx> TyCtxt<'tcx> { def_id: DefId, id: Option<HirId>, span: Span, - unmarked: impl FnOnce(Span, DefId) -> (), + unmarked: impl FnOnce(Span, DefId), ) { let soft_handler = |lint, span, msg: &_| { self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| { diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index d41e5680602..e35ff6b996e 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -81,6 +81,12 @@ impl From<ErrorHandled> for InterpErrorInfo<'_> { } } +impl From<ErrorReported> for InterpErrorInfo<'_> { + fn from(err: ErrorReported) -> Self { + InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err)).into() + } +} + impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> { fn from(kind: InterpError<'tcx>) -> Self { let capture_backtrace = tls::with_opt(|tcx| { @@ -115,8 +121,8 @@ pub enum InvalidProgramInfo<'tcx> { /// Cannot compute this constant because it depends on another one /// which already produced an error. ReferencedConstant, - /// Abort in case type errors are reached. - TypeckError(ErrorReported), + /// Abort in case errors are already reported. + AlreadyReported(ErrorReported), /// An error occurred during layout computation. Layout(layout::LayoutError<'tcx>), /// An invalid transmute happened. @@ -129,7 +135,7 @@ impl fmt::Display for InvalidProgramInfo<'_> { match self { TooGeneric => write!(f, "encountered overly generic constant"), ReferencedConstant => write!(f, "referenced constant has errors"), - TypeckError(ErrorReported) => { + AlreadyReported(ErrorReported) => { write!(f, "encountered constants with type errors, stopping evaluation") } Layout(ref err) => write!(f, "{}", err), diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index b5beb3babe2..bcf85797313 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -110,7 +110,7 @@ use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_serialize::{Decodable, Encodable}; -use rustc_target::abi::{Endian, Size}; +use rustc_target::abi::Endian; use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; @@ -590,39 +590,6 @@ pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result<u128, i uint } -//////////////////////////////////////////////////////////////////////////////// -// Methods to facilitate working with signed integers stored in a u128 -//////////////////////////////////////////////////////////////////////////////// - -/// Truncates `value` to `size` bits and then sign-extend it to 128 bits -/// (i.e., if it is negative, fill with 1's on the left). -#[inline] -pub fn sign_extend(value: u128, size: Size) -> u128 { - let size = size.bits(); - if size == 0 { - // Truncated until nothing is left. - return 0; - } - // Sign-extend it. - let shift = 128 - size; - // Shift the unsigned value to the left, then shift back to the right as signed - // (essentially fills with FF on the left). - (((value << shift) as i128) >> shift) as u128 -} - -/// Truncates `value` to `size` bits. -#[inline] -pub fn truncate(value: u128, size: Size) -> u128 { - let size = size.bits(); - if size == 0 { - // Truncated until nothing is left. - return 0; - } - let shift = 128 - size; - // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). - (value << shift) >> shift -} - /// Computes the unsigned absolute value without wrapping or panicking. #[inline] pub fn uabs(value: i64) -> u64 { diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index cb8782ce817..5e97862ecf2 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -8,9 +8,9 @@ use rustc_apfloat::{ use rustc_macros::HashStable; use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; -use crate::ty::{ParamEnv, Ty, TyCtxt}; +use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt}; -use super::{sign_extend, truncate, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; +use super::{AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; /// Represents the result of const evaluation via the `eval_to_allocation` query. #[derive(Clone, HashStable, TyEncodable, TyDecodable)] @@ -103,12 +103,7 @@ impl<'tcx> ConstValue<'tcx> { #[derive(HashStable)] pub enum Scalar<Tag = ()> { /// The raw bytes of a simple value. - Raw { - /// The first `size` bytes of `data` are the value. - /// Do not try to read less or more bytes than that. The remaining bytes must be 0. - data: u128, - size: u8, - }, + Int(ScalarInt), /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the @@ -125,16 +120,7 @@ impl<Tag: fmt::Debug> fmt::Debug for Scalar<Tag> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr) => write!(f, "{:?}", ptr), - &Scalar::Raw { data, size } => { - Scalar::check_data(data, size); - if size == 0 { - write!(f, "<ZST>") - } else { - // Format as hex number wide enough to fit any value of the given `size`. - // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014". - write!(f, "0x{:>0width$x}", data, width = (size * 2) as usize) - } - } + Scalar::Int(int) => write!(f, "{:?}", int), } } } @@ -143,7 +129,7 @@ impl<Tag: fmt::Debug> fmt::Display for Scalar<Tag> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr) => write!(f, "pointer to {}", ptr), - Scalar::Raw { .. } => fmt::Debug::fmt(self, f), + Scalar::Int { .. } => fmt::Debug::fmt(self, f), } } } @@ -163,21 +149,6 @@ impl<Tag> From<Double> for Scalar<Tag> { } impl Scalar<()> { - /// Make sure the `data` fits in `size`. - /// This is guaranteed by all constructors here, but since the enum variants are public, - /// it could still be violated (even though no code outside this file should - /// construct `Scalar`s). - #[inline(always)] - fn check_data(data: u128, size: u8) { - debug_assert_eq!( - truncate(data, Size::from_bytes(u64::from(size))), - data, - "Scalar value {:#x} exceeds size of {} bytes", - data, - size - ); - } - /// Tag this scalar with `new_tag` if it is a pointer, leave it unchanged otherwise. /// /// Used by `MemPlace::replace_tag`. @@ -185,12 +156,14 @@ impl Scalar<()> { pub fn with_tag<Tag>(self, new_tag: Tag) -> Scalar<Tag> { match self { Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_tag(new_tag)), - Scalar::Raw { data, size } => Scalar::Raw { data, size }, + Scalar::Int(int) => Scalar::Int(int), } } } impl<'tcx, Tag> Scalar<Tag> { + pub const ZST: Self = Scalar::Int(ScalarInt::ZST); + /// Erase the tag from the scalar, if any. /// /// Used by error reporting code to avoid having the error type depend on `Tag`. @@ -198,18 +171,13 @@ impl<'tcx, Tag> Scalar<Tag> { pub fn erase_tag(self) -> Scalar { match self { Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()), - Scalar::Raw { data, size } => Scalar::Raw { data, size }, + Scalar::Int(int) => Scalar::Int(int), } } #[inline] pub fn null_ptr(cx: &impl HasDataLayout) -> Self { - Scalar::Raw { data: 0, size: cx.data_layout().pointer_size.bytes() as u8 } - } - - #[inline] - pub fn zst() -> Self { - Scalar::Raw { data: 0, size: 0 } + Scalar::Int(ScalarInt::null(cx.data_layout().pointer_size)) } #[inline(always)] @@ -220,10 +188,7 @@ impl<'tcx, Tag> Scalar<Tag> { f_ptr: impl FnOnce(Pointer<Tag>) -> InterpResult<'tcx, Pointer<Tag>>, ) -> InterpResult<'tcx, Self> { match self { - Scalar::Raw { data, size } => { - assert_eq!(u64::from(size), dl.pointer_size.bytes()); - Ok(Scalar::Raw { data: u128::from(f_int(u64::try_from(data).unwrap())?), size }) - } + Scalar::Int(int) => Ok(Scalar::Int(int.ptr_sized_op(dl, f_int)?)), Scalar::Ptr(ptr) => Ok(Scalar::Ptr(f_ptr(ptr)?)), } } @@ -264,24 +229,17 @@ impl<'tcx, Tag> Scalar<Tag> { #[inline] pub fn from_bool(b: bool) -> Self { - // Guaranteed to be truncated and does not need sign extension. - Scalar::Raw { data: b as u128, size: 1 } + Scalar::Int(b.into()) } #[inline] pub fn from_char(c: char) -> Self { - // Guaranteed to be truncated and does not need sign extension. - Scalar::Raw { data: c as u128, size: 4 } + Scalar::Int(c.into()) } #[inline] pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> { - let i = i.into(); - if truncate(i, size) == i { - Some(Scalar::Raw { data: i, size: size.bytes() as u8 }) - } else { - None - } + ScalarInt::try_from_uint(i, size).map(Scalar::Int) } #[inline] @@ -293,26 +251,22 @@ impl<'tcx, Tag> Scalar<Tag> { #[inline] pub fn from_u8(i: u8) -> Self { - // Guaranteed to be truncated and does not need sign extension. - Scalar::Raw { data: i.into(), size: 1 } + Scalar::Int(i.into()) } #[inline] pub fn from_u16(i: u16) -> Self { - // Guaranteed to be truncated and does not need sign extension. - Scalar::Raw { data: i.into(), size: 2 } + Scalar::Int(i.into()) } #[inline] pub fn from_u32(i: u32) -> Self { - // Guaranteed to be truncated and does not need sign extension. - Scalar::Raw { data: i.into(), size: 4 } + Scalar::Int(i.into()) } #[inline] pub fn from_u64(i: u64) -> Self { - // Guaranteed to be truncated and does not need sign extension. - Scalar::Raw { data: i.into(), size: 8 } + Scalar::Int(i.into()) } #[inline] @@ -322,14 +276,7 @@ impl<'tcx, Tag> Scalar<Tag> { #[inline] pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> { - let i = i.into(); - // `into` performed sign extension, we have to truncate - let truncated = truncate(i as u128, size); - if sign_extend(truncated, size) as i128 == i { - Some(Scalar::Raw { data: truncated, size: size.bytes() as u8 }) - } else { - None - } + ScalarInt::try_from_int(i, size).map(Scalar::Int) } #[inline] @@ -366,14 +313,12 @@ impl<'tcx, Tag> Scalar<Tag> { #[inline] pub fn from_f32(f: Single) -> Self { - // We trust apfloat to give us properly truncated data. - Scalar::Raw { data: f.to_bits(), size: 4 } + Scalar::Int(f.into()) } #[inline] pub fn from_f64(f: Double) -> Self { - // We trust apfloat to give us properly truncated data. - Scalar::Raw { data: f.to_bits(), size: 8 } + Scalar::Int(f.into()) } /// This is very rarely the method you want! You should dispatch on the type @@ -388,11 +333,7 @@ impl<'tcx, Tag> Scalar<Tag> { ) -> Result<u128, Pointer<Tag>> { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); match self { - Scalar::Raw { data, size } => { - assert_eq!(target_size.bytes(), u64::from(size)); - Scalar::check_data(data, size); - Ok(data) - } + Scalar::Int(int) => Ok(int.assert_bits(target_size)), Scalar::Ptr(ptr) => { assert_eq!(target_size, cx.data_layout().pointer_size); Err(ptr) @@ -406,16 +347,13 @@ impl<'tcx, Tag> Scalar<Tag> { fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); match self { - Scalar::Raw { data, size } => { - if target_size.bytes() != u64::from(size) { - throw_ub!(ScalarSizeMismatch { - target_size: target_size.bytes(), - data_size: u64::from(size), - }); - } - Scalar::check_data(data, size); - Ok(data) - } + Scalar::Int(int) => int.to_bits(target_size).map_err(|size| { + err_ub!(ScalarSizeMismatch { + target_size: target_size.bytes(), + data_size: size.bytes(), + }) + .into() + }), Scalar::Ptr(_) => throw_unsup!(ReadPointerAsBytes), } } @@ -426,17 +364,25 @@ impl<'tcx, Tag> Scalar<Tag> { } #[inline] + pub fn assert_int(self) -> ScalarInt { + match self { + Scalar::Ptr(_) => bug!("expected an int but got an abstract pointer"), + Scalar::Int(int) => int, + } + } + + #[inline] pub fn assert_ptr(self) -> Pointer<Tag> { match self { Scalar::Ptr(p) => p, - Scalar::Raw { .. } => bug!("expected a Pointer but got Raw bits"), + Scalar::Int { .. } => bug!("expected a Pointer but got Raw bits"), } } /// Do not call this method! Dispatch based on the type instead. #[inline] pub fn is_bits(self) -> bool { - matches!(self, Scalar::Raw { .. }) + matches!(self, Scalar::Int { .. }) } /// Do not call this method! Dispatch based on the type instead. @@ -502,7 +448,7 @@ impl<'tcx, Tag> Scalar<Tag> { fn to_signed_with_bit_width(self, bits: u64) -> InterpResult<'static, i128> { let sz = Size::from_bits(bits); let b = self.to_bits(sz)?; - Ok(sign_extend(b, sz) as i128) + Ok(sz.sign_extend(b) as i128) } /// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer. @@ -533,7 +479,7 @@ impl<'tcx, Tag> Scalar<Tag> { pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'static, i64> { let sz = cx.data_layout().pointer_size; let b = self.to_bits(sz)?; - let b = sign_extend(b, sz) as i128; + let b = sz.sign_extend(b) as i128; Ok(i64::try_from(b).unwrap()) } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index a753732d364..bf091201e10 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -28,11 +28,10 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_serialize::{Decodable, Encodable}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi; use rustc_target::asm::InlineAsmRegOrRegClass; use std::borrow::Cow; use std::fmt::{self, Debug, Display, Formatter, Write}; -use std::ops::{Index, IndexMut}; +use std::ops::{ControlFlow, Index, IndexMut}; use std::slice; use std::{iter, mem, option}; @@ -1952,10 +1951,10 @@ impl<'tcx> Operand<'tcx> { .layout_of(param_env_and_ty) .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e)) .size; - let scalar_size = abi::Size::from_bytes(match val { - Scalar::Raw { size, .. } => size, + let scalar_size = match val { + Scalar::Int(int) => int.size(), _ => panic!("Invalid scalar type {:?}", val), - }); + }; scalar_size == type_size }); Operand::Constant(box Constant { @@ -2489,7 +2488,7 @@ impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { UserTypeProjection { base, projs } } - fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool { + fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<()> { self.base.visit_with(visitor) // Note: there's nothing in `self.proj` to visit. } diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index c9493c67987..709ffc3049a 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -46,7 +46,7 @@ impl SwitchTargets { pub fn new(targets: impl Iterator<Item = (u128, BasicBlock)>, otherwise: BasicBlock) -> Self { let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip(); targets.push(otherwise); - Self { values: values.into(), targets } + Self { values, targets } } /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`, diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 6aab54b9274..391bd8be7e4 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -87,41 +87,46 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { Terminator { source_info: self.source_info, kind } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { use crate::mir::TerminatorKind::*; match self.kind { SwitchInt { ref discr, switch_ty, .. } => { - discr.visit_with(visitor) || switch_ty.visit_with(visitor) + discr.visit_with(visitor)?; + switch_ty.visit_with(visitor) } Drop { ref place, .. } => place.visit_with(visitor), DropAndReplace { ref place, ref value, .. } => { - place.visit_with(visitor) || value.visit_with(visitor) + place.visit_with(visitor)?; + value.visit_with(visitor) } Yield { ref value, .. } => value.visit_with(visitor), Call { ref func, ref args, ref destination, .. } => { - let dest = if let Some((ref loc, _)) = *destination { - loc.visit_with(visitor) - } else { - false + if let Some((ref loc, _)) = *destination { + loc.visit_with(visitor)?; }; - dest || func.visit_with(visitor) || args.visit_with(visitor) + func.visit_with(visitor)?; + args.visit_with(visitor) } Assert { ref cond, ref msg, .. } => { - if cond.visit_with(visitor) { + if cond.visit_with(visitor).is_break() { use AssertKind::*; match msg { BoundsCheck { ref len, ref index } => { - len.visit_with(visitor) || index.visit_with(visitor) + len.visit_with(visitor)?; + index.visit_with(visitor) + } + Overflow(_, l, r) => { + l.visit_with(visitor)?; + r.visit_with(visitor) } - Overflow(_, l, r) => l.visit_with(visitor) || r.visit_with(visitor), OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => { op.visit_with(visitor) } - ResumedAfterReturn(_) | ResumedAfterPanic(_) => false, + ResumedAfterReturn(_) | ResumedAfterPanic(_) => ControlFlow::CONTINUE, } } else { - false + ControlFlow::CONTINUE } } InlineAsm { ref operands, .. } => operands.visit_with(visitor), @@ -132,7 +137,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { | GeneratorDrop | Unreachable | FalseEdge { .. } - | FalseUnwind { .. } => false, + | FalseUnwind { .. } => ControlFlow::CONTINUE, } } } @@ -142,8 +147,8 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorKind { *self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { - false + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> { + ControlFlow::CONTINUE } } @@ -152,8 +157,9 @@ impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.local.visit_with(visitor) || self.projection.visit_with(visitor) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.local.visit_with(visitor)?; + self.projection.visit_with(visitor) } } @@ -163,8 +169,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> { folder.tcx().intern_place_elems(&v) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -213,32 +219,47 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { use crate::mir::Rvalue::*; match *self { Use(ref op) => op.visit_with(visitor), Repeat(ref op, _) => op.visit_with(visitor), ThreadLocalRef(did) => did.visit_with(visitor), - Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor), + Ref(region, _, ref place) => { + region.visit_with(visitor)?; + place.visit_with(visitor) + } AddressOf(_, ref place) => place.visit_with(visitor), Len(ref place) => place.visit_with(visitor), - Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor), + Cast(_, ref op, ty) => { + op.visit_with(visitor)?; + ty.visit_with(visitor) + } BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => { - rhs.visit_with(visitor) || lhs.visit_with(visitor) + rhs.visit_with(visitor)?; + lhs.visit_with(visitor) } UnaryOp(_, ref val) => val.visit_with(visitor), Discriminant(ref place) => place.visit_with(visitor), NullaryOp(_, ty) => ty.visit_with(visitor), Aggregate(ref kind, ref fields) => { - (match **kind { - AggregateKind::Array(ty) => ty.visit_with(visitor), - AggregateKind::Tuple => false, + match **kind { + AggregateKind::Array(ty) => { + ty.visit_with(visitor)?; + } + AggregateKind::Tuple => {} AggregateKind::Adt(_, _, substs, user_ty, _) => { - substs.visit_with(visitor) || user_ty.visit_with(visitor) + substs.visit_with(visitor)?; + user_ty.visit_with(visitor)?; + } + AggregateKind::Closure(_, substs) => { + substs.visit_with(visitor)?; } - AggregateKind::Closure(_, substs) => substs.visit_with(visitor), - AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor), - }) || fields.visit_with(visitor) + AggregateKind::Generator(_, substs, _) => { + substs.visit_with(visitor)?; + } + } + fields.visit_with(visitor) } } } @@ -253,7 +274,7 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { match *self { Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), Operand::Constant(ref c) => c.visit_with(visitor), @@ -277,13 +298,13 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> { } } - fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool { + fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<()> { use crate::mir::ProjectionElem::*; match self { Field(_, ty) => ty.visit_with(visitor), Index(v) => v.visit_with(visitor), - _ => false, + _ => ControlFlow::CONTINUE, } } } @@ -292,8 +313,8 @@ impl<'tcx> TypeFoldable<'tcx> for Field { fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { *self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { - false + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> { + ControlFlow::CONTINUE } } @@ -301,8 +322,8 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal { fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { *self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { - false + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> { + ControlFlow::CONTINUE } } @@ -310,8 +331,8 @@ impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> { fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { self.clone() } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { - false + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> { + ControlFlow::CONTINUE } } @@ -323,7 +344,7 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { literal: self.literal.fold_with(folder), } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { self.literal.visit_with(visitor) } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 89faa97d50f..72360e219ec 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1168,7 +1168,7 @@ rustc_queries! { } Other { - query foreign_modules(_: CrateNum) -> &'tcx [ForeignModule] { + query foreign_modules(_: CrateNum) -> Lrc<FxHashMap<DefId, ForeignModule>> { desc { "looking up the foreign modules of a linked crate" } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 64faacc1c0b..0af884a286d 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -132,7 +132,7 @@ impl<'tcx> Const<'tcx> { #[inline] /// Creates an interned zst constant. pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Self { - Self::from_scalar(tcx, Scalar::zst(), ty) + Self::from_scalar(tcx, Scalar::ZST, ty) } #[inline] diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index ced0429deab..126257a5b49 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -1,31 +1,32 @@ -use crate::mir::interpret::truncate; -use rustc_target::abi::Size; +use rustc_apfloat::ieee::{Double, Single}; +use rustc_apfloat::Float; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use rustc_target::abi::{Size, TargetDataLayout}; +use std::convert::{TryFrom, TryInto}; +use std::fmt; #[derive(Copy, Clone)] /// A type for representing any integer. Only used for printing. -// FIXME: Use this for the integer-tree representation needed for type level ints and -// const generics? pub struct ConstInt { - /// Number of bytes of the integer. Only 1, 2, 4, 8, 16 are legal values. - size: u8, + /// The "untyped" variant of `ConstInt`. + int: ScalarInt, /// Whether the value is of a signed integer type. signed: bool, /// Whether the value is a `usize` or `isize` type. is_ptr_sized_integral: bool, - /// Raw memory of the integer. All bytes beyond the `size` are unused and must be zero. - raw: u128, } impl ConstInt { - pub fn new(raw: u128, size: Size, signed: bool, is_ptr_sized_integral: bool) -> Self { - assert!(raw <= truncate(u128::MAX, size)); - Self { raw, size: size.bytes() as u8, signed, is_ptr_sized_integral } + pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self { + Self { int, signed, is_ptr_sized_integral } } } impl std::fmt::Debug for ConstInt { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self { size, signed, raw, is_ptr_sized_integral } = *self; + let Self { int, signed, is_ptr_sized_integral } = *self; + let size = int.size().bytes(); + let raw = int.data; if signed { let bit_size = size * 8; let min = 1u128 << (bit_size - 1); @@ -73,7 +74,7 @@ impl std::fmt::Debug for ConstInt { Ok(()) } } else { - let max = truncate(u128::MAX, Size::from_bytes(size)); + let max = Size::from_bytes(size).truncate(u128::MAX); if raw == max { match (size, is_ptr_sized_integral) { (_, true) => write!(fmt, "usize::MAX"), @@ -109,3 +110,257 @@ impl std::fmt::Debug for ConstInt { } } } + +/// The raw bytes of a simple value. +/// +/// This is a packed struct in order to allow this type to be optimally embedded in enums +/// (like Scalar). +#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[repr(packed)] +pub struct ScalarInt { + /// The first `size` bytes of `data` are the value. + /// Do not try to read less or more bytes than that. The remaining bytes must be 0. + data: u128, + size: u8, +} + +// Cannot derive these, as the derives take references to the fields, and we +// can't take references to fields of packed structs. +impl<CTX> crate::ty::HashStable<CTX> for ScalarInt { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) { + // Using a block `{self.data}` here to force a copy instead of using `self.data` + // directly, because `hash_stable` takes `&self` and would thus borrow `self.data`. + // Since `Self` is a packed struct, that would create a possibly unaligned reference, + // which is UB. + { self.data }.hash_stable(hcx, hasher); + self.size.hash_stable(hcx, hasher); + } +} + +impl<S: Encoder> Encodable<S> for ScalarInt { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_u128(self.data)?; + s.emit_u8(self.size) + } +} + +impl<D: Decoder> Decodable<D> for ScalarInt { + fn decode(d: &mut D) -> Result<ScalarInt, D::Error> { + Ok(ScalarInt { data: d.read_u128()?, size: d.read_u8()? }) + } +} + +impl ScalarInt { + pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: 1 }; + + pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: 1 }; + + pub const ZST: ScalarInt = ScalarInt { data: 0_u128, size: 0 }; + + #[inline] + pub fn size(self) -> Size { + Size::from_bytes(self.size) + } + + /// Make sure the `data` fits in `size`. + /// This is guaranteed by all constructors here, but having had this check saved us from + /// bugs many times in the past, so keeping it around is definitely worth it. + #[inline(always)] + fn check_data(self) { + // Using a block `{self.data}` here to force a copy instead of using `self.data` + // directly, because `assert_eq` takes references to its arguments and formatting + // arguments and would thus borrow `self.data`. Since `Self` + // is a packed struct, that would create a possibly unaligned reference, which + // is UB. + debug_assert_eq!( + self.size().truncate(self.data), + { self.data }, + "Scalar value {:#x} exceeds size of {} bytes", + { self.data }, + self.size + ); + } + + #[inline] + pub fn null(size: Size) -> Self { + Self { data: 0, size: size.bytes() as u8 } + } + + #[inline] + pub fn is_null(self) -> bool { + self.data == 0 + } + + pub(crate) fn ptr_sized_op<E>( + self, + dl: &TargetDataLayout, + f_int: impl FnOnce(u64) -> Result<u64, E>, + ) -> Result<Self, E> { + assert_eq!(u64::from(self.size), dl.pointer_size.bytes()); + Ok(Self::try_from_uint(f_int(u64::try_from(self.data).unwrap())?, self.size()).unwrap()) + } + + #[inline] + pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> { + let data = i.into(); + if size.truncate(data) == data { + Some(Self { data, size: size.bytes() as u8 }) + } else { + None + } + } + + #[inline] + pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> { + let i = i.into(); + // `into` performed sign extension, we have to truncate + let truncated = size.truncate(i as u128); + if size.sign_extend(truncated) as i128 == i { + Some(Self { data: truncated, size: size.bytes() as u8 }) + } else { + None + } + } + + #[inline] + pub fn assert_bits(self, target_size: Size) -> u128 { + self.to_bits(target_size).unwrap_or_else(|size| { + bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes()) + }) + } + + #[inline] + pub fn to_bits(self, target_size: Size) -> Result<u128, Size> { + assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); + if target_size.bytes() == u64::from(self.size) { + self.check_data(); + Ok(self.data) + } else { + Err(self.size()) + } + } +} + +macro_rules! from { + ($($ty:ty),*) => { + $( + impl From<$ty> for ScalarInt { + #[inline] + fn from(u: $ty) -> Self { + Self { + data: u128::from(u), + size: std::mem::size_of::<$ty>() as u8, + } + } + } + )* + } +} + +macro_rules! try_from { + ($($ty:ty),*) => { + $( + impl TryFrom<ScalarInt> for $ty { + type Error = Size; + #[inline] + fn try_from(int: ScalarInt) -> Result<Self, Size> { + // The `unwrap` cannot fail because to_bits (if it succeeds) + // is guaranteed to return a value that fits into the size. + int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())) + .map(|u| u.try_into().unwrap()) + } + } + )* + } +} + +from!(u8, u16, u32, u64, u128, bool); +try_from!(u8, u16, u32, u64, u128); + +impl From<char> for ScalarInt { + #[inline] + fn from(c: char) -> Self { + Self { data: c as u128, size: std::mem::size_of::<char>() as u8 } + } +} + +impl TryFrom<ScalarInt> for char { + type Error = Size; + #[inline] + fn try_from(int: ScalarInt) -> Result<Self, Size> { + int.to_bits(Size::from_bytes(std::mem::size_of::<char>())) + .map(|u| char::from_u32(u.try_into().unwrap()).unwrap()) + } +} + +impl From<Single> for ScalarInt { + #[inline] + fn from(f: Single) -> Self { + // We trust apfloat to give us properly truncated data. + Self { data: f.to_bits(), size: 4 } + } +} + +impl TryFrom<ScalarInt> for Single { + type Error = Size; + #[inline] + fn try_from(int: ScalarInt) -> Result<Self, Size> { + int.to_bits(Size::from_bytes(4)).map(Self::from_bits) + } +} + +impl From<Double> for ScalarInt { + #[inline] + fn from(f: Double) -> Self { + // We trust apfloat to give us properly truncated data. + Self { data: f.to_bits(), size: 8 } + } +} + +impl TryFrom<ScalarInt> for Double { + type Error = Size; + #[inline] + fn try_from(int: ScalarInt) -> Result<Self, Size> { + int.to_bits(Size::from_bytes(8)).map(Self::from_bits) + } +} + +impl fmt::Debug for ScalarInt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.size == 0 { + self.check_data(); + write!(f, "<ZST>") + } else { + // Dispatch to LowerHex below. + write!(f, "0x{:x}", self) + } + } +} + +impl fmt::LowerHex for ScalarInt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.check_data(); + // Format as hex number wide enough to fit any value of the given `size`. + // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014". + // Using a block `{self.data}` here to force a copy instead of using `self.data` + // directly, because `write!` takes references to its formatting arguments and + // would thus borrow `self.data`. Since `Self` + // is a packed struct, that would create a possibly unaligned reference, which + // is UB. + write!(f, "{:01$x}", { self.data }, self.size as usize * 2) + } +} + +impl fmt::UpperHex for ScalarInt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.check_data(); + // Format as hex number wide enough to fit any value of the given `size`. + // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014". + // Using a block `{self.data}` here to force a copy instead of using `self.data` + // directly, because `write!` takes references to its formatting arguments and + // would thus borrow `self.data`. Since `Self` + // is a packed struct, that would create a possibly unaligned reference, which + // is UB. + write!(f, "{:01$X}", { self.data }, self.size as usize * 2) + } +} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f6ea6743a0e..216451f268f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -844,7 +844,7 @@ impl<'tcx> CommonConsts<'tcx> { CommonConsts { unit: mk_const(ty::Const { - val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::zst())), + val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::ZST)), ty: types.unit, }), } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 0e5e22dcaae..70a8157c04a 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -37,6 +37,7 @@ use rustc_hir::def_id::DefId; use rustc_data_structures::fx::FxHashSet; use std::collections::BTreeMap; use std::fmt; +use std::ops::ControlFlow; /// This trait is implemented for every type that can be folded. /// Basically, every type that has a corresponding method in `TypeFolder`. @@ -48,8 +49,8 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.super_fold_with(folder) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool; - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()>; + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { self.super_visit_with(visitor) } @@ -58,7 +59,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { /// If `binder` is `ty::INNERMOST`, this indicates whether /// there are any late-bound regions that appear free. fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { - self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }) + self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break() } /// Returns `true` if this `self` has any regions that escape `binder` (and @@ -72,7 +73,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } fn has_type_flags(&self, flags: TypeFlags) -> bool { - self.visit_with(&mut HasTypeFlagsVisitor { flags }) + self.visit_with(&mut HasTypeFlagsVisitor { flags }).is_break() } fn has_projections(&self) -> bool { self.has_type_flags(TypeFlags::HAS_PROJECTION) @@ -143,11 +144,11 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } /// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`. - fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> bool) -> bool { + fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> ControlFlow<()>) -> ControlFlow<()> { pub struct Visitor<F>(F); - impl<'tcx, F: FnMut(Ty<'tcx>) -> bool> TypeVisitor<'tcx> for Visitor<F> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + impl<'tcx, F: FnMut(Ty<'tcx>) -> ControlFlow<()>> TypeVisitor<'tcx> for Visitor<F> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { self.0(ty) } } @@ -160,8 +161,8 @@ impl TypeFoldable<'tcx> for hir::Constness { fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { *self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { - false + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> { + ControlFlow::CONTINUE } } @@ -194,23 +195,23 @@ pub trait TypeFolder<'tcx>: Sized { } pub trait TypeVisitor<'tcx>: Sized { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> { t.super_visit_with(self) } - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { t.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { r.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { c.super_visit_with(self) } - fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> bool { + fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<()> { p.super_visit_with(self) } } @@ -302,8 +303,6 @@ impl<'tcx> TyCtxt<'tcx> { value: &impl TypeFoldable<'tcx>, callback: impl FnMut(ty::Region<'tcx>) -> bool, ) -> bool { - return value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }); - struct RegionVisitor<F> { /// The index of a binder *just outside* the things we have /// traversed. If we encounter a bound region bound by this @@ -330,31 +329,39 @@ impl<'tcx> TyCtxt<'tcx> { where F: FnMut(ty::Region<'tcx>) -> bool, { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> { self.outer_index.shift_in(1); let result = t.as_ref().skip_binder().visit_with(self); self.outer_index.shift_out(1); result } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => { - false // ignore bound regions, keep visiting + ControlFlow::CONTINUE + } + _ => { + if (self.callback)(r) { + ControlFlow::BREAK + } else { + ControlFlow::CONTINUE + } } - _ => (self.callback)(r), } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { // We're only interested in types involving regions if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { ty.super_visit_with(self) } else { - false // keep visiting + ControlFlow::CONTINUE } } } + + value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break() } } @@ -670,7 +677,7 @@ impl<'tcx> TyCtxt<'tcx> { { let mut collector = LateBoundRegionsCollector::new(just_constraint); let result = value.as_ref().skip_binder().visit_with(&mut collector); - assert!(!result); // should never have stopped early + assert!(result.is_continue()); // should never have stopped early collector.regions } @@ -684,7 +691,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Rewrite any late-bound regions so that they are anonymous. Region numbers are - /// assigned starting at 1 and increasing monotonically in the order traversed + /// assigned starting at 0 and increasing monotonically in the order traversed /// by the fold operation. /// /// The chief purpose of this function is to canonicalize regions so that two @@ -698,8 +705,9 @@ impl<'tcx> TyCtxt<'tcx> { let mut counter = 0; Binder::bind( self.replace_late_bound_regions(sig, |_| { + let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(counter))); counter += 1; - self.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(counter))) + r }) .0, ) @@ -836,43 +844,55 @@ struct HasEscapingVarsVisitor { } impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> { self.outer_index.shift_in(1); let result = t.super_visit_with(self); self.outer_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { // If the outer-exclusive-binder is *strictly greater* than // `outer_index`, that means that `t` contains some content // bound at `outer_index` or above (because // `outer_exclusive_binder` is always 1 higher than the // content in `t`). Therefore, `t` has some escaping vars. - t.outer_exclusive_binder > self.outer_index + if t.outer_exclusive_binder > self.outer_index { + ControlFlow::BREAK + } else { + ControlFlow::CONTINUE + } } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { // If the region is bound by `outer_index` or anything outside // of outer index, then it escapes the binders we have // visited. - r.bound_at_or_above_binder(self.outer_index) + if r.bound_at_or_above_binder(self.outer_index) { + ControlFlow::BREAK + } else { + ControlFlow::CONTINUE + } } - fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> bool { + fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { // we don't have a `visit_infer_const` callback, so we have to // hook in here to catch this case (annoying...), but // otherwise we do want to remember to visit the rest of the // const, as it has types/regions embedded in a lot of other // places. match ct.val { - ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => true, + ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => ControlFlow::BREAK, _ => ct.super_visit_with(self), } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool { - predicate.inner.outer_exclusive_binder > self.outer_index + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> { + if predicate.inner.outer_exclusive_binder > self.outer_index { + ControlFlow::BREAK + } else { + ControlFlow::CONTINUE + } } } @@ -882,34 +902,38 @@ struct HasTypeFlagsVisitor { } impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { - fn visit_ty(&mut self, t: Ty<'_>) -> bool { + fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<()> { debug!( "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, t.flags(), self.flags ); - t.flags().intersects(self.flags) + if t.flags().intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { let flags = r.type_flags(); debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); - flags.intersects(self.flags) + if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { let flags = FlagComputation::for_const(c); debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); - flags.intersects(self.flags) + if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> { debug!( "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", predicate, predicate.inner.flags, self.flags ); - predicate.inner.flags.intersects(self.flags) + if predicate.inner.flags.intersects(self.flags) { + ControlFlow::BREAK + } else { + ControlFlow::CONTINUE + } } } @@ -940,45 +964,45 @@ impl LateBoundRegionsCollector { } impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> { self.current_index.shift_in(1); let result = t.super_visit_with(self); self.current_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { // if we are only looking for "constrained" region, we have to // ignore the inputs to a projection, as they may not appear // in the normalized form if self.just_constrained { if let ty::Projection(..) | ty::Opaque(..) = t.kind() { - return false; + return ControlFlow::CONTINUE; } } t.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { // if we are only looking for "constrained" region, we have to // ignore the inputs of an unevaluated const, as they may not appear // in the normalized form if self.just_constrained { if let ty::ConstKind::Unevaluated(..) = c.val { - return false; + return ControlFlow::CONTINUE; } } c.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { if let ty::ReLateBound(debruijn, br) = *r { if debruijn == self.current_index { self.regions.insert(br); } } - false + ControlFlow::CONTINUE } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a400b85cdb7..aa5a696b09c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -46,7 +46,7 @@ use std::cell::RefCell; use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; -use std::ops::Range; +use std::ops::{ControlFlow, Range}; use std::ptr; use std::str; @@ -87,7 +87,7 @@ pub use self::trait_def::TraitDef; pub use self::query::queries; -pub use self::consts::{Const, ConstInt, ConstKind, InferConst}; +pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt}; pub mod _match; pub mod adjustment; @@ -1641,7 +1641,7 @@ pub type PlaceholderConst = Placeholder<BoundVar>; #[derive(Hash, HashStable)] pub struct WithOptConstParam<T> { pub did: T, - /// The `DefId` of the corresponding generic paramter in case `did` is + /// The `DefId` of the corresponding generic parameter in case `did` is /// a const argument. /// /// Note that even if `did` is a const argument, this may still be `None`. @@ -1776,8 +1776,9 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.caller_bounds().visit_with(visitor) || self.reveal().visit_with(visitor) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.caller_bounds().visit_with(visitor)?; + self.reveal().visit_with(visitor) } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 9735099a4e1..8ff4adda606 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,12 +1,9 @@ use crate::middle::cstore::{ExternCrate, ExternCrateSource}; use crate::mir::interpret::{AllocId, ConstValue, GlobalAlloc, Pointer, Scalar}; -use crate::ty::layout::IntegerExt; use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; -use crate::ty::{self, ConstInt, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable}; use rustc_apfloat::ieee::{Double, Single}; -use rustc_apfloat::Float; use rustc_ast as ast; -use rustc_attr::{SignedInt, UnsignedInt}; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; @@ -15,14 +12,15 @@ use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathD use rustc_hir::ItemKind; use rustc_session::config::TrimmedDefPaths; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_target::abi::{Integer, Size}; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use std::cell::Cell; use std::char; use std::collections::BTreeMap; +use std::convert::TryFrom; use std::fmt::{self, Write as _}; -use std::ops::{Deref, DerefMut}; +use std::ops::{ControlFlow, Deref, DerefMut}; // `pretty` is a separate module only for organization. use super::*; @@ -960,11 +958,7 @@ pub trait PrettyPrinter<'tcx>: ty::Array( ty::TyS { kind: ty::Uint(ast::UintTy::U8), .. }, ty::Const { - val: - ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { - data, - .. - })), + val: ty::ConstKind::Value(ConstValue::Scalar(int)), .. }, ), @@ -974,8 +968,9 @@ pub trait PrettyPrinter<'tcx>: ), ) => match self.tcx().get_global_alloc(ptr.alloc_id) { Some(GlobalAlloc::Memory(alloc)) => { - if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), ptr, Size::from_bytes(*data)) - { + let bytes = int.assert_bits(self.tcx().data_layout.pointer_size); + let size = Size::from_bytes(bytes); + if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), ptr, size) { p!(pretty_print_byte_str(byte_str)) } else { p!("<too short allocation>") @@ -987,32 +982,28 @@ pub trait PrettyPrinter<'tcx>: None => p!("<dangling pointer>"), }, // Bool - (Scalar::Raw { data: 0, .. }, ty::Bool) => p!("false"), - (Scalar::Raw { data: 1, .. }, ty::Bool) => p!("true"), + (Scalar::Int(int), ty::Bool) if int == ScalarInt::FALSE => p!("false"), + (Scalar::Int(int), ty::Bool) if int == ScalarInt::TRUE => p!("true"), // Float - (Scalar::Raw { data, .. }, ty::Float(ast::FloatTy::F32)) => { - p!(write("{}f32", Single::from_bits(data))) + (Scalar::Int(int), ty::Float(ast::FloatTy::F32)) => { + p!(write("{}f32", Single::try_from(int).unwrap())) } - (Scalar::Raw { data, .. }, ty::Float(ast::FloatTy::F64)) => { - p!(write("{}f64", Double::from_bits(data))) + (Scalar::Int(int), ty::Float(ast::FloatTy::F64)) => { + p!(write("{}f64", Double::try_from(int).unwrap())) } // Int - (Scalar::Raw { data, .. }, ty::Uint(ui)) => { - let size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size(); - let int = ConstInt::new(data, size, false, ty.is_ptr_sized_integral()); - if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) } - } - (Scalar::Raw { data, .. }, ty::Int(i)) => { - let size = Integer::from_attr(&self.tcx(), SignedInt(*i)).size(); - let int = ConstInt::new(data, size, true, ty.is_ptr_sized_integral()); + (Scalar::Int(int), ty::Uint(_) | ty::Int(_)) => { + let int = + ConstInt::new(int, matches!(ty.kind(), ty::Int(_)), ty.is_ptr_sized_integral()); if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) } } // Char - (Scalar::Raw { data, .. }, ty::Char) if char::from_u32(data as u32).is_some() => { - p!(write("{:?}", char::from_u32(data as u32).unwrap())) + (Scalar::Int(int), ty::Char) if char::try_from(int).is_ok() => { + p!(write("{:?}", char::try_from(int).unwrap())) } // Raw pointers - (Scalar::Raw { data, .. }, ty::RawPtr(_)) => { + (Scalar::Int(int), ty::RawPtr(_)) => { + let data = int.assert_bits(self.tcx().data_layout.pointer_size); self = self.typed_value( |mut this| { write!(this, "0x{:x}", data)?; @@ -1034,14 +1025,16 @@ pub trait PrettyPrinter<'tcx>: )?; } // For function type zsts just printing the path is enough - (Scalar::Raw { size: 0, .. }, ty::FnDef(d, s)) => p!(print_value_path(*d, s)), + (Scalar::Int(int), ty::FnDef(d, s)) if int == ScalarInt::ZST => { + p!(print_value_path(*d, s)) + } // Nontrivial types with scalar bit representation - (Scalar::Raw { data, size }, _) => { + (Scalar::Int(int), _) => { let print = |mut this: Self| { - if size == 0 { + if int.size() == Size::ZERO { write!(this, "transmute(())")?; } else { - write!(this, "transmute(0x{:01$x})", data, size as usize * 2)?; + write!(this, "transmute(0x{:x})", int)?; } Ok(this) }; @@ -1803,7 +1796,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { { struct LateBoundRegionNameCollector<'a>(&'a mut FxHashSet<Symbol>); impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_> { - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { if let ty::ReLateBound(_, ty::BrNamed(_, name)) = *r { self.0.insert(name); } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 53521d0e9f3..431225e2767 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -14,6 +14,7 @@ use rustc_index::vec::{Idx, IndexVec}; use smallvec::SmallVec; use std::fmt; +use std::ops::ControlFlow; use std::rc::Rc; use std::sync::Arc; @@ -727,8 +728,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef { *self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool { - false + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<()> { + ControlFlow::CONTINUE } } @@ -737,8 +738,9 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (self.0.fold_with(folder), self.1.fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.0.visit_with(visitor) || self.1.visit_with(visitor) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.0.visit_with(visitor)?; + self.1.visit_with(visitor) } } @@ -749,8 +751,10 @@ impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.0.visit_with(visitor) || self.1.visit_with(visitor) || self.2.visit_with(visitor) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.0.visit_with(visitor)?; + self.1.visit_with(visitor)?; + self.2.visit_with(visitor) } } @@ -773,7 +777,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> { Rc::new((**self).fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { (**self).visit_with(visitor) } } @@ -783,7 +787,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> { Arc::new((**self).fold_with(folder)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { (**self).visit_with(visitor) } } @@ -794,7 +798,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> { box content } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { (**self).visit_with(visitor) } } @@ -804,8 +808,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> { self.iter().map(|t| t.fold_with(folder)).collect() } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -814,8 +818,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>().into_boxed_slice() } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -828,11 +832,11 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> { folder.fold_binder(self) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { self.as_ref().skip_binder().visit_with(visitor) } - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { visitor.visit_binder(self) } } @@ -842,8 +846,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> fold_list(*self, folder, |tcx, v| tcx.intern_existential_predicates(v)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|p| p.visit_with(visitor)) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.iter().try_for_each(|p| p.visit_with(visitor)) } } @@ -852,8 +856,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> { fold_list(*self, folder, |tcx, v| tcx.intern_type_list(v)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -862,8 +866,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> { fold_list(*self, folder, |tcx, v| tcx.intern_projs(v)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -888,20 +892,24 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { use crate::ty::InstanceDef::*; - self.substs.visit_with(visitor) - || match self.def { - Item(def) => def.visit_with(visitor), - VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { - did.visit_with(visitor) - } - FnPtrShim(did, ty) | CloneShim(did, ty) => { - did.visit_with(visitor) || ty.visit_with(visitor) - } - DropGlue(did, ty) => did.visit_with(visitor) || ty.visit_with(visitor), - ClosureOnceShim { call_once } => call_once.visit_with(visitor), + self.substs.visit_with(visitor)?; + match self.def { + Item(def) => def.visit_with(visitor), + VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { + did.visit_with(visitor) + } + FnPtrShim(did, ty) | CloneShim(did, ty) => { + did.visit_with(visitor)?; + ty.visit_with(visitor) + } + DropGlue(did, ty) => { + did.visit_with(visitor)?; + ty.visit_with(visitor) } + ClosureOnceShim { call_once } => call_once.visit_with(visitor), + } } } @@ -910,7 +918,7 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { Self { instance: self.instance.fold_with(folder), promoted: self.promoted } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { self.instance.visit_with(visitor) } } @@ -959,19 +967,26 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { folder.fold_ty(*self) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { match self.kind() { ty::RawPtr(ref tm) => tm.visit_with(visitor), - ty::Array(typ, sz) => typ.visit_with(visitor) || sz.visit_with(visitor), + ty::Array(typ, sz) => { + typ.visit_with(visitor)?; + sz.visit_with(visitor) + } ty::Slice(typ) => typ.visit_with(visitor), ty::Adt(_, substs) => substs.visit_with(visitor), ty::Dynamic(ref trait_ty, ref reg) => { - trait_ty.visit_with(visitor) || reg.visit_with(visitor) + trait_ty.visit_with(visitor)?; + reg.visit_with(visitor) } ty::Tuple(ts) => ts.visit_with(visitor), ty::FnDef(_, substs) => substs.visit_with(visitor), ty::FnPtr(ref f) => f.visit_with(visitor), - ty::Ref(r, ty, _) => r.visit_with(visitor) || ty.visit_with(visitor), + ty::Ref(r, ty, _) => { + r.visit_with(visitor)?; + ty.visit_with(visitor) + } ty::Generator(_did, ref substs, _) => substs.visit_with(visitor), ty::GeneratorWitness(ref types) => types.visit_with(visitor), ty::Closure(_did, ref substs) => substs.visit_with(visitor), @@ -990,11 +1005,11 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { | ty::Placeholder(..) | ty::Param(..) | ty::Never - | ty::Foreign(..) => false, + | ty::Foreign(..) => ControlFlow::CONTINUE, } } - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { visitor.visit_ty(self) } } @@ -1008,11 +1023,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { folder.fold_region(*self) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool { - false + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<()> { + ControlFlow::CONTINUE } - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { visitor.visit_region(*self) } } @@ -1023,11 +1038,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { folder.tcx().reuse_or_mk_predicate(*self, new) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { ty::PredicateKind::super_visit_with(&self.inner.kind, visitor) } - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { visitor.visit_predicate(*self) } @@ -1045,8 +1060,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> { fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v)) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|p| p.visit_with(visitor)) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.iter().try_for_each(|p| p.visit_with(visitor)) } } @@ -1055,8 +1070,8 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> self.iter().map(|x| x.fold_with(folder)).collect() } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.iter().try_for_each(|t| t.visit_with(visitor)) } } @@ -1075,11 +1090,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { folder.fold_const(*self) } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.ty.visit_with(visitor) || self.val.visit_with(visitor) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.ty.visit_with(visitor)?; + self.val.visit_with(visitor) } - fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { visitor.visit_const(self) } } @@ -1099,7 +1115,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { match *self { ty::ConstKind::Infer(ic) => ic.visit_with(visitor), ty::ConstKind::Param(p) => p.visit_with(visitor), @@ -1107,7 +1123,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) - | ty::ConstKind::Error(_) => false, + | ty::ConstKind::Error(_) => ControlFlow::CONTINUE, } } } @@ -1117,8 +1133,8 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { *self } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool { - false + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<()> { + ControlFlow::CONTINUE } } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index f04144c218e..07f775cf8b1 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -17,6 +17,7 @@ use std::fmt; use std::marker::PhantomData; use std::mem; use std::num::NonZeroUsize; +use std::ops::ControlFlow; /// An entity in the Rust type system, which can be one of /// several kinds (types, lifetimes, and consts). @@ -159,7 +160,7 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> { } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { match self.unpack() { GenericArgKind::Lifetime(lt) => lt.visit_with(visitor), GenericArgKind::Type(ty) => ty.visit_with(visitor), @@ -391,8 +392,8 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> { } } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> { + self.iter().try_for_each(|t| t.visit_with(visitor)) } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 4a20e1c32f9..5f117e19eca 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -2,7 +2,6 @@ use crate::ich::NodeIdHashingMode; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::mir::interpret::{sign_extend, truncate}; use crate::ty::fold::TypeFolder; use crate::ty::layout::IntegerExt; use crate::ty::query::TyCtxtAt; @@ -38,7 +37,7 @@ impl<'tcx> fmt::Display for Discr<'tcx> { let size = ty::tls::with(|tcx| Integer::from_attr(&tcx, SignedInt(ity)).size()); let x = self.val; // sign extend the raw representation to be an i128 - let x = sign_extend(x, size) as i128; + let x = size.sign_extend(x) as i128; write!(fmt, "{}", x) } _ => write!(fmt, "{}", self.val), @@ -47,7 +46,7 @@ impl<'tcx> fmt::Display for Discr<'tcx> { } fn signed_min(size: Size) -> i128 { - sign_extend(1_u128 << (size.bits() - 1), size) as i128 + size.sign_extend(1_u128 << (size.bits() - 1)) as i128 } fn signed_max(size: Size) -> i128 { @@ -77,14 +76,14 @@ impl<'tcx> Discr<'tcx> { let (val, oflo) = if signed { let min = signed_min(size); let max = signed_max(size); - let val = sign_extend(self.val, size) as i128; + let val = size.sign_extend(self.val) as i128; assert!(n < (i128::MAX as u128)); let n = n as i128; let oflo = val > max - n; let val = if oflo { min + (n - (max - val) - 1) } else { val + n }; // zero the upper bits let val = val as u128; - let val = truncate(val, size); + let val = size.truncate(val); (val, oflo) } else { let max = unsigned_max(size); @@ -650,7 +649,7 @@ impl<'tcx> ty::TyS<'tcx> { let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); - let val = if signed { truncate(signed_min(size) as u128, size) } else { 0 }; + let val = if signed { size.truncate(signed_min(size) as u128) } else { 0 }; Some(val) } ty::Char => Some(0), diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index dca0d6d7790..1474c7abfad 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -120,7 +120,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let move_out = self.move_data.moves[(*move_site).moi]; let moved_place = &self.move_data.move_paths[move_out.path].place; // `*(_1)` where `_1` is a `Box` is actually a move out. - let is_box_move = moved_place.as_ref().projection == &[ProjectionElem::Deref] + let is_box_move = moved_place.as_ref().projection == [ProjectionElem::Deref] && self.body.local_decls[moved_place.local].ty.is_box(); !is_box_move diff --git a/compiler/rustc_mir/src/borrow_check/nll.rs b/compiler/rustc_mir/src/borrow_check/nll.rs index aa428328fe9..359c5f261a4 100644 --- a/compiler/rustc_mir/src/borrow_check/nll.rs +++ b/compiler/rustc_mir/src/borrow_check/nll.rs @@ -275,8 +275,8 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( let polonius_output = all_facts.and_then(|all_facts| { if infcx.tcx.sess.opts.debugging_opts.nll_facts { let def_path = infcx.tcx.def_path(def_id); - let dir_path = - PathBuf::from("nll-facts").join(def_path.to_filename_friendly_no_crate()); + let dir_path = PathBuf::from(&infcx.tcx.sess.opts.debugging_opts.nll_facts_dir) + .join(def_path.to_filename_friendly_no_crate()); all_facts.write_to_dir(dir_path, location_table).unwrap(); } diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs index 044d27a6a9d..39358e03e75 100644 --- a/compiler/rustc_mir/src/const_eval/error.rs +++ b/compiler/rustc_mir/src/const_eval/error.rs @@ -141,7 +141,7 @@ impl<'tcx> ConstEvalErr<'tcx> { err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { return ErrorHandled::TooGeneric; } - err_inval!(TypeckError(error_reported)) => { + err_inval!(AlreadyReported(error_reported)) => { return ErrorHandled::Reported(error_reported); } // We must *always* hard error on these, even if the caller wants just a lint. diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 7b9a4ec873d..0cac7c087d4 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, subst::Subst, TyCtxt}; use rustc_span::source_map::Span; use rustc_target::abi::{Abi, LayoutOf}; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryInto; pub fn note_on_undefined_behavior_error() -> &'static str { "The rules on what exactly is undefined behavior aren't clear, \ @@ -67,7 +67,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( None => InternKind::Constant, } }; - intern_const_alloc_recursive(ecx, intern_kind, ret); + intern_const_alloc_recursive(ecx, intern_kind, ret)?; debug!("eval_body_using_ecx done: {:?}", *ret); Ok(ret) @@ -137,15 +137,16 @@ pub(super) fn op_to_const<'tcx>( let alloc = ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(); ConstValue::ByRef { alloc, offset: ptr.offset } } - Scalar::Raw { data, .. } => { + Scalar::Int(int) => { assert!(mplace.layout.is_zst()); assert_eq!( - u64::try_from(data).unwrap() % mplace.layout.align.abi.bytes(), + int.assert_bits(ecx.tcx.data_layout.pointer_size) + % u128::from(mplace.layout.align.abi.bytes()), 0, "this MPlaceTy must come from a validated constant, thus we can assume the \ alignment is correct", ); - ConstValue::Scalar(Scalar::zst()) + ConstValue::Scalar(Scalar::ZST) } }; match immediate { @@ -161,7 +162,7 @@ pub(super) fn op_to_const<'tcx>( Scalar::Ptr(ptr) => { (ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(), ptr.offset.bytes()) } - Scalar::Raw { .. } => ( + Scalar::Int { .. } => ( ecx.tcx .intern_const_alloc(Allocation::from_byte_aligned_bytes(b"" as &[u8])), 0, diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 7e2cae09481..c72089ec55a 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -181,9 +181,9 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool { match (a, b) { // Comparisons between integers are always known. - (Scalar::Raw { .. }, Scalar::Raw { .. }) => a == b, + (Scalar::Int { .. }, Scalar::Int { .. }) => a == b, // Equality with integers can never be known for sure. - (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false, + (Scalar::Int { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Int { .. }) => false, // FIXME: return `true` for when both sides are the same pointer, *except* that // some things (like functions and vtables) do not have stable addresses // so we need to be careful around them (see e.g. #73722). @@ -194,13 +194,13 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> bool { match (a, b) { // Comparisons between integers are always known. - (Scalar::Raw { .. }, Scalar::Raw { .. }) => a != b, + (Scalar::Int(_), Scalar::Int(_)) => a != b, // Comparisons of abstract pointers with null pointers are known if the pointer // is in bounds, because if they are in bounds, the pointer can't be null. - (Scalar::Raw { data: 0, .. }, Scalar::Ptr(ptr)) - | (Scalar::Ptr(ptr), Scalar::Raw { data: 0, .. }) => !self.memory.ptr_may_be_null(ptr), // Inequality with integers other than null can never be known for sure. - (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false, + (Scalar::Int(int), Scalar::Ptr(ptr)) | (Scalar::Ptr(ptr), Scalar::Int(int)) => { + int.is_null() && !self.memory.ptr_may_be_null(ptr) + } // FIXME: return `true` for at least some comparisons where we can reliably // determine the result of runtime inequality tests at compile-time. // Examples include comparison of addresses in different static items. diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index 11a211ef7b3..9dd2a8592a7 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -29,7 +29,9 @@ pub(crate) fn const_caller_location( let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false); let loc_place = ecx.alloc_caller_location(file, line, col); - intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place); + if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place).is_err() { + bug!("intern_const_alloc_recursive should not error in this case") + } ConstValue::Scalar(loc_place.ptr) } diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs index affeae546b2..6d224bcc50b 100644 --- a/compiler/rustc_mir/src/interpret/cast.rs +++ b/compiler/rustc_mir/src/interpret/cast.rs @@ -13,8 +13,7 @@ use rustc_span::symbol::sym; use rustc_target::abi::{Integer, LayoutOf, Variants}; use super::{ - truncate, util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, - PlaceTy, + util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, }; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { @@ -209,7 +208,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { RawPtr(_) => self.pointer_size(), _ => bug!(), }; - let v = truncate(v, size); + let v = size.truncate(v); Scalar::from_uint(v, size) } diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index ec1195d3703..8d0c8c18537 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -9,9 +9,7 @@ use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_middle::ich::StableHashingContext; use rustc_middle::mir; -use rustc_middle::mir::interpret::{ - sign_extend, truncate, GlobalId, InterpResult, Pointer, Scalar, -}; +use rustc_middle::mir::interpret::{GlobalId, InterpResult, Pointer, Scalar}; use rustc_middle::ty::layout::{self, TyAndLayout}; use rustc_middle::ty::{ self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, @@ -443,12 +441,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn sign_extend(&self, value: u128, ty: TyAndLayout<'_>) -> u128 { assert!(ty.abi.is_signed()); - sign_extend(value, ty.size) + ty.size.sign_extend(value) } #[inline(always)] pub fn truncate(&self, value: u128, ty: TyAndLayout<'_>) -> u128 { - truncate(value, ty.size) + ty.size.truncate(value) } #[inline] @@ -471,7 +469,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Some(def) = def.as_local() { if self.tcx.has_typeck_results(def.did) { if let Some(error_reported) = self.tcx.typeck_opt_const_arg(def).tainted_by_errors { - throw_inval!(TypeckError(error_reported)) + throw_inval!(AlreadyReported(error_reported)) } } } @@ -527,8 +525,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(Some(instance)) => Ok(instance), Ok(None) => throw_inval!(TooGeneric), - // FIXME(eddyb) this could be a bit more specific than `TypeckError`. - Err(error_reported) => throw_inval!(TypeckError(error_reported)), + // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`. + Err(error_reported) => throw_inval!(AlreadyReported(error_reported)), } } diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index 5e5c74a3723..413be427339 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -16,6 +16,7 @@ use super::validity::RefTracking; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_middle::mir::interpret::InterpResult; use rustc_middle::ty::{self, layout::TyAndLayout, Ty}; @@ -285,11 +286,13 @@ pub enum InternKind { /// tracks where in the value we are and thus can show much better error messages. /// Any errors here would anyway be turned into `const_err` lints, whereas validation failures /// are hard errors. +#[tracing::instrument(skip(ecx))] pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>( ecx: &mut InterpCx<'mir, 'tcx, M>, intern_kind: InternKind, ret: MPlaceTy<'tcx>, -) where +) -> Result<(), ErrorReported> +where 'tcx: 'mir, { let tcx = ecx.tcx; @@ -405,12 +408,14 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>( // Codegen does not like dangling pointers, and generally `tcx` assumes that // all allocations referenced anywhere actually exist. So, make sure we error here. ecx.tcx.sess.span_err(ecx.tcx.span, "encountered dangling pointer in final constant"); + return Err(ErrorReported); } else if ecx.tcx.get_global_alloc(alloc_id).is_none() { // We have hit an `AllocId` that is neither in local or global memory and isn't // marked as dangling by local memory. That should be impossible. span_bug!(ecx.tcx.span, "encountered unknown alloc id {:?}", alloc_id); } } + Ok(()) } impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 3c68b1c8355..d9437a312ae 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -211,14 +211,8 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> { #[inline] pub fn to_const_int(self) -> ConstInt { assert!(self.layout.ty.is_integral()); - ConstInt::new( - self.to_scalar() - .expect("to_const_int doesn't work on scalar pairs") - .assert_bits(self.layout.size), - self.layout.size, - self.layout.ty.is_signed(), - self.layout.ty.is_ptr_sized_integral(), - ) + let int = self.to_scalar().expect("to_const_int doesn't work on scalar pairs").assert_int(); + ConstInt::new(int, self.layout.ty.is_signed(), self.layout.ty.is_ptr_sized_integral()) } } @@ -262,7 +256,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } return Ok(Some(ImmTy { // zero-sized type - imm: Scalar::zst().into(), + imm: Scalar::ZST.into(), layout: mplace.layout, })); } @@ -361,7 +355,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let field_layout = op.layout.field(self, field)?; if field_layout.is_zst() { - let immediate = Scalar::zst().into(); + let immediate = Scalar::ZST.into(); return Ok(OpTy { op: Operand::Immediate(immediate), layout: field_layout }); } let offset = op.layout.fields.offset(field); @@ -446,7 +440,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = self.layout_of_local(frame, local, layout)?; let op = if layout.is_zst() { // Do not read from ZST, they might not be initialized - Operand::Immediate(Scalar::zst().into()) + Operand::Immediate(Scalar::ZST.into()) } else { M::access_local(&self, frame, local)? }; @@ -544,13 +538,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let tag_scalar = |scalar| -> InterpResult<'tcx, _> { Ok(match scalar { Scalar::Ptr(ptr) => Scalar::Ptr(self.global_base_pointer(ptr)?), - Scalar::Raw { data, size } => Scalar::Raw { data, size }, + Scalar::Int(int) => Scalar::Int(int), }) }; // Early-return cases. let val_val = match val.val { ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), - ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)), + ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)), ty::ConstKind::Unevaluated(def, substs, promoted) => { let instance = self.resolve(def, substs)?; return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into()); diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs index fe25f8ce962..a003380dda7 100644 --- a/compiler/rustc_mir/src/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -14,9 +14,9 @@ use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding}; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants}; use super::{ - mir_assign_valid_types, truncate, AllocId, AllocMap, Allocation, AllocationExtra, ConstAlloc, - ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, - Pointer, PointerArithmetic, Scalar, ScalarMaybeUninit, + mir_assign_valid_types, AllocId, AllocMap, Allocation, AllocationExtra, ConstAlloc, ImmTy, + Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, + PointerArithmetic, Scalar, ScalarMaybeUninit, }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] @@ -721,12 +721,8 @@ where dest.layout.size, "Size mismatch when writing pointer" ), - Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::Raw { size, .. })) => { - assert_eq!( - Size::from_bytes(size), - dest.layout.size, - "Size mismatch when writing bits" - ) + Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::Int(int))) => { + assert_eq!(int.size(), dest.layout.size, "Size mismatch when writing bits") } Immediate::Scalar(ScalarMaybeUninit::Uninit) => {} // uninit can have any size Immediate::ScalarPair(_, _) => { @@ -1077,7 +1073,7 @@ where // their computation, but the in-memory tag is the smallest possible // representation let size = tag_layout.value.size(self); - let tag_val = truncate(discr_val, size); + let tag_val = size.truncate(discr_val); let tag_dest = self.place_field(dest, tag_field)?; self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?; diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index fc5a25ffbf2..fce5553c993 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -1,6 +1,7 @@ use rustc_middle::mir::interpret::InterpResult; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use std::convert::TryInto; +use std::ops::ControlFlow; /// Returns `true` if a used generic parameter requires substitution. crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx> @@ -17,24 +18,24 @@ where }; impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { if !c.needs_subst() { - return false; + return ControlFlow::CONTINUE; } match c.val { - ty::ConstKind::Param(..) => true, + ty::ConstKind::Param(..) => ControlFlow::BREAK, _ => c.super_visit_with(self), } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { if !ty.needs_subst() { - return false; + return ControlFlow::CONTINUE; } match *ty.kind() { - ty::Param(_) => true, + ty::Param(_) => ControlFlow::BREAK, ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) | ty::FnDef(def_id, substs) => { @@ -50,11 +51,7 @@ where match (is_used, subst.needs_subst()) { // Just in case there are closures or generators within this subst, // recurse. - (true, true) if subst.super_visit_with(self) => { - // Only return when we find a parameter so the remaining substs - // are not skipped. - return true; - } + (true, true) => return subst.super_visit_with(self), // Confirm that polymorphization replaced the parameter with // `ty::Param`/`ty::ConstKind::Param`. (false, true) if cfg!(debug_assertions) => match subst.unpack() { @@ -69,7 +66,7 @@ where _ => {} } } - false + ControlFlow::CONTINUE } _ => ty.super_visit_with(self), } @@ -77,7 +74,7 @@ where } let mut vis = UsedParamsNeedSubstVisitor { tcx }; - if ty.visit_with(&mut vis) { + if ty.visit_with(&mut vis).is_break() { throw_inval!(TooGeneric); } else { Ok(()) diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index c00c6860903..2ed115b1297 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -27,6 +27,7 @@ Rust MIR: a lowered representation of Rust. #![feature(option_expect_none)] #![feature(or_patterns)] #![feature(once_cell)] +#![feature(control_flow_enum)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs index 3f6f117acdc..c2ebc954a22 100644 --- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs +++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::{ }; use rustc_span::symbol::sym; use std::convert::TryInto; +use std::ops::ControlFlow; /// Provide implementations of queries relating to polymorphization analysis. pub fn provide(providers: &mut Providers) { @@ -138,7 +139,7 @@ fn mark_used_by_predicates<'tcx>( // predicate is used. let any_param_used = { let mut vis = HasUsedGenericParams { unused_parameters }; - predicate.visit_with(&mut vis) + predicate.visit_with(&mut vis).is_break() }; if any_param_used { @@ -249,17 +250,17 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool { + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<()> { debug!("visit_const: c={:?}", c); if !c.has_param_types_or_consts() { - return false; + return ControlFlow::CONTINUE; } match c.val { ty::ConstKind::Param(param) => { debug!("visit_const: param={:?}", param); self.unused_parameters.clear(param.index); - false + ControlFlow::CONTINUE } ty::ConstKind::Unevaluated(def, _, Some(p)) // Avoid considering `T` unused when constants are of the form: @@ -270,22 +271,22 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { // the generic parameters, instead, traverse the promoted MIR. let promoted = self.tcx.promoted_mir(def.did); self.visit_body(&promoted[p]); - false + ControlFlow::CONTINUE } ty::ConstKind::Unevaluated(def, unevaluated_substs, None) if self.tcx.def_kind(def.did) == DefKind::AnonConst => { self.visit_child_body(def.did, unevaluated_substs); - false + ControlFlow::CONTINUE } _ => c.super_visit_with(self), } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { debug!("visit_ty: ty={:?}", ty); if !ty.has_param_types_or_consts() { - return false; + return ControlFlow::CONTINUE; } match *ty.kind() { @@ -293,18 +294,18 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { debug!("visit_ty: def_id={:?}", def_id); // Avoid cycle errors with generators. if def_id == self.def_id { - return false; + return ControlFlow::CONTINUE; } // Consider any generic parameters used by any closures/generators as used in the // parent. self.visit_child_body(def_id, substs); - false + ControlFlow::CONTINUE } ty::Param(param) => { debug!("visit_ty: param={:?}", param); self.unused_parameters.clear(param.index); - false + ControlFlow::CONTINUE } _ => ty.super_visit_with(self), } @@ -317,28 +318,38 @@ struct HasUsedGenericParams<'a> { } impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool { + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<()> { debug!("visit_const: c={:?}", c); if !c.has_param_types_or_consts() { - return false; + return ControlFlow::CONTINUE; } match c.val { ty::ConstKind::Param(param) => { - !self.unused_parameters.contains(param.index).unwrap_or(false) + if self.unused_parameters.contains(param.index).unwrap_or(false) { + ControlFlow::CONTINUE + } else { + ControlFlow::BREAK + } } _ => c.super_visit_with(self), } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { debug!("visit_ty: ty={:?}", ty); if !ty.has_param_types_or_consts() { - return false; + return ControlFlow::CONTINUE; } match ty.kind() { - ty::Param(param) => !self.unused_parameters.contains(param.index).unwrap_or(false), + ty::Param(param) => { + if self.unused_parameters.contains(param.index).unwrap_or(false) { + ControlFlow::CONTINUE + } else { + ControlFlow::BREAK + } + } _ => ty.super_visit_with(self), } } diff --git a/compiler/rustc_mir/src/transform/add_retag.rs b/compiler/rustc_mir/src/transform/add_retag.rs index eec704e6cb7..6fe9f64be32 100644 --- a/compiler/rustc_mir/src/transform/add_retag.rs +++ b/compiler/rustc_mir/src/transform/add_retag.rs @@ -73,6 +73,19 @@ impl<'tcx> MirPass<'tcx> for AddRetag { // a temporary and retag on that. is_stable(place.as_ref()) && may_be_reference(place.ty(&*local_decls, tcx).ty) }; + let place_base_raw = |place: &Place<'tcx>| { + // If this is a `Deref`, get the type of what we are deref'ing. + let deref_base = + place.projection.iter().rposition(|p| matches!(p, ProjectionElem::Deref)); + if let Some(deref_base) = deref_base { + let base_proj = &place.projection[..deref_base]; + let ty = Place::ty_from(place.local, base_proj, &*local_decls, tcx).ty; + ty.is_unsafe_ptr() + } else { + // Not a deref, and thus not raw. + false + } + }; // PART 1 // Retag arguments at the beginning of the start block. @@ -136,13 +149,14 @@ impl<'tcx> MirPass<'tcx> for AddRetag { // iterate backwards using indices. for i in (0..block_data.statements.len()).rev() { let (retag_kind, place) = match block_data.statements[i].kind { - // Retag-as-raw after escaping to a raw pointer. - StatementKind::Assign(box (place, Rvalue::AddressOf(..))) => { - (RetagKind::Raw, place) + // Retag-as-raw after escaping to a raw pointer, if the referent + // is not already a raw pointer. + StatementKind::Assign(box (lplace, Rvalue::AddressOf(_, ref rplace))) + if !place_base_raw(rplace) => + { + (RetagKind::Raw, lplace) } - // Assignments of reference or ptr type are the ones where we may have - // to update tags. This includes `x = &[mut] ...` and hence - // we also retag after taking a reference! + // Retag after assignments of reference type. StatementKind::Assign(box (ref place, ref rvalue)) if needs_retag(place) => { let kind = match rvalue { Rvalue::Ref(_, borrow_kind, _) diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index d47e549b7be..aeb9920c0e3 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -19,7 +19,9 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::layout::{HasTyCtxt, LayoutError, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, ConstInt, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ + self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable, +}; use rustc_session::lint; use rustc_span::{def_id::DefId, Span}; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout}; @@ -27,10 +29,9 @@ use rustc_trait_selection::traits; use crate::const_eval::ConstEvalErr; use crate::interpret::{ - self, compile_time_machine, truncate, AllocId, Allocation, ConstValue, CtfeValidationMode, - Frame, ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, Memory, - MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, - StackPopCleanup, + self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy, + Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, + Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup, }; use crate::transform::MirPass; @@ -578,8 +579,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Some(l) => l.to_const_int(), // Invent a dummy value, the diagnostic ignores it anyway None => ConstInt::new( - 1, - left_size, + ScalarInt::try_from_uint(1_u8, left_size).unwrap(), left_ty.is_signed(), left_ty.is_ptr_sized_integral(), ), @@ -745,7 +745,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } BinOp::BitOr => { - if arg_value == truncate(u128::MAX, const_arg.layout.size) + if arg_value == const_arg.layout.size.truncate(u128::MAX) || (const_arg.layout.ty.is_bool() && arg_value == 1) { this.ecx.write_immediate(*const_arg, dest)?; diff --git a/compiler/rustc_mir/src/transform/function_item_references.rs b/compiler/rustc_mir/src/transform/function_item_references.rs index 61427422e4b..d592580af9c 100644 --- a/compiler/rustc_mir/src/transform/function_item_references.rs +++ b/compiler/rustc_mir/src/transform/function_item_references.rs @@ -51,10 +51,11 @@ impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> { let arg_ty = args[0].ty(self.body, self.tcx); for generic_inner_ty in arg_ty.walk() { if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { - if let Some(fn_id) = FunctionItemRefChecker::is_fn_ref(inner_ty) { - let ident = self.tcx.item_name(fn_id).to_ident_string(); + if let Some((fn_id, fn_substs)) = + FunctionItemRefChecker::is_fn_ref(inner_ty) + { let span = self.nth_arg_span(&args, 0); - self.emit_lint(ident, fn_id, source_info, span); + self.emit_lint(fn_id, fn_substs, source_info, span); } } } @@ -66,6 +67,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> { } self.super_terminator(terminator, location); } + /// Emits a lint for function references formatted with `fmt::Pointer::fmt` by macros. These /// cases are handled as operands instead of call terminators to avoid any dependence on /// unstable, internal formatting details like whether `fmt` is called directly or not. @@ -76,13 +78,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> { if let ty::FnDef(def_id, substs_ref) = *op_ty.kind() { if self.tcx.is_diagnostic_item(sym::pointer_trait_fmt, def_id) { let param_ty = substs_ref.type_at(0); - if let Some(fn_id) = FunctionItemRefChecker::is_fn_ref(param_ty) { + if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(param_ty) { // The operand's ctxt wouldn't display the lint since it's inside a macro so // we have to use the callsite's ctxt. let callsite_ctxt = source_info.span.source_callsite().ctxt(); let span = source_info.span.with_ctxt(callsite_ctxt); - let ident = self.tcx.item_name(fn_id).to_ident_string(); - self.emit_lint(ident, fn_id, source_info, span); + self.emit_lint(fn_id, fn_substs, source_info, span); } } } @@ -115,10 +116,11 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> { if TyS::same_type(inner_ty, bound_ty) { // Do a substitution using the parameters from the callsite let subst_ty = inner_ty.subst(self.tcx, substs_ref); - if let Some(fn_id) = FunctionItemRefChecker::is_fn_ref(subst_ty) { - let ident = self.tcx.item_name(fn_id).to_ident_string(); + if let Some((fn_id, fn_substs)) = + FunctionItemRefChecker::is_fn_ref(subst_ty) + { let span = self.nth_arg_span(args, arg_num); - self.emit_lint(ident, fn_id, source_info, span); + self.emit_lint(fn_id, fn_substs, source_info, span); } } } @@ -127,6 +129,7 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> { } } } + /// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type. fn is_pointer_trait(&self, bound: &PredicateAtom<'tcx>) -> Option<Ty<'tcx>> { if let ty::PredicateAtom::Trait(predicate, _) = bound { @@ -139,22 +142,26 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> { None } } + /// If a type is a reference or raw pointer to the anonymous type of a function definition, - /// returns that function's `DefId`. - fn is_fn_ref(ty: Ty<'tcx>) -> Option<DefId> { + /// returns that function's `DefId` and `SubstsRef`. + fn is_fn_ref(ty: Ty<'tcx>) -> Option<(DefId, SubstsRef<'tcx>)> { let referent_ty = match ty.kind() { ty::Ref(_, referent_ty, _) => Some(referent_ty), ty::RawPtr(ty_and_mut) => Some(&ty_and_mut.ty), _ => None, }; referent_ty - .map( - |ref_ty| { - if let ty::FnDef(def_id, _) = *ref_ty.kind() { Some(def_id) } else { None } - }, - ) + .map(|ref_ty| { + if let ty::FnDef(def_id, substs_ref) = *ref_ty.kind() { + Some((def_id, substs_ref)) + } else { + None + } + }) .unwrap_or(None) } + fn nth_arg_span(&self, args: &Vec<Operand<'tcx>>, n: usize) -> Span { match &args[n] { Operand::Copy(place) | Operand::Move(place) => { @@ -163,7 +170,14 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> { Operand::Constant(constant) => constant.span, } } - fn emit_lint(&self, ident: String, fn_id: DefId, source_info: SourceInfo, span: Span) { + + fn emit_lint( + &self, + fn_id: DefId, + fn_substs: SubstsRef<'tcx>, + source_info: SourceInfo, + span: Span, + ) { let lint_root = self.body.source_scopes[source_info.scope] .local_data .as_ref() @@ -180,6 +194,10 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> { s } }; + let ident = self.tcx.item_name(fn_id).to_ident_string(); + let ty_params = fn_substs.types().map(|ty| format!("{}", ty)); + let const_params = fn_substs.consts().map(|c| format!("{}", c)); + let params = ty_params.chain(const_params).collect::<Vec<String>>().join(", "); let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder(); let variadic = if fn_sig.c_variadic() { ", ..." } else { "" }; let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" }; @@ -190,7 +208,7 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> { &format!("cast `{}` to obtain a function pointer", ident), format!( "{} as {}{}fn({}{}){}", - ident, + if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) }, unsafety, abi, vec!["_"; num_args].join(", "), diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index 944f41c61a2..5407226e386 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -8,6 +8,7 @@ use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; +use rustc_span::{hygiene::ExpnKind, ExpnData, Span}; use rustc_target::spec::abi::Abi; use super::simplify::{remove_dead_blocks, CfgSimplifier}; @@ -93,96 +94,79 @@ impl Inliner<'tcx> { return; } - let mut local_change; let mut changed = false; + while let Some(callsite) = callsites.pop_front() { + debug!("checking whether to inline callsite {:?}", callsite); - loop { - local_change = false; - while let Some(callsite) = callsites.pop_front() { - debug!("checking whether to inline callsite {:?}", callsite); - - if let InstanceDef::Item(_) = callsite.callee.def { - if !self.tcx.is_mir_available(callsite.callee.def_id()) { - debug!( - "checking whether to inline callsite {:?} - MIR unavailable", - callsite, - ); - continue; - } + if let InstanceDef::Item(_) = callsite.callee.def { + if !self.tcx.is_mir_available(callsite.callee.def_id()) { + debug!("checking whether to inline callsite {:?} - MIR unavailable", callsite,); + continue; } + } - let callee_body = if let Some(callee_def_id) = callsite.callee.def_id().as_local() { - let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id); - // Avoid a cycle here by only using `instance_mir` only if we have - // a lower `HirId` than the callee. This ensures that the callee will - // not inline us. This trick only works without incremental compilation. - // So don't do it if that is enabled. Also avoid inlining into generators, - // since their `optimized_mir` is used for layout computation, which can - // create a cycle, even when no attempt is made to inline the function - // in the other direction. - if !self.tcx.dep_graph.is_fully_enabled() - && self_hir_id < callee_hir_id - && caller_body.generator_kind.is_none() - { - self.tcx.instance_mir(callsite.callee.def) - } else { - continue; - } - } else { - // This cannot result in a cycle since the callee MIR is from another crate - // and is already optimized. + let callee_body = if let Some(callee_def_id) = callsite.callee.def_id().as_local() { + let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id); + // Avoid a cycle here by only using `instance_mir` only if we have + // a lower `HirId` than the callee. This ensures that the callee will + // not inline us. This trick only works without incremental compilation. + // So don't do it if that is enabled. Also avoid inlining into generators, + // since their `optimized_mir` is used for layout computation, which can + // create a cycle, even when no attempt is made to inline the function + // in the other direction. + if !self.tcx.dep_graph.is_fully_enabled() + && self_hir_id < callee_hir_id + && caller_body.generator_kind.is_none() + { self.tcx.instance_mir(callsite.callee.def) - }; - - let callee_body: &Body<'tcx> = &*callee_body; - - let callee_body = if self.consider_optimizing(callsite, callee_body) { - self.tcx.subst_and_normalize_erasing_regions( - &callsite.callee.substs, - self.param_env, - callee_body, - ) } else { continue; - }; + } + } else { + // This cannot result in a cycle since the callee MIR is from another crate + // and is already optimized. + self.tcx.instance_mir(callsite.callee.def) + }; - // Copy only unevaluated constants from the callee_body into the caller_body. - // Although we are only pushing `ConstKind::Unevaluated` consts to - // `required_consts`, here we may not only have `ConstKind::Unevaluated` - // because we are calling `subst_and_normalize_erasing_regions`. - caller_body.required_consts.extend( - callee_body.required_consts.iter().copied().filter(|&constant| { - matches!(constant.literal.val, ConstKind::Unevaluated(_, _, _)) - }), - ); + let callee_body: &Body<'tcx> = &*callee_body; - let start = caller_body.basic_blocks().len(); - debug!("attempting to inline callsite {:?} - body={:?}", callsite, callee_body); - if !self.inline_call(callsite, caller_body, callee_body) { - debug!("attempting to inline callsite {:?} - failure", callsite); - continue; - } - debug!("attempting to inline callsite {:?} - success", callsite); - - // Add callsites from inlined function - for (bb, bb_data) in caller_body.basic_blocks().iter_enumerated().skip(start) { - if let Some(new_callsite) = - self.get_valid_function_call(bb, bb_data, caller_body) - { - // Don't inline the same function multiple times. - if callsite.callee != new_callsite.callee { - callsites.push_back(new_callsite); - } + let callee_body = if self.consider_optimizing(callsite, callee_body) { + self.tcx.subst_and_normalize_erasing_regions( + &callsite.callee.substs, + self.param_env, + callee_body, + ) + } else { + continue; + }; + + // Copy only unevaluated constants from the callee_body into the caller_body. + // Although we are only pushing `ConstKind::Unevaluated` consts to + // `required_consts`, here we may not only have `ConstKind::Unevaluated` + // because we are calling `subst_and_normalize_erasing_regions`. + caller_body.required_consts.extend(callee_body.required_consts.iter().copied().filter( + |&constant| matches!(constant.literal.val, ConstKind::Unevaluated(_, _, _)), + )); + + let start = caller_body.basic_blocks().len(); + debug!("attempting to inline callsite {:?} - body={:?}", callsite, callee_body); + if !self.inline_call(callsite, caller_body, callee_body) { + debug!("attempting to inline callsite {:?} - failure", callsite); + continue; + } + debug!("attempting to inline callsite {:?} - success", callsite); + + // Add callsites from inlined function + for (bb, bb_data) in caller_body.basic_blocks().iter_enumerated().skip(start) { + if let Some(new_callsite) = self.get_valid_function_call(bb, bb_data, caller_body) { + // Don't inline the same function multiple times. + if callsite.callee != new_callsite.callee { + callsites.push_back(new_callsite); } } - - local_change = true; - changed = true; } - if !local_change { - break; - } + changed = true; } // Simplify if we inlined anything. @@ -488,6 +472,8 @@ impl Inliner<'tcx> { cleanup_block: cleanup, in_cleanup_block: false, tcx: self.tcx, + callsite_span: callsite.source_info.span, + body_span: callee_body.span, }; // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones @@ -699,6 +685,8 @@ struct Integrator<'a, 'tcx> { cleanup_block: Option<BasicBlock>, in_cleanup_block: bool, tcx: TyCtxt<'tcx>, + callsite_span: Span, + body_span: Span, } impl<'a, 'tcx> Integrator<'a, 'tcx> { @@ -743,6 +731,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { *scope = self.map_scope(*scope); } + fn visit_span(&mut self, span: &mut Span) { + // Make sure that all spans track the fact that they were inlined. + *span = self.callsite_span.fresh_expansion(ExpnData { + def_site: self.body_span, + ..ExpnData::default(ExpnKind::Inlined, *span, self.tcx.sess.edition(), None) + }); + } + fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { // If this is the `RETURN_PLACE`, we need to rebase any projections onto it. let dest_proj_len = self.destination.projection.len(); diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index 06690dcbf6e..82c0b924f28 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -63,7 +63,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { }; // Check that destinations are identical, and if not, then don't optimize this block - if &bbs[first].terminator().kind != &bbs[second].terminator().kind { + if bbs[first].terminator().kind != bbs[second].terminator().kind { continue; } diff --git a/compiler/rustc_mir/src/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs index 7e05d66074b..45b906bf542 100644 --- a/compiler/rustc_mir/src/transform/nrvo.rs +++ b/compiler/rustc_mir/src/transform/nrvo.rs @@ -1,3 +1,5 @@ +//! See the docs for [`RenameReturnPlace`]. + use rustc_hir::Mutability; use rustc_index::bit_set::HybridBitSet; use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor}; diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs index 6372f8960dd..ea56080c752 100644 --- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs +++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs @@ -26,22 +26,26 @@ use rustc_middle::{ pub struct SimplifyComparisonIntegral; impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { - fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("Running SimplifyComparisonIntegral on {:?}", body.source); let helper = OptimizationFinder { body }; let opts = helper.find_optimizations(); let mut storage_deads_to_insert = vec![]; let mut storage_deads_to_remove: Vec<(usize, BasicBlock)> = vec![]; + let param_env = tcx.param_env(body.source.def_id()); for opt in opts { trace!("SUCCESS: Applying {:?}", opt); // replace terminator with a switchInt that switches on the integer directly let bbs = &mut body.basic_blocks_mut(); let bb = &mut bbs[opt.bb_idx]; - // We only use the bits for the untyped, not length checked `values` field. Thus we are - // not using any of the convenience wrappers here and directly access the bits. let new_value = match opt.branch_value_scalar { - Scalar::Raw { data, .. } => data, + Scalar::Int(int) => { + let layout = tcx + .layout_of(param_env.and(opt.branch_value_ty)) + .expect("if we have an evaluated constant we must know the layout"); + int.assert_bits(layout.size) + } Scalar::Ptr(_) => continue, }; const FALSE: u128 = 0; diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs index 7b22d643ab6..1868d3b47f2 100644 --- a/compiler/rustc_mir/src/transform/validate.rs +++ b/compiler/rustc_mir/src/transform/validate.rs @@ -5,13 +5,13 @@ use crate::dataflow::{Analysis, ResultsCursor}; use crate::util::storage::AlwaysLiveLocals; use super::MirPass; +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::traversal; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ - interpret::Scalar, - visit::{PlaceContext, Visitor}, -}; -use rustc_middle::mir::{ - AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, Rvalue, - SourceScope, Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo, + AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceRef, + Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo, }; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; @@ -46,8 +46,17 @@ impl<'tcx> MirPass<'tcx> for Validator { .iterate_to_fixpoint() .into_results_cursor(body); - TypeChecker { when: &self.when, body, tcx, param_env, mir_phase, storage_liveness } - .visit_body(body); + TypeChecker { + when: &self.when, + body, + tcx, + param_env, + mir_phase, + reachable_blocks: traversal::reachable_as_bitset(body), + storage_liveness, + place_cache: Vec::new(), + } + .visit_body(body); } } @@ -149,7 +158,9 @@ struct TypeChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, mir_phase: MirPhase, + reachable_blocks: BitSet<BasicBlock>, storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>, + place_cache: Vec<PlaceRef<'tcx>>, } impl<'a, 'tcx> TypeChecker<'a, 'tcx> { @@ -223,7 +234,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { - if context.is_use() { + if self.reachable_blocks.contains(location.block) && context.is_use() { // Uses of locals must occur while the local's storage is allocated. self.storage_liveness.seek_after_primary_effect(location); let locals_with_storage = self.storage_liveness.get(); @@ -240,13 +251,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { - // `Operand::Copy` is only supposed to be used with `Copy` types. - if let Operand::Copy(place) = operand { - let ty = place.ty(&self.body.local_decls, self.tcx).ty; - let span = self.body.source_info(location).span; - - if !ty.is_copy_modulo_regions(self.tcx.at(span), self.param_env) { - self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty)); + // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed. + if self.tcx.sess.opts.debugging_opts.validate_mir { + // `Operand::Copy` is only supposed to be used with `Copy` types. + if let Operand::Copy(place) = operand { + let ty = place.ty(&self.body.local_decls, self.tcx).ty; + let span = self.body.source_info(location).span; + + if !ty.is_copy_modulo_regions(self.tcx.at(span), self.param_env) { + self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty)); + } } } @@ -332,6 +346,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } _ => {} } + + self.super_statement(statement, location); } fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { @@ -391,7 +407,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.check_edge(location, *unwind, EdgeKind::Unwind); } } - TerminatorKind::Call { func, destination, cleanup, .. } => { + TerminatorKind::Call { func, args, destination, cleanup, .. } => { let func_ty = func.ty(&self.body.local_decls, self.tcx); match func_ty.kind() { ty::FnPtr(..) | ty::FnDef(..) => {} @@ -406,6 +422,32 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if let Some(cleanup) = cleanup { self.check_edge(location, *cleanup, EdgeKind::Unwind); } + + // The call destination place and Operand::Move place used as an argument might be + // passed by a reference to the callee. Consequently they must be non-overlapping. + // Currently this simply checks for duplicate places. + self.place_cache.clear(); + if let Some((destination, _)) = destination { + self.place_cache.push(destination.as_ref()); + } + for arg in args { + if let Operand::Move(place) = arg { + self.place_cache.push(place.as_ref()); + } + } + let all_len = self.place_cache.len(); + self.place_cache.sort_unstable(); + self.place_cache.dedup(); + let has_duplicates = all_len != self.place_cache.len(); + if has_duplicates { + self.fail( + location, + format!( + "encountered overlapping memory in `Call` terminator: {:?}", + terminator.kind, + ), + ); + } } TerminatorKind::Assert { cond, target, cleanup, .. } => { let cond_ty = cond.ty(&self.body.local_decls, self.tcx); @@ -454,6 +496,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop => {} } + + self.super_terminator(terminator, location); } fn visit_source_scope(&mut self, scope: &SourceScope) { diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index ac4d6563d6c..8bee8417c51 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -19,6 +19,7 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_target::abi::Size; +use std::ops::ControlFlow; const INDENT: &str = " "; /// Alignment for lining up comments following MIR statements @@ -629,7 +630,7 @@ pub fn write_allocations<'tcx>( ConstValue::Scalar(interpret::Scalar::Ptr(ptr)) => { Either::Left(Either::Left(std::iter::once(ptr.alloc_id))) } - ConstValue::Scalar(interpret::Scalar::Raw { .. }) => { + ConstValue::Scalar(interpret::Scalar::Int { .. }) => { Either::Left(Either::Right(std::iter::empty())) } ConstValue::ByRef { alloc, .. } | ConstValue::Slice { data: alloc, .. } => { @@ -639,7 +640,7 @@ pub fn write_allocations<'tcx>( } struct CollectAllocIds(BTreeSet<AllocId>); impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { if let ty::ConstKind::Value(val) = c.val { self.0.extend(alloc_ids_from_const(val)); } diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 443025c4f84..b94346fa439 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -262,10 +262,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::ThreadLocalRef(_) | ExprKind::Call { .. } => { // these are not places, so we need to make a temporary. - debug_assert!(match Category::of(&expr.kind) { - Some(Category::Place) => false, - _ => true, - }); + debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place))); let temp = unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability)); block.and(PlaceBuilder::from(temp)) diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 4033cc6cf46..2853bf887fa 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -260,10 +260,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::ValueTypeAscription { .. } => { // these do not have corresponding `Rvalue` variants, // so make an operand and then return that - debug_assert!(match Category::of(&expr.kind) { - Some(Category::Rvalue(RvalueFunc::AsRvalue)) => false, - _ => true, - }); + debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Rvalue(RvalueFunc::AsRvalue)))); let operand = unpack!(block = this.as_operand(block, scope, expr)); block.and(Rvalue::Use(operand)) } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index a268b0b46ff..9dc596a345f 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -58,10 +58,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::NeverToAny { source } => { let source = this.hir.mirror(source); - let is_call = match source.kind { - ExprKind::Call { .. } | ExprKind::InlineAsm { .. } => true, - _ => false, - }; + let is_call = matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. }); // (#66975) Source could be a const of type `!`, so has to // exist in the generated MIR. diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 29fc23c324f..705266d4a0b 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -17,7 +17,6 @@ use crate::build::Builder; use crate::thir::{self, *}; use rustc_attr::{SignedInt, UnsignedInt}; use rustc_hir::RangeEnd; -use rustc_middle::mir::interpret::truncate; use rustc_middle::mir::Place; use rustc_middle::ty; use rustc_middle::ty::layout::IntegerExt; @@ -205,13 +204,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ty::Int(ity) => { let size = Integer::from_attr(&tcx, SignedInt(ity)).size(); - let max = truncate(u128::MAX, size); + let max = size.truncate(u128::MAX); let bias = 1u128 << (size.bits() - 1); (Some((0, max, size)), bias) } ty::Uint(uty) => { let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size(); - let max = truncate(u128::MAX, size); + let max = size.truncate(u128::MAX); (Some((0, max, size)), 0) } _ => (None, 0), diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index c4191900147..7bea8220ada 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -250,15 +250,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place, ty, ); + } else if let [success, fail] = *make_target_blocks(self) { + assert_eq!(value.ty, ty); + let expect = self.literal_operand(test.span, value); + let val = Operand::Copy(place); + self.compare(block, success, fail, source_info, BinOp::Eq, expect, val); } else { - if let [success, fail] = *make_target_blocks(self) { - assert_eq!(value.ty, ty); - let expect = self.literal_operand(test.span, value); - let val = Operand::Copy(place); - self.compare(block, success, fail, source_info, BinOp::Eq, expect, val); - } else { - bug!("`TestKind::Eq` should have two target blocks"); - } + bug!("`TestKind::Eq` should have two target blocks"); } } diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index b6321c3bf67..e91227d8357 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -331,13 +331,11 @@ impl DropTree { } if let DropKind::Value = drop_data.0.kind { needs_block[drop_data.1] = Block::Own; - } else { - if drop_idx != ROOT_NODE { - match &mut needs_block[drop_data.1] { - pred @ Block::None => *pred = Block::Shares(drop_idx), - pred @ Block::Shares(_) => *pred = Block::Own, - Block::Own => (), - } + } else if drop_idx != ROOT_NODE { + match &mut needs_block[drop_data.1] { + pred @ Block::None => *pred = Block::Shares(drop_idx), + pred @ Block::Shares(_) => *pred = Block::Own, + Block::Own => (), } } } @@ -461,9 +459,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let breakable_scope = self.scopes.breakable_scopes.pop().unwrap(); assert!(breakable_scope.region_scope == region_scope); let break_block = self.build_exit_tree(breakable_scope.break_drops, None); - breakable_scope.continue_drops.map(|drops| { - self.build_exit_tree(drops, loop_block); - }); + if let Some(drops) = breakable_scope.continue_drops { self.build_exit_tree(drops, loop_block); } match (normal_exit_block, break_block) { (Some(block), None) | (None, Some(block)) => block, (None, None) => self.cfg.start_new_block().unit(), diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index b71ff6e7557..dfe82317f48 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_middle::mir::interpret::{ - truncate, Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar, + Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar, }; use rustc_middle::ty::{self, ParamEnv, TyCtxt}; use rustc_span::symbol::Symbol; @@ -16,7 +16,7 @@ crate fn lit_to_const<'tcx>( let param_ty = ParamEnv::reveal_all().and(ty); let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size; trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); - let result = truncate(n, width); + let result = width.truncate(n); trace!("trunc result: {}", result); Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) }; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 731bd954246..6ed7ed575fc 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -316,16 +316,14 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Unary(hir::UnOp::UnNeg, ref arg) => { if cx.typeck_results().is_method_call(expr) { overloaded_operator(cx, expr, vec![arg.to_ref()]) - } else { - if let hir::ExprKind::Lit(ref lit) = arg.kind { - ExprKind::Literal { - literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), - user_ty: None, - const_id: None, - } - } else { - ExprKind::Unary { op: UnOp::Neg, arg: arg.to_ref() } + } else if let hir::ExprKind::Lit(ref lit) = arg.kind { + ExprKind::Literal { + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), + user_ty: None, + const_id: None, } + } else { + ExprKind::Unary { op: UnOp::Neg, arg: arg.to_ref() } } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs index 843a6c0e461..9e096f9ad68 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -304,7 +304,7 @@ use rustc_arena::TypedArena; use rustc_attr::{SignedInt, UnsignedInt}; use rustc_hir::def_id::DefId; use rustc_hir::{HirId, RangeEnd}; -use rustc_middle::mir::interpret::{truncate, ConstValue}; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::Field; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; @@ -327,9 +327,23 @@ struct LiteralExpander; impl<'tcx> PatternFolder<'tcx> for LiteralExpander { fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> { debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind); - match (pat.ty.kind(), &*pat.kind) { - (_, &PatKind::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self), - (_, &PatKind::AscribeUserType { subpattern: ref s, .. }) => s.fold_with(self), + match (pat.ty.kind(), pat.kind.as_ref()) { + (_, PatKind::Binding { subpattern: Some(s), .. }) => s.fold_with(self), + (_, PatKind::AscribeUserType { subpattern: s, .. }) => s.fold_with(self), + (ty::Ref(_, t, _), PatKind::Constant { .. }) if t.is_str() => { + // Treat string literal patterns as deref patterns to a `str` constant, i.e. + // `&CONST`. This expands them like other const patterns. This could have been done + // in `const_to_pat`, but that causes issues with the rest of the matching code. + let mut new_pat = pat.super_fold_with(self); + // Make a fake const pattern of type `str` (instead of `&str`). That the carried + // constant value still knows it is of type `&str`. + new_pat.ty = t; + Pat { + kind: Box::new(PatKind::Deref { subpattern: new_pat }), + span: pat.span, + ty: pat.ty, + } + } _ => pat.super_fold_with(self), } } @@ -337,10 +351,7 @@ impl<'tcx> PatternFolder<'tcx> for LiteralExpander { impl<'tcx> Pat<'tcx> { pub(super) fn is_wildcard(&self) -> bool { - match *self.kind { - PatKind::Binding { subpattern: None, .. } | PatKind::Wild => true, - _ => false, - } + matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) } } @@ -785,11 +796,9 @@ enum Constructor<'tcx> { /// boxes for the purposes of exhaustiveness: we must not inspect them, and they /// don't count towards making a match exhaustive. Opaque, - /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. + /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used + /// for those types for which we cannot list constructors explicitly, like `f64` and `str`. NonExhaustive, - /// Fake constructor for those types for which we can't list constructors explicitly, like - /// `f64` and `&str`. - Unlistable, /// Wildcard pattern. Wildcard, } @@ -883,6 +892,7 @@ impl<'tcx> Constructor<'tcx> { /// For the simple cases, this is simply checking for equality. For the "grouped" constructors, /// this checks for inclusion. fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool { + // This must be kept in sync with `is_covered_by_any`. match (self, other) { // Wildcards cover anything (_, Wildcard) => true, @@ -925,18 +935,19 @@ impl<'tcx> Constructor<'tcx> { (Opaque, _) | (_, Opaque) => false, // Only a wildcard pattern can match the special extra constructor. (NonExhaustive, _) => false, - // If we encounter a `Single` here, this means there was only one constructor for this - // type after all. - (Unlistable, Single) => true, - // Otherwise, only a wildcard pattern can match the special extra constructor. - (Unlistable, _) => false, - _ => bug!("trying to compare incompatible constructors {:?} and {:?}", self, other), + _ => span_bug!( + pcx.span, + "trying to compare incompatible constructors {:?} and {:?}", + self, + other + ), } } /// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is - /// assumed to be built from `matrix.head_ctors()`, and `self` is assumed to have been split. + /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is + /// assumed to have been split from a wildcard. fn is_covered_by_any<'p>( &self, pcx: PatCtxt<'_, 'p, 'tcx>, @@ -946,8 +957,9 @@ impl<'tcx> Constructor<'tcx> { return false; } + // This must be kept in sync with `is_covered_by`. match self { - // `used_ctors` cannot contain anything else than `Single`s. + // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s. Single => !used_ctors.is_empty(), Variant(_) => used_ctors.iter().any(|c| c == self), IntRange(range) => used_ctors @@ -960,8 +972,6 @@ impl<'tcx> Constructor<'tcx> { .any(|other| slice.is_covered_by(other)), // This constructor is never covered by anything else NonExhaustive => false, - // This constructor is only covered by `Single`s - Unlistable => used_ctors.iter().any(|c| *c == Single), Str(..) | FloatRange(..) | Opaque | Wildcard => { bug!("found unexpected ctor in all_ctors: {:?}", self) } @@ -1009,6 +1019,10 @@ impl<'tcx> Constructor<'tcx> { PatKind::Leaf { subpatterns } } } + // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should + // be careful to reconstruct the correct constant pattern here. However a string + // literal pattern will never be reported as a non-exhaustiveness witness, so we + // can ignore this issue. ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, pcx.ty), _ => PatKind::Wild, @@ -1041,7 +1055,7 @@ impl<'tcx> Constructor<'tcx> { &Str(value) => PatKind::Constant { value }, &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }), IntRange(range) => return range.to_pat(pcx.cx.tcx), - NonExhaustive | Unlistable => PatKind::Wild, + NonExhaustive => PatKind::Wild, Opaque => bug!("we should not try to apply an opaque constructor"), Wildcard => bug!( "trying to apply a wildcard constructor; this should have been done in `apply_constructors`" @@ -1190,8 +1204,9 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { } _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), }, - Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Unlistable - | Wildcard => Fields::empty(), + Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Wildcard => { + Fields::empty() + } }; debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret); ret @@ -1303,9 +1318,13 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { /// [Some(0), ..] => {} /// } /// ``` + /// This is guaranteed to preserve the number of patterns in `self`. fn replace_with_pattern_arguments(&self, pat: &'p Pat<'tcx>) -> Self { match pat.kind.as_ref() { - PatKind::Deref { subpattern } => Self::from_single_pattern(subpattern), + PatKind::Deref { subpattern } => { + assert_eq!(self.len(), 1); + Fields::from_single_pattern(subpattern) + } PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { self.replace_with_fieldpats(subpatterns) } @@ -1358,10 +1377,7 @@ impl<'tcx> Usefulness<'tcx> { } fn is_useful(&self) -> bool { - match *self { - NotUseful => false, - _ => true, - } + !matches!(*self, NotUseful) } fn apply_constructor<'p>( @@ -1592,14 +1608,13 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc } &ty::Uint(uty) => { let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size(); - let max = truncate(u128::MAX, size); + let max = size.truncate(u128::MAX); vec![make_range(0, max)] } _ if cx.is_uninhabited(pcx.ty) => vec![], - ty::Adt(..) | ty::Tuple(..) => vec![Single], - ty::Ref(_, t, _) if !t.is_str() => vec![Single], - // This type is one for which we don't know how to list constructors, like `&str` or `f64`. - _ => vec![Unlistable], + ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => vec![Single], + // This type is one for which we cannot list constructors, like `str` or `f64`. + _ => vec![NonExhaustive], } } @@ -1623,10 +1638,7 @@ struct IntRange<'tcx> { impl<'tcx> IntRange<'tcx> { #[inline] fn is_integral(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool => true, - _ => false, - } + matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool) } fn is_singleton(&self) -> bool { @@ -2161,20 +2173,23 @@ fn pat_constructor<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, pat: &'p Pat<'tcx>, ) -> Constructor<'tcx> { - match *pat.kind { + match pat.kind.as_ref() { PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` PatKind::Binding { .. } | PatKind::Wild => Wildcard, PatKind::Leaf { .. } | PatKind::Deref { .. } => Single, - PatKind::Variant { adt_def, variant_index, .. } => { + &PatKind::Variant { adt_def, variant_index, .. } => { Variant(adt_def.variants[variant_index].def_id) } PatKind::Constant { value } => { if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value, pat.span) { IntRange(int_range) } else { - match value.ty.kind() { + match pat.ty.kind() { ty::Float(_) => FloatRange(value, value, RangeEnd::Included), - ty::Ref(_, t, _) if t.is_str() => Str(value), + // In `expand_pattern`, we convert string literals to `&CONST` patterns with + // `CONST` a pattern of type `str`. In truth this contains a constant of type + // `&str`. + ty::Str => Str(value), // All constants that can be structurally matched have already been expanded // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are // opaque. @@ -2182,7 +2197,7 @@ fn pat_constructor<'p, 'tcx>( } } } - PatKind::Range(PatRange { lo, hi, end }) => { + &PatKind::Range(PatRange { lo, hi, end }) => { let ty = lo.ty; if let Some(int_range) = IntRange::from_range( cx.tcx, @@ -2197,8 +2212,7 @@ fn pat_constructor<'p, 'tcx>( FloatRange(lo, hi, end) } } - PatKind::Array { ref prefix, ref slice, ref suffix } - | PatKind::Slice { ref prefix, ref slice, ref suffix } => { + PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => { let array_len = match pat.ty.kind() { ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env)), ty::Slice(_) => None, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 25e18724341..db0ecd701bc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -15,7 +15,7 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::RangeEnd; use rustc_index::vec::Idx; -use rustc_middle::mir::interpret::{get_slice_bytes, sign_extend, ConstValue}; +use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue}; use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput}; use rustc_middle::mir::UserTypeProjection; use rustc_middle::mir::{BorrowKind, Field, Mutability}; @@ -223,10 +223,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { BindingMode::ByValue => mutability == Mutability::Mut, BindingMode::ByRef(bk) => { write!(f, "ref ")?; - match bk { - BorrowKind::Mut { .. } => true, - _ => false, - } + matches!(bk, BorrowKind::Mut { .. }) } }; if is_mut { @@ -1085,8 +1082,8 @@ crate fn compare_const_vals<'tcx>( use rustc_attr::SignedInt; use rustc_middle::ty::layout::IntegerExt; let size = rustc_target::abi::Integer::from_attr(&tcx, SignedInt(ity)).size(); - let a = sign_extend(a, size); - let b = sign_extend(b, size); + let a = size.sign_extend(a); + let b = size.sign_extend(b); Some((a as i128).cmp(&(b as i128))) } _ => Some(a.cmp(&b)), diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index ba416be6b38..bad43cd5350 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -249,29 +249,30 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // came from. Here we attempt to extract these lossless token streams // before we fall back to the stringification. - let convert_tokens = |tokens: Option<LazyTokenStream>| tokens.map(|t| t.into_token_stream()); + let convert_tokens = + |tokens: &Option<LazyTokenStream>| tokens.as_ref().map(|t| t.create_token_stream()); let tokens = match *nt { Nonterminal::NtItem(ref item) => prepend_attrs(&item.attrs, item.tokens.as_ref()), - Nonterminal::NtBlock(ref block) => convert_tokens(block.tokens.clone()), + Nonterminal::NtBlock(ref block) => convert_tokens(&block.tokens), Nonterminal::NtStmt(ref stmt) => { // FIXME: We currently only collect tokens for `:stmt` // matchers in `macro_rules!` macros. When we start collecting // tokens for attributes on statements, we will need to prepend // attributes here - convert_tokens(stmt.tokens.clone()) + convert_tokens(&stmt.tokens) } - Nonterminal::NtPat(ref pat) => convert_tokens(pat.tokens.clone()), - Nonterminal::NtTy(ref ty) => convert_tokens(ty.tokens.clone()), + Nonterminal::NtPat(ref pat) => convert_tokens(&pat.tokens), + Nonterminal::NtTy(ref ty) => convert_tokens(&ty.tokens), Nonterminal::NtIdent(ident, is_raw) => { Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into()) } Nonterminal::NtLifetime(ident) => { Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into()) } - Nonterminal::NtMeta(ref attr) => convert_tokens(attr.tokens.clone()), - Nonterminal::NtPath(ref path) => convert_tokens(path.tokens.clone()), - Nonterminal::NtVis(ref vis) => convert_tokens(vis.tokens.clone()), + Nonterminal::NtMeta(ref attr) => convert_tokens(&attr.tokens), + Nonterminal::NtPath(ref path) => convert_tokens(&path.tokens), + Nonterminal::NtVis(ref vis) => convert_tokens(&vis.tokens), Nonterminal::NtTT(ref tt) => Some(tt.clone().into()), Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => { if expr.tokens.is_none() { @@ -604,24 +605,24 @@ fn prepend_attrs( attrs: &[ast::Attribute], tokens: Option<&tokenstream::LazyTokenStream>, ) -> Option<tokenstream::TokenStream> { - let tokens = tokens?.clone().into_token_stream(); + let tokens = tokens?.create_token_stream(); if attrs.is_empty() { - return Some(tokens.clone()); + return Some(tokens); } let mut builder = tokenstream::TokenStreamBuilder::new(); for attr in attrs { - assert_eq!( - attr.style, - ast::AttrStyle::Outer, - "inner attributes should prevent cached tokens from existing" - ); + // FIXME: Correctly handle tokens for inner attributes. + // For now, we fall back to reparsing the original AST node + if attr.style == ast::AttrStyle::Inner { + return None; + } builder.push( attr.tokens - .clone() + .as_ref() .unwrap_or_else(|| panic!("Attribute {:?} is missing tokens!", attr)) - .into_token_stream(), + .create_token_stream(), ); } - builder.push(tokens.clone()); + builder.push(tokens); Some(builder.build()) } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index f13a4329d3b..cd3b8db2303 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1359,11 +1359,7 @@ impl<'a> Parser<'a> { (self.token == token::Lt && // `foo:<bar`, likely a typoed turbofish. self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())) || self.token.is_ident() && - match node { - // `foo::` → `foo:` or `foo.bar::` → `foo.bar:` - ast::ExprKind::Path(..) | ast::ExprKind::Field(..) => true, - _ => false, - } && + matches!(node, ast::ExprKind::Path(..) | ast::ExprKind::Field(..)) && !self.token.is_reserved_ident() && // v `foo:bar(baz)` self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) || self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) // `foo:bar {` diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 39d4875f37b..5954b370e6d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -7,7 +7,7 @@ use crate::maybe_whole; use rustc_ast::ptr::P; use rustc_ast::token::{self, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; -use rustc_ast::{self as ast, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID}; +use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID}; use rustc_ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind, Mod}; use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind}; use rustc_ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind}; @@ -127,34 +127,19 @@ impl<'a> Parser<'a> { let (mut item, tokens) = if needs_tokens { let (item, tokens) = self.collect_tokens(parse_item)?; - (item, Some(tokens)) + (item, tokens) } else { (parse_item(self)?, None) }; - - self.unclosed_delims.append(&mut unclosed_delims); - - // Once we've parsed an item and recorded the tokens we got while - // parsing we may want to store `tokens` into the item we're about to - // return. Note, though, that we specifically didn't capture tokens - // related to outer attributes. The `tokens` field here may later be - // used with procedural macros to convert this item back into a token - // stream, but during expansion we may be removing attributes as we go - // along. - // - // If we've got inner attributes then the `tokens` we've got above holds - // these inner attributes. If an inner attribute is expanded we won't - // actually remove it from the token stream, so we'll just keep yielding - // it (bad!). To work around this case for now we just avoid recording - // `tokens` if we detect any inner attributes. This should help keep - // expansion correct, but we should fix this bug one day! - if let Some(tokens) = tokens { - if let Some(item) = &mut item { - if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { - item.tokens = tokens; - } + if let Some(item) = &mut item { + // If we captured tokens during parsing (due to encountering an `NtItem`), + // use those instead + if item.tokens.is_none() { + item.tokens = tokens; } } + + self.unclosed_delims.append(&mut unclosed_delims); Ok(item) } @@ -376,21 +361,19 @@ impl<'a> Parser<'a> { format!(" {} ", kw), Applicability::MachineApplicable, ); + } else if let Ok(snippet) = self.span_to_snippet(ident_sp) { + err.span_suggestion( + full_sp, + "if you meant to call a macro, try", + format!("{}!", snippet), + // this is the `ambiguous` conditional branch + Applicability::MaybeIncorrect, + ); } else { - if let Ok(snippet) = self.span_to_snippet(ident_sp) { - err.span_suggestion( - full_sp, - "if you meant to call a macro, try", - format!("{}!", snippet), - // this is the `ambiguous` conditional branch - Applicability::MaybeIncorrect, - ); - } else { - err.help( - "if you meant to call a macro, remove the `pub` \ - and add a trailing `!` after the identifier", - ); - } + err.help( + "if you meant to call a macro, remove the `pub` \ + and add a trailing `!` after the identifier", + ); } Err(err) } else if self.look_ahead(1, |t| *t == token::Lt) { @@ -982,10 +965,7 @@ impl<'a> Parser<'a> { if token.is_keyword(kw::Move) { return true; } - match token.kind { - token::BinOp(token::Or) | token::OrOr => true, - _ => false, - } + matches!(token.kind, token::BinOp(token::Or) | token::OrOr) }) } else { false @@ -1666,19 +1646,10 @@ impl<'a> Parser<'a> { req_name: ReqName, ret_allow_plus: AllowPlus, ) -> PResult<'a, P<FnDecl>> { - let inputs = self.parse_fn_params(req_name)?; - let output = self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?; - - if let ast::FnRetTy::Ty(ty) = &output { - if let TyKind::Path(_, Path { segments, .. }) = &ty.kind { - if let [.., last] = &segments[..] { - // Detect and recover `fn foo() -> Vec<i32>> {}` - self.check_trailing_angle_brackets(last, &[&token::OpenDelim(token::Brace)]); - } - } - } - - Ok(P(FnDecl { inputs, output })) + Ok(P(FnDecl { + inputs: self.parse_fn_params(req_name)?, + output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?, + })) } /// Parses the parameter list of a function, including the `(` and `)` delimiters. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d99fcb0c4a1..da1c54e88b5 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -16,8 +16,8 @@ pub use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{self, DelimToken, Token, TokenKind}; -use rustc_ast::tokenstream::{self, DelimSpan, LazyTokenStream, LazyTokenStreamInner, Spacing}; -use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::tokenstream::{self, DelimSpan, LazyTokenStream, Spacing}; +use rustc_ast::tokenstream::{CreateTokenStream, TokenStream, TokenTree}; use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe}; use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit}; @@ -1199,15 +1199,12 @@ impl<'a> Parser<'a> { f: impl FnOnce(&mut Self) -> PResult<'a, R>, ) -> PResult<'a, (R, Option<LazyTokenStream>)> { let start_token = (self.token.clone(), self.token_spacing); - let mut cursor_snapshot = self.token_cursor.clone(); + let cursor_snapshot = self.token_cursor.clone(); let ret = f(self)?; - let new_calls = self.token_cursor.num_next_calls; - let num_calls = new_calls - cursor_snapshot.num_next_calls; - let desugar_doc_comments = self.desugar_doc_comments; - // We didn't capture any tokens + let num_calls = self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls; if num_calls == 0 { return Ok((ret, None)); } @@ -1220,27 +1217,41 @@ impl<'a> Parser<'a> { // // This also makes `Parser` very cheap to clone, since // there is no intermediate collection buffer to clone. - let lazy_cb = move || { - // The token produced by the final call to `next` or `next_desugared` - // was not actually consumed by the callback. The combination - // of chaining the initial token and using `take` produces the desired - // result - we produce an empty `TokenStream` if no calls were made, - // and omit the final token otherwise. - let tokens = std::iter::once(start_token) - .chain((0..num_calls).map(|_| { - if desugar_doc_comments { - cursor_snapshot.next_desugared() - } else { - cursor_snapshot.next() - } - })) - .take(num_calls); + struct LazyTokenStreamImpl { + start_token: (Token, Spacing), + cursor_snapshot: TokenCursor, + num_calls: usize, + desugar_doc_comments: bool, + } + impl CreateTokenStream for LazyTokenStreamImpl { + fn create_token_stream(&self) -> TokenStream { + // The token produced by the final call to `next` or `next_desugared` + // was not actually consumed by the callback. The combination + // of chaining the initial token and using `take` produces the desired + // result - we produce an empty `TokenStream` if no calls were made, + // and omit the final token otherwise. + let mut cursor_snapshot = self.cursor_snapshot.clone(); + let tokens = std::iter::once(self.start_token.clone()) + .chain((0..self.num_calls).map(|_| { + if self.desugar_doc_comments { + cursor_snapshot.next_desugared() + } else { + cursor_snapshot.next() + } + })) + .take(self.num_calls); - make_token_stream(tokens) - }; - let stream = LazyTokenStream::new(LazyTokenStreamInner::Lazy(Box::new(lazy_cb))); + make_token_stream(tokens) + } + } - Ok((ret, Some(stream))) + let lazy_impl = LazyTokenStreamImpl { + start_token, + cursor_snapshot, + num_calls, + desugar_doc_comments: self.desugar_doc_comments, + }; + Ok((ret, Some(LazyTokenStream::new(lazy_impl)))) } /// `::{` or `::*` diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 98fb1c82925..ab88362dad9 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -38,16 +38,13 @@ impl<'a> Parser<'a> { }, NonterminalKind::Block => match token.kind { token::OpenDelim(token::Brace) => true, - token::Interpolated(ref nt) => match **nt { - token::NtItem(_) + token::Interpolated(ref nt) => !matches!(**nt, token::NtItem(_) | token::NtPat(_) | token::NtTy(_) | token::NtIdent(..) | token::NtMeta(_) | token::NtPath(_) - | token::NtVis(_) => false, // none of these may start with '{'. - _ => true, - }, + | token::NtVis(_)), _ => false, }, NonterminalKind::Path | NonterminalKind::Meta => match token.kind { @@ -76,17 +73,14 @@ impl<'a> Parser<'a> { }, NonterminalKind::Lifetime => match token.kind { token::Lifetime(_) => true, - token::Interpolated(ref nt) => match **nt { - token::NtLifetime(_) | token::NtTT(_) => true, - _ => false, - }, + token::Interpolated(ref nt) => { + matches!(**nt, token::NtLifetime(_) | token::NtTT(_)) + } _ => false, }, - NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => match token.kind - { - token::CloseDelim(_) => false, - _ => true, - }, + NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => { + !matches!(token.kind, token::CloseDelim(_)) + } } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 27fe75a23b6..196790a0ab3 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -149,8 +149,10 @@ impl<'a> Parser<'a> { /// Note that there are more tokens such as `@` for which we know that the `|` /// is an illegal parse. However, the user's intent is less clear in that case. fn recover_trailing_vert(&mut self, lo: Option<Span>) -> bool { - let is_end_ahead = self.look_ahead(1, |token| match &token.uninterpolate().kind { - token::FatArrow // e.g. `a | => 0,`. + let is_end_ahead = self.look_ahead(1, |token| { + matches!( + &token.uninterpolate().kind, + token::FatArrow // e.g. `a | => 0,`. | token::Ident(kw::If, false) // e.g. `a | if expr`. | token::Eq // e.g. `let a | = 0`. | token::Semi // e.g. `let a |;`. @@ -158,8 +160,8 @@ impl<'a> Parser<'a> { | token::Comma // e.g. `let (a |,)`. | token::CloseDelim(token::Bracket) // e.g. `let [a | ]`. | token::CloseDelim(token::Paren) // e.g. `let (a | )`. - | token::CloseDelim(token::Brace) => true, // e.g. `let A { f: a | }`. - _ => false, + | token::CloseDelim(token::Brace) // e.g. `let A { f: a | }`. + ) }); match (is_end_ahead, &self.token.kind) { (true, token::BinOp(token::Or) | token::OrOr) => { @@ -766,14 +768,12 @@ impl<'a> Parser<'a> { && !self.token.is_path_segment_keyword() // Avoid e.g. `Self` as it is a path. // Avoid `in`. Due to recovery in the list parser this messes with `for ( $pat in $expr )`. && !self.token.is_keyword(kw::In) - && self.look_ahead(1, |t| match t.kind { // Try to do something more complex? - token::OpenDelim(token::Paren) // A tuple struct pattern. + // Try to do something more complex? + && self.look_ahead(1, |t| !matches!(t.kind, token::OpenDelim(token::Paren) // A tuple struct pattern. | token::OpenDelim(token::Brace) // A struct pattern. | token::DotDotDot | token::DotDotEq | token::DotDot // A range pattern. | token::ModSep // A tuple / struct variant pattern. - | token::Not => false, // A macro expanding to a pattern. - _ => true, - }) + | token::Not)) // A macro expanding to a pattern. } /// Parses `ident` or `ident @ pat`. diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 06760547eba..79e73749038 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -187,12 +187,14 @@ impl<'a> Parser<'a> { pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> { let ident = self.parse_path_segment_ident()?; - let is_args_start = |token: &Token| match token.kind { - token::Lt - | token::BinOp(token::Shl) - | token::OpenDelim(token::Paren) - | token::LArrow => true, - _ => false, + let is_args_start = |token: &Token| { + matches!( + token.kind, + token::Lt + | token::BinOp(token::Shl) + | token::OpenDelim(token::Paren) + | token::LArrow + ) }; let check_args_start = |this: &mut Self| { this.expected_tokens.extend_from_slice(&[ diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 94592935c7f..0f4aa72d5c4 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -102,7 +102,7 @@ fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> FxHashMap<Symbol, DefId> { tcx.hir().krate().visit_all_item_likes(&mut collector); // FIXME(visit_all_item_likes): Foreign items are not visited // here, so we have to manually look at them for now. - for foreign_module in tcx.foreign_modules(LOCAL_CRATE) { + for (_, foreign_module) in tcx.foreign_modules(LOCAL_CRATE).iter() { for &foreign_item in foreign_module.foreign_items.iter() { match tcx.hir().get(tcx.hir().local_def_id_to_hir_id(foreign_item.expect_local())) { hir::Node::ForeignItem(item) => { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index c9497f2a5b2..04b5c65e464 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -15,7 +15,7 @@ use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability::{DeprecationEntry, Index}; use rustc_middle::ty::{self, query::Providers, TyCtxt}; use rustc_session::lint; -use rustc_session::lint::builtin::INEFFECTIVE_UNSTABLE_TRAIT_IMPL; +use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED}; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; @@ -31,6 +31,8 @@ enum AnnotationKind { Required, // Annotation is useless, reject it Prohibited, + // Deprecation annotation is useless, reject it. (Stability attribute is still required.) + DeprecationProhibited, // Annotation itself is useless, but it can be propagated to children Container, } @@ -83,14 +85,22 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { did_error = self.forbid_staged_api_attrs(hir_id, attrs, inherit_deprecation.clone()); } - let depr = - if did_error { None } else { attr::find_deprecation(&self.tcx.sess, attrs, item_sp) }; + let depr = if did_error { None } else { attr::find_deprecation(&self.tcx.sess, attrs) }; let mut is_deprecated = false; - if let Some(depr) = &depr { + if let Some((depr, span)) = &depr { is_deprecated = true; - if kind == AnnotationKind::Prohibited { - self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless"); + if kind == AnnotationKind::Prohibited || kind == AnnotationKind::DeprecationProhibited { + self.tcx.struct_span_lint_hir(USELESS_DEPRECATED, hir_id, *span, |lint| { + lint.build("this `#[deprecated]` annotation has no effect") + .span_suggestion_short( + *span, + "remove the unnecessary deprecation attribute", + String::new(), + rustc_errors::Applicability::MachineApplicable, + ) + .emit() + }); } // `Deprecation` is just two pointers, no need to intern it @@ -114,7 +124,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } else { self.recurse_with_stability_attrs( - depr.map(|d| DeprecationEntry::local(d, hir_id)), + depr.map(|(d, _)| DeprecationEntry::local(d, hir_id)), None, None, visit_children, @@ -139,11 +149,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - if depr.as_ref().map_or(false, |d| d.is_since_rustc_version) { + if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr { if stab.is_none() { struct_span_err!( self.tcx.sess, - item_sp, + *span, E0549, "rustc_deprecated attribute must be paired with \ either stable or unstable attribute" @@ -166,7 +176,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // Check if deprecated_since < stable_since. If it is, // this is *almost surely* an accident. if let (&Some(dep_since), &attr::Stable { since: stab_since }) = - (&depr.as_ref().and_then(|d| d.since), &stab.level) + (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level) { // Explicit version of iter::order::lt to handle parse errors properly for (dep_v, stab_v) in @@ -212,7 +222,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } self.recurse_with_stability_attrs( - depr.map(|d| DeprecationEntry::local(d, hir_id)), + depr.map(|(d, _)| DeprecationEntry::local(d, hir_id)), stab, const_stab, visit_children, @@ -322,6 +332,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } hir::ItemKind::Impl { of_trait: Some(_), .. } => { self.in_trait_impl = true; + kind = AnnotationKind::DeprecationProhibited; } hir::ItemKind::Struct(ref sd, _) => { if let Some(ctor_hir_id) = sd.ctor_hir_id() { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 851e0dfbe0d..4c0941120a6 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -2,6 +2,8 @@ #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] +#![feature(control_flow_enum)] +#![feature(try_blocks)] #![recursion_limit = "256"] use rustc_attr as attr; @@ -26,6 +28,7 @@ use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; use std::marker::PhantomData; +use std::ops::ControlFlow; use std::{cmp, fmt, mem}; //////////////////////////////////////////////////////////////////////////////// @@ -48,7 +51,12 @@ trait DefIdVisitor<'tcx> { fn skip_assoc_tys(&self) -> bool { false } - fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool; + fn visit_def_id( + &mut self, + def_id: DefId, + kind: &str, + descr: &dyn fmt::Display, + ) -> ControlFlow<()>; /// Not overridden, but used to actually visit types and traits. fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> { @@ -58,13 +66,13 @@ trait DefIdVisitor<'tcx> { dummy: Default::default(), } } - fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> bool { + fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow<()> { ty_fragment.visit_with(&mut self.skeleton()) } - fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool { + fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<()> { self.skeleton().visit_trait(trait_ref) } - fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> bool { + fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<()> { self.skeleton().visit_predicates(predicates) } } @@ -79,25 +87,25 @@ impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V> where V: DefIdVisitor<'tcx> + ?Sized, { - fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool { + fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<()> { let TraitRef { def_id, substs } = trait_ref; - self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path()) - || (!self.def_id_visitor.shallow() && substs.visit_with(self)) + self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?; + if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) } } - fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool { + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> { match predicate.skip_binders() { ty::PredicateAtom::Trait(ty::TraitPredicate { trait_ref }, _) => { self.visit_trait(trait_ref) } ty::PredicateAtom::Projection(ty::ProjectionPredicate { projection_ty, ty }) => { - ty.visit_with(self) - || self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx())) + ty.visit_with(self)?; + self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx())) } ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => { ty.visit_with(self) } - ty::PredicateAtom::RegionOutlives(..) => false, + ty::PredicateAtom::RegionOutlives(..) => ControlFlow::CONTINUE, ty::PredicateAtom::ConstEvaluatable(..) if self.def_id_visitor.tcx().features().const_evaluatable_checked => { @@ -105,20 +113,15 @@ where // private function we may have to do something here... // // For now, let's just pretend that everything is fine. - false + ControlFlow::CONTINUE } _ => bug!("unexpected predicate: {:?}", predicate), } } - fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> bool { + fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<()> { let ty::GenericPredicates { parent: _, predicates } = predicates; - for &(predicate, _span) in predicates { - if self.visit_predicate(predicate) { - return true; - } - } - false + predicates.iter().try_for_each(|&(predicate, _span)| self.visit_predicate(predicate)) } } @@ -126,7 +129,7 @@ impl<'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'tcx, V> where V: DefIdVisitor<'tcx> + ?Sized, { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { let tcx = self.def_id_visitor.tcx(); // InternalSubsts are not visited here because they are visited below in `super_visit_with`. match *ty.kind() { @@ -135,19 +138,15 @@ where | ty::FnDef(def_id, ..) | ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => { - if self.def_id_visitor.visit_def_id(def_id, "type", &ty) { - return true; - } + self.def_id_visitor.visit_def_id(def_id, "type", &ty)?; if self.def_id_visitor.shallow() { - return false; + return ControlFlow::CONTINUE; } // Default type visitor doesn't visit signatures of fn types. // Something like `fn() -> Priv {my_func}` is considered a private type even if // `my_func` is public, so we need to visit signatures. if let ty::FnDef(..) = ty.kind() { - if tcx.fn_sig(def_id).visit_with(self) { - return true; - } + tcx.fn_sig(def_id).visit_with(self)?; } // Inherent static methods don't have self type in substs. // Something like `fn() {my_method}` type of the method @@ -155,9 +154,7 @@ where // so we need to visit the self type additionally. if let Some(assoc_item) = tcx.opt_associated_item(def_id) { if let ty::ImplContainer(impl_def_id) = assoc_item.container { - if tcx.type_of(impl_def_id).visit_with(self) { - return true; - } + tcx.type_of(impl_def_id).visit_with(self)?; } } } @@ -168,7 +165,7 @@ where // as visible/reachable even if both `Type` and `Trait` are private. // Ideally, associated types should be substituted in the same way as // free type aliases, but this isn't done yet. - return false; + return ControlFlow::CONTINUE; } // This will also visit substs if necessary, so we don't need to recurse. return self.visit_trait(proj.trait_ref(tcx)); @@ -185,9 +182,7 @@ where } }; let ty::ExistentialTraitRef { def_id, substs: _ } = trait_ref; - if self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) { - return true; - } + self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)?; } } ty::Opaque(def_id, ..) => { @@ -200,12 +195,10 @@ where // through the trait list (default type visitor doesn't visit those traits). // All traits in the list are considered the "primary" part of the type // and are visited by shallow visitors. - if self.visit_predicates(ty::GenericPredicates { + self.visit_predicates(ty::GenericPredicates { parent: None, predicates: tcx.explicit_item_bounds(def_id), - }) { - return true; - } + })?; } } // These types don't have their own def-ids (but may have subcomponents @@ -231,7 +224,11 @@ where } } - !self.def_id_visitor.shallow() && ty.super_visit_with(self) + if self.def_id_visitor.shallow() { + ControlFlow::CONTINUE + } else { + ty.super_visit_with(self) + } } } @@ -281,9 +278,14 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL> fn skip_assoc_tys(&self) -> bool { true } - fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool { + fn visit_def_id( + &mut self, + def_id: DefId, + _kind: &str, + _descr: &dyn fmt::Display, + ) -> ControlFlow<()> { self.min = VL::new_min(self, def_id); - false + ControlFlow::CONTINUE } } @@ -895,7 +897,12 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.ev.tcx } - fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool { + fn visit_def_id( + &mut self, + def_id: DefId, + _kind: &str, + _descr: &dyn fmt::Display, + ) -> ControlFlow<()> { if let Some(def_id) = def_id.as_local() { if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) = (self.tcx().visibility(def_id.to_def_id()), self.access_level) @@ -904,7 +911,7 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { self.ev.update(hir_id, self.access_level); } } - false + ControlFlow::CONTINUE } } @@ -1072,17 +1079,14 @@ impl<'tcx> TypePrivacyVisitor<'tcx> { fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool { self.span = span; let typeck_results = self.typeck_results(); - if self.visit(typeck_results.node_type(id)) || self.visit(typeck_results.node_substs(id)) { - return true; - } - if let Some(adjustments) = typeck_results.adjustments().get(id) { - for adjustment in adjustments { - if self.visit(adjustment.target) { - return true; - } + let result: ControlFlow<()> = try { + self.visit(typeck_results.node_type(id))?; + self.visit(typeck_results.node_substs(id))?; + if let Some(adjustments) = typeck_results.adjustments().get(id) { + adjustments.iter().try_for_each(|adjustment| self.visit(adjustment.target))?; } - } - false + }; + result.is_break() } fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { @@ -1124,14 +1128,14 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { self.span = hir_ty.span; if let Some(typeck_results) = self.maybe_typeck_results { // Types in bodies. - if self.visit(typeck_results.node_type(hir_ty.hir_id)) { + if self.visit(typeck_results.node_type(hir_ty.hir_id)).is_break() { return; } } else { // Types in signatures. // FIXME: This is very ineffective. Ideally each HIR type should be converted // into a semantic type only once and the result should be cached somehow. - if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, hir_ty)) { + if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, hir_ty)).is_break() { return; } } @@ -1153,15 +1157,17 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { ); for (trait_predicate, _, _) in bounds.trait_bounds { - if self.visit_trait(trait_predicate.skip_binder()) { + if self.visit_trait(trait_predicate.skip_binder()).is_break() { return; } } for (poly_predicate, _) in bounds.projection_bounds { let tcx = self.tcx; - if self.visit(poly_predicate.skip_binder().ty) - || self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) + if self.visit(poly_predicate.skip_binder().ty).is_break() + || self + .visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) + .is_break() { return; } @@ -1188,7 +1194,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { // Method calls have to be checked specially. self.span = span; if let Some(def_id) = self.typeck_results().type_dependent_def_id(expr.hir_id) { - if self.visit(self.tcx.type_of(def_id)) { + if self.visit(self.tcx.type_of(def_id)).is_break() { return; } } else { @@ -1219,9 +1225,11 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { .maybe_typeck_results .and_then(|typeck_results| typeck_results.type_dependent_def(id)), }; - let def = def.filter(|(kind, _)| match kind { - DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static => true, - _ => false, + let def = def.filter(|(kind, _)| { + matches!( + kind, + DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static + ) }); if let Some((kind, def_id)) = def { let is_local_static = @@ -1286,8 +1294,17 @@ impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } - fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { - self.check_def_id(def_id, kind, descr) + fn visit_def_id( + &mut self, + def_id: DefId, + kind: &str, + descr: &dyn fmt::Display, + ) -> ControlFlow<()> { + if self.check_def_id(def_id, kind, descr) { + ControlFlow::BREAK + } else { + ControlFlow::CONTINUE + } } } @@ -1777,8 +1794,17 @@ impl DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } - fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { - self.check_def_id(def_id, kind, descr) + fn visit_def_id( + &mut self, + def_id: DefId, + kind: &str, + descr: &dyn fmt::Display, + ) -> ControlFlow<()> { + if self.check_def_id(def_id, kind, descr) { + ControlFlow::BREAK + } else { + ControlFlow::CONTINUE + } } } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 85335f0ba50..d9b687c48af 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -292,10 +292,8 @@ impl<K: DepKind> DepGraph<K> { ); data.colors.insert(prev_index, color); - } else { - if print_status { - eprintln!("[task::new] {:?}", key); - } + } else if print_status { + eprintln!("[task::new] {:?}", key); } (result, dep_node_index) diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 50f443716f4..426f5bb41d6 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -612,10 +612,8 @@ where prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - if unlikely!(!diagnostics.is_empty()) { - if dep_node.kind != DepKind::NULL { - tcx.store_diagnostics(dep_node_index, diagnostics); - } + if unlikely!(!diagnostics.is_empty()) && dep_node.kind != DepKind::NULL { + tcx.store_diagnostics(dep_node_index, diagnostics); } let result = job.complete(result, dep_node_index); diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index feeea726f4c..83016ed36a7 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -15,7 +15,6 @@ use crate::{ }; use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding}; -use rustc_ast::token::{self, Token}; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId}; use rustc_ast::{AssocItem, AssocItemKind, MetaItemKind, StmtKind}; @@ -344,10 +343,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn block_needs_anonymous_module(&mut self, block: &Block) -> bool { // If any statements are items, we need to create an anonymous module - block.stmts.iter().any(|statement| match statement.kind { - StmtKind::Item(_) | StmtKind::MacCall(_) => true, - _ => false, - }) + block + .stmts + .iter() + .any(|statement| matches!(statement.kind, StmtKind::Item(_) | StmtKind::MacCall(_))) } // Add an import to the current module. @@ -1395,16 +1394,6 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { visit::walk_assoc_item(self, item, ctxt); } - fn visit_token(&mut self, t: Token) { - if let token::Interpolated(nt) = t.kind { - if let token::NtExpr(ref expr) = *nt { - if let ast::ExprKind::MacCall(..) = expr.kind { - self.visit_invoc(expr.id); - } - } - } - } - fn visit_attribute(&mut self, attr: &'b ast::Attribute) { if !attr.is_doc_comment() && attr::is_builtin_attr(attr) { self.r diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index a4de4d500f5..69773ba1d72 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -1,5 +1,4 @@ use crate::Resolver; -use rustc_ast::token::{self, Token}; use rustc_ast::visit::{self, FnKind}; use rustc_ast::walk_list; use rustc_ast::*; @@ -256,16 +255,6 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { } } - fn visit_token(&mut self, t: Token) { - if let token::Interpolated(nt) = t.kind { - if let token::NtExpr(ref expr) = *nt { - if let ExprKind::MacCall(..) = expr.kind { - self.visit_macro_invoc(expr.id); - } - } - } - } - fn visit_arm(&mut self, arm: &'a Arm) { if arm.is_placeholder { self.visit_macro_invoc(arm.id) } else { visit::walk_arm(self, arm) } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 33ab09a8f42..4e115c62c9e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -922,15 +922,10 @@ impl<'a> Resolver<'a> { ); self.add_typo_suggestion(err, suggestion, ident.span); - let import_suggestions = self.lookup_import_candidates( - ident, - Namespace::MacroNS, - parent_scope, - |res| match res { - Res::Def(DefKind::Macro(MacroKind::Bang), _) => true, - _ => false, - }, - ); + let import_suggestions = + self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, |res| { + matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _)) + }); show_candidates(err, None, &import_suggestions, false, true); if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { @@ -1010,11 +1005,9 @@ impl<'a> Resolver<'a> { fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String { let res = b.res(); if b.span.is_dummy() { - let add_built_in = match b.res() { - // These already contain the "built-in" prefix or look bad with it. - Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod => false, - _ => true, - }; + // These already contain the "built-in" prefix or look bad with it. + let add_built_in = + !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod); let (built_in, from) = if from_prelude { ("", " from prelude") } else if b.is_extern_crate() @@ -1610,10 +1603,7 @@ fn find_span_immediately_after_crate_name( if *c == ':' { num_colons += 1; } - match c { - ':' if num_colons == 2 => false, - _ => true, - } + !matches!(c, ':' if num_colons == 2) }); // Find everything after the second colon.. `foo::{baz, makro};` let from_second_colon = use_span.with_lo(until_second_colon.hi() + BytePos(1)); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index adff4542b0f..269d25be0a5 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -114,10 +114,7 @@ crate struct Import<'a> { impl<'a> Import<'a> { pub fn is_glob(&self) -> bool { - match self.kind { - ImportKind::Glob { .. } => true, - _ => false, - } + matches!(self.kind, ImportKind::Glob { .. }) } pub fn is_nested(&self) -> bool { @@ -898,12 +895,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let msg = "inconsistent resolution for an import"; self.r.session.span_err(import.span, msg); } - } else { - if self.r.privacy_errors.is_empty() { - let msg = "cannot determine resolution for the import"; - let msg_note = "import resolution is stuck, try simplifying other imports"; - self.r.session.struct_span_err(import.span, msg).note(msg_note).emit(); - } + } else if self.r.privacy_errors.is_empty() { + let msg = "cannot determine resolution for the import"; + let msg_note = "import resolution is stuck, try simplifying other imports"; + self.r.session.struct_span_err(import.span, msg).note(msg_note).emit(); } module @@ -1044,19 +1039,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if res != initial_res && this.ambiguity_errors.is_empty() { span_bug!(import.span, "inconsistent resolution for an import"); } - } else { - if res != Res::Err - && this.ambiguity_errors.is_empty() - && this.privacy_errors.is_empty() - { - let msg = "cannot determine resolution for the import"; - let msg_note = - "import resolution is stuck, try simplifying other imports"; - this.session - .struct_span_err(import.span, msg) - .note(msg_note) - .emit(); - } + } else if res != Res::Err + && this.ambiguity_errors.is_empty() + && this.privacy_errors.is_empty() + { + let msg = "cannot determine resolution for the import"; + let msg_note = + "import resolution is stuck, try simplifying other imports"; + this.session.struct_span_err(import.span, msg).note(msg_note).emit(); } } Err(..) => { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index d323aebe597..2337f0d09ab 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -257,16 +257,12 @@ impl<'a> PathSource<'a> { } fn is_call(self) -> bool { - match self { - PathSource::Expr(Some(&Expr { kind: ExprKind::Call(..), .. })) => true, - _ => false, - } + matches!(self, PathSource::Expr(Some(&Expr { kind: ExprKind::Call(..), .. }))) } crate fn is_expected(self, res: Res) -> bool { match self { - PathSource::Type => match res { - Res::Def( + PathSource::Type => matches!(res, Res::Def( DefKind::Struct | DefKind::Union | DefKind::Enum @@ -280,19 +276,12 @@ impl<'a> PathSource<'a> { _, ) | Res::PrimTy(..) - | Res::SelfTy(..) => true, - _ => false, - }, - PathSource::Trait(AliasPossibility::No) => match res { - Res::Def(DefKind::Trait, _) => true, - _ => false, - }, - PathSource::Trait(AliasPossibility::Maybe) => match res { - Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => true, - _ => false, - }, - PathSource::Expr(..) => match res { - Res::Def( + | Res::SelfTy(..)), + PathSource::Trait(AliasPossibility::No) => matches!(res, Res::Def(DefKind::Trait, _)), + PathSource::Trait(AliasPossibility::Maybe) => { + matches!(res, Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) + } + PathSource::Expr(..) => matches!(res, Res::Def( DefKind::Ctor(_, CtorKind::Const | CtorKind::Fn) | DefKind::Const | DefKind::Static @@ -303,23 +292,16 @@ impl<'a> PathSource<'a> { _, ) | Res::Local(..) - | Res::SelfCtor(..) => true, - _ => false, - }, - PathSource::Pat => match res { - Res::Def( + | Res::SelfCtor(..)), + PathSource::Pat => matches!(res, Res::Def( DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::AssocConst, _, ) - | Res::SelfCtor(..) => true, - _ => false, - }, - PathSource::TupleStruct(..) => match res { - Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true, - _ => false, - }, - PathSource::Struct => match res { - Res::Def( + | Res::SelfCtor(..)), + PathSource::TupleStruct(..) => { + matches!(res, Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..)) + } + PathSource::Struct => matches!(res, Res::Def( DefKind::Struct | DefKind::Union | DefKind::Variant @@ -327,9 +309,7 @@ impl<'a> PathSource<'a> { | DefKind::AssocTy, _, ) - | Res::SelfTy(..) => true, - _ => false, - }, + | Res::SelfTy(..)), PathSource::TraitItem(ns) => match res { Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) if ns == ValueNS => true, Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true, @@ -359,8 +339,8 @@ impl<'a> PathSource<'a> { #[derive(Default)] struct DiagnosticMetadata<'ast> { - /// The current trait's associated types' ident, used for diagnostic suggestions. - current_trait_assoc_types: Vec<Ident>, + /// The current trait's associated items' ident, used for diagnostic suggestions. + current_trait_assoc_items: Option<&'ast [P<AssocItem>]>, /// The current self type if inside an impl (used for better errors). current_self_type: Option<Ty>, @@ -1177,26 +1157,18 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { result } - /// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412. + /// When evaluating a `trait` use its associated types' idents for suggestions in E0412. fn with_trait_items<T>( &mut self, - trait_items: &Vec<P<AssocItem>>, + trait_items: &'ast Vec<P<AssocItem>>, f: impl FnOnce(&mut Self) -> T, ) -> T { - let trait_assoc_types = replace( - &mut self.diagnostic_metadata.current_trait_assoc_types, - trait_items - .iter() - .filter_map(|item| match &item.kind { - AssocItemKind::TyAlias(_, _, bounds, _) if bounds.is_empty() => { - Some(item.ident) - } - _ => None, - }) - .collect(), + let trait_assoc_items = replace( + &mut self.diagnostic_metadata.current_trait_assoc_items, + Some(&trait_items[..]), ); let result = f(self); - self.diagnostic_metadata.current_trait_assoc_types = trait_assoc_types; + self.diagnostic_metadata.current_trait_assoc_items = trait_assoc_items; result } @@ -1450,10 +1422,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } fn is_base_res_local(&self, nid: NodeId) -> bool { - match self.r.partial_res_map.get(&nid).map(|res| res.base_res()) { - Some(Res::Local(..)) => true, - _ => false, - } + matches!(self.r.partial_res_map.get(&nid).map(|res| res.base_res()), Some(Res::Local(..))) } /// Checks that all of the arms in an or-pattern have exactly the diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index cafceff4f29..14f8c7b09f8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -30,7 +30,21 @@ type Res = def::Res<ast::NodeId>; enum AssocSuggestion { Field, MethodWithSelf, - AssocItem, + AssocFn, + AssocType, + AssocConst, +} + +impl AssocSuggestion { + fn action(&self) -> &'static str { + match self { + AssocSuggestion::Field => "use the available field", + AssocSuggestion::MethodWithSelf => "call the method with the fully-qualified path", + AssocSuggestion::AssocFn => "call the associated function", + AssocSuggestion::AssocConst => "use the associated `const`", + AssocSuggestion::AssocType => "use the associated type", + } + } } crate enum MissingLifetimeSpot<'tcx> { @@ -386,15 +400,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { AssocSuggestion::MethodWithSelf if self_is_available => { err.span_suggestion( span, - "try", + "you might have meant to call the method", format!("self.{}", path_str), Applicability::MachineApplicable, ); } - AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => { + AssocSuggestion::MethodWithSelf + | AssocSuggestion::AssocFn + | AssocSuggestion::AssocConst + | AssocSuggestion::AssocType => { err.span_suggestion( span, - "try", + &format!("you might have meant to {}", candidate.action()), format!("Self::{}", path_str), Applicability::MachineApplicable, ); @@ -702,10 +719,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { _ => break, } } - let followed_by_brace = match sm.span_to_snippet(sp) { - Ok(ref snippet) if snippet == "{" => true, - _ => false, - }; + let followed_by_brace = matches!(sm.span_to_snippet(sp), Ok(ref snippet) if snippet == "{"); // In case this could be a struct literal that needs to be surrounded // by parentheses, find the appropriate span. let mut i = 0; @@ -1065,9 +1079,19 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } - for assoc_type_ident in &self.diagnostic_metadata.current_trait_assoc_types { - if *assoc_type_ident == ident { - return Some(AssocSuggestion::AssocItem); + if let Some(items) = self.diagnostic_metadata.current_trait_assoc_items { + for assoc_item in &items[..] { + if assoc_item.ident == ident { + return Some(match &assoc_item.kind { + ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst, + ast::AssocItemKind::Fn(_, sig, ..) if sig.decl.has_self() => { + AssocSuggestion::MethodWithSelf + } + ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn, + ast::AssocItemKind::TyAlias(..) => AssocSuggestion::AssocType, + ast::AssocItemKind::MacCall(_) => continue, + }); + } } } @@ -1083,11 +1107,20 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { ) { let res = binding.res(); if filter_fn(res) { - return Some(if self.r.has_self.contains(&res.def_id()) { - AssocSuggestion::MethodWithSelf + if self.r.has_self.contains(&res.def_id()) { + return Some(AssocSuggestion::MethodWithSelf); } else { - AssocSuggestion::AssocItem - }); + match res { + Res::Def(DefKind::AssocFn, _) => return Some(AssocSuggestion::AssocFn), + Res::Def(DefKind::AssocConst, _) => { + return Some(AssocSuggestion::AssocConst); + } + Res::Def(DefKind::AssocTy, _) => { + return Some(AssocSuggestion::AssocType); + } + _ => {} + } + } } } } @@ -1788,12 +1821,11 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { } msg = "consider introducing a named lifetime parameter".to_string(); should_break = true; - if let Some(param) = generics.params.iter().find(|p| match p.kind { - hir::GenericParamKind::Type { + if let Some(param) = generics.params.iter().find(|p| { + !matches!(p.kind, hir::GenericParamKind::Type { synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. - } => false, - _ => true, + }) }) { (param.span.shrink_to_lo(), "'a, ".to_string()) } else { @@ -1854,9 +1886,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { if snippet.starts_with('&') && !snippet.starts_with("&'") { introduce_suggestion .push((param.span, format!("&'a {}", &snippet[1..]))); - } else if snippet.starts_with("&'_ ") { - introduce_suggestion - .push((param.span, format!("&'a {}", &snippet[4..]))); + } else if let Some(stripped) = snippet.strip_prefix("&'_ ") { + introduce_suggestion.push((param.span, format!("&'a {}", &stripped))); } } } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 072fb509b19..c79d670737e 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -351,10 +351,7 @@ fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap { /// We have to account for this when computing the index of the other generic parameters. /// This function returns whether there is such an implicit parameter defined on the given item. fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool { - match *node { - hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => true, - _ => false, - } + matches!(*node, hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..)) } impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { @@ -417,10 +414,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name". // This is not true for other kinds of items.x - let track_lifetime_uses = match item.kind { - hir::ItemKind::Impl { .. } => true, - _ => false, - }; + let track_lifetime_uses = matches!(item.kind, hir::ItemKind::Impl { .. }); // These kinds of items have only early-bound lifetime parameters. let mut index = if sub_items_have_self_param(&item.kind) { 1 // Self comes before lifetimes @@ -970,10 +964,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let trait_ref_hack = take(&mut self.trait_ref_hack); if !trait_ref_hack - || trait_ref.bound_generic_params.iter().any(|param| match param.kind { - GenericParamKind::Lifetime { .. } => true, - _ => false, - }) + || trait_ref + .bound_generic_params + .iter() + .any(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) { if trait_ref_hack { struct_span_err!( @@ -1384,18 +1378,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } if in_band { Some(param.span) + } else if generics.params.len() == 1 { + // if sole lifetime, remove the entire `<>` brackets + Some(generics.span) } else { - if generics.params.len() == 1 { - // if sole lifetime, remove the entire `<>` brackets - Some(generics.span) + // if removing within `<>` brackets, we also want to + // delete a leading or trailing comma as appropriate + if i >= generics.params.len() - 1 { + Some(generics.params[i - 1].span.shrink_to_hi().to(param.span)) } else { - // if removing within `<>` brackets, we also want to - // delete a leading or trailing comma as appropriate - if i >= generics.params.len() - 1 { - Some(generics.params[i - 1].span.shrink_to_hi().to(param.span)) - } else { - Some(param.span.to(generics.params[i + 1].span.shrink_to_lo())) - } + Some(param.span.to(generics.params[i + 1].span.shrink_to_lo())) } } } else { @@ -2047,10 +2039,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // // This is intended to leave room for us to implement the // correct behavior in the future. - let has_lifetime_parameter = generic_args.args.iter().any(|arg| match arg { - GenericArg::Lifetime(_) => true, - _ => false, - }); + let has_lifetime_parameter = + generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))); // Resolve lifetimes found in the type `XX` from `Item = XX` bindings. for b in generic_args.bindings { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 902ee5f4d09..30cd9944b1a 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -313,17 +313,17 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder { ItemKind::ExternCrate(_) => {} // but place them before the first other item _ => { - if self.span.map_or(true, |span| item.span < span) { - if !item.span.from_expansion() { - // don't insert between attributes and an item - if item.attrs.is_empty() { - self.span = Some(item.span.shrink_to_lo()); - } else { - // find the first attribute on the item - for attr in &item.attrs { - if self.span.map_or(true, |span| attr.span < span) { - self.span = Some(attr.span.shrink_to_lo()); - } + if self.span.map_or(true, |span| item.span < span) + && !item.span.from_expansion() + { + // don't insert between attributes and an item + if item.attrs.is_empty() { + self.span = Some(item.span.shrink_to_lo()); + } else { + // find the first attribute on the item + for attr in &item.attrs { + if self.span.map_or(true, |span| attr.span < span) { + self.span = Some(attr.span.shrink_to_lo()); } } } @@ -558,17 +558,11 @@ impl<'a> ModuleData<'a> { // `self` resolves to the first module ancestor that `is_normal`. fn is_normal(&self) -> bool { - match self.kind { - ModuleKind::Def(DefKind::Mod, _, _) => true, - _ => false, - } + matches!(self.kind, ModuleKind::Def(DefKind::Mod, _, _)) } fn is_trait(&self) -> bool { - match self.kind { - ModuleKind::Def(DefKind::Trait, _, _) => true, - _ => false, - } + matches!(self.kind, ModuleKind::Def(DefKind::Trait, _, _)) } fn nearest_item_scope(&'a self) -> Module<'a> { @@ -628,10 +622,7 @@ enum NameBindingKind<'a> { impl<'a> NameBindingKind<'a> { /// Is this a name binding of a import? fn is_import(&self) -> bool { - match *self { - NameBindingKind::Import { .. } => true, - _ => false, - } + matches!(*self, NameBindingKind::Import { .. }) } } @@ -750,13 +741,10 @@ impl<'a> NameBinding<'a> { } fn is_variant(&self) -> bool { - match self.kind { - NameBindingKind::Res( + matches!(self.kind, NameBindingKind::Res( Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _), _, - ) => true, - _ => false, - } + )) } fn is_extern_crate(&self) -> bool { @@ -774,10 +762,7 @@ impl<'a> NameBinding<'a> { } fn is_import(&self) -> bool { - match self.kind { - NameBindingKind::Import { .. } => true, - _ => false, - } + matches!(self.kind, NameBindingKind::Import { .. }) } fn is_glob_import(&self) -> bool { @@ -788,17 +773,14 @@ impl<'a> NameBinding<'a> { } fn is_importable(&self) -> bool { - match self.res() { - Res::Def(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy, _) => false, - _ => true, - } + !matches!( + self.res(), + Res::Def(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy, _) + ) } fn is_macro_def(&self) -> bool { - match self.kind { - NameBindingKind::Res(Res::Def(DefKind::Macro(..), _), _) => true, - _ => false, - } + matches!(self.kind, NameBindingKind::Res(Res::Def(DefKind::Macro(..), _), _)) } fn macro_kind(&self) -> Option<MacroKind> { @@ -1380,7 +1362,7 @@ impl<'a> Resolver<'a> { let maybe_unused_extern_crates = self.maybe_unused_extern_crates; let glob_map = self.glob_map; ResolverOutputs { - definitions: definitions, + definitions, cstore: Box::new(self.crate_loader.into_cstore()), visibilities, extern_crate_map, @@ -1992,11 +1974,12 @@ impl<'a> Resolver<'a> { // The macro is a proc macro derive if let Some(def_id) = module.expansion.expn_data().macro_def_id { if let Some(ext) = self.get_macro_by_def_id(def_id) { - if !ext.is_builtin && ext.macro_kind() == MacroKind::Derive { - if parent.expansion.outer_expn_is_descendant_of(span.ctxt()) { - *poisoned = Some(node_id); - return module.parent; - } + if !ext.is_builtin + && ext.macro_kind() == MacroKind::Derive + && parent.expansion.outer_expn_is_descendant_of(span.ctxt()) + { + *poisoned = Some(node_id); + return module.parent; } } } @@ -2390,10 +2373,7 @@ impl<'a> Resolver<'a> { _ => None, }; let (label, suggestion) = if module_res == self.graph_root.res() { - let is_mod = |res| match res { - Res::Def(DefKind::Mod, _) => true, - _ => false, - }; + let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _)); // Don't look up import candidates if this is a speculative resolve let mut candidates = if record_used { self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod) diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 48d15370ee3..eed9f2eb74d 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -799,7 +799,9 @@ impl<'tcx> SaveContext<'tcx> { // These are not macros. // FIXME(eddyb) maybe there is a way to handle them usefully? - ExpnKind::Root | ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => return None, + ExpnKind::Inlined | ExpnKind::Root | ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => { + return None; + } }; let callee_span = self.span_from_span(callee.def_site); diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index cdff1662fdb..4c72920502f 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -18,3 +18,4 @@ rustc_span = { path = "../rustc_span" } rustc_fs_util = { path = "../rustc_fs_util" } num_cpus = "1.0" rustc_ast = { path = "../rustc_ast" } +rustc_lint_defs = { path = "../rustc_lint_defs" } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f33bebf99d6..b632bfbed30 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2057,10 +2057,7 @@ impl PpMode { pub fn needs_analysis(&self) -> bool { use PpMode::*; - match *self { - PpmMir | PpmMirCFG => true, - _ => false, - } + matches!(*self, PpmMir | PpmMirCFG) } } diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index a808261798d..d002f597391 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -9,8 +9,8 @@ extern crate rustc_macros; pub mod cgu_reuse_tracker; pub mod utils; -#[macro_use] -pub mod lint; +pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass}; +pub use rustc_lint_defs as lint; pub mod parse; mod code_stats; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 750f2e19ee2..4c00361dd31 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -893,6 +893,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, all `statement`s (including terminators), only `terminator` spans, or \ computed `block` spans (one span encompassing a block's terminator and \ all statements)."), + emit_future_incompat_report: bool = (false, parse_bool, [UNTRACKED], + "emits a future-incompatibility report for lints (RFC 2834)"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), fewer_names: bool = (false, parse_bool, [TRACKED], @@ -969,6 +971,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "use new LLVM pass manager (default: no)"), nll_facts: bool = (false, parse_bool, [UNTRACKED], "dump facts from NLL analysis into side files (default: no)"), + nll_facts_dir: String = ("nll-facts".to_string(), parse_string, [UNTRACKED], + "the directory the NLL facts are dumped into (default: `nll-facts`)"), no_analysis: bool = (false, parse_no_flag, [UNTRACKED], "parse and expand the source, but run no analysis"), no_codegen: bool = (false, parse_no_flag, [TRACKED], @@ -1030,6 +1034,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "enable queries of the dependency graph for regression testing (default: no)"), query_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about the query system (default: no)"), + relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED], + "whether ELF relocations can be relaxed"), relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED], "choose which RELRO level to use"), report_delayed_bugs: bool = (false, parse_bool, [TRACKED], @@ -1070,7 +1076,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, span_free_formats: bool = (false, parse_bool, [UNTRACKED], "exclude spans when debug-printing compiler state (default: no)"), src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED], - "hash algorithm of source files in debug info (`md5`, or `sha1`)"), + "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy, diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 0766c55da74..130c3a06122 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -199,10 +199,8 @@ pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool _ => {} } } - if !sess.target.options.executables { - if crate_type == CrateType::Executable { - return true; - } + if !sess.target.options.executables && crate_type == CrateType::Executable { + return true; } false diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 8312f89b271..0b7c35a8afd 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -3,7 +3,7 @@ use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; use crate::config::{self, CrateType, OutputType, PrintRequest, SanitizerSet, SwitchWithOptPath}; use crate::filesearch; -use crate::lint; +use crate::lint::{self, LintId}; use crate::parse::ParseSess; use crate::search_paths::{PathKind, SearchPath}; @@ -21,7 +21,8 @@ use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter; use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; -use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorReported}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported}; +use rustc_lint_defs::FutureBreakage; use rustc_span::edition::Edition; use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span}; use rustc_span::{sym, SourceFileHashAlgorithm, Symbol}; @@ -40,6 +41,10 @@ use std::str::FromStr; use std::sync::Arc; use std::time::Duration; +pub trait SessionLintStore: sync::Send + sync::Sync { + fn name_to_lint(&self, lint_name: &str) -> LintId; +} + pub struct OptimizationFuel { /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`. remaining: u64, @@ -131,6 +136,8 @@ pub struct Session { features: OnceCell<rustc_feature::Features>, + lint_store: OnceCell<Lrc<dyn SessionLintStore>>, + /// The maximum recursion limit for potentially infinitely recursive /// operations such as auto-dereference and monomorphization. pub recursion_limit: OnceCell<Limit>, @@ -297,6 +304,35 @@ impl Session { pub fn finish_diagnostics(&self, registry: &Registry) { self.check_miri_unleashed_features(); self.diagnostic().print_error_count(registry); + self.emit_future_breakage(); + } + + fn emit_future_breakage(&self) { + if !self.opts.debugging_opts.emit_future_incompat_report { + return; + } + + let diags = self.diagnostic().take_future_breakage_diagnostics(); + if diags.is_empty() { + return; + } + // If any future-breakage lints were registered, this lint store + // should be available + let lint_store = self.lint_store.get().expect("`lint_store` not initialized!"); + let diags_and_breakage: Vec<(FutureBreakage, Diagnostic)> = diags + .into_iter() + .map(|diag| { + let lint_name = match &diag.code { + Some(DiagnosticId::Lint { name, has_future_breakage: true }) => name, + _ => panic!("Unexpected code in diagnostic {:?}", diag), + }; + let lint = lint_store.name_to_lint(&lint_name); + let future_breakage = + lint.lint.future_incompatible.unwrap().future_breakage.unwrap(); + (future_breakage, diag) + }) + .collect(); + self.parse_sess.span_diagnostic.emit_future_breakage_report(diags_and_breakage); } pub fn local_crate_disambiguator(&self) -> CrateDisambiguator { @@ -337,6 +373,12 @@ impl Session { pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> { self.diagnostic().struct_warn(msg) } + pub fn struct_span_allow<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> { + self.diagnostic().struct_span_allow(sp, msg) + } + pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_> { + self.diagnostic().struct_allow(msg) + } pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> { self.diagnostic().struct_span_err(sp, msg) } @@ -611,6 +653,13 @@ impl Session { } } + pub fn init_lint_store(&self, lint_store: Lrc<dyn SessionLintStore>) { + self.lint_store + .set(lint_store) + .map_err(|_| ()) + .expect("`lint_store` was initialized twice"); + } + /// Calculates the flavor of LTO to use for this compilation. pub fn lto(&self) -> config::Lto { // If our target has codegen requirements ignore the command line @@ -1388,6 +1437,7 @@ pub fn build_session( crate_types: OnceCell::new(), crate_disambiguator: OnceCell::new(), features: OnceCell::new(), + lint_store: OnceCell::new(), recursion_limit: OnceCell::new(), type_length_limit: OnceCell::new(), const_eval_limit: OnceCell::new(), diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 1abfd50f003..08645990c48 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -17,5 +17,6 @@ scoped-tls = "1.0" unicode-width = "0.1.4" cfg-if = "0.1.2" tracing = "0.1" -sha-1 = "0.8" -md-5 = "0.8" +sha-1 = "0.9" +sha2 = "0.9" +md-5 = "0.9" diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 31f3d8e3791..0f82db1d05a 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -766,6 +766,8 @@ pub enum ExpnKind { AstPass(AstPass), /// Desugaring done by the compiler during HIR lowering. Desugaring(DesugaringKind), + /// MIR inlining + Inlined, } impl ExpnKind { @@ -779,6 +781,7 @@ impl ExpnKind { }, ExpnKind::AstPass(kind) => kind.descr().to_string(), ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()), + ExpnKind::Inlined => "inlined source".to_string(), } } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 0e3027273ab..f52b64f4883 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -59,6 +59,7 @@ use std::str::FromStr; use md5::Md5; use sha1::Digest; use sha1::Sha1; +use sha2::Sha256; use tracing::debug; @@ -1034,6 +1035,7 @@ pub struct OffsetOverflowError; pub enum SourceFileHashAlgorithm { Md5, Sha1, + Sha256, } impl FromStr for SourceFileHashAlgorithm { @@ -1043,6 +1045,7 @@ impl FromStr for SourceFileHashAlgorithm { match s { "md5" => Ok(SourceFileHashAlgorithm::Md5), "sha1" => Ok(SourceFileHashAlgorithm::Sha1), + "sha256" => Ok(SourceFileHashAlgorithm::Sha256), _ => Err(()), } } @@ -1055,7 +1058,7 @@ rustc_data_structures::impl_stable_hash_via_hash!(SourceFileHashAlgorithm); #[derive(HashStable_Generic, Encodable, Decodable)] pub struct SourceFileHash { pub kind: SourceFileHashAlgorithm, - value: [u8; 20], + value: [u8; 32], } impl SourceFileHash { @@ -1071,6 +1074,9 @@ impl SourceFileHash { SourceFileHashAlgorithm::Sha1 => { value.copy_from_slice(&Sha1::digest(data)); } + SourceFileHashAlgorithm::Sha256 => { + value.copy_from_slice(&Sha256::digest(data)); + } } hash } @@ -1090,6 +1096,7 @@ impl SourceFileHash { match self.kind { SourceFileHashAlgorithm::Md5 => 16, SourceFileHashAlgorithm::Sha1 => 20, + SourceFileHashAlgorithm::Sha256 => 32, } } } @@ -1567,7 +1574,7 @@ fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec<NormalizedPos> { /// Removes UTF-8 BOM, if any. fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) { - if src.starts_with("\u{feff}") { + if src.starts_with('\u{feff}') { src.drain(..3); normalized_pos.push(NormalizedPos { pos: BytePos(0), diff: 3 }); } diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 3b929c4acb9..f067cdb7308 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -12,7 +12,7 @@ pub use crate::*; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::StableHasher; -use rustc_data_structures::sync::{AtomicU32, Lock, LockGuard, Lrc, MappedLockGuard}; +use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock}; use std::cmp; use std::convert::TryFrom; use std::hash::Hash; @@ -168,7 +168,7 @@ pub struct SourceMap { /// The address space below this value is currently used by the files in the source map. used_address_space: AtomicU32, - files: Lock<SourceMapFiles>, + files: RwLock<SourceMapFiles>, file_loader: Box<dyn FileLoader + Sync + Send>, // This is used to apply the file path remapping as specified via // `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`. @@ -236,8 +236,8 @@ impl SourceMap { // By returning a `MonotonicVec`, we ensure that consumers cannot invalidate // any existing indices pointing into `files`. - pub fn files(&self) -> MappedLockGuard<'_, monotonic::MonotonicVec<Lrc<SourceFile>>> { - LockGuard::map(self.files.borrow(), |files| &mut files.source_files) + pub fn files(&self) -> MappedReadGuard<'_, monotonic::MonotonicVec<Lrc<SourceFile>>> { + ReadGuard::map(self.files.borrow(), |files| &files.source_files) } pub fn source_file_by_stable_id( diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 2c9caf73b8e..ac91fcf6293 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -237,7 +237,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { // only print integers - if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { .. })) = ct.val { + if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int { .. })) = ct.val { if ct.ty.is_integral() { return self.pretty_print_const(ct, true); } @@ -326,10 +326,8 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { ) -> Result<Self::Path, Self::Error> { self = print_prefix(self)?; - let args = args.iter().cloned().filter(|arg| match arg.unpack() { - GenericArgKind::Lifetime(_) => false, - _ => true, - }); + let args = + args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_))); if args.clone().next().is_some() { self.generic_delimiters(|cx| cx.comma_sep(args)) diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 28b4a78929e..10245d21b63 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -174,10 +174,7 @@ fn compute_symbol_name( return tcx.sess.generate_proc_macro_decls_symbol(disambiguator); } let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - match tcx.hir().get(hir_id) { - Node::ForeignItem(_) => true, - _ => false, - } + matches!(tcx.hir().get(hir_id), Node::ForeignItem(_)) } else { tcx.is_foreign_item(def_id) }; @@ -200,15 +197,14 @@ fn compute_symbol_name( // show up in the `wasm-import-name` custom attribute in LLVM IR. // // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316 - if is_foreign { - if tcx.sess.target.arch != "wasm32" - || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id) - { - if let Some(name) = attrs.link_name { - return name.to_string(); - } - return tcx.item_name(def_id).to_string(); + if is_foreign + && (tcx.sess.target.arch != "wasm32" + || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id)) + { + if let Some(name) = attrs.link_name { + return name.to_string(); } + return tcx.item_name(def_id).to_string(); } if let Some(name) = attrs.export_name { @@ -234,10 +230,7 @@ fn compute_symbol_name( // codegen units) then this symbol may become an exported (but hidden // visibility) symbol. This means that multiple crates may do the same // and we want to be sure to avoid any symbol conflicts here. - match MonoItem::Fn(instance).instantiation_mode(tcx) { - InstantiationMode::GloballyShared { may_conflict: true } => true, - _ => false, - }; + matches!(MonoItem::Fn(instance).instantiation_mode(tcx), InstantiationMode::GloballyShared { may_conflict: true }); let instantiating_crate = if avoid_cross_crate_conflicts { Some(compute_instantiating_crate()) } else { None }; diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 7833385cbc9..c28c2fecfbb 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -4,7 +4,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_middle::mir::interpret::sign_extend; use rustc_middle::ty::print::{Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; @@ -200,15 +199,9 @@ impl SymbolMangler<'tcx> { let lifetimes = regions .into_iter() - .map(|br| { - match br { - ty::BrAnon(i) => { - // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`. - assert_ne!(i, 0); - i - 1 - } - _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value), - } + .map(|br| match br { + ty::BrAnon(i) => i, + _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value), }) .max() .map_or(0, |max| max + 1); @@ -327,10 +320,6 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { // Late-bound lifetimes use indices starting at 1, // see `BinderLevel` for more details. ty::ReLateBound(debruijn, ty::BrAnon(i)) => { - // FIXME(eddyb) for some reason, `anonymize_late_bound_regions` starts at `1`. - assert_ne!(i, 0); - let i = i - 1; - let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; let depth = binder.lifetime_depths.start + i; @@ -537,7 +526,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { let param_env = ty::ParamEnv::reveal_all(); ct.try_eval_bits(self.tcx, param_env, ct.ty).and_then(|b| { let sz = self.tcx.layout_of(param_env.and(ct.ty)).ok()?.size; - let val = sign_extend(b, sz) as i128; + let val = sz.sign_extend(b) as i128; if val < 0 { neg = true; } diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 8f7e2bba5aa..507ae10877b 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -474,31 +474,19 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } pub fn is_indirect(&self) -> bool { - match self.mode { - PassMode::Indirect(..) => true, - _ => false, - } + matches!(self.mode, PassMode::Indirect(..)) } pub fn is_sized_indirect(&self) -> bool { - match self.mode { - PassMode::Indirect(_, None) => true, - _ => false, - } + matches!(self.mode, PassMode::Indirect(_, None)) } pub fn is_unsized_indirect(&self) -> bool { - match self.mode { - PassMode::Indirect(_, Some(_)) => true, - _ => false, - } + matches!(self.mode, PassMode::Indirect(_, Some(_))) } pub fn is_ignore(&self) -> bool { - match self.mode { - PassMode::Ignore => true, - _ => false, - } + matches!(self.mode, PassMode::Ignore) } } diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs index 2e10bed3bd4..47530eeacd0 100644 --- a/compiler/rustc_target/src/abi/call/riscv.rs +++ b/compiler/rustc_target/src/abi/call/riscv.rs @@ -333,10 +333,8 @@ where let mut avail_gprs = 8; let mut avail_fprs = 8; - if !fn_abi.ret.is_ignore() { - if classify_ret(cx, &mut fn_abi.ret, xlen, flen) { - avail_gprs -= 1; - } + if !fn_abi.ret.is_ignore() && classify_ret(cx, &mut fn_abi.ret, xlen, flen) { + avail_gprs -= 1; } for (i, arg) in fn_abi.args.iter_mut().enumerate() { diff --git a/compiler/rustc_target/src/abi/call/wasm32.rs b/compiler/rustc_target/src/abi/call/wasm32.rs index 510f671a501..ff2c0e9bb6f 100644 --- a/compiler/rustc_target/src/abi/call/wasm32.rs +++ b/compiler/rustc_target/src/abi/call/wasm32.rs @@ -24,10 +24,8 @@ where C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout, { ret.extend_integer_width_to(32); - if ret.layout.is_aggregate() { - if !unwrap_trivial_aggregate(cx, ret) { - ret.make_indirect(); - } + if ret.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, ret) { + ret.make_indirect(); } } @@ -37,10 +35,8 @@ where C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout, { arg.extend_integer_width_to(32); - if arg.layout.is_aggregate() { - if !unwrap_trivial_aggregate(cx, arg) { - arg.make_indirect_byval(); - } + if arg.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, arg) { + arg.make_indirect_byval(); } } diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 047b8cf5cdb..d3c31773c1e 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -306,6 +306,35 @@ impl Size { let bytes = self.bytes().checked_mul(count)?; if bytes < dl.obj_size_bound() { Some(Size::from_bytes(bytes)) } else { None } } + + /// Truncates `value` to `self` bits and then sign-extends it to 128 bits + /// (i.e., if it is negative, fill with 1's on the left). + #[inline] + pub fn sign_extend(self, value: u128) -> u128 { + let size = self.bits(); + if size == 0 { + // Truncated until nothing is left. + return 0; + } + // Sign-extend it. + let shift = 128 - size; + // Shift the unsigned value to the left, then shift back to the right as signed + // (essentially fills with sign bit on the left). + (((value << shift) as i128) >> shift) as u128 + } + + /// Truncates `value` to `self` bits. + #[inline] + pub fn truncate(self, value: u128) -> u128 { + let size = self.bits(); + if size == 0 { + // Truncated until nothing is left. + return 0; + } + let shift = 128 - size; + // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). + (value << shift) >> shift + } } // Panicking addition, subtraction and multiplication for convenience. @@ -557,17 +586,11 @@ impl Primitive { } pub fn is_float(self) -> bool { - match self { - F32 | F64 => true, - _ => false, - } + matches!(self, F32 | F64) } pub fn is_int(self) -> bool { - match self { - Int(..) => true, - _ => false, - } + matches!(self, Int(..)) } } @@ -794,18 +817,12 @@ impl Abi { /// Returns `true` if this is an uninhabited type pub fn is_uninhabited(&self) -> bool { - match *self { - Abi::Uninhabited => true, - _ => false, - } + matches!(*self, Abi::Uninhabited) } /// Returns `true` is this is a scalar type pub fn is_scalar(&self) -> bool { - match *self { - Abi::Scalar(_) => true, - _ => false, - } + matches!(*self, Abi::Scalar(_)) } } diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 0d691dc441e..8e60085262a 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -478,10 +478,7 @@ pub enum InlineAsmType { impl InlineAsmType { pub fn is_integer(self) -> bool { - match self { - Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128 => true, - _ => false, - } + matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128) } pub fn size(self) -> Size { diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs new file mode 100644 index 00000000000..1651ff9c2d6 --- /dev/null +++ b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs @@ -0,0 +1,42 @@ +//! Bare MIPS32r2, little endian, softfloat, O32 calling convention +//! +//! Can be used for MIPS M4K core (e.g. on PIC32MX devices) + +use crate::spec::abi::Abi; +use crate::spec::{LinkerFlavor, LldFlavor, RelocModel}; +use crate::spec::{PanicStrategy, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "mipsel-unknown-none".to_string(), + target_endian: "little".to_string(), + pointer_width: 32, + target_c_int_width: "32".to_string(), + data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), + arch: "mips".to_string(), + target_os: "none".to_string(), + target_env: String::new(), + target_vendor: String::new(), + linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), + + options: TargetOptions { + cpu: "mips32r2".to_string(), + features: "+mips32r2,+soft-float,+noabicalls".to_string(), + max_atomic_width: Some(32), + executables: true, + linker: Some("rust-lld".to_owned()), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + unsupported_abis: vec![ + Abi::Stdcall, + Abi::Fastcall, + Abi::Vectorcall, + Abi::Thiscall, + Abi::Win64, + Abi::SysV64, + ], + emit_debug_gdb_scripts: false, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 1d3e61c4992..ba9e2f7fa06 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -653,6 +653,7 @@ supported_targets! { ("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks), ("mipsel-sony-psp", mipsel_sony_psp), + ("mipsel-unknown-none", mipsel_unknown_none), ("thumbv4t-none-eabi", thumbv4t_none_eabi), } diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 406e8936e6e..42509cd8975 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -19,6 +19,7 @@ #![feature(never_type)] #![feature(crate_visibility_modifier)] #![feature(or_patterns)] +#![feature(control_flow_enum)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index ecaafee77e2..914fa1e52c2 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -15,6 +15,8 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config::nightly_options; use rustc_span::Span; +use std::ops::ControlFlow; + pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>; /// Information about the opaque types whose values we @@ -691,26 +693,26 @@ impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP> where OP: FnMut(ty::Region<'tcx>), { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool { + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ControlFlow<()> { t.as_ref().skip_binder().visit_with(self); - false // keep visiting + ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { match *r { // ignore bound regions, keep visiting - ty::ReLateBound(_, _) => false, + ty::ReLateBound(_, _) => ControlFlow::CONTINUE, _ => { (self.op)(r); - false + ControlFlow::CONTINUE } } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { // We're only interested in types involving regions if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { - return false; // keep visiting + return ControlFlow::CONTINUE; } match ty.kind() { @@ -745,7 +747,7 @@ where } } - false + ControlFlow::CONTINUE } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 5f6d8ac751e..638a8253e7e 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -24,6 +24,7 @@ use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; use std::cmp; +use std::ops::ControlFlow; /// Check if a given constant can be evaluated. pub fn is_const_evaluatable<'cx, 'tcx>( @@ -86,9 +87,11 @@ pub fn is_const_evaluatable<'cx, 'tcx>( failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); } - false + ControlFlow::CONTINUE + } + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE } - Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => false, }); match failure_kind { @@ -564,29 +567,33 @@ pub(super) fn try_unify_abstract_consts<'tcx>( // on `ErrorReported`. } -// FIXME: Use `std::ops::ControlFlow` instead of `bool` here. -pub fn walk_abstract_const<'tcx, F>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F) -> bool +pub fn walk_abstract_const<'tcx, F>( + tcx: TyCtxt<'tcx>, + ct: AbstractConst<'tcx>, + mut f: F, +) -> ControlFlow<()> where - F: FnMut(Node<'tcx>) -> bool, + F: FnMut(Node<'tcx>) -> ControlFlow<()>, { fn recurse<'tcx>( tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, - f: &mut dyn FnMut(Node<'tcx>) -> bool, - ) -> bool { + f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow<()>, + ) -> ControlFlow<()> { let root = ct.root(); - f(root) - || match root { - Node::Leaf(_) => false, - Node::Binop(_, l, r) => { - recurse(tcx, ct.subtree(l), f) || recurse(tcx, ct.subtree(r), f) - } - Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f), - Node::FunctionCall(func, args) => { - recurse(tcx, ct.subtree(func), f) - || args.iter().any(|&arg| recurse(tcx, ct.subtree(arg), f)) - } + f(root)?; + match root { + Node::Leaf(_) => ControlFlow::CONTINUE, + Node::Binop(_, l, r) => { + recurse(tcx, ct.subtree(l), f)?; + recurse(tcx, ct.subtree(r), f) + } + Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f), + Node::FunctionCall(func, args) => { + recurse(tcx, ct.subtree(func), f)?; + args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f)) } + } } recurse(tcx, ct, &mut f) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index f8bd3ab96e2..2d57c39f7c7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1388,11 +1388,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref: &ty::PolyTraitRef<'tcx>, ) { let get_trait_impl = |trait_def_id| { - self.tcx.find_map_relevant_impl( - trait_def_id, - trait_ref.skip_binder().self_ty(), - |impl_def_id| Some(impl_def_id), - ) + self.tcx.find_map_relevant_impl(trait_def_id, trait_ref.skip_binder().self_ty(), Some) }; let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); let all_traits = self.tcx.all_traits(LOCAL_CRATE); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index c0881befe24..1c6e661782f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1570,36 +1570,130 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { format!("does not implement `{}`", trait_ref.print_only_trait_path()) }; - let mut explain_yield = |interior_span: Span, - yield_span: Span, - scope_span: Option<Span>| { - let mut span = MultiSpan::from_span(yield_span); - if let Ok(snippet) = source_map.span_to_snippet(interior_span) { - span.push_span_label( - yield_span, - format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), - ); - // If available, use the scope span to annotate the drop location. - if let Some(scope_span) = scope_span { - span.push_span_label( - source_map.end_point(scope_span), - format!("`{}` is later dropped here", snippet), - ); + let mut explain_yield = + |interior_span: Span, yield_span: Span, scope_span: Option<Span>| { + let mut span = MultiSpan::from_span(yield_span); + if let Ok(snippet) = source_map.span_to_snippet(interior_span) { + // #70935: If snippet contains newlines, display "the value" instead + // so that we do not emit complex diagnostics. + let snippet = &format!("`{}`", snippet); + let snippet = if snippet.contains('\n') { "the value" } else { snippet }; + // The multispan can be complex here, like: + // note: future is not `Send` as this value is used across an await + // --> $DIR/issue-70935-complex-spans.rs:13:9 + // | + // LL | baz(|| async{ + // | __________^___- + // | | _________| + // | || + // LL | || foo(tx.clone()); + // LL | || }).await; + // | || - ^- value is later dropped here + // | ||_________|______| + // | |__________| await occurs here, with value maybe used later + // | has type `closure` which is not `Send` + // + // So, detect it and separate into some notes, like: + // + // note: future is not `Send` as this value is used across an await + // --> $DIR/issue-70935-complex-spans.rs:13:9 + // | + // LL | / baz(|| async{ + // LL | | foo(tx.clone()); + // LL | | }).await; + // | |________________^ first, await occurs here, with the value maybe used later... + // note: the value is later dropped here + // --> $DIR/issue-70935-complex-spans.rs:15:17 + // | + // LL | }).await; + // | ^ + // + // If available, use the scope span to annotate the drop location. + if let Some(scope_span) = scope_span { + let scope_span = source_map.end_point(scope_span); + let is_overlapped = + yield_span.overlaps(scope_span) || yield_span.overlaps(interior_span); + if is_overlapped { + span.push_span_label( + yield_span, + format!( + "first, {} occurs here, with {} maybe used later...", + await_or_yield, snippet + ), + ); + err.span_note( + span, + &format!( + "{} {} as this value is used across {}", + future_or_generator, trait_explanation, an_await_or_yield + ), + ); + if source_map.is_multiline(interior_span) { + err.span_note( + scope_span, + &format!("{} is later dropped here", snippet), + ); + err.span_note( + interior_span, + &format!( + "this has type `{}` which {}", + target_ty, trait_explanation + ), + ); + } else { + let mut span = MultiSpan::from_span(scope_span); + span.push_span_label( + interior_span, + format!("has type `{}` which {}", target_ty, trait_explanation), + ); + err.span_note(span, &format!("{} is later dropped here", snippet)); + } + } else { + span.push_span_label( + yield_span, + format!( + "{} occurs here, with {} maybe used later", + await_or_yield, snippet + ), + ); + span.push_span_label( + scope_span, + format!("{} is later dropped here", snippet), + ); + span.push_span_label( + interior_span, + format!("has type `{}` which {}", target_ty, trait_explanation), + ); + err.span_note( + span, + &format!( + "{} {} as this value is used across {}", + future_or_generator, trait_explanation, an_await_or_yield + ), + ); + } + } else { + span.push_span_label( + yield_span, + format!( + "{} occurs here, with {} maybe used later", + await_or_yield, snippet + ), + ); + span.push_span_label( + interior_span, + format!("has type `{}` which {}", target_ty, trait_explanation), + ); + err.span_note( + span, + &format!( + "{} {} as this value is used across {}", + future_or_generator, trait_explanation, an_await_or_yield + ), + ); + } } - } - span.push_span_label( - interior_span, - format!("has type `{}` which {}", target_ty, trait_explanation), - ); - - err.span_note( - span, - &format!( - "{} {} as this value is used across {}", - future_or_generator, trait_explanation, an_await_or_yield - ), - ); - }; + }; match interior_or_upvar_span { GeneratorInteriorOrUpvar::Interior(interior_span) => { if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 9a8b5534dfe..538c14c6b72 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -499,7 +499,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { Err(ErrorHandled::TooGeneric) => { pending_obligation.stalled_on = substs .iter() - .filter_map(|ty| TyOrConstInferVar::maybe_from_generic_arg(ty)) + .filter_map(TyOrConstInferVar::maybe_from_generic_arg) .collect(); ProcessResult::Unchanged } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index c52fd0b5786..50efbbbe0fd 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -27,6 +27,7 @@ use smallvec::SmallVec; use std::array; use std::iter; +use std::ops::ControlFlow; pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation}; @@ -770,9 +771,15 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { match t.kind() { - ty::Param(_) => t == self.tcx.types.self_param, + ty::Param(_) => { + if t == self.tcx.types.self_param { + ControlFlow::BREAK + } else { + ControlFlow::CONTINUE + } + } ty::Projection(ref data) => { // This is a projected type `<Foo as SomeTrait>::X`. @@ -796,7 +803,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( self.supertraits.as_ref().unwrap().contains(&projection_trait_ref); if is_supertrait_of_current_trait { - false // do not walk contained types, do not report error, do collect $200 + ControlFlow::CONTINUE // do not walk contained types, do not report error, do collect $200 } else { t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error } @@ -805,11 +812,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } } - fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> bool { + fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow<()> { // First check if the type of this constant references `Self`. - if self.visit_ty(ct.ty) { - return true; - } + self.visit_ty(ct.ty)?; // Constants can only influence object safety if they reference `Self`. // This is only possible for unevaluated constants, so we walk these here. @@ -830,14 +835,16 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) } - Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => false, + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } }) } else { - false + ControlFlow::CONTINUE } } - fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> bool { + fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<()> { if let ty::PredicateAtom::ConstEvaluatable(def, substs) = pred.skip_binders() { // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to @@ -849,10 +856,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) } - Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => false, + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } }) } else { - false + ControlFlow::CONTINUE } } else { pred.super_visit_with(self) @@ -860,7 +869,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( } } - value.visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None }) + value + .visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None }) + .is_break() } pub fn provide(providers: &mut ty::query::Providers) { diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 4f7fa2c3988..ce0d3ef8a6a 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -8,6 +8,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_span::Span; +use std::ops::ControlFlow; #[derive(Debug)] pub enum NonStructuralMatchTy<'tcx> { @@ -134,38 +135,38 @@ impl Search<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { debug!("Search visiting ty: {:?}", ty); let (adt_def, substs) = match *ty.kind() { ty::Adt(adt_def, substs) => (adt_def, substs), ty::Param(_) => { self.found = Some(NonStructuralMatchTy::Param); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::Dynamic(..) => { self.found = Some(NonStructuralMatchTy::Dynamic); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::Foreign(_) => { self.found = Some(NonStructuralMatchTy::Foreign); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::Opaque(..) => { self.found = Some(NonStructuralMatchTy::Opaque); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::Projection(..) => { self.found = Some(NonStructuralMatchTy::Projection); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::Generator(..) | ty::GeneratorWitness(..) => { self.found = Some(NonStructuralMatchTy::Generator); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::Closure(..) => { self.found = Some(NonStructuralMatchTy::Closure); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::RawPtr(..) => { // structural-match ignores substructure of @@ -182,39 +183,31 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { // Even though `NonStructural` does not implement `PartialEq`, // structural equality on `T` does not recur into the raw // pointer. Therefore, one can still use `C` in a pattern. - - // (But still tell the caller to continue search.) - return false; + return ControlFlow::CONTINUE; } ty::FnDef(..) | ty::FnPtr(..) => { // Types of formals and return in `fn(_) -> _` are also irrelevant; // so we do not recur into them via `super_visit_with` - // - // (But still tell the caller to continue search.) - return false; + return ControlFlow::CONTINUE; } ty::Array(_, n) if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } => { // rust-lang/rust#62336: ignore type of contents // for empty array. - // - // (But still tell the caller to continue search.) - return false; + return ControlFlow::CONTINUE; } ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { // These primitive types are always structural match. // // `Never` is kind of special here, but as it is not inhabitable, this should be fine. - // - // (But still tell the caller to continue search.) - return false; + return ControlFlow::CONTINUE; } ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { // First check all contained types and then tell the caller to continue searching. ty.super_visit_with(self); - return false; + return ControlFlow::CONTINUE; } ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => { bug!("unexpected type during structural-match checking: {:?}", ty); @@ -223,22 +216,19 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check"); // We still want to check other types after encountering an error, // as this may still emit relevant errors. - // - // So we continue searching here. - return false; + return ControlFlow::CONTINUE; } }; if !self.seen.insert(adt_def.did) { debug!("Search already seen adt_def: {:?}", adt_def); - // Let caller continue its search. - return false; + return ControlFlow::CONTINUE; } if !self.type_marked_structural(ty) { debug!("Search found ty: {:?}", ty); self.found = Some(NonStructuralMatchTy::Adt(&adt_def)); - return true; // Halt visiting! + return ControlFlow::BREAK; } // structural-match does not care about the @@ -258,16 +248,16 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty); - if ty.visit_with(self) { + if ty.visit_with(self).is_break() { // found an ADT without structural-match; halt visiting! assert!(self.found.is_some()); - return true; + return ControlFlow::BREAK; } } // Even though we do not want to recur on substs, we do // want our caller to continue its own search. - false + ControlFlow::CONTINUE } } diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 3368c5b7699..e5ae899a2f3 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -342,29 +342,29 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t } (ty::Bool, Scalar(Bool)) => true, (ty::Char, Scalar(Char)) => true, - (ty::Int(ty1), Scalar(Int(ty2))) => match (ty1, ty2) { + (ty::Int(ty1), Scalar(Int(ty2))) => matches!( + (ty1, ty2), (ast::IntTy::Isize, chalk_ir::IntTy::Isize) - | (ast::IntTy::I8, chalk_ir::IntTy::I8) - | (ast::IntTy::I16, chalk_ir::IntTy::I16) - | (ast::IntTy::I32, chalk_ir::IntTy::I32) - | (ast::IntTy::I64, chalk_ir::IntTy::I64) - | (ast::IntTy::I128, chalk_ir::IntTy::I128) => true, - _ => false, - }, - (ty::Uint(ty1), Scalar(Uint(ty2))) => match (ty1, ty2) { + | (ast::IntTy::I8, chalk_ir::IntTy::I8) + | (ast::IntTy::I16, chalk_ir::IntTy::I16) + | (ast::IntTy::I32, chalk_ir::IntTy::I32) + | (ast::IntTy::I64, chalk_ir::IntTy::I64) + | (ast::IntTy::I128, chalk_ir::IntTy::I128) + ), + (ty::Uint(ty1), Scalar(Uint(ty2))) => matches!( + (ty1, ty2), (ast::UintTy::Usize, chalk_ir::UintTy::Usize) - | (ast::UintTy::U8, chalk_ir::UintTy::U8) - | (ast::UintTy::U16, chalk_ir::UintTy::U16) - | (ast::UintTy::U32, chalk_ir::UintTy::U32) - | (ast::UintTy::U64, chalk_ir::UintTy::U64) - | (ast::UintTy::U128, chalk_ir::UintTy::U128) => true, - _ => false, - }, - (ty::Float(ty1), Scalar(Float(ty2))) => match (ty1, ty2) { + | (ast::UintTy::U8, chalk_ir::UintTy::U8) + | (ast::UintTy::U16, chalk_ir::UintTy::U16) + | (ast::UintTy::U32, chalk_ir::UintTy::U32) + | (ast::UintTy::U64, chalk_ir::UintTy::U64) + | (ast::UintTy::U128, chalk_ir::UintTy::U128) + ), + (ty::Float(ty1), Scalar(Float(ty2))) => matches!( + (ty1, ty2), (ast::FloatTy::F32, chalk_ir::FloatTy::F32) - | (ast::FloatTy::F64, chalk_ir::FloatTy::F64) => true, - _ => false, - }, + | (ast::FloatTy::F64, chalk_ir::FloatTy::F64) + ), (&ty::Tuple(..), Tuple(..)) => true, (&ty::Array(..), Array) => true, (&ty::Slice(..), Slice) => true, diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 5ca0fc0c88b..01c4dd12487 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -42,6 +42,7 @@ use rustc_span::def_id::DefId; use chalk_ir::{FnSig, ForeignDefId}; use rustc_hir::Unsafety; use std::collections::btree_map::{BTreeMap, Entry}; +use std::ops::ControlFlow; /// Essentially an `Into` with a `&RustInterner` parameter crate trait LowerInto<'tcx, T> { @@ -897,14 +898,14 @@ impl<'tcx> BoundVarsCollector<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> { self.binder_index.shift_in(1); let result = t.super_visit_with(self); self.binder_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { match *t.kind() { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { match self.parameters.entry(bound_ty.var.as_u32()) { @@ -924,7 +925,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { t.super_visit_with(self) } - fn visit_region(&mut self, r: Region<'tcx>) -> bool { + fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<()> { match r { ty::ReLateBound(index, br) if *index == self.binder_index => match br { ty::BoundRegion::BrNamed(def_id, _name) => { @@ -1114,7 +1115,7 @@ impl PlaceholdersCollector { } impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { match t.kind() { ty::Placeholder(p) if p.universe == self.universe_index => { self.next_ty_placeholder = self.next_ty_placeholder.max(p.name.as_usize() + 1); @@ -1126,7 +1127,7 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { t.super_visit_with(self) } - fn visit_region(&mut self, r: Region<'tcx>) -> bool { + fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<()> { match r { ty::RePlaceholder(p) if p.universe == self.universe_index => { if let ty::BoundRegion::BrAnon(anon) = p.name { diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index bc5c07fce04..c44fd1d5859 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -62,7 +62,7 @@ fn compute_implied_outlives_bounds<'tcx>( // unresolved inference variables here anyway, but there might be // during typeck under some circumstances.) let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP) - .unwrap_or(vec![]); + .unwrap_or_default(); // N.B., all of these predicates *ought* to be easily proven // true. In fact, their correctness is (mostly) implied by diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index d0b05beb4e6..7b688cd3e21 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -4,6 +4,7 @@ #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(nll)] +#![feature(control_flow_enum)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 6dd8a143ec0..70d94ef869d 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -24,6 +24,8 @@ use rustc_trait_selection::opaque_types::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCauseCode}; +use std::ops::ControlFlow; + pub fn check_wf_new(tcx: TyCtxt<'_>) { let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); tcx.hir().krate().par_visit_all_item_likes(&visit); @@ -448,30 +450,34 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( }; impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); - if t != self.opaque_identity_ty && t.super_visit_with(self) { + if t != self.opaque_identity_ty && t.super_visit_with(self).is_break() { self.ty = Some(t); - return true; + return ControlFlow::BREAK; } - false + ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { - return *index < self.generics.parent_count as u32; + if *index < self.generics.parent_count as u32 { + return ControlFlow::BREAK; + } else { + return ControlFlow::CONTINUE; + } } r.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { if let ty::ConstKind::Unevaluated(..) = c.val { // FIXME(#72219) We currenctly don't detect lifetimes within substs // which would violate this check. Even though the particular substitution is not used // within the const, this should still be fixed. - return false; + return ControlFlow::CONTINUE; } c.super_visit_with(self) } @@ -493,7 +499,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( let prohibit_opaque = tcx .explicit_item_bounds(def_id) .iter() - .any(|(predicate, _)| predicate.visit_with(&mut visitor)); + .any(|(predicate, _)| predicate.visit_with(&mut visitor).is_break()); debug!( "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", prohibit_opaque, visitor @@ -1449,11 +1455,11 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { { struct VisitTypes(Vec<DefId>); impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { match *t.kind() { ty::Opaque(def, _) => { self.0.push(def); - false + ControlFlow::CONTINUE } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 8cd83c39f9e..2ba05071c05 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -605,6 +605,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ret_ty = self.inh.infcx.shallow_resolve(ret_ty); let ret_vid = match *ret_ty.kind() { ty::Infer(ty::TyVar(ret_vid)) => ret_vid, + ty::Error(_) => return None, _ => span_bug!( self.tcx.def_span(expr_def_id), "async fn generator return type not an inference variable" diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 4473aa2081f..293a995887c 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -186,8 +186,9 @@ pub fn resolve_interior<'a, 'tcx>( // which means that none of the regions inside relate to any other, even if // typeck had previously found constraints that would cause them to be related. let folded = fcx.tcx.fold_regions(&erased, &mut false, |_, current_depth| { + let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, ty::BrAnon(counter))); counter += 1; - fcx.tcx.mk_region(ty::ReLateBound(current_depth, ty::BrAnon(counter))) + r }); cause.ty = folded; @@ -344,6 +345,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // The type table might not have information for this expression // if it is in a malformed scope. (#66387) if let Some(ty) = self.fcx.typeck_results.borrow().expr_ty_opt(expr) { + if guard_borrowing_from_pattern { + // Match guards create references to all the bindings in the pattern that are used + // in the guard, e.g. `y if is_even(y) => ...` becomes `is_even(*r_y)` where `r_y` + // is a reference to `y`, so we must record a reference to the type of the binding. + let tcx = self.fcx.tcx; + let ref_ty = tcx.mk_ref( + // Use `ReErased` as `resolve_interior` is going to replace all the regions anyway. + tcx.mk_region(ty::RegionKind::ReErased), + ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }, + ); + self.record(ref_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern); + } self.record(ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern); } else { self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node"); diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 02268b11a7a..247b5256726 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -19,6 +19,8 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; +use std::ops::ControlFlow; + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Checks a `a <op>= b` pub fn check_binop_assign( @@ -981,7 +983,7 @@ fn suggest_constraining_param( struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>); impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { if let ty::Param(_) = ty.kind() { self.0.push(ty); } diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 1e97bd65a79..e9dfef718fd 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -279,11 +279,12 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { fn adjust_upvar_borrow_kind_for_consume( &mut self, place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, mode: euv::ConsumeMode, ) { debug!( - "adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, mode={:?})", - place_with_id, mode + "adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, diag_expr_id={:?}, mode={:?})", + place_with_id, diag_expr_id, mode ); // we only care about moves @@ -303,7 +304,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { debug!("adjust_upvar_borrow_kind_for_consume: upvar={:?}", upvar_id); - let usage_span = tcx.hir().span(place_with_id.hir_id); + let usage_span = tcx.hir().span(diag_expr_id); // To move out of an upvar, this must be a FnOnce closure self.adjust_closure_kind( @@ -313,14 +314,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { var_name(tcx, upvar_id.var_path.hir_id), ); - // In a case like `let pat = upvar`, don't use the span - // of the pattern, as this just looks confusing. - let by_value_span = match tcx.hir().get(place_with_id.hir_id) { - hir::Node::Pat(_) => None, - _ => Some(usage_span), - }; - - let new_capture = ty::UpvarCapture::ByValue(by_value_span); + let new_capture = ty::UpvarCapture::ByValue(Some(usage_span)); match self.adjust_upvar_captures.entry(upvar_id) { Entry::Occupied(mut e) => { match e.get() { @@ -345,8 +339,15 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { /// Indicates that `place_with_id` is being directly mutated (e.g., assigned /// to). If the place is based on a by-ref upvar, this implies that /// the upvar must be borrowed using an `&mut` borrow. - fn adjust_upvar_borrow_kind_for_mut(&mut self, place_with_id: &PlaceWithHirId<'tcx>) { - debug!("adjust_upvar_borrow_kind_for_mut(place_with_id={:?})", place_with_id); + fn adjust_upvar_borrow_kind_for_mut( + &mut self, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, + ) { + debug!( + "adjust_upvar_borrow_kind_for_mut(place_with_id={:?}, diag_expr_id={:?})", + place_with_id, diag_expr_id + ); if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { let mut borrow_kind = ty::MutBorrow; @@ -362,16 +363,19 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { _ => (), } } - self.adjust_upvar_deref( - upvar_id, - self.fcx.tcx.hir().span(place_with_id.hir_id), - borrow_kind, - ); + self.adjust_upvar_deref(upvar_id, self.fcx.tcx.hir().span(diag_expr_id), borrow_kind); } } - fn adjust_upvar_borrow_kind_for_unique(&mut self, place_with_id: &PlaceWithHirId<'tcx>) { - debug!("adjust_upvar_borrow_kind_for_unique(place_with_id={:?})", place_with_id); + fn adjust_upvar_borrow_kind_for_unique( + &mut self, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, + ) { + debug!( + "adjust_upvar_borrow_kind_for_unique(place_with_id={:?}, diag_expr_id={:?})", + place_with_id, diag_expr_id + ); if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { @@ -381,7 +385,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { // for a borrowed pointer to be unique, its base must be unique self.adjust_upvar_deref( upvar_id, - self.fcx.tcx.hir().span(place_with_id.hir_id), + self.fcx.tcx.hir().span(diag_expr_id), ty::UniqueImmBorrow, ); } @@ -500,29 +504,44 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { } impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { - fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, mode: euv::ConsumeMode) { - debug!("consume(place_with_id={:?},mode={:?})", place_with_id, mode); - self.adjust_upvar_borrow_kind_for_consume(place_with_id, mode); + fn consume( + &mut self, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, + mode: euv::ConsumeMode, + ) { + debug!( + "consume(place_with_id={:?}, diag_expr_id={:?}, mode={:?})", + place_with_id, diag_expr_id, mode + ); + self.adjust_upvar_borrow_kind_for_consume(&place_with_id, diag_expr_id, mode); } - fn borrow(&mut self, place_with_id: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) { - debug!("borrow(place_with_id={:?}, bk={:?})", place_with_id, bk); + fn borrow( + &mut self, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, + bk: ty::BorrowKind, + ) { + debug!( + "borrow(place_with_id={:?}, diag_expr_id={:?}, bk={:?})", + place_with_id, diag_expr_id, bk + ); match bk { ty::ImmBorrow => {} ty::UniqueImmBorrow => { - self.adjust_upvar_borrow_kind_for_unique(place_with_id); + self.adjust_upvar_borrow_kind_for_unique(&place_with_id, diag_expr_id); } ty::MutBorrow => { - self.adjust_upvar_borrow_kind_for_mut(place_with_id); + self.adjust_upvar_borrow_kind_for_mut(&place_with_id, diag_expr_id); } } } - fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>) { - debug!("mutate(assignee_place={:?})", assignee_place); - - self.adjust_upvar_borrow_kind_for_mut(assignee_place); + fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) { + debug!("mutate(assignee_place={:?}, diag_expr_id={:?})", assignee_place, diag_expr_id); + self.adjust_upvar_borrow_kind_for_mut(assignee_place, diag_expr_id); } } diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index b4e950ab6e9..1e27357ce44 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -24,6 +24,8 @@ use rustc_trait_selection::opaque_types::may_define_opaque_type; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; +use std::ops::ControlFlow; + /// Helper type of a temporary returned by `.for_item(...)`. /// This is necessary because we can't write the following bound: /// @@ -798,18 +800,18 @@ fn check_where_clauses<'tcx, 'fcx>( params: FxHashSet<u32>, } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { if let ty::Param(param) = t.kind() { self.params.insert(param.index); } t.super_visit_with(self) } - fn visit_region(&mut self, _: ty::Region<'tcx>) -> bool { - true + fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<()> { + ControlFlow::BREAK } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { if let ty::ConstKind::Param(param) = c.val { self.params.insert(param.index); } @@ -817,7 +819,7 @@ fn check_where_clauses<'tcx, 'fcx>( } } let mut param_count = CountParams::default(); - let has_region = pred.visit_with(&mut param_count); + let has_region = pred.visit_with(&mut param_count).is_break(); let substituted_pred = pred.subst(fcx.tcx, substs); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 136867d78f5..f014ea3d5a9 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -50,6 +50,8 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; +use std::ops::ControlFlow; + mod item_bounds; mod type_of; @@ -2060,14 +2062,14 @@ fn const_evaluatable_predicates_of<'tcx>( } impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> { - fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool { + fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow<()> { if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { self.preds.insert(( ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), self.span, )); } - false + ControlFlow::CONTINUE } } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index a754d4dbac7..61d1efc837b 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -79,7 +79,13 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< let _tables = tcx.typeck(body_owner); &*path } - _ => span_bug!(DUMMY_SP, "unexpected const parent path {:?}", parent_node), + _ => { + tcx.sess.delay_span_bug( + tcx.def_span(def_id), + &format!("unexpected const parent path {:?}", parent_node), + ); + return None; + } }; // We've encountered an `AnonConst` in some path, so we need to diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index 09b5a9b0a65..bae5bde7002 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::source_map::Span; +use std::ops::ControlFlow; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct Parameter(pub u32); @@ -56,11 +57,11 @@ struct ParameterCollector { } impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> { match *t.kind() { ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { // projections are not injective - return false; + return ControlFlow::CONTINUE; } ty::Param(data) => { self.parameters.push(Parameter::from(data)); @@ -71,14 +72,14 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { t.super_visit_with(self) } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> { if let ty::ReEarlyBound(data) = *r { self.parameters.push(Parameter::from(data)); } - false + ControlFlow::CONTINUE } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> { match c.val { ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => { // Constant expressions are not injective diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 471909a092f..57bd89b9d3d 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -27,14 +27,31 @@ use rustc_span::Span; /// employing the ExprUseVisitor. pub trait Delegate<'tcx> { // The value found at `place` is either copied or moved, depending - // on mode. - fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, mode: ConsumeMode); + // on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`. + // + // The parameter `diag_expr_id` indicates the HIR id that ought to be used for + // diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic + // id will be the id of the expression `expr` but the place itself will have + // the id of the binding in the pattern `pat`. + fn consume( + &mut self, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, + mode: ConsumeMode, + ); // The value found at `place` is being borrowed with kind `bk`. - fn borrow(&mut self, place_with_id: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind); - - // The path at `place_with_id` is being assigned to. - fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>); + // `diag_expr_id` is the id used for diagnostics (see `consume` for more details). + fn borrow( + &mut self, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: hir::HirId, + bk: ty::BorrowKind, + ); + + // The path at `assignee_place` is being assigned to. + // `diag_expr_id` is the id used for diagnostics (see `consume` for more details). + fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId); } #[derive(Copy, Clone, PartialEq, Debug)] @@ -116,11 +133,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.mc.tcx() } - fn delegate_consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>) { + fn delegate_consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) { debug!("delegate_consume(place_with_id={:?})", place_with_id); let mode = copy_or_move(&self.mc, place_with_id); - self.delegate.consume(place_with_id, mode); + self.delegate.consume(place_with_id, diag_expr_id, mode); } fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) { @@ -133,13 +150,13 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { debug!("consume_expr(expr={:?})", expr); let place_with_id = return_if_err!(self.mc.cat_expr(expr)); - self.delegate_consume(&place_with_id); + self.delegate_consume(&place_with_id, place_with_id.hir_id); self.walk_expr(expr); } fn mutate_expr(&mut self, expr: &hir::Expr<'_>) { let place_with_id = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.mutate(&place_with_id); + self.delegate.mutate(&place_with_id, place_with_id.hir_id); self.walk_expr(expr); } @@ -147,7 +164,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk); let place_with_id = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.borrow(&place_with_id, bk); + self.delegate.borrow(&place_with_id, place_with_id.hir_id, bk); self.walk_expr(expr) } @@ -404,7 +421,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { with_field.ty(self.tcx(), substs), ProjectionKind::Field(f_index as u32, VariantIdx::new(0)), ); - self.delegate_consume(&field_place); + self.delegate_consume(&field_place, field_place.hir_id); } } } @@ -436,7 +453,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. - self.delegate_consume(&place_with_id); + self.delegate_consume(&place_with_id, place_with_id.hir_id); } adjustment::Adjust::Deref(None) => {} @@ -448,7 +465,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // this is an autoref of `x`. adjustment::Adjust::Deref(Some(ref deref)) => { let bk = ty::BorrowKind::from_mutbl(deref.mutbl); - self.delegate.borrow(&place_with_id, bk); + self.delegate.borrow(&place_with_id, place_with_id.hir_id, bk); } adjustment::Adjust::Borrow(ref autoref) => { @@ -476,13 +493,17 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { match *autoref { adjustment::AutoBorrow::Ref(_, m) => { - self.delegate.borrow(base_place, ty::BorrowKind::from_mutbl(m.into())); + self.delegate.borrow( + base_place, + base_place.hir_id, + ty::BorrowKind::from_mutbl(m.into()), + ); } adjustment::AutoBorrow::RawPtr(m) => { debug!("walk_autoref: expr.hir_id={} base_place={:?}", expr.hir_id, base_place); - self.delegate.borrow(base_place, ty::BorrowKind::from_mutbl(m)); + self.delegate.borrow(base_place, base_place.hir_id, ty::BorrowKind::from_mutbl(m)); } } } @@ -525,19 +546,22 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // binding being produced. let def = Res::Local(canonical_id); if let Ok(ref binding_place) = mc.cat_res(pat.hir_id, pat.span, pat_ty, def) { - delegate.mutate(binding_place); + delegate.mutate(binding_place, binding_place.hir_id); } // It is also a borrow or copy/move of the value being matched. + // In a cases of pattern like `let pat = upvar`, don't use the span + // of the pattern, as this just looks confusing, instead use the span + // of the discriminant. match bm { ty::BindByReference(m) => { let bk = ty::BorrowKind::from_mutbl(m); - delegate.borrow(place, bk); + delegate.borrow(place, discr_place.hir_id, bk); } ty::BindByValue(..) => { - let mode = copy_or_move(mc, place); + let mode = copy_or_move(mc, &place); debug!("walk_pat binding consuming pat"); - delegate.consume(place, mode); + delegate.consume(place, discr_place.hir_id, mode); } } } @@ -564,10 +588,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { match upvar_capture { ty::UpvarCapture::ByValue(_) => { let mode = copy_or_move(&self.mc, &captured_place); - self.delegate.consume(&captured_place, mode); + self.delegate.consume(&captured_place, captured_place.hir_id, mode); } ty::UpvarCapture::ByRef(upvar_borrow) => { - self.delegate.borrow(&captured_place, upvar_borrow.kind); + self.delegate.borrow( + &captured_place, + captured_place.hir_id, + upvar_borrow.kind, + ); } } } diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index c1fa39e96eb..30904091c1b 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -66,6 +66,7 @@ This API is completely unstable and subject to change. #![feature(try_blocks)] #![feature(never_type)] #![feature(slice_partition_dedup)] +#![feature(control_flow_enum)] #![recursion_limit = "256"] #[macro_use] |
