From b4d64b7b28038d7e4b0bc75f1d407d5382512996 Mon Sep 17 00:00:00 2001 From: Richard Diamond Date: Thu, 14 Jun 2018 01:13:44 -0500 Subject: [PATCH 01/21] Initialize LLVM's AMDGPU target machine, if available. Note this isn't useful, yet. More changes will be necessary to be able to actually codegen for this machine. As such, it is not enabled by default. This patch is on its own for the benefit of the reviewers. --- src/librustc_llvm/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 07830d54d0c9e..741758cb954ba 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -331,6 +331,12 @@ pub fn initialize_available_targets() { LLVMInitializeAArch64TargetMC, LLVMInitializeAArch64AsmPrinter, LLVMInitializeAArch64AsmParser); + init_target!(llvm_component = "amdgpu", + LLVMInitializeAMDGPUTargetInfo, + LLVMInitializeAMDGPUTarget, + LLVMInitializeAMDGPUTargetMC, + LLVMInitializeAMDGPUAsmPrinter, + LLVMInitializeAMDGPUAsmParser); init_target!(llvm_component = "mips", LLVMInitializeMipsTargetInfo, LLVMInitializeMipsTarget, From 7015dfd1b9cfc02cd1f6dc30cd88b106211a3921 Mon Sep 17 00:00:00 2001 From: Dror Levin Date: Tue, 26 Jun 2018 13:29:36 +0300 Subject: [PATCH 02/21] Add read_exact_at and write_all_at methods to FileExt on unix --- src/libstd/sys/unix/ext/fs.rs | 127 ++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 4e98101266903..4c2cea0d32c35 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -59,6 +59,78 @@ pub trait FileExt { #[stable(feature = "file_offset", since = "1.15.0")] fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result; + /// Reads the exact number of byte required to fill `buf` from the given offset. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`. + /// + /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact + /// [`read_at`]: #tymethod.read_at + /// + /// # Errors + /// + /// If this function encounters an error of the kind + /// [`ErrorKind::Interrupted`] then the error is ignored and the operation + /// will continue. + /// + /// If this function encounters an "end of file" before completely filling + /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. + /// The contents of `buf` are unspecified in this case. + /// + /// If any other read error is encountered then this function immediately + /// returns. The contents of `buf` are unspecified in this case. + /// + /// If this function returns an error, it is unspecified how many bytes it + /// has read, but it will never read more than would be necessary to + /// completely fill the buffer. + /// + /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted + /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof + /// + /// # Examples + /// + /// ```no_run + /// #![feature(rw_exact_all_at)] + /// use std::io; + /// use std::fs::File; + /// use std::os::unix::prelude::FileExt; + /// + /// fn main() -> io::Result<()> { + /// let mut buf = [0u8; 8]; + /// let file = File::open("foo.txt")?; + /// + /// // We now read exactly 8 bytes from the offset 10. + /// file.read_exact_at(&mut buf, 10)?; + /// println!("read {} bytes: {:?}", buf.len(), buf); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "rw_exact_all_at", issue = "0")] + fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { + while !buf.is_empty() { + match self.read_at(buf, offset) { + Ok(0) => break, + Ok(n) => { + let tmp = buf; + buf = &mut tmp[n..]; + offset += n as u64; + } + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + if !buf.is_empty() { + Err(io::Error::new(io::ErrorKind::UnexpectedEof, + "failed to fill whole buffer")) + } else { + Ok(()) + } + } + /// Writes a number of bytes starting from a given offset. /// /// Returns the number of bytes written. @@ -93,6 +165,61 @@ pub trait FileExt { /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn write_at(&self, buf: &[u8], offset: u64) -> io::Result; + + /// Attempts to write an entire buffer starting from a given offset. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// This method will continuously call [`write_at`] until there is no more data + /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is + /// returned. This method will not return until the entire buffer has been + /// successfully written or such an error occurs. The first error that is + /// not of [`ErrorKind::Interrupted`] kind generated from this method will be + /// returned. + /// + /// # Errors + /// + /// This function will return the first error of + /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns. + /// + /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted + /// [`write_at`]: #tymethod.write_at + /// + /// # Examples + /// + /// ```no_run + /// #![feature(rw_exact_all_at)] + /// use std::fs::File; + /// use std::io; + /// use std::os::unix::prelude::FileExt; + /// + /// fn main() -> io::Result<()> { + /// let file = File::open("foo.txt")?; + /// + /// // We now write at the offset 10. + /// file.write_all_at(b"sushi", 10)?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "rw_exact_all_at", issue = "0")] + fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { + while !buf.is_empty() { + match self.write_at(buf, offset) { + Ok(0) => return Err(io::Error::new(io::ErrorKind::WriteZero, + "failed to write whole buffer")), + Ok(n) => { + buf = &buf[n..]; + offset += n as u64 + } + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } } #[stable(feature = "file_offset", since = "1.15.0")] From 011eaed59d9f04b3c9d539490c9891bcd2aabefc Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sat, 30 Jun 2018 12:19:18 -0400 Subject: [PATCH 03/21] factor built-in attribute parsing into submodule --- src/libsyntax/attr/builtin.rs | 708 +++++++++++++++++++++++++ src/libsyntax/{attr.rs => attr/mod.rs} | 688 +----------------------- 2 files changed, 718 insertions(+), 678 deletions(-) create mode 100644 src/libsyntax/attr/builtin.rs rename src/libsyntax/{attr.rs => attr/mod.rs} (50%) diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs new file mode 100644 index 0000000000000..7b626a0fc2748 --- /dev/null +++ b/src/libsyntax/attr/builtin.rs @@ -0,0 +1,708 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Parsing and validation of builtin attributes + +use ast::{self, Attribute, MetaItem, Name, NestedMetaItemKind}; +use errors::{Applicability, Handler}; +use feature_gate::{Features, GatedCfg}; +use parse::ParseSess; +use syntax_pos::{symbol::Symbol, Span}; + +use super::{list_contains_name, mark_used, MetaItemKind}; + +enum AttrError { + MultipleItem(Name), + UnknownMetaItem(Name), + MissingSince, + MissingFeature, + MultipleStabilityLevels, + UnsupportedLiteral +} + +fn handle_errors(diag: &Handler, span: Span, error: AttrError) { + match error { + AttrError::MultipleItem(item) => span_err!(diag, span, E0538, + "multiple '{}' items", item), + AttrError::UnknownMetaItem(item) => span_err!(diag, span, E0541, + "unknown meta item '{}'", item), + AttrError::MissingSince => span_err!(diag, span, E0542, "missing 'since'"), + AttrError::MissingFeature => span_err!(diag, span, E0546, "missing 'feature'"), + AttrError::MultipleStabilityLevels => span_err!(diag, span, E0544, + "multiple stability levels"), + AttrError::UnsupportedLiteral => span_err!(diag, span, E0565, "unsupported literal"), + } +} + +#[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)] +pub enum InlineAttr { + None, + Hint, + Always, + Never, +} + +#[derive(Copy, Clone, PartialEq)] +pub enum UnwindAttr { + Allowed, + Aborts, +} + +/// Determine what `#[unwind]` attribute is present in `attrs`, if any. +pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option { + let syntax_error = |attr: &Attribute| { + mark_used(attr); + diagnostic.map(|d| { + span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute"); + }); + None + }; + + attrs.iter().fold(None, |ia, attr| { + if attr.path != "unwind" { + return ia; + } + let meta = match attr.meta() { + Some(meta) => meta.node, + None => return ia, + }; + match meta { + MetaItemKind::Word => { + syntax_error(attr) + } + MetaItemKind::List(ref items) => { + mark_used(attr); + if items.len() != 1 { + syntax_error(attr) + } else if list_contains_name(&items[..], "allowed") { + Some(UnwindAttr::Allowed) + } else if list_contains_name(&items[..], "aborts") { + Some(UnwindAttr::Aborts) + } else { + syntax_error(attr) + } + } + _ => ia, + } + }) +} + +/// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes. +#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)] +pub struct Stability { + pub level: StabilityLevel, + pub feature: Symbol, + pub rustc_depr: Option, + pub rustc_const_unstable: Option, +} + +/// The available stability levels. +#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] +pub enum StabilityLevel { + // Reason for the current stability level and the relevant rust-lang issue + Unstable { reason: Option, issue: u32 }, + Stable { since: Symbol }, +} + +impl StabilityLevel { + pub fn is_unstable(&self) -> bool { + if let StabilityLevel::Unstable {..} = *self { + true + } else { + false + } + } + pub fn is_stable(&self) -> bool { + if let StabilityLevel::Stable {..} = *self { + true + } else { + false + } + } +} + +#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] +pub struct RustcDeprecation { + pub since: Symbol, + pub reason: Symbol, +} + +#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] +pub struct RustcConstUnstable { + pub feature: Symbol, +} + +/// Check if `attrs` contains an attribute like `#![feature(feature_name)]`. +/// This will not perform any "sanity checks" on the form of the attributes. +pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool { + attrs.iter().any(|item| { + item.check_name("feature") && + item.meta_item_list().map(|list| { + list.iter().any(|mi| { + mi.word().map(|w| w.name() == feature_name) + .unwrap_or(false) + }) + }).unwrap_or(false) + }) +} + +/// Find the first stability attribute. `None` if none exists. +pub fn find_stability(diagnostic: &Handler, attrs: &[Attribute], + item_sp: Span) -> Option { + find_stability_generic(diagnostic, attrs.iter(), item_sp) +} + +fn find_stability_generic<'a, I>(diagnostic: &Handler, + attrs_iter: I, + item_sp: Span) + -> Option + where I: Iterator +{ + use self::StabilityLevel::*; + + let mut stab: Option = None; + let mut rustc_depr: Option = None; + let mut rustc_const_unstable: Option = None; + + 'outer: for attr in attrs_iter { + if ![ + "rustc_deprecated", + "rustc_const_unstable", + "unstable", + "stable", + ].iter().any(|&s| attr.path == s) { + continue // not a stability level + } + + mark_used(attr); + + let meta = attr.meta(); + if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta { + let meta = meta.as_ref().unwrap(); + let get = |meta: &MetaItem, item: &mut Option| { + if item.is_some() { + handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); + return false + } + if let Some(v) = meta.value_str() { + *item = Some(v); + true + } else { + span_err!(diagnostic, meta.span, E0539, "incorrect meta item"); + false + } + }; + + macro_rules! get_meta { + ($($name:ident),+) => { + $( + let mut $name = None; + )+ + for meta in metas { + if let Some(mi) = meta.meta_item() { + match &*mi.name().as_str() { + $( + stringify!($name) + => if !get(mi, &mut $name) { continue 'outer }, + )+ + _ => { + handle_errors(diagnostic, mi.span, + AttrError::UnknownMetaItem(mi.name())); + continue 'outer + } + } + } else { + handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); + continue 'outer + } + } + } + } + + match &*meta.name().as_str() { + "rustc_deprecated" => { + if rustc_depr.is_some() { + span_err!(diagnostic, item_sp, E0540, + "multiple rustc_deprecated attributes"); + continue 'outer + } + + get_meta!(since, reason); + + match (since, reason) { + (Some(since), Some(reason)) => { + rustc_depr = Some(RustcDeprecation { + since, + reason, + }) + } + (None, _) => { + handle_errors(diagnostic, attr.span(), AttrError::MissingSince); + continue + } + _ => { + span_err!(diagnostic, attr.span(), E0543, "missing 'reason'"); + continue + } + } + } + "rustc_const_unstable" => { + if rustc_const_unstable.is_some() { + span_err!(diagnostic, item_sp, E0553, + "multiple rustc_const_unstable attributes"); + continue 'outer + } + + get_meta!(feature); + if let Some(feature) = feature { + rustc_const_unstable = Some(RustcConstUnstable { + feature + }); + } else { + span_err!(diagnostic, attr.span(), E0629, "missing 'feature'"); + continue + } + } + "unstable" => { + if stab.is_some() { + handle_errors(diagnostic, attr.span(), AttrError::MultipleStabilityLevels); + break + } + + let mut feature = None; + let mut reason = None; + let mut issue = None; + for meta in metas { + if let Some(mi) = meta.meta_item() { + match &*mi.name().as_str() { + "feature" => if !get(mi, &mut feature) { continue 'outer }, + "reason" => if !get(mi, &mut reason) { continue 'outer }, + "issue" => if !get(mi, &mut issue) { continue 'outer }, + _ => { + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(mi.name())); + continue 'outer + } + } + } else { + handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); + continue 'outer + } + } + + match (feature, reason, issue) { + (Some(feature), reason, Some(issue)) => { + stab = Some(Stability { + level: Unstable { + reason, + issue: { + if let Ok(issue) = issue.as_str().parse() { + issue + } else { + span_err!(diagnostic, attr.span(), E0545, + "incorrect 'issue'"); + continue + } + } + }, + feature, + rustc_depr: None, + rustc_const_unstable: None, + }) + } + (None, _, _) => { + handle_errors(diagnostic, attr.span(), AttrError::MissingFeature); + continue + } + _ => { + span_err!(diagnostic, attr.span(), E0547, "missing 'issue'"); + continue + } + } + } + "stable" => { + if stab.is_some() { + handle_errors(diagnostic, attr.span(), AttrError::MultipleStabilityLevels); + break + } + + let mut feature = None; + let mut since = None; + for meta in metas { + if let NestedMetaItemKind::MetaItem(ref mi) = meta.node { + match &*mi.name().as_str() { + "feature" => if !get(mi, &mut feature) { continue 'outer }, + "since" => if !get(mi, &mut since) { continue 'outer }, + _ => { + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(mi.name())); + continue 'outer + } + } + } else { + handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); + continue 'outer + } + } + + match (feature, since) { + (Some(feature), Some(since)) => { + stab = Some(Stability { + level: Stable { + since, + }, + feature, + rustc_depr: None, + rustc_const_unstable: None, + }) + } + (None, _) => { + handle_errors(diagnostic, attr.span(), AttrError::MissingFeature); + continue + } + _ => { + handle_errors(diagnostic, attr.span(), AttrError::MissingSince); + continue + } + } + } + _ => unreachable!() + } + } else { + span_err!(diagnostic, attr.span(), E0548, "incorrect stability attribute type"); + continue + } + } + + // Merge the deprecation info into the stability info + if let Some(rustc_depr) = rustc_depr { + if let Some(ref mut stab) = stab { + stab.rustc_depr = Some(rustc_depr); + } else { + span_err!(diagnostic, item_sp, E0549, + "rustc_deprecated attribute must be paired with \ + either stable or unstable attribute"); + } + } + + // Merge the const-unstable info into the stability info + if let Some(rustc_const_unstable) = rustc_const_unstable { + if let Some(ref mut stab) = stab { + stab.rustc_const_unstable = Some(rustc_const_unstable); + } else { + span_err!(diagnostic, item_sp, E0630, + "rustc_const_unstable attribute must be paired with \ + either stable or unstable attribute"); + } + } + + stab +} + +pub fn find_crate_name(attrs: &[Attribute]) -> Option { + super::first_attr_value_str_by_name(attrs, "crate_name") +} + +/// Tests if a cfg-pattern matches the cfg set +pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool { + eval_condition(cfg, sess, &mut |cfg| { + if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { + gated_cfg.check_and_emit(sess, feats); + } + sess.config.contains(&(cfg.name(), cfg.value_str())) + }) +} + +/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to +/// evaluate individual items. +pub fn eval_condition(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) + -> bool + where F: FnMut(&ast::MetaItem) -> bool +{ + match cfg.node { + ast::MetaItemKind::List(ref mis) => { + for mi in mis.iter() { + if !mi.is_meta_item() { + handle_errors(&sess.span_diagnostic, mi.span, AttrError::UnsupportedLiteral); + return false; + } + } + + // The unwraps below may look dangerous, but we've already asserted + // that they won't fail with the loop above. + match &*cfg.name().as_str() { + "any" => mis.iter().any(|mi| { + eval_condition(mi.meta_item().unwrap(), sess, eval) + }), + "all" => mis.iter().all(|mi| { + eval_condition(mi.meta_item().unwrap(), sess, eval) + }), + "not" => { + if mis.len() != 1 { + span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern"); + return false; + } + + !eval_condition(mis[0].meta_item().unwrap(), sess, eval) + }, + p => { + span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p); + false + } + } + }, + ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => { + eval(cfg) + } + } +} + + +#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] +pub struct Deprecation { + pub since: Option, + pub note: Option, +} + +/// Find the deprecation attribute. `None` if none exists. +pub fn find_deprecation(diagnostic: &Handler, attrs: &[Attribute], + item_sp: Span) -> Option { + find_deprecation_generic(diagnostic, attrs.iter(), item_sp) +} + +fn find_deprecation_generic<'a, I>(diagnostic: &Handler, + attrs_iter: I, + item_sp: Span) + -> Option + where I: Iterator +{ + let mut depr: Option = None; + + 'outer: for attr in attrs_iter { + if attr.path != "deprecated" { + continue + } + + mark_used(attr); + + if depr.is_some() { + span_err!(diagnostic, item_sp, E0550, "multiple deprecated attributes"); + break + } + + depr = if let Some(metas) = attr.meta_item_list() { + let get = |meta: &MetaItem, item: &mut Option| { + if item.is_some() { + handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); + return false + } + if let Some(v) = meta.value_str() { + *item = Some(v); + true + } else { + span_err!(diagnostic, meta.span, E0551, "incorrect meta item"); + false + } + }; + + let mut since = None; + let mut note = None; + for meta in metas { + if let NestedMetaItemKind::MetaItem(ref mi) = meta.node { + match &*mi.name().as_str() { + "since" => if !get(mi, &mut since) { continue 'outer }, + "note" => if !get(mi, &mut note) { continue 'outer }, + _ => { + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(mi.name())); + continue 'outer + } + } + } else { + handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); + continue 'outer + } + } + + Some(Deprecation {since: since, note: note}) + } else { + Some(Deprecation{since: None, note: None}) + } + } + + depr +} + +#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] +pub enum ReprAttr { + ReprInt(IntType), + ReprC, + ReprPacked(u32), + ReprSimd, + ReprTransparent, + ReprAlign(u32), +} + +#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] +pub enum IntType { + SignedInt(ast::IntTy), + UnsignedInt(ast::UintTy) +} + +impl IntType { + #[inline] + pub fn is_signed(self) -> bool { + use self::IntType::*; + + match self { + SignedInt(..) => true, + UnsignedInt(..) => false + } + } +} + +/// Parse #[repr(...)] forms. +/// +/// Valid repr contents: any of the primitive integral type names (see +/// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use +/// the same discriminant size that the corresponding C enum would or C +/// structure layout, `packed` to remove padding, and `transparent` to elegate representation +/// concerns to the only non-ZST field. +pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec { + use self::ReprAttr::*; + + let mut acc = Vec::new(); + if attr.path == "repr" { + if let Some(items) = attr.meta_item_list() { + mark_used(attr); + for item in items { + if !item.is_meta_item() { + handle_errors(diagnostic, item.span, AttrError::UnsupportedLiteral); + continue + } + + let mut recognised = false; + if let Some(mi) = item.word() { + let word = &*mi.name().as_str(); + let hint = match word { + "C" => Some(ReprC), + "packed" => Some(ReprPacked(1)), + "simd" => Some(ReprSimd), + "transparent" => Some(ReprTransparent), + _ => match int_type_of_word(word) { + Some(ity) => Some(ReprInt(ity)), + None => { + None + } + } + }; + + if let Some(h) = hint { + recognised = true; + acc.push(h); + } + } else if let Some((name, value)) = item.name_value_literal() { + let parse_alignment = |node: &ast::LitKind| -> Result { + if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { + if literal.is_power_of_two() { + // rustc::ty::layout::Align restricts align to <= 2^29 + if *literal <= 1 << 29 { + Ok(*literal as u32) + } else { + Err("larger than 2^29") + } + } else { + Err("not a power of two") + } + } else { + Err("not an unsuffixed integer") + } + }; + + let mut literal_error = None; + if name == "align" { + recognised = true; + match parse_alignment(&value.node) { + Ok(literal) => acc.push(ReprAlign(literal)), + Err(message) => literal_error = Some(message) + }; + } + else if name == "packed" { + recognised = true; + match parse_alignment(&value.node) { + Ok(literal) => acc.push(ReprPacked(literal)), + Err(message) => literal_error = Some(message) + }; + } + if let Some(literal_error) = literal_error { + span_err!(diagnostic, item.span, E0589, + "invalid `repr(align)` attribute: {}", literal_error); + } + } else { + if let Some(meta_item) = item.meta_item() { + if meta_item.name() == "align" { + if let MetaItemKind::NameValue(ref value) = meta_item.node { + recognised = true; + let mut err = struct_span_err!(diagnostic, item.span, E0693, + "incorrect `repr(align)` attribute format"); + match value.node { + ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { + err.span_suggestion_with_applicability( + item.span, + "use parentheses instead", + format!("align({})", int), + Applicability::MachineApplicable + ); + } + ast::LitKind::Str(s, _) => { + err.span_suggestion_with_applicability( + item.span, + "use parentheses instead", + format!("align({})", s), + Applicability::MachineApplicable + ); + } + _ => {} + } + err.emit(); + } + } + } + } + if !recognised { + // Not a word we recognize + span_err!(diagnostic, item.span, E0552, + "unrecognized representation hint"); + } + } + } + } + acc +} + +fn int_type_of_word(s: &str) -> Option { + use self::IntType::*; + + match s { + "i8" => Some(SignedInt(ast::IntTy::I8)), + "u8" => Some(UnsignedInt(ast::UintTy::U8)), + "i16" => Some(SignedInt(ast::IntTy::I16)), + "u16" => Some(UnsignedInt(ast::UintTy::U16)), + "i32" => Some(SignedInt(ast::IntTy::I32)), + "u32" => Some(UnsignedInt(ast::UintTy::U32)), + "i64" => Some(SignedInt(ast::IntTy::I64)), + "u64" => Some(UnsignedInt(ast::UintTy::U64)), + "i128" => Some(SignedInt(ast::IntTy::I128)), + "u128" => Some(UnsignedInt(ast::UintTy::U128)), + "isize" => Some(SignedInt(ast::IntTy::Isize)), + "usize" => Some(UnsignedInt(ast::UintTy::Usize)), + _ => None + } +} diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr/mod.rs similarity index 50% rename from src/libsyntax/attr.rs rename to src/libsyntax/attr/mod.rs index ded493fe3958c..4e27d6c15258b 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr/mod.rs @@ -8,11 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Functions dealing with attributes and meta items +//! Functions dealing with attributes and meta items -pub use self::StabilityLevel::*; -pub use self::ReprAttr::*; +mod builtin; + +pub use self::builtin::{ + cfg_matches, contains_feature_attr, eval_condition, find_crate_name, find_deprecation, + find_repr_attrs, find_stability, find_unwind_attr, Deprecation, InlineAttr, IntType, ReprAttr, + RustcConstUnstable, RustcDeprecation, Stability, StabilityLevel, UnwindAttr, +}; pub use self::IntType::*; +pub use self::ReprAttr::*; +pub use self::StabilityLevel::*; use ast; use ast::{AttrId, Attribute, Name, Ident, Path, PathSegment}; @@ -20,8 +27,6 @@ use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind, GenericParam}; use codemap::{BytePos, Spanned, respan, dummy_spanned}; use syntax_pos::Span; -use errors::{Applicability, Handler}; -use feature_gate::{Features, GatedCfg}; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use parse::parser::Parser; use parse::{self, ParseSess, PResult}; @@ -34,29 +39,6 @@ use GLOBALS; use std::iter; -enum AttrError { - MultipleItem(Name), - UnknownMetaItem(Name), - MissingSince, - MissingFeature, - MultipleStabilityLevels, - UnsupportedLiteral -} - -fn handle_errors(diag: &Handler, span: Span, error: AttrError) { - match error { - AttrError::MultipleItem(item) => span_err!(diag, span, E0538, - "multiple '{}' items", item), - AttrError::UnknownMetaItem(item) => span_err!(diag, span, E0541, - "unknown meta item '{}'", item), - AttrError::MissingSince => span_err!(diag, span, E0542, "missing 'since'"), - AttrError::MissingFeature => span_err!(diag, span, E0546, "missing 'feature'"), - AttrError::MultipleStabilityLevels => span_err!(diag, span, E0544, - "multiple stability levels"), - AttrError::UnsupportedLiteral => span_err!(diag, span, E0565, "unsupported literal"), - } -} - pub fn mark_used(attr: &Attribute) { debug!("Marking {:?} as used.", attr); let AttrId(id) = attr.id; @@ -442,7 +424,6 @@ pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: MetaItem) -> Attribute } } - /// Returns an outer attribute with the given value. pub fn mk_attr_outer(span: Span, id: AttrId, item: MetaItem) -> Attribute { mk_spanned_attr_outer(span, id, item) @@ -495,655 +476,6 @@ pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option bool { - attrs.iter().any(|item| { - item.check_name("feature") && - item.meta_item_list().map(|list| { - list.iter().any(|mi| { - mi.word().map(|w| w.name() == feature_name) - .unwrap_or(false) - }) - }).unwrap_or(false) - }) -} - -/* Higher-level applications */ - -pub fn find_crate_name(attrs: &[Attribute]) -> Option { - first_attr_value_str_by_name(attrs, "crate_name") -} - -#[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)] -pub enum InlineAttr { - None, - Hint, - Always, - Never, -} - -#[derive(Copy, Clone, PartialEq)] -pub enum UnwindAttr { - Allowed, - Aborts, -} - -/// Determine what `#[unwind]` attribute is present in `attrs`, if any. -pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option { - let syntax_error = |attr: &Attribute| { - mark_used(attr); - diagnostic.map(|d| { - span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute"); - }); - None - }; - - attrs.iter().fold(None, |ia, attr| { - if attr.path != "unwind" { - return ia; - } - let meta = match attr.meta() { - Some(meta) => meta.node, - None => return ia, - }; - match meta { - MetaItemKind::Word => { - syntax_error(attr) - } - MetaItemKind::List(ref items) => { - mark_used(attr); - if items.len() != 1 { - syntax_error(attr) - } else if list_contains_name(&items[..], "allowed") { - Some(UnwindAttr::Allowed) - } else if list_contains_name(&items[..], "aborts") { - Some(UnwindAttr::Aborts) - } else { - syntax_error(attr) - } - } - _ => ia, - } - }) -} - - -/// Tests if a cfg-pattern matches the cfg set -pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool { - eval_condition(cfg, sess, &mut |cfg| { - if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { - gated_cfg.check_and_emit(sess, feats); - } - sess.config.contains(&(cfg.name(), cfg.value_str())) - }) -} - -/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to -/// evaluate individual items. -pub fn eval_condition(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) - -> bool - where F: FnMut(&ast::MetaItem) -> bool -{ - match cfg.node { - ast::MetaItemKind::List(ref mis) => { - for mi in mis.iter() { - if !mi.is_meta_item() { - handle_errors(&sess.span_diagnostic, mi.span, AttrError::UnsupportedLiteral); - return false; - } - } - - // The unwraps below may look dangerous, but we've already asserted - // that they won't fail with the loop above. - match &*cfg.name().as_str() { - "any" => mis.iter().any(|mi| { - eval_condition(mi.meta_item().unwrap(), sess, eval) - }), - "all" => mis.iter().all(|mi| { - eval_condition(mi.meta_item().unwrap(), sess, eval) - }), - "not" => { - if mis.len() != 1 { - span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern"); - return false; - } - - !eval_condition(mis[0].meta_item().unwrap(), sess, eval) - }, - p => { - span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p); - false - } - } - }, - ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => { - eval(cfg) - } - } -} - -/// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes. -#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)] -pub struct Stability { - pub level: StabilityLevel, - pub feature: Symbol, - pub rustc_depr: Option, - pub rustc_const_unstable: Option, -} - -/// The available stability levels. -#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] -pub enum StabilityLevel { - // Reason for the current stability level and the relevant rust-lang issue - Unstable { reason: Option, issue: u32 }, - Stable { since: Symbol }, -} - -#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] -pub struct RustcDeprecation { - pub since: Symbol, - pub reason: Symbol, -} - -#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] -pub struct RustcConstUnstable { - pub feature: Symbol, -} - -#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] -pub struct Deprecation { - pub since: Option, - pub note: Option, -} - -impl StabilityLevel { - pub fn is_unstable(&self) -> bool { if let Unstable {..} = *self { true } else { false }} - pub fn is_stable(&self) -> bool { if let Stable {..} = *self { true } else { false }} -} - -fn find_stability_generic<'a, I>(diagnostic: &Handler, - attrs_iter: I, - item_sp: Span) - -> Option - where I: Iterator -{ - let mut stab: Option = None; - let mut rustc_depr: Option = None; - let mut rustc_const_unstable: Option = None; - - 'outer: for attr in attrs_iter { - if ![ - "rustc_deprecated", - "rustc_const_unstable", - "unstable", - "stable", - ].iter().any(|&s| attr.path == s) { - continue // not a stability level - } - - mark_used(attr); - - let meta = attr.meta(); - if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta { - let meta = meta.as_ref().unwrap(); - let get = |meta: &MetaItem, item: &mut Option| { - if item.is_some() { - handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); - return false - } - if let Some(v) = meta.value_str() { - *item = Some(v); - true - } else { - span_err!(diagnostic, meta.span, E0539, "incorrect meta item"); - false - } - }; - - macro_rules! get_meta { - ($($name:ident),+) => { - $( - let mut $name = None; - )+ - for meta in metas { - if let Some(mi) = meta.meta_item() { - match &*mi.name().as_str() { - $( - stringify!($name) - => if !get(mi, &mut $name) { continue 'outer }, - )+ - _ => { - handle_errors(diagnostic, mi.span, - AttrError::UnknownMetaItem(mi.name())); - continue 'outer - } - } - } else { - handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); - continue 'outer - } - } - } - } - - match &*meta.name().as_str() { - "rustc_deprecated" => { - if rustc_depr.is_some() { - span_err!(diagnostic, item_sp, E0540, - "multiple rustc_deprecated attributes"); - continue 'outer - } - - get_meta!(since, reason); - - match (since, reason) { - (Some(since), Some(reason)) => { - rustc_depr = Some(RustcDeprecation { - since, - reason, - }) - } - (None, _) => { - handle_errors(diagnostic, attr.span(), AttrError::MissingSince); - continue - } - _ => { - span_err!(diagnostic, attr.span(), E0543, "missing 'reason'"); - continue - } - } - } - "rustc_const_unstable" => { - if rustc_const_unstable.is_some() { - span_err!(diagnostic, item_sp, E0553, - "multiple rustc_const_unstable attributes"); - continue 'outer - } - - get_meta!(feature); - if let Some(feature) = feature { - rustc_const_unstable = Some(RustcConstUnstable { - feature - }); - } else { - span_err!(diagnostic, attr.span(), E0629, "missing 'feature'"); - continue - } - } - "unstable" => { - if stab.is_some() { - handle_errors(diagnostic, attr.span(), AttrError::MultipleStabilityLevels); - break - } - - let mut feature = None; - let mut reason = None; - let mut issue = None; - for meta in metas { - if let Some(mi) = meta.meta_item() { - match &*mi.name().as_str() { - "feature" => if !get(mi, &mut feature) { continue 'outer }, - "reason" => if !get(mi, &mut reason) { continue 'outer }, - "issue" => if !get(mi, &mut issue) { continue 'outer }, - _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(mi.name())); - continue 'outer - } - } - } else { - handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); - continue 'outer - } - } - - match (feature, reason, issue) { - (Some(feature), reason, Some(issue)) => { - stab = Some(Stability { - level: Unstable { - reason, - issue: { - if let Ok(issue) = issue.as_str().parse() { - issue - } else { - span_err!(diagnostic, attr.span(), E0545, - "incorrect 'issue'"); - continue - } - } - }, - feature, - rustc_depr: None, - rustc_const_unstable: None, - }) - } - (None, _, _) => { - handle_errors(diagnostic, attr.span(), AttrError::MissingFeature); - continue - } - _ => { - span_err!(diagnostic, attr.span(), E0547, "missing 'issue'"); - continue - } - } - } - "stable" => { - if stab.is_some() { - handle_errors(diagnostic, attr.span(), AttrError::MultipleStabilityLevels); - break - } - - let mut feature = None; - let mut since = None; - for meta in metas { - if let NestedMetaItemKind::MetaItem(ref mi) = meta.node { - match &*mi.name().as_str() { - "feature" => if !get(mi, &mut feature) { continue 'outer }, - "since" => if !get(mi, &mut since) { continue 'outer }, - _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(mi.name())); - continue 'outer - } - } - } else { - handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); - continue 'outer - } - } - - match (feature, since) { - (Some(feature), Some(since)) => { - stab = Some(Stability { - level: Stable { - since, - }, - feature, - rustc_depr: None, - rustc_const_unstable: None, - }) - } - (None, _) => { - handle_errors(diagnostic, attr.span(), AttrError::MissingFeature); - continue - } - _ => { - handle_errors(diagnostic, attr.span(), AttrError::MissingSince); - continue - } - } - } - _ => unreachable!() - } - } else { - span_err!(diagnostic, attr.span(), E0548, "incorrect stability attribute type"); - continue - } - } - - // Merge the deprecation info into the stability info - if let Some(rustc_depr) = rustc_depr { - if let Some(ref mut stab) = stab { - stab.rustc_depr = Some(rustc_depr); - } else { - span_err!(diagnostic, item_sp, E0549, - "rustc_deprecated attribute must be paired with \ - either stable or unstable attribute"); - } - } - - // Merge the const-unstable info into the stability info - if let Some(rustc_const_unstable) = rustc_const_unstable { - if let Some(ref mut stab) = stab { - stab.rustc_const_unstable = Some(rustc_const_unstable); - } else { - span_err!(diagnostic, item_sp, E0630, - "rustc_const_unstable attribute must be paired with \ - either stable or unstable attribute"); - } - } - - stab -} - -fn find_deprecation_generic<'a, I>(diagnostic: &Handler, - attrs_iter: I, - item_sp: Span) - -> Option - where I: Iterator -{ - let mut depr: Option = None; - - 'outer: for attr in attrs_iter { - if attr.path != "deprecated" { - continue - } - - mark_used(attr); - - if depr.is_some() { - span_err!(diagnostic, item_sp, E0550, "multiple deprecated attributes"); - break - } - - depr = if let Some(metas) = attr.meta_item_list() { - let get = |meta: &MetaItem, item: &mut Option| { - if item.is_some() { - handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); - return false - } - if let Some(v) = meta.value_str() { - *item = Some(v); - true - } else { - span_err!(diagnostic, meta.span, E0551, "incorrect meta item"); - false - } - }; - - let mut since = None; - let mut note = None; - for meta in metas { - if let NestedMetaItemKind::MetaItem(ref mi) = meta.node { - match &*mi.name().as_str() { - "since" => if !get(mi, &mut since) { continue 'outer }, - "note" => if !get(mi, &mut note) { continue 'outer }, - _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(mi.name())); - continue 'outer - } - } - } else { - handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); - continue 'outer - } - } - - Some(Deprecation {since: since, note: note}) - } else { - Some(Deprecation{since: None, note: None}) - } - } - - depr -} - -/// Find the first stability attribute. `None` if none exists. -pub fn find_stability(diagnostic: &Handler, attrs: &[Attribute], - item_sp: Span) -> Option { - find_stability_generic(diagnostic, attrs.iter(), item_sp) -} - -/// Find the deprecation attribute. `None` if none exists. -pub fn find_deprecation(diagnostic: &Handler, attrs: &[Attribute], - item_sp: Span) -> Option { - find_deprecation_generic(diagnostic, attrs.iter(), item_sp) -} - - -/// Parse #[repr(...)] forms. -/// -/// Valid repr contents: any of the primitive integral type names (see -/// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use -/// the same discriminant size that the corresponding C enum would or C -/// structure layout, `packed` to remove padding, and `transparent` to elegate representation -/// concerns to the only non-ZST field. -pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec { - let mut acc = Vec::new(); - if attr.path == "repr" { - if let Some(items) = attr.meta_item_list() { - mark_used(attr); - for item in items { - if !item.is_meta_item() { - handle_errors(diagnostic, item.span, AttrError::UnsupportedLiteral); - continue - } - - let mut recognised = false; - if let Some(mi) = item.word() { - let word = &*mi.name().as_str(); - let hint = match word { - "C" => Some(ReprC), - "packed" => Some(ReprPacked(1)), - "simd" => Some(ReprSimd), - "transparent" => Some(ReprTransparent), - _ => match int_type_of_word(word) { - Some(ity) => Some(ReprInt(ity)), - None => { - None - } - } - }; - - if let Some(h) = hint { - recognised = true; - acc.push(h); - } - } else if let Some((name, value)) = item.name_value_literal() { - let parse_alignment = |node: &ast::LitKind| -> Result { - if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { - if literal.is_power_of_two() { - // rustc::ty::layout::Align restricts align to <= 2^29 - if *literal <= 1 << 29 { - Ok(*literal as u32) - } else { - Err("larger than 2^29") - } - } else { - Err("not a power of two") - } - } else { - Err("not an unsuffixed integer") - } - }; - - let mut literal_error = None; - if name == "align" { - recognised = true; - match parse_alignment(&value.node) { - Ok(literal) => acc.push(ReprAlign(literal)), - Err(message) => literal_error = Some(message) - }; - } - else if name == "packed" { - recognised = true; - match parse_alignment(&value.node) { - Ok(literal) => acc.push(ReprPacked(literal)), - Err(message) => literal_error = Some(message) - }; - } - if let Some(literal_error) = literal_error { - span_err!(diagnostic, item.span, E0589, - "invalid `repr(align)` attribute: {}", literal_error); - } - } else { - if let Some(meta_item) = item.meta_item() { - if meta_item.name() == "align" { - if let MetaItemKind::NameValue(ref value) = meta_item.node { - recognised = true; - let mut err = struct_span_err!(diagnostic, item.span, E0693, - "incorrect `repr(align)` attribute format"); - match value.node { - ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { - err.span_suggestion_with_applicability( - item.span, - "use parentheses instead", - format!("align({})", int), - Applicability::MachineApplicable - ); - } - ast::LitKind::Str(s, _) => { - err.span_suggestion_with_applicability( - item.span, - "use parentheses instead", - format!("align({})", s), - Applicability::MachineApplicable - ); - } - _ => {} - } - err.emit(); - } - } - } - } - if !recognised { - // Not a word we recognize - span_err!(diagnostic, item.span, E0552, - "unrecognized representation hint"); - } - } - } - } - acc -} - -fn int_type_of_word(s: &str) -> Option { - match s { - "i8" => Some(SignedInt(ast::IntTy::I8)), - "u8" => Some(UnsignedInt(ast::UintTy::U8)), - "i16" => Some(SignedInt(ast::IntTy::I16)), - "u16" => Some(UnsignedInt(ast::UintTy::U16)), - "i32" => Some(SignedInt(ast::IntTy::I32)), - "u32" => Some(UnsignedInt(ast::UintTy::U32)), - "i64" => Some(SignedInt(ast::IntTy::I64)), - "u64" => Some(UnsignedInt(ast::UintTy::U64)), - "i128" => Some(SignedInt(ast::IntTy::I128)), - "u128" => Some(UnsignedInt(ast::UintTy::U128)), - "isize" => Some(SignedInt(ast::IntTy::Isize)), - "usize" => Some(UnsignedInt(ast::UintTy::Usize)), - _ => None - } -} - -#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] -pub enum ReprAttr { - ReprInt(IntType), - ReprC, - ReprPacked(u32), - ReprSimd, - ReprTransparent, - ReprAlign(u32), -} - -#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] -pub enum IntType { - SignedInt(ast::IntTy), - UnsignedInt(ast::UintTy) -} - -impl IntType { - #[inline] - pub fn is_signed(self) -> bool { - match self { - SignedInt(..) => true, - UnsignedInt(..) => false - } - } -} - impl MetaItem { fn tokens(&self) -> TokenStream { let mut idents = vec![]; From f31594397072f24a06bc9a28b0451eb833bb7cbd Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sat, 30 Jun 2018 13:02:58 -0400 Subject: [PATCH 04/21] move deprecation-sanity test to ui --- .../deprecation-sanity.rs | 0 src/test/ui/deprecation-sanity.stderr | 46 +++++++++++++++++++ 2 files changed, 46 insertions(+) rename src/test/{compile-fail => ui}/deprecation-sanity.rs (100%) create mode 100644 src/test/ui/deprecation-sanity.stderr diff --git a/src/test/compile-fail/deprecation-sanity.rs b/src/test/ui/deprecation-sanity.rs similarity index 100% rename from src/test/compile-fail/deprecation-sanity.rs rename to src/test/ui/deprecation-sanity.rs diff --git a/src/test/ui/deprecation-sanity.stderr b/src/test/ui/deprecation-sanity.stderr new file mode 100644 index 0000000000000..4481c61a98723 --- /dev/null +++ b/src/test/ui/deprecation-sanity.stderr @@ -0,0 +1,46 @@ +error[E0541]: unknown meta item 'reason' + --> $DIR/deprecation-sanity.rs:14:43 + | +LL | #[deprecated(since = "a", note = "a", reason)] //~ ERROR unknown meta item 'reason' + | ^^^^^^ + +error[E0551]: incorrect meta item + --> $DIR/deprecation-sanity.rs:17:31 + | +LL | #[deprecated(since = "a", note)] //~ ERROR incorrect meta item + | ^^^^ + +error[E0551]: incorrect meta item + --> $DIR/deprecation-sanity.rs:20:18 + | +LL | #[deprecated(since, note = "a")] //~ ERROR incorrect meta item + | ^^^^^ + +error[E0551]: incorrect meta item + --> $DIR/deprecation-sanity.rs:23:31 + | +LL | #[deprecated(since = "a", note(b))] //~ ERROR incorrect meta item + | ^^^^^^^ + +error[E0551]: incorrect meta item + --> $DIR/deprecation-sanity.rs:26:18 + | +LL | #[deprecated(since(b), note = "a")] //~ ERROR incorrect meta item + | ^^^^^^^^ + +error[E0550]: multiple deprecated attributes + --> $DIR/deprecation-sanity.rs:32:1 + | +LL | fn multiple1() { } //~ ERROR multiple deprecated attributes + | ^^^^^^^^^^^^^^^^^^ + +error[E0538]: multiple 'since' items + --> $DIR/deprecation-sanity.rs:34:27 + | +LL | #[deprecated(since = "a", since = "b", note = "c")] //~ ERROR multiple 'since' items + | ^^^^^^^^^^^ + +error: aborting due to 7 previous errors + +Some errors occurred: E0538, E0541, E0550, E0551. +For more information about an error, try `rustc --explain E0538`. From 5468e12ca056a6ac46b36e244d235b9a0c987c58 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sat, 30 Jun 2018 15:33:59 -0400 Subject: [PATCH 05/21] add label to unknown meta item error --- src/libsyntax/attr/builtin.rs | 44 ++++++++++++++++++++------- src/test/ui/deprecation-sanity.stderr | 2 +- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 7b626a0fc2748..ecd52a62eab26 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -20,7 +20,7 @@ use super::{list_contains_name, mark_used, MetaItemKind}; enum AttrError { MultipleItem(Name), - UnknownMetaItem(Name), + UnknownMetaItem(Name, &'static [&'static str]), MissingSince, MissingFeature, MultipleStabilityLevels, @@ -31,8 +31,15 @@ fn handle_errors(diag: &Handler, span: Span, error: AttrError) { match error { AttrError::MultipleItem(item) => span_err!(diag, span, E0538, "multiple '{}' items", item), - AttrError::UnknownMetaItem(item) => span_err!(diag, span, E0541, - "unknown meta item '{}'", item), + AttrError::UnknownMetaItem(item, expected) => { + let expected = expected + .iter() + .map(|name| format!("`{}`", name)) + .collect::>(); + struct_span_err!(diag, span, E0541, "unknown meta item '{}'", item) + .span_label(span, format!("expected one of {}", expected.join(", "))) + .emit(); + } AttrError::MissingSince => span_err!(diag, span, E0542, "missing 'since'"), AttrError::MissingFeature => span_err!(diag, span, E0546, "missing 'feature'"), AttrError::MultipleStabilityLevels => span_err!(diag, span, E0544, @@ -213,8 +220,11 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, => if !get(mi, &mut $name) { continue 'outer }, )+ _ => { - handle_errors(diagnostic, mi.span, - AttrError::UnknownMetaItem(mi.name())); + let expected = &[ $( stringify!($name) ),+ ]; + handle_errors( + diagnostic, + mi.span, + AttrError::UnknownMetaItem(mi.name(), expected)); continue 'outer } } @@ -286,8 +296,14 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, "reason" => if !get(mi, &mut reason) { continue 'outer }, "issue" => if !get(mi, &mut issue) { continue 'outer }, _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(mi.name())); + handle_errors( + diagnostic, + meta.span, + AttrError::UnknownMetaItem( + mi.name(), + &["feature", "reason", "issue"] + ), + ); continue 'outer } } @@ -341,8 +357,11 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, "feature" => if !get(mi, &mut feature) { continue 'outer }, "since" => if !get(mi, &mut since) { continue 'outer }, _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(mi.name())); + handle_errors( + diagnostic, + meta.span, + AttrError::UnknownMetaItem(mi.name(), &["since", "note"]), + ); continue 'outer } } @@ -520,8 +539,11 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler, "since" => if !get(mi, &mut since) { continue 'outer }, "note" => if !get(mi, &mut note) { continue 'outer }, _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(mi.name())); + handle_errors( + diagnostic, + meta.span, + AttrError::UnknownMetaItem(mi.name(), &["since", "note"]), + ); continue 'outer } } diff --git a/src/test/ui/deprecation-sanity.stderr b/src/test/ui/deprecation-sanity.stderr index 4481c61a98723..967eb6e23a379 100644 --- a/src/test/ui/deprecation-sanity.stderr +++ b/src/test/ui/deprecation-sanity.stderr @@ -2,7 +2,7 @@ error[E0541]: unknown meta item 'reason' --> $DIR/deprecation-sanity.rs:14:43 | LL | #[deprecated(since = "a", note = "a", reason)] //~ ERROR unknown meta item 'reason' - | ^^^^^^ + | ^^^^^^ expected one of `since`, `note` error[E0551]: incorrect meta item --> $DIR/deprecation-sanity.rs:17:31 From e89db3030d322ca7cb20d13df5578b60b0c8a942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 1 Jul 2018 20:03:35 -0700 Subject: [PATCH 06/21] Do not suggest changes to str literal if it isn't one --- src/librustc_typeck/check/demand.rs | 16 ++++++++++------ src/test/ui/suggestions/issue-48364.rs | 16 ++++++++++++++++ src/test/ui/suggestions/issue-48364.stderr | 12 ++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/suggestions/issue-48364.rs create mode 100644 src/test/ui/suggestions/issue-48364.stderr diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 08d8dd2e498b6..aee64ad3b550c 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -264,9 +264,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (&ty::TyStr, &ty::TySlice(arr)) if arr == self.tcx.types.u8 => { if let hir::ExprLit(_) = expr.node { if let Ok(src) = cm.span_to_snippet(sp) { - return Some((sp, - "consider removing the leading `b`", - src[1..].to_string())); + if src.starts_with("b\"") { + return Some((sp, + "consider removing the leading `b`", + src[1..].to_string())); + } } } }, @@ -274,9 +276,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (&ty::TySlice(arr), &ty::TyStr) if arr == self.tcx.types.u8 => { if let hir::ExprLit(_) = expr.node { if let Ok(src) = cm.span_to_snippet(sp) { - return Some((sp, - "consider adding a leading `b`", - format!("b{}", src))); + if src.starts_with("\"") { + return Some((sp, + "consider adding a leading `b`", + format!("b{}", src))); + } } } } diff --git a/src/test/ui/suggestions/issue-48364.rs b/src/test/ui/suggestions/issue-48364.rs new file mode 100644 index 0000000000000..82cb722a65600 --- /dev/null +++ b/src/test/ui/suggestions/issue-48364.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() -> bool { + b"".starts_with(stringify!(foo)) + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-48364.stderr b/src/test/ui/suggestions/issue-48364.stderr new file mode 100644 index 0000000000000..b420654a32d8c --- /dev/null +++ b/src/test/ui/suggestions/issue-48364.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/issue-48364.rs:12:21 + | +LL | b"".starts_with(stringify!(foo)) + | ^^^^^^^^^^^^^^^ expected slice, found str + | + = note: expected type `&[u8]` + found type `&'static str` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 6e5b9c1472175c090700eaae71a7033bc33cd253 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 29 Jun 2018 10:58:17 +0200 Subject: [PATCH 07/21] Get rid of `TyImplTraitExistential` --- src/librustc/hir/intravisit.rs | 7 - src/librustc/hir/lowering.rs | 29 ++-- src/librustc/hir/mod.rs | 12 -- src/librustc/hir/print.rs | 9 -- src/librustc/ich/impls_hir.rs | 1 - src/librustc/middle/resolve_lifetime.rs | 191 +++++++++++++----------- src/librustc_privacy/lib.rs | 44 ++---- src/librustc_typeck/astconv.rs | 16 +- src/librustc_typeck/collect.rs | 4 - 9 files changed, 144 insertions(+), 169 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 60e944e5affc3..a7ed854d01649 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -607,13 +607,6 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { } visitor.visit_lifetime(lifetime); } - TyImplTraitExistential(_, def_id, ref lifetimes) => { - // we are not recursing into the `existential` item, because it is already being visited - // as part of the surrounding module. The `NodeId` just exists so we don't have to look - // it up everywhere else in the compiler - visitor.visit_def_mention(Def::Existential(def_id)); - walk_list!(visitor, visit_lifetime, lifetimes); - } TyTypeof(ref expression) => { visitor.visit_anon_const(expression) } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e59e50ae9e698..5990340ae2955 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1306,13 +1306,20 @@ impl<'a> LoweringContext<'a> { lctx.items.insert(exist_ty_id.node_id, exist_ty_item); // `impl Trait` now just becomes `Foo<'a, 'b, ..>` - hir::TyImplTraitExistential( - hir::ItemId { - id: exist_ty_id.node_id - }, - DefId::local(exist_ty_def_index), - lifetimes, - ) + let path = P(hir::Path { + span: exist_ty_span, + def: Def::Existential(DefId::local(exist_ty_def_index)), + segments: hir_vec![hir::PathSegment { + infer_types: false, + ident: Ident::new(keywords::Invalid.name(), exist_ty_span), + args: Some(P(hir::GenericArgs { + parenthesized: false, + bindings: HirVec::new(), + args: lifetimes, + })) + }], + }); + hir::TyPath(hir::QPath::Resolved(None, path)) }) } @@ -1321,7 +1328,7 @@ impl<'a> LoweringContext<'a> { exist_ty_id: NodeId, parent_index: DefIndex, bounds: &hir::GenericBounds, - ) -> (HirVec, HirVec) { + ) -> (HirVec, HirVec) { // This visitor walks over impl trait bounds and creates defs for all lifetimes which // appear in the bounds, excluding lifetimes that are created within the bounds. // e.g. 'a, 'b, but not 'c in `impl for<'c> SomeTrait<'a, 'b, 'c>` @@ -1332,7 +1339,7 @@ impl<'a> LoweringContext<'a> { collect_elided_lifetimes: bool, currently_bound_lifetimes: Vec, already_defined_lifetimes: HashSet, - output_lifetimes: Vec, + output_lifetimes: Vec, output_lifetime_params: Vec, } @@ -1416,11 +1423,11 @@ impl<'a> LoweringContext<'a> { && !self.already_defined_lifetimes.contains(&name) { self.already_defined_lifetimes.insert(name); - self.output_lifetimes.push(hir::Lifetime { + self.output_lifetimes.push(hir::GenericArg::Lifetime(hir::Lifetime { id: self.context.next_id().node_id, span: lifetime.span, name, - }); + })); // We need to manually create the ids here, because the // definitions will go into the explicit `existential type` diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index b0b81316148ea..8d83dd3279c64 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1692,18 +1692,6 @@ pub enum Ty_ { /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TyTraitObject(HirVec, Lifetime), - /// An existentially quantified (there exists a type satisfying) `impl - /// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime. - /// - /// The `Item` is the generated - /// `existential type Foo<'a, 'b>: MyTrait<'a, 'b>;`. - /// - /// The `HirVec` is the list of lifetimes applied as parameters - /// to the `abstract type`, e.g. the `'c` and `'d` in `-> Foo<'c, 'd>`. - /// This list is only a list of lifetimes and not type parameters - /// because all in-scope type parameters are captured by `impl Trait`, - /// so they are resolved directly through the parent `Generics`. - TyImplTraitExistential(ItemId, DefId, HirVec), /// Unused for now TyTypeof(AnonConst), /// TyInfer means the type should be inferred instead of it having been diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 255009c94c6ab..4d0969d898e91 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -420,15 +420,6 @@ impl<'a> State<'a> { self.print_lifetime(lifetime)?; } } - hir::TyImplTraitExistential(hir_id, _def_id, ref _lifetimes) => { - match self.ann.try_fetch_item(hir_id.id).map(|it| &it.node) { - None => self.word_space("impl {{Trait}}")?, - Some(&hir::ItemExistential(ref exist_ty)) => { - self.print_bounds("impl", &exist_ty.bounds)?; - }, - other => bug!("impl Trait pointed to {:#?}", other), - } - } hir::TyArray(ref ty, ref length) => { self.s.word("[")?; self.print_type(&ty)?; diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 0c7baea85ad8f..dd19d59578fc1 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -340,7 +340,6 @@ impl_stable_hash_for!(enum hir::Ty_ { TyTup(ts), TyPath(qpath), TyTraitObject(trait_refs, lifetime), - TyImplTraitExistential(existty, def_id, lifetimes), TyTypeof(body_id), TyErr, TyInfer diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index ed2b9c5068929..369f65c214aa1 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -625,122 +625,131 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; self.with(scope, |_, this| this.visit_ty(&mt.ty)); } - hir::TyImplTraitExistential(item_id, _, ref lifetimes) => { - // Resolve the lifetimes that are applied to the existential type. - // These are resolved in the current scope. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `fn foo<'a>() -> MyAnonTy<'a> { ... }` - // ^ ^this gets resolved in the current scope - for lifetime in lifetimes { - self.visit_lifetime(lifetime); - - // Check for predicates like `impl for<'a> SomeTrait>` - // and ban them. Type variables instantiated inside binders aren't - // well-supported at the moment, so this doesn't work. - // In the future, this should be fixed and this error should be removed. - let def = self.map.defs.get(&lifetime.id).cloned(); - if let Some(Region::LateBound(_, def_id, _)) = def { - if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) { - // Ensure that the parent of the def is an item, not HRTB - let parent_id = self.tcx.hir.get_parent_node(node_id); - let parent_impl_id = hir::ImplItemId { node_id: parent_id }; - let parent_trait_id = hir::TraitItemId { node_id: parent_id }; - let krate = self.tcx.hir.forest.krate(); - if !(krate.items.contains_key(&parent_id) - || krate.impl_items.contains_key(&parent_impl_id) - || krate.trait_items.contains_key(&parent_trait_id)) - { - span_err!( - self.tcx.sess, - lifetime.span, - E0657, - "`impl Trait` can only capture lifetimes \ - bound at the fn or impl level" - ); - self.uninsert_lifetime_on_error(lifetime, def.unwrap()); + hir::TyPath(hir::QPath::Resolved(None, ref path)) => { + if let Def::Existential(exist_ty_did) = path.def { + assert!(exist_ty_did.is_local()); + // Resolve the lifetimes that are applied to the existential type. + // These are resolved in the current scope. + // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + // `fn foo<'a>() -> MyAnonTy<'a> { ... }` + // ^ ^this gets resolved in the current scope + for lifetime in &path.segments[0].args.as_ref().unwrap().args { + if let hir::GenericArg::Lifetime(lifetime) = lifetime { + self.visit_lifetime(lifetime); + + // Check for predicates like `impl for<'a> Trait>` + // and ban them. Type variables instantiated inside binders aren't + // well-supported at the moment, so this doesn't work. + // In the future, this should be fixed and this error should be removed. + let def = self.map.defs.get(&lifetime.id).cloned(); + if let Some(Region::LateBound(_, def_id, _)) = def { + if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) { + // Ensure that the parent of the def is an item, not HRTB + let parent_id = self.tcx.hir.get_parent_node(node_id); + let parent_impl_id = hir::ImplItemId { node_id: parent_id }; + let parent_trait_id = hir::TraitItemId { node_id: parent_id }; + let krate = self.tcx.hir.forest.krate(); + if !(krate.items.contains_key(&parent_id) + || krate.impl_items.contains_key(&parent_impl_id) + || krate.trait_items.contains_key(&parent_trait_id)) + { + span_err!( + self.tcx.sess, + lifetime.span, + E0657, + "`impl Trait` can only capture lifetimes \ + bound at the fn or impl level" + ); + self.uninsert_lifetime_on_error(lifetime, def.unwrap()); + } + } } } } - } - // Resolve the lifetimes in the bounds to the lifetime defs in the generics. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `abstract type MyAnonTy<'b>: MyTrait<'b>;` - // ^ ^ this gets resolved in the scope of - // the exist_ty generics - let (generics, bounds) = match self.tcx.hir.expect_item(item_id.id).node { - hir::ItemExistential(hir::ExistTy{ ref generics, ref bounds, .. }) => ( - generics, - bounds, - ), - ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i), - }; + let id = self.tcx.hir.as_local_node_id(exist_ty_did).unwrap(); + + // Resolve the lifetimes in the bounds to the lifetime defs in the generics. + // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + // `abstract type MyAnonTy<'b>: MyTrait<'b>;` + // ^ ^ this gets resolved in the scope of + // the exist_ty generics + let (generics, bounds) = match self.tcx.hir.expect_item(id).node { + hir::ItemExistential(hir::ExistTy{ ref generics, ref bounds, .. }) => ( + generics, + bounds, + ), + ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i), + }; - // We want to start our early-bound indices at the end of the parent scope, - // not including any parent `impl Trait`s. - let mut index = self.next_early_index_for_abstract_type(); - debug!("visit_ty: index = {}", index); + // We want to start our early-bound indices at the end of the parent scope, + // not including any parent `impl Trait`s. + let mut index = self.next_early_index_for_abstract_type(); + debug!("visit_ty: index = {}", index); - let mut elision = None; - let mut lifetimes = FxHashMap(); - let mut type_count = 0; - for param in &generics.params { - match param.kind { - GenericParamKind::Lifetime { .. } => { - let (name, reg) = Region::early(&self.tcx.hir, &mut index, ¶m); - if let hir::ParamName::Plain(param_name) = name { - if param_name.name == keywords::UnderscoreLifetime.name() { - // Pick the elided lifetime "definition" if one exists - // and use it to make an elision scope. - elision = Some(reg); + let mut elision = None; + let mut lifetimes = FxHashMap(); + let mut type_count = 0; + for param in &generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => { + let (name, reg) = Region::early(&self.tcx.hir, &mut index, ¶m); + if let hir::ParamName::Plain(param_name) = name { + if param_name.name == keywords::UnderscoreLifetime.name() { + // Pick the elided lifetime "definition" if one exists + // and use it to make an elision scope. + elision = Some(reg); + } else { + lifetimes.insert(name, reg); + } } else { lifetimes.insert(name, reg); } - } else { - lifetimes.insert(name, reg); } - } - GenericParamKind::Type { .. } => { - type_count += 1; + GenericParamKind::Type { .. } => { + type_count += 1; + } } } - } - let next_early_index = index + type_count; + let next_early_index = index + type_count; - if let Some(elision_region) = elision { - let scope = Scope::Elision { - elide: Elide::Exact(elision_region), - s: self.scope, - }; - self.with(scope, |_old_scope, this| { + if let Some(elision_region) = elision { + let scope = Scope::Elision { + elide: Elide::Exact(elision_region), + s: self.scope, + }; + self.with(scope, |_old_scope, this| { + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: this.scope, + track_lifetime_uses: true, + abstract_type_parent: false, + }; + this.with(scope, |_old_scope, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }); + }); + } else { let scope = Scope::Binder { lifetimes, next_early_index, - s: this.scope, + s: self.scope, track_lifetime_uses: true, abstract_type_parent: false, }; - this.with(scope, |_old_scope, this| { + self.with(scope, |_old_scope, this| { this.visit_generics(generics); for bound in bounds { this.visit_param_bound(bound); } }); - }); + } } else { - let scope = Scope::Binder { - lifetimes, - next_early_index, - s: self.scope, - track_lifetime_uses: true, - abstract_type_parent: false, - }; - self.with(scope, |_old_scope, this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - }); + intravisit::walk_ty(self, ty) } } _ => intravisit::walk_ty(self, ty), diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index c55d57cb91631..3919ba13076f6 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -229,8 +229,12 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { hir::ItemUse(..) => {} // The interface is empty hir::ItemGlobalAsm(..) => {} - // Checked by visit_ty - hir::ItemExistential(..) => {} + hir::ItemExistential(..) => { + if item_level.is_some() { + // Reach the (potentially private) type and the API being exposed + self.reach(item.id).ty().predicates(); + } + } // Visit everything hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { @@ -390,17 +394,6 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { module_id = self.tcx.hir.get_parent_node(module_id); } } - - fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - if let hir::TyImplTraitExistential(item_id, _, _) = ty.node { - if self.get(item_id.id).is_some() { - // Reach the (potentially private) type and the API being exposed - self.reach(item_id.id).ty().predicates(); - } - } - - intravisit::walk_ty(self, ty); - } } impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { @@ -1568,8 +1561,15 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> hir::ItemUse(..) => {} // No subitems hir::ItemGlobalAsm(..) => {} - // Checked in visit_ty - hir::ItemExistential(..) => {} + hir::ItemExistential(..) => { + // Check the traits being exposed, as they're separate, + // e.g. `impl Iterator` has two predicates, + // `X: Iterator` and `::Item == T`, + // where `X` is the `impl Iterator` itself, + // stored in `predicates_of`, not in the `Ty` itself. + + self.check(item.id, self.inner_visibility).predicates(); + } // Subitems of these items have inherited publicity hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { @@ -1667,20 +1667,6 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> // handled in `visit_item` above } - fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - if let hir::TyImplTraitExistential(ref exist_item, _, _) = ty.node { - // Check the traits being exposed, as they're separate, - // e.g. `impl Iterator` has two predicates, - // `X: Iterator` and `::Item == T`, - // where `X` is the `impl Iterator` itself, - // stored in `predicates_of`, not in the `Ty` itself. - - self.check(exist_item.id, self.inner_visibility).predicates(); - } - - intravisit::walk_ty(self, ty); - } - // Don't recurse into expressions in array sizes or const initializers fn visit_expr(&mut self, _: &'tcx hir::Expr) {} // Don't recurse into patterns in function arguments diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 762dc5d26f5a4..2e467d315bedd 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1095,6 +1095,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyStr => tcx.mk_str() } } + Def::Existential(exist_ty_did) => { + assert!(exist_ty_did.is_local()); + let lifetimes = &path.segments[0].args.as_ref().unwrap().args; + self.impl_trait_ty_to_ty(exist_ty_did, lifetimes) + } Def::Err => { self.set_tainted_by_errors(); return self.tcx().types.err; @@ -1140,9 +1145,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyTraitObject(ref bounds, ref lifetime) => { self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime) } - hir::TyImplTraitExistential(_, def_id, ref lifetimes) => { - self.impl_trait_ty_to_ty(def_id, lifetimes) - } hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => { debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); let opt_self_ty = maybe_qself.as_ref().map(|qself| { @@ -1195,7 +1197,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn impl_trait_ty_to_ty( &self, def_id: DefId, - lifetimes: &[hir::Lifetime], + lifetimes: &[hir::GenericArg], ) -> Ty<'tcx> { debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes); let tcx = self.tcx(); @@ -1208,7 +1210,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Our own parameters are the resolved lifetimes. match param.kind { GenericParamDefKind::Lifetime => { - self.ast_region_to_region(&lifetimes[i], None).into() + if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] { + self.ast_region_to_region(lifetime, None).into() + } else { + bug!() + } } _ => bug!() } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 852603ac51c35..4931cbfa5acc3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -875,10 +875,6 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - NodeTy(&hir::Ty { node: hir::TyImplTraitExistential(..), .. }) => { - bug!("impl Trait is desugared to existential type items"); - } - _ => &no_generics, }; From 75a6fde6a49b7e497163c9a415b147cec26cbc56 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 2 Jul 2018 10:37:49 +0200 Subject: [PATCH 08/21] Update rustdoc --- src/librustdoc/clean/mod.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b8abb98edec48..f71d62d5a04e1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2987,14 +2987,6 @@ impl Clean for hir::Ty { } } TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)), - TyImplTraitExistential(hir_id, _, _) => { - match cx.tcx.hir.expect_item(hir_id.id).node { - hir::ItemExistential(ref exist_ty) => { - ImplTrait(exist_ty.bounds.clean(cx)) - }, - ref other => panic!("impl Trait pointed to {:#?}", other), - } - }, TyInfer | TyErr => Infer, TyTypeof(..) => panic!("Unimplemented type {:?}", self.node), } From 3779a4cb74d567153557036c4d86266bc8df196a Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 2 Jul 2018 11:40:32 +0200 Subject: [PATCH 09/21] Emit column info in debuginfo for non msvc like targets --- src/librustc_codegen_llvm/debuginfo/source_loc.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs index eb37e7f931cc3..958d09413edfa 100644 --- a/src/librustc_codegen_llvm/debuginfo/source_loc.rs +++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs @@ -81,16 +81,22 @@ impl InternalDebugLocation { pub fn set_debug_location(bx: &Builder, debug_location: InternalDebugLocation) { let metadata_node = match debug_location { - KnownLocation { scope, line, .. } => { - // Always set the column to zero like Clang and GCC - let col = UNKNOWN_COLUMN_NUMBER; + KnownLocation { scope, line, col } => { + // For MSVC, set the column number to zero. + // Otherwise, emit it. This mimics clang behaviour. + // See discussion in https://github.com/rust-lang/rust/issues/42921 + let col_used = if bx.cx.sess().target.target.options.is_like_msvc { + UNKNOWN_COLUMN_NUMBER + } else { + col as c_uint + }; debug!("setting debug location to {} {}", line, col); unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation( debug_context(bx.cx).llcontext, line as c_uint, - col as c_uint, + col_used, scope, ptr::null_mut()) } From 79d8d087a3d911ddcd881e452a7e72a8a7121435 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 2 Jul 2018 16:21:34 +0200 Subject: [PATCH 10/21] incr.comp.: Take names of children into account when computing the ICH of a module's HIR. --- src/librustc/ich/impls_hir.rs | 29 +++++++++++++++++++------- src/librustc_codegen_llvm/mono_item.rs | 5 ++--- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 0c7baea85ad8f..8917051bfd8ae 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -756,13 +756,28 @@ impl_stable_hash_for!(enum hir::ImplPolarity { Negative }); -impl_stable_hash_for!(struct hir::Mod { - inner, - // We are not hashing the IDs of the items contained in the module. - // This is harmless and matches the current behavior but it's not - // actually correct. See issue #40876. - item_ids -> _, -}); +impl<'a> HashStable> for hir::Mod { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + let hir::Mod { + inner: ref inner_span, + ref item_ids, + } = *self; + + inner_span.hash_stable(hcx, hasher); + + let mut item_ids: Vec = item_ids.iter().map(|id| { + let (def_path_hash, local_id) = id.id.to_stable_hash_key(hcx); + debug_assert_eq!(local_id, hir::ItemLocalId(0)); + def_path_hash + }).collect(); + + item_ids.sort_unstable(); + + item_ids.hash_stable(hcx, hasher); + } +} impl_stable_hash_for!(struct hir::ForeignMod { abi, diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs index 6ba3582f0143b..c4a23ac653ca0 100644 --- a/src/librustc_codegen_llvm/mono_item.rs +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -25,11 +25,10 @@ use monomorphize::Instance; use type_of::LayoutLlvmExt; use rustc::hir; use rustc::hir::def::Def; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::mir::mono::{Linkage, Visibility}; use rustc::ty::TypeFoldable; use rustc::ty::layout::LayoutOf; -use syntax::attr; use std::fmt; pub use rustc::mir::mono::MonoItem; @@ -173,7 +172,7 @@ fn predefine_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, // visibility as we're going to link this object all over the place but // don't want the symbols to get exported. if linkage != Linkage::Internal && linkage != Linkage::Private && - attr::contains_name(cx.tcx.hir.krate_attrs(), "compiler_builtins") { + cx.tcx.is_compiler_builtins(LOCAL_CRATE) { unsafe { llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden); } From 73166f751b7509dd95ce903ecdeab2dd5d89aa90 Mon Sep 17 00:00:00 2001 From: Dror Levin Date: Mon, 2 Jul 2018 17:38:15 +0300 Subject: [PATCH 11/21] Fill in tracking issue number for read_exact_at/write_all_at --- src/libstd/sys/unix/ext/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 4c2cea0d32c35..507e9d881717b 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -109,7 +109,7 @@ pub trait FileExt { /// Ok(()) /// } /// ``` - #[unstable(feature = "rw_exact_all_at", issue = "0")] + #[unstable(feature = "rw_exact_all_at", issue = "51984")] fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { while !buf.is_empty() { match self.read_at(buf, offset) { @@ -204,7 +204,7 @@ pub trait FileExt { /// Ok(()) /// } /// ``` - #[unstable(feature = "rw_exact_all_at", issue = "0")] + #[unstable(feature = "rw_exact_all_at", issue = "51984")] fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { while !buf.is_empty() { match self.write_at(buf, offset) { From 59f2edbf1adfea256216cb7fb65d291d324ea857 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 20 Feb 2018 10:26:48 -0500 Subject: [PATCH 12/21] add outlives annotations to `BTreeMap` nll requires these annotations, I believe because of https://github.com/rust-lang/rust/issues/29149 --- src/liballoc/collections/btree/map.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 2aad3149bb211..8c950cd06d9e3 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -149,12 +149,11 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for BTreeMap { fn clone(&self) -> BTreeMap { - fn clone_subtree(node: node::NodeRef) - -> BTreeMap { - + fn clone_subtree<'a, K: Clone, V: Clone>( + node: node::NodeRef, K, V, marker::LeafOrInternal> + ) -> BTreeMap + where K: 'a, V: 'a, + { match node.force() { Leaf(leaf) => { let mut out_tree = BTreeMap { @@ -1080,7 +1079,11 @@ impl BTreeMap { /// Calculates the number of elements if it is incorrect. fn recalc_length(&mut self) { - fn dfs(node: NodeRef) -> usize { + fn dfs<'a, K, V>( + node: NodeRef, K, V, marker::LeafOrInternal> + ) -> usize + where K: 'a, V: 'a + { let mut res = node.len(); if let Internal(node) = node.force() { From ddc1d294429e39cbc0b2b9e883b46592f896f412 Mon Sep 17 00:00:00 2001 From: Nikolai Merinov Date: Mon, 2 Jul 2018 01:45:35 +0500 Subject: [PATCH 13/21] bootstrap: tests should use rustc from config.toml Tests should always use "rustc" and "cargo" from config.toml instead of assuming that stage0 binaries was downloaded to build directory. --- src/bootstrap/bootstrap.py | 2 ++ src/bootstrap/config.rs | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index a94792a2f9f59..512d4d8c5b792 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -816,6 +816,8 @@ def bootstrap(help_triggered): env["BOOTSTRAP_PYTHON"] = sys.executable env["BUILD_DIR"] = build.build_dir env["RUSTC_BOOTSTRAP"] = '1' + env["CARGO"] = build.cargo() + env["RUSTC"] = build.rustc() run(args, env=env, verbose=build.verbose) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index e4d467c927245..b3ed10257bdac 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -23,7 +23,6 @@ use std::cmp; use num_cpus; use toml; -use util::exe; use cache::{INTERNER, Interned}; use flags::Flags; pub use flags::Subcommand; @@ -367,9 +366,8 @@ impl Config { config.src = Config::path_from_python("SRC"); config.out = Config::path_from_python("BUILD_DIR"); - let stage0_root = config.out.join(&config.build).join("stage0/bin"); - config.initial_rustc = stage0_root.join(exe("rustc", &config.build)); - config.initial_cargo = stage0_root.join(exe("cargo", &config.build)); + config.initial_rustc = Config::path_from_python("RUSTC"); + config.initial_cargo = Config::path_from_python("CARGO"); config } From 29851baf0cf3e71ec70bf319b7a5edd0b535f40c Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 2 Jul 2018 13:47:51 -0400 Subject: [PATCH 14/21] add entry for cargo-metadata feature to RELEASES --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index fba68ce043e26..9d922f493d08b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -65,6 +65,7 @@ Cargo ----- - [`cargo-metadata` now includes `authors`, `categories`, `keywords`, `readme`, and `repository` fields.][cargo/5386] +- [`cargo-metadata` now includes a package's `metadata` table.][cargo/5360] - [Added the `--target-dir` optional argument.][cargo/5393] This allows you to specify a different directory than `target` for placing compilation artifacts. - [Cargo will be adding automatic target inference for binaries, benchmarks, @@ -114,6 +115,7 @@ Compatibility Notes [cargo/5203]: https://github.com/rust-lang/cargo/pull/5203/ [cargo/5335]: https://github.com/rust-lang/cargo/pull/5335/ [cargo/5359]: https://github.com/rust-lang/cargo/pull/5359/ +[cargo/5360]: https://github.com/rust-lang/cargo/pull/5360/ [cargo/5386]: https://github.com/rust-lang/cargo/pull/5386/ [cargo/5393]: https://github.com/rust-lang/cargo/pull/5393/ [`DoubleEndedIterator::rfind`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.rfind From 9797665b286db3f34cc475560a68380012fadde7 Mon Sep 17 00:00:00 2001 From: Evan Simmons Date: Sun, 1 Jul 2018 14:30:16 -0700 Subject: [PATCH 15/21] Make Stdio handle UnwindSafe --- src/libstd/io/stdio.rs | 22 ++++++++++++++++++++++ src/libstd/sys_common/remutex.rs | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 2472bed5ba435..fce85a200ba2e 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -712,9 +712,31 @@ pub fn _eprint(args: fmt::Arguments) { #[cfg(test)] mod tests { + use panic::{UnwindSafe, RefUnwindSafe}; use thread; use super::*; + #[test] + fn stdout_unwind_safe() { + assert_unwind_safe::(); + } + #[test] + fn stdoutlock_unwind_safe() { + assert_unwind_safe::(); + assert_unwind_safe::>(); + } + #[test] + fn stderr_unwind_safe() { + assert_unwind_safe::(); + } + #[test] + fn stderrlock_unwind_safe() { + assert_unwind_safe::(); + assert_unwind_safe::>(); + } + + fn assert_unwind_safe() {} + #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn panic_doesnt_poison() { diff --git a/src/libstd/sys_common/remutex.rs b/src/libstd/sys_common/remutex.rs index 022056f8a8a70..071a3a25c7acd 100644 --- a/src/libstd/sys_common/remutex.rs +++ b/src/libstd/sys_common/remutex.rs @@ -13,6 +13,7 @@ use marker; use ops::Deref; use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; use sys::mutex as sys; +use panic::{UnwindSafe, RefUnwindSafe}; /// A re-entrant mutual exclusion /// @@ -28,6 +29,9 @@ pub struct ReentrantMutex { unsafe impl Send for ReentrantMutex {} unsafe impl Sync for ReentrantMutex {} +impl UnwindSafe for ReentrantMutex {} +impl RefUnwindSafe for ReentrantMutex {} + /// An RAII implementation of a "scoped lock" of a mutex. When this structure is /// dropped (falls out of scope), the lock will be unlocked. From f5570d0ef66847d6617682058a9fa680cdce392b Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 2 Jul 2018 14:46:40 -0600 Subject: [PATCH 16/21] Make explicit that assemble is not run from CLI --- src/bootstrap/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 642f22b11ade3..24e5bb2a9ed60 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -873,7 +873,7 @@ impl Step for Assemble { type Output = Compiler; fn should_run(run: ShouldRun) -> ShouldRun { - run.all_krates("rustc-main") + run.never() } /// Prepare a new compiler from the artifacts in `stage` From d91457495b2f551e34ecbe1111885d6ccceceb15 Mon Sep 17 00:00:00 2001 From: kennytm Date: Tue, 3 Jul 2018 04:49:42 +0800 Subject: [PATCH 17/21] Fix the tool's path in toolstate verification. This ensure we do block the tools when they are broken during an update. --- src/ci/docker/x86_64-gnu-tools/checktools.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index 56e637249f5ca..e8197e9085182 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -79,11 +79,11 @@ status_check() { check_dispatch $1 beta nomicon src/doc/nomicon check_dispatch $1 beta reference src/doc/reference check_dispatch $1 beta rust-by-example src/doc/rust-by-example - check_dispatch $1 beta rls src/tool/rls - check_dispatch $1 beta rustfmt src/tool/rustfmt + check_dispatch $1 beta rls src/tools/rls + check_dispatch $1 beta rustfmt src/tools/rustfmt # these tools are not required for beta to successfully branch - check_dispatch $1 nightly clippy-driver src/tool/clippy - check_dispatch $1 nightly miri src/tool/miri + check_dispatch $1 nightly clippy-driver src/tools/clippy + check_dispatch $1 nightly miri src/tools/miri } # If this PR is intended to update one of these tools, do not let the build pass From 20231d774bcda2d6f9bd52fe402fd22f2d22d223 Mon Sep 17 00:00:00 2001 From: kennytm Date: Tue, 3 Jul 2018 05:53:18 +0800 Subject: [PATCH 18/21] Fixed detection of test-fail for doctests. --- src/bootstrap/test.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 90688b1c0e181..3adfbb5e36b51 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1269,17 +1269,15 @@ impl Step for DocTest { files.sort(); + let mut toolstate = ToolState::TestPass; for file in files { - let test_result = markdown_test(builder, compiler, &file); - if self.is_ext_doc { - let toolstate = if test_result { - ToolState::TestPass - } else { - ToolState::TestFail - }; - builder.save_toolstate(self.name, toolstate); + if !markdown_test(builder, compiler, &file) { + toolstate = ToolState::TestFail; } } + if self.is_ext_doc { + builder.save_toolstate(self.name, toolstate); + } } } From 689cffa211e4c2c2c74dbc759020be40fe222d23 Mon Sep 17 00:00:00 2001 From: kennytm Date: Tue, 3 Jul 2018 06:01:58 +0800 Subject: [PATCH 19/21] Run "tools" job on PR when commit message starts with "Update RLS/miri/..." --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2e6722cf85563..ba8a39f355c4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -169,7 +169,7 @@ matrix: - env: IMAGE=x86_64-gnu-aux if: branch = auto - env: IMAGE=x86_64-gnu-tools - if: branch = auto + if: branch = auto OR (type = pull_request AND commit_message =~ /(?i:^update.*\b(rls|rustfmt|clippy|miri)\b)/) - env: IMAGE=x86_64-gnu-debug if: branch = auto - env: IMAGE=x86_64-gnu-nopt From 9eda4aabff138add785c6e672d9c67cc612f7503 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 2 Jul 2018 16:04:58 -0600 Subject: [PATCH 20/21] Change --keep-stage to apply more Previously, the --keep-stage argument would only function for compilers that were depended on by future stages. For example, if trying to build a stage 1 compiler you could --keep-stage 0 to avoid re-building the stage 0 compiler. However, this is often not what users want in practice. The new implementation essentially skips builds all higher stages of the compiler, so an argument of 1 to keep-stage will skip rebuilds of the libraries, just linking them into the sysroot. This is unlikely to work well in cases where metadata or similar changes have been made, but is likely fine otherwise. This change is somewhat untested, but since it shouldn't have any effect except with --keep-stage, I don't see that as a large problem. --- src/bootstrap/compile.rs | 63 +++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 24e5bb2a9ed60..aef2df3e2780f 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -24,7 +24,6 @@ use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::str; -use std::cmp::min; use build_helper::{output, mtime, up_to_date}; use filetime::FileTime; @@ -68,6 +67,18 @@ impl Step for Std { let target = self.target; let compiler = self.compiler; + if let Some(keep_stage) = builder.config.keep_stage { + if keep_stage <= compiler.stage { + println!("Warning: Using a potentially old libstd. This may not behave well."); + builder.ensure(StdLink { + compiler: compiler, + target_compiler: compiler, + target, + }); + return; + } + } + builder.ensure(StartupObjects { compiler, target }); if builder.force_use_stage1(compiler, target) { @@ -351,6 +362,18 @@ impl Step for Test { let target = self.target; let compiler = self.compiler; + if let Some(keep_stage) = builder.config.keep_stage { + if keep_stage <= compiler.stage { + println!("Warning: Using a potentially old libtest. This may not behave well."); + builder.ensure(TestLink { + compiler: compiler, + target_compiler: compiler, + target, + }); + return; + } + } + builder.ensure(Std { compiler, target }); if builder.force_use_stage1(compiler, target) { @@ -467,6 +490,18 @@ impl Step for Rustc { let compiler = self.compiler; let target = self.target; + if let Some(keep_stage) = builder.config.keep_stage { + if keep_stage <= compiler.stage { + println!("Warning: Using a potentially old librustc. This may not behave well."); + builder.ensure(RustcLink { + compiler: compiler, + target_compiler: compiler, + target, + }); + return; + } + } + builder.ensure(Test { compiler, target }); if builder.force_use_stage1(compiler, target) { @@ -915,28 +950,16 @@ impl Step for Assemble { // link to these. (FIXME: Is that correct? It seems to be correct most // of the time but I think we do link to these for stage2/bin compilers // when not performing a full bootstrap). - if builder.config.keep_stage.map_or(false, |s| target_compiler.stage <= s) { - builder.verbose("skipping compilation of compiler due to --keep-stage"); - let compiler = build_compiler; - for stage in 0..min(target_compiler.stage, builder.config.keep_stage.unwrap()) { - let target_compiler = builder.compiler(stage, target_compiler.host); - let target = target_compiler.host; - builder.ensure(StdLink { compiler, target_compiler, target }); - builder.ensure(TestLink { compiler, target_compiler, target }); - builder.ensure(RustcLink { compiler, target_compiler, target }); - } - } else { - builder.ensure(Rustc { + builder.ensure(Rustc { + compiler: build_compiler, + target: target_compiler.host, + }); + for &backend in builder.config.rust_codegen_backends.iter() { + builder.ensure(CodegenBackend { compiler: build_compiler, target: target_compiler.host, + backend, }); - for &backend in builder.config.rust_codegen_backends.iter() { - builder.ensure(CodegenBackend { - compiler: build_compiler, - target: target_compiler.host, - backend, - }); - } } let lld_install = if builder.config.lld_enabled { From 447f1f3f5cca20c15d2ed023310b07218aabe7fa Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 3 Jul 2018 11:16:38 +0200 Subject: [PATCH 21/21] Avoid sorting the item_ids array the StableHash impl of hir::Mod. --- src/librustc/hir/map/definitions.rs | 8 ++++++++ src/librustc/ich/fingerprint.rs | 12 ++++++++++++ src/librustc/ich/impls_hir.rs | 26 ++++++++++++++++---------- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index fa01a1ccca59b..328cb8225478b 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -23,6 +23,7 @@ use rustc_data_structures::indexed_vec::{IndexVec}; use rustc_data_structures::stable_hasher::StableHasher; use serialize::{Encodable, Decodable, Encoder, Decoder}; use session::CrateDisambiguator; +use std::borrow::Borrow; use std::fmt::Write; use std::hash::Hash; use syntax::ast; @@ -389,6 +390,13 @@ pub struct DefPathHash(pub Fingerprint); impl_stable_hash_for!(tuple_struct DefPathHash { fingerprint }); +impl Borrow for DefPathHash { + #[inline] + fn borrow(&self) -> &Fingerprint { + &self.0 + } +} + impl Definitions { /// Create new empty definition map. pub fn new() -> Definitions { diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs index 2a3b1ce6a36a5..a6e35d78dcb5a 100644 --- a/src/librustc/ich/fingerprint.rs +++ b/src/librustc/ich/fingerprint.rs @@ -45,6 +45,18 @@ impl Fingerprint { ) } + // Combines two hashes in an order independent way. Make sure this is what + // you want. + #[inline] + pub fn combine_commutative(self, other: Fingerprint) -> Fingerprint { + let a = (self.1 as u128) << 64 | self.0 as u128; + let b = (other.1 as u128) << 64 | other.0 as u128; + + let c = a.wrapping_add(b); + + Fingerprint((c >> 64) as u64, c as u64) + } + pub fn to_hex(&self) -> String { format!("{:x}{:x}", self.0, self.1) } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 8917051bfd8ae..70905bf9612f2 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -14,7 +14,7 @@ use hir; use hir::map::DefPathHash; use hir::def_id::{DefId, LocalDefId, CrateNum, CRATE_DEF_INDEX}; -use ich::{StableHashingContext, NodeIdHashingMode}; +use ich::{StableHashingContext, NodeIdHashingMode, Fingerprint}; use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher, StableHasherResult}; use std::mem; @@ -767,15 +767,21 @@ impl<'a> HashStable> for hir::Mod { inner_span.hash_stable(hcx, hasher); - let mut item_ids: Vec = item_ids.iter().map(|id| { - let (def_path_hash, local_id) = id.id.to_stable_hash_key(hcx); - debug_assert_eq!(local_id, hir::ItemLocalId(0)); - def_path_hash - }).collect(); - - item_ids.sort_unstable(); - - item_ids.hash_stable(hcx, hasher); + // Combining the DefPathHashes directly is faster than feeding them + // into the hasher. Because we use a commutative combine, we also don't + // have to sort the array. + let item_ids_hash = item_ids + .iter() + .map(|id| { + let (def_path_hash, local_id) = id.id.to_stable_hash_key(hcx); + debug_assert_eq!(local_id, hir::ItemLocalId(0)); + def_path_hash.0 + }).fold(Fingerprint::ZERO, |a, b| { + a.combine_commutative(b) + }); + + item_ids.len().hash_stable(hcx, hasher); + item_ids_hash.hash_stable(hcx, hasher); } }