diff --git a/src/Cargo.lock b/src/Cargo.lock index 4364d7001cdfe..4cb82f94251ff 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1844,6 +1844,27 @@ dependencies = [ "rustc_target 0.0.0", ] +[[package]] +name = "rustc-rayon" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-rayon-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-serialize" version = "0.3.24" @@ -1911,6 +1932,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", "serialize 0.0.0", "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1926,6 +1948,7 @@ dependencies = [ "graphviz 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", + "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_borrowck 0.0.0", "rustc_data_structures 0.0.0", @@ -1943,6 +1966,7 @@ dependencies = [ "rustc_traits 0.0.0", "rustc_trans_utils 0.0.0", "rustc_typeck 0.0.0", + "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", "syntax_ext 0.0.0", @@ -3118,6 +3142,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-ap-syntax 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b50671adb9b0a7c57a4690ac6a40cb614879f543b64aada42f55b66212492323" "checksum rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55793c2a775230c42661194c48d44b35d4c8439d79ad8528e56651e854c48c63" "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" +"checksum rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1aa5cd8c3a706edb19b6ec6aa7b056bdc635b6e99c5cf7014f9af9d92f15e99" +"checksum rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d69983f8613a9c3ba1a3bbf5e8bdf2fd5c42317b1d8dd8623ca8030173bf8a6b" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a54aa04a10c68c1c4eacb4337fd883b435997ede17a9385784b990777686b09a" "checksum rustfix 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "165a212dd11124d7070892da20f71d82970ef1d1dd41cd804b70f39740a21c85" diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index 3fed0175371a7..d71d5daf8113b 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -23,6 +23,8 @@ SIX_WEEK_CYCLE="$(( ($(date +%s) / 604800 - 3) % 6 ))" touch "$TOOLSTATE_FILE" +# Try to test all the tools and store the build/test success in the TOOLSTATE_FILE + set +e python2.7 "$X_PY" test --no-fail-fast \ src/doc/book \ @@ -38,6 +40,7 @@ set -e cat "$TOOLSTATE_FILE" echo +# This function checks that if a tool's submodule changed, the tool's state must improve verify_status() { echo "Verifying status of $1..." if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then @@ -57,17 +60,36 @@ verify_status() { fi } +# deduplicates the submodule check and the assertion that on beta some tools MUST be passing +check_dispatch() { + if [ "$1" = submodule_changed ]; then + # ignore $2 (branch id) + verify_status $3 $4 + elif [ "$2" = beta ]; then + echo "Requiring test passing for $3..." + if grep -q '"'"$3"'":"\(test\|build\)-fail"' "$TOOLSTATE_FILE"; then + exit 4 + fi + fi +} + +# list all tools here +status_check() { + check_dispatch $1 beta book src/doc/book + 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 + # 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 +} + # If this PR is intended to update one of these tools, do not let the build pass # when they do not test-pass. -verify_status book src/doc/book -verify_status nomicon src/doc/nomicon -verify_status reference src/doc/reference -verify_status rust-by-example src/doc/rust-by-example -verify_status rls src/tool/rls -verify_status rustfmt src/tool/rustfmt -verify_status clippy-driver src/tool/clippy -verify_status miri src/tool/miri +status_check "submodule_changed" if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then . "$(dirname $0)/repo.sh" @@ -86,6 +108,6 @@ $COMMIT\t$(cat "$TOOLSTATE_FILE") exit 0 fi -if grep -q fail "$TOOLSTATE_FILE"; then - exit 4 -fi +# abort compilation if an important tool doesn't build +# (this code is reachable if not on the nightly channel) +status_check "beta_required" diff --git a/src/doc/unstable-book/src/language-features/macro-literal-matcher.md b/src/doc/unstable-book/src/language-features/macro-literal-matcher.md new file mode 100644 index 0000000000000..7e3638fd1cf4c --- /dev/null +++ b/src/doc/unstable-book/src/language-features/macro-literal-matcher.md @@ -0,0 +1,17 @@ +# `macro_literal_matcher` + +The tracking issue for this feature is: [#35625] + +The RFC is: [rfc#1576]. + +With this feature gate enabled, the [list of fragment specifiers][frags] gains one more entry: + +* `literal`: a literal. Examples: 2, "string", 'c' + +A `literal` may be followed by anything, similarly to the `ident` specifier. + +[rfc#1576]: http://rust-lang.github.io/rfcs/1576-macros-literal-matcher.html +[#35625]: https://github.com/rust-lang/rust/issues/35625 +[frags]: ../book/first-edition/macros.html#syntactic-requirements + +------------------------ diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs index 2221ecf07b434..a62000e10c79f 100644 --- a/src/librustc/hir/itemlikevisit.rs +++ b/src/librustc/hir/itemlikevisit.rs @@ -88,3 +88,33 @@ impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V> self.visitor.visit_impl_item(impl_item); } } + +/// A parallel variant of ItemLikeVisitor +pub trait ParItemLikeVisitor<'hir> { + fn visit_item(&self, item: &'hir Item); + fn visit_trait_item(&self, trait_item: &'hir TraitItem); + fn visit_impl_item(&self, impl_item: &'hir ImplItem); +} + +pub trait IntoVisitor<'hir> { + type Visitor: Visitor<'hir>; + fn into_visitor(&self) -> Self::Visitor; +} + +pub struct ParDeepVisitor(pub V); + +impl<'hir, V> ParItemLikeVisitor<'hir> for ParDeepVisitor + where V: IntoVisitor<'hir> +{ + fn visit_item(&self, item: &'hir Item) { + self.0.into_visitor().visit_item(item); + } + + fn visit_trait_item(&self, trait_item: &'hir TraitItem) { + self.0.into_visitor().visit_trait_item(trait_item); + } + + fn visit_impl_item(&self, impl_item: &'hir ImplItem) { + self.0.into_visitor().visit_impl_item(impl_item); + } +} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 0dc89d64bd501..33076267dbc9d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -48,6 +48,7 @@ use ty::AdtKind; use ty::maps::Providers; use rustc_data_structures::indexed_vec; +use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope}; use serialize::{self, Encoder, Encodable, Decoder, Decodable}; use std::collections::BTreeMap; @@ -720,6 +721,31 @@ impl Crate { } } + /// A parallel version of visit_all_item_likes + pub fn par_visit_all_item_likes<'hir, V>(&'hir self, visitor: &V) + where V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send + { + scope(|s| { + s.spawn(|_| { + par_iter(&self.items).for_each(|(_, item)| { + visitor.visit_item(item); + }); + }); + + s.spawn(|_| { + par_iter(&self.trait_items).for_each(|(_, trait_item)| { + visitor.visit_trait_item(trait_item); + }); + }); + + s.spawn(|_| { + par_iter(&self.impl_items).for_each(|(_, impl_item)| { + visitor.visit_impl_item(impl_item); + }); + }); + }); + } + pub fn body(&self, id: BodyId) -> &Body { &self.bodies[&id] } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 4400ebc294fd8..61c8470b616f8 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -38,7 +38,7 @@ use syntax::ext::base::SyntaxExtension; use syntax::symbol::Symbol; use syntax_pos::Span; use rustc_target::spec::Target; -use rustc_data_structures::sync::{MetadataRef, Lrc}; +use rustc_data_structures::sync::{self, MetadataRef, Lrc}; pub use self::NativeLibraryKind::*; @@ -255,6 +255,8 @@ pub trait CrateStore { fn metadata_encoding_version(&self) -> &[u8]; } +pub type CrateStoreDyn = CrateStore + sync::Sync; + // FIXME: find a better place for this? pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option) { let mut err_count = 0; diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 279908d2b675f..d6a7d5e8472ac 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -764,7 +764,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { "unions with `Drop` implementations are unstable"); } else { let param_env = self.tcx.param_env(def_id); - if !param_env.can_type_implement_copy(self.tcx, ty, item.span).is_ok() { + if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() { emit_feature_err(&self.tcx.sess.parse_sess, "untagged_unions", item.span, GateIssue::Language, "unions with non-`Copy` fields are unstable"); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 23f84881c7980..bbf873290a928 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -869,10 +869,16 @@ impl Session { ret } + /// Returns the number of query threads that should be used for this + /// compilation + pub fn query_threads_from_opts(opts: &config::Options) -> usize { + opts.debugging_opts.query_threads.unwrap_or(1) + } + /// Returns the number of query threads that should be used for this /// compilation pub fn query_threads(&self) -> usize { - self.opts.debugging_opts.query_threads.unwrap_or(1) + Self::query_threads_from_opts(&self.opts) } /// Returns the number of codegen units that should be used for this diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 10d88063ac35f..a765ffe2396bf 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -674,7 +674,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // we move over to lazy normalization *anyway*. let fulfill_cx = FulfillmentContext::new_ignoring_regions(); - let predicates = match fully_normalize_with_fulfillcx( + let predicates = match fully_normalize( &infcx, fulfill_cx, cause, @@ -734,31 +734,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T) - -> Result>> - where T : TypeFoldable<'tcx> -{ - // FIXME (@jroesch) ISSUE 26721 - // I'm not sure if this is a bug or not, needs further investigation. - // It appears that by reusing the fulfillment_cx here we incur more - // obligations and later trip an assertion on regionck.rs line 337. - // - // The two possibilities I see is: - // - normalization is not actually fully happening and we - // have a bug else where - // - we are adding a duplicate bound into the list causing - // its size to change. - // - // I think we should probably land this refactor and then come - // back to this is a follow-up patch. - let fulfillcx = FulfillmentContext::new(); - fully_normalize_with_fulfillcx(infcx, fulfillcx, cause, param_env, value) -} - -pub fn fully_normalize_with_fulfillcx<'a, 'gcx, 'tcx, T>( +pub fn fully_normalize<'a, 'gcx, 'tcx, T>( infcx: &InferCtxt<'a, 'gcx, 'tcx>, mut fulfill_cx: FulfillmentContext<'tcx>, cause: ObligationCause<'tcx>, @@ -779,13 +755,7 @@ pub fn fully_normalize_with_fulfillcx<'a, 'gcx, 'tcx, T>( } debug!("fully_normalize: select_all_or_error start"); - match fulfill_cx.select_all_or_error(infcx) { - Ok(()) => { } - Err(e) => { - debug!("fully_normalize: error={:?}", e); - return Err(e); - } - } + fulfill_cx.select_all_or_error(infcx)?; debug!("fully_normalize: select_all_or_error complete"); let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value); debug!("fully_normalize: resolved_value={:?}", resolved_value); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 30b2c55afa194..d33806285142e 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -196,6 +196,7 @@ pub(super) fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // that this always succeeds. let impl1_trait_ref = match traits::fully_normalize(&infcx, + FulfillmentContext::new(), ObligationCause::dummy(), penv, &impl1_trait_ref) { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index f224f87da0a05..dcd20465fbb9a 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -26,7 +26,7 @@ use lint::{self, Lint}; use ich::{StableHashingContext, NodeIdHashingMode}; use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use infer::outlives::free_region_map::FreeRegionMap; -use middle::cstore::{CrateStore, LinkMeta}; +use middle::cstore::{CrateStoreDyn, LinkMeta}; use middle::cstore::EncodedMetadata; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; @@ -852,7 +852,7 @@ pub struct GlobalCtxt<'tcx> { global_arenas: &'tcx GlobalArenas<'tcx>, global_interners: CtxtInterners<'tcx>, - cstore: &'tcx dyn CrateStore, + cstore: &'tcx CrateStoreDyn, pub sess: &'tcx Session, @@ -1188,7 +1188,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// value (types, substs, etc.) can only be used while `ty::tls` has a valid /// reference to the context, to allow formatting values that need it. pub fn create_and_enter(s: &'tcx Session, - cstore: &'tcx dyn CrateStore, + cstore: &'tcx CrateStoreDyn, local_providers: ty::maps::Providers<'tcx>, extern_providers: ty::maps::Providers<'tcx>, arenas: &'tcx AllArenas<'tcx>, @@ -1800,9 +1800,11 @@ pub mod tls { /// in librustc otherwise. It is used to when diagnostic messages are /// emitted and stores them in the current query, if there is one. fn track_diagnostic(diagnostic: &Diagnostic) { - with_context(|context| { - if let Some(ref query) = context.query { - query.diagnostics.lock().push(diagnostic.clone()); + with_context_opt(|icx| { + if let Some(icx) = icx { + if let Some(ref query) = icx.query { + query.diagnostics.lock().push(diagnostic.clone()); + } } }) } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 9cbee14399079..b22c025e86c0b 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -325,10 +325,6 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { offsets.len(), ty); } - if field.abi == Abi::Uninhabited { - return Ok(LayoutDetails::uninhabited(fields.len())); - } - if field.is_unsized() { sized = false; } @@ -451,6 +447,10 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } } + if sized && fields.iter().any(|f| f.abi == Abi::Uninhabited) { + abi = Abi::Uninhabited; + } + Ok(LayoutDetails { variants: Variants::Single { index: 0 }, fields: FieldPlacement::Arbitrary { @@ -497,7 +497,13 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // The never type. ty::TyNever => { - tcx.intern_layout(LayoutDetails::uninhabited(0)) + tcx.intern_layout(LayoutDetails { + variants: Variants::Single { index: 0 }, + fields: FieldPlacement::Union(0), + abi: Abi::Uninhabited, + align: dl.i8_align, + size: Size::from_bytes(0) + }) } // Potentially-fat pointers. @@ -711,27 +717,37 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { })); } - let (inh_first, inh_second) = { - let mut inh_variants = (0..variants.len()).filter(|&v| { - variants[v].iter().all(|f| f.abi != Abi::Uninhabited) + // A variant is absent if it's uninhabited and only has ZST fields. + // Present uninhabited variants only require space for their fields, + // but *not* an encoding of the discriminant (e.g. a tag value). + // See issue #49298 for more details on the need to leave space + // for non-ZST uninhabited data (mostly partial initialization). + let absent = |fields: &[TyLayout]| { + let uninhabited = fields.iter().any(|f| f.abi == Abi::Uninhabited); + let is_zst = fields.iter().all(|f| f.is_zst()); + uninhabited && is_zst + }; + let (present_first, present_second) = { + let mut present_variants = (0..variants.len()).filter(|&v| { + !absent(&variants[v]) }); - (inh_variants.next(), inh_variants.next()) + (present_variants.next(), present_variants.next()) }; - if inh_first.is_none() { - // Uninhabited because it has no variants, or only uninhabited ones. - return Ok(tcx.intern_layout(LayoutDetails::uninhabited(0))); + if present_first.is_none() { + // Uninhabited because it has no variants, or only absent ones. + return tcx.layout_raw(param_env.and(tcx.types.never)); } let is_struct = !def.is_enum() || - // Only one variant is inhabited. - (inh_second.is_none() && + // Only one variant is present. + (present_second.is_none() && // Representation optimizations are allowed. !def.repr.inhibit_enum_layout_opt()); if is_struct { // Struct, or univariant enum equivalent to a struct. // (Typechecking will reject discriminant-sizing attrs.) - let v = inh_first.unwrap(); + let v = present_first.unwrap(); let kind = if def.is_enum() || variants[v].len() == 0 { StructKind::AlwaysSized } else { @@ -773,7 +789,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // Find one non-ZST variant. 'variants: for (v, fields) in variants.iter().enumerate() { - if fields.iter().any(|f| f.abi == Abi::Uninhabited) { + if absent(fields) { continue 'variants; } for f in fields { @@ -816,7 +832,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let offset = st[i].fields.offset(field_index) + offset; let size = st[i].size; - let abi = match st[i].abi { + let mut abi = match st[i].abi { Abi::Scalar(_) => Abi::Scalar(niche.clone()), Abi::ScalarPair(ref first, ref second) => { // We need to use scalar_unit to reset the @@ -833,6 +849,10 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { _ => Abi::Aggregate { sized: true }, }; + if st.iter().all(|v| v.abi == Abi::Uninhabited) { + abi = Abi::Uninhabited; + } + return Ok(tcx.intern_layout(LayoutDetails { variants: Variants::NicheFilling { dataful_variant: i, @@ -959,9 +979,6 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let old_ity_size = min_ity.size(); let new_ity_size = ity.size(); for variant in &mut layout_variants { - if variant.abi == Abi::Uninhabited { - continue; - } match variant.fields { FieldPlacement::Arbitrary { ref mut offsets, .. } => { for i in offsets { @@ -1055,6 +1072,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } } } + + if layout_variants.iter().all(|v| v.abi == Abi::Uninhabited) { + abi = Abi::Uninhabited; + } + tcx.intern_layout(LayoutDetails { variants: Variants::Tagged { tag, @@ -1523,9 +1545,14 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> ty::TyAdt(def, _) => def.variants[variant_index].fields.len(), _ => bug!() }; - let mut details = LayoutDetails::uninhabited(fields); - details.variants = Variants::Single { index: variant_index }; - cx.tcx().intern_layout(details) + let tcx = cx.tcx(); + tcx.intern_layout(LayoutDetails { + variants: Variants::Single { index: variant_index }, + fields: FieldPlacement::Union(fields), + abi: Abi::Uninhabited, + align: tcx.data_layout.i8_align, + size: Size::from_bytes(0) + }) } Variants::NicheFilling { ref variants, .. } | diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 76803f4503129..fdd0754730feb 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -16,7 +16,7 @@ use hir::map::{DefPathData, Node}; use hir; use ich::NodeIdHashingMode; use middle::const_val::ConstVal; -use traits; +use traits::{self, ObligationCause}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::TypeVisitor; use ty::subst::UnpackedKind; @@ -166,9 +166,9 @@ impl IntTypeExt for attr::IntType { } -#[derive(Copy, Clone)] +#[derive(Clone)] pub enum CopyImplementationError<'tcx> { - InfrigingField(&'tcx ty::FieldDef), + InfrigingFields(Vec<&'tcx ty::FieldDef>), NotAnAdt, HasDestructor, } @@ -191,7 +191,7 @@ pub enum Representability { impl<'tcx> ty::ParamEnv<'tcx> { pub fn can_type_implement_copy<'a>(self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - self_type: Ty<'tcx>, span: Span) + self_type: Ty<'tcx>) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt().enter(|infcx| { @@ -207,22 +207,29 @@ impl<'tcx> ty::ParamEnv<'tcx> { _ => return Err(CopyImplementationError::NotAnAdt), }; - let field_implements_copy = |field: &ty::FieldDef| { - let cause = traits::ObligationCause::dummy(); - match traits::fully_normalize(&infcx, cause, self, &field.ty(tcx, substs)) { - Ok(ty) => !infcx.type_moves_by_default(self, ty, span), - Err(..) => false, - } - }; - + let mut infringing = Vec::new(); for variant in &adt.variants { for field in &variant.fields { - if !field_implements_copy(field) { - return Err(CopyImplementationError::InfrigingField(field)); + let span = tcx.def_span(field.did); + let ty = field.ty(tcx, substs); + if ty.references_error() { + continue; } + let cause = ObligationCause { span, ..ObligationCause::dummy() }; + let ctx = traits::FulfillmentContext::new(); + match traits::fully_normalize(&infcx, ctx, cause, self, &ty) { + Ok(ty) => if infcx.type_moves_by_default(self, ty, span) { + infringing.push(field); + } + Err(errors) => { + infcx.report_fulfillment_errors(&errors, None, false); + } + }; } } - + if !infringing.is_empty() { + return Err(CopyImplementationError::InfrigingFields(infringing)); + } if adt.has_dtor(tcx) { return Err(CopyImplementationError::HasDestructor); } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 9178d0d00faa4..6f1cbcad2f46c 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -16,6 +16,7 @@ serialize = { path = "../libserialize" } cfg-if = "0.1.2" stable_deref_trait = "1.0.0" parking_lot_core = "0.2.8" +rustc-rayon = "0.1.0" [dependencies.parking_lot] version = "0.5" diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 597d1627ada03..b2e7450e76cdf 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -44,6 +44,7 @@ extern crate parking_lot; #[macro_use] extern crate cfg_if; extern crate stable_deref_trait; +extern crate rustc_rayon as rayon; // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 3b7d6efbdae1e..3661763133014 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! This mdoule defines types which are thread safe if cfg!(parallel_queries) is true. +//! This module defines types which are thread safe if cfg!(parallel_queries) is true. //! //! `Lrc` is an alias of either Rc or Arc. //! @@ -40,6 +40,29 @@ use std; use std::ops::{Deref, DerefMut}; use owning_ref::{Erased, OwningRef}; +pub fn serial_join(oper_a: A, oper_b: B) -> (RA, RB) + where A: FnOnce() -> RA, + B: FnOnce() -> RB +{ + (oper_a(), oper_b()) +} + +pub struct SerialScope; + +impl SerialScope { + pub fn spawn(&self, f: F) + where F: FnOnce(&SerialScope) + { + f(self) + } +} + +pub fn serial_scope(f: F) -> R + where F: FnOnce(&SerialScope) -> R +{ + f(&SerialScope) +} + cfg_if! { if #[cfg(not(parallel_queries))] { pub auto trait Send {} @@ -55,9 +78,19 @@ cfg_if! { } } + pub use self::serial_join as join; + pub use self::serial_scope as scope; + + pub use std::iter::Iterator as ParallelIterator; + + pub fn par_iter(t: T) -> T::IntoIter { + t.into_iter() + } + pub type MetadataRef = OwningRef, [u8]>; pub use std::rc::Rc as Lrc; + pub use std::rc::Weak as Weak; pub use std::cell::Ref as ReadGuard; pub use std::cell::RefMut as WriteGuard; pub use std::cell::RefMut as LockGuard; @@ -160,6 +193,7 @@ cfg_if! { pub use parking_lot::MutexGuard as LockGuard; pub use std::sync::Arc as Lrc; + pub use std::sync::Weak as Weak; pub use self::Lock as MTLock; @@ -167,6 +201,14 @@ cfg_if! { use parking_lot::RwLock as InnerRwLock; use std::thread; + pub use rayon::{join, scope}; + + pub use rayon::iter::ParallelIterator; + use rayon::iter::IntoParallelIterator; + + pub fn par_iter(t: T) -> T::Iter { + t.into_par_iter() + } pub type MetadataRef = OwningRef, [u8]>; diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 5aae1bcad896f..1827533f0acb5 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -13,6 +13,8 @@ arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } log = "0.4" env_logger = { version = "0.5", default-features = false } +rustc-rayon = "0.1.0" +scoped-tls = { version = "0.1.1", features = ["nightly"] } rustc = { path = "../librustc" } rustc_allocator = { path = "../librustc_allocator" } rustc_target = { path = "../librustc_target" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 1e74039503d51..62b3accc46f18 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -20,7 +20,7 @@ use rustc::session::config::{self, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc::lint; use rustc::middle::{self, reachable, resolve_lifetime, stability}; -use rustc::middle::cstore::CrateStore; +use rustc::middle::cstore::CrateStoreDyn; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, AllArenas, Resolutions, TyCtxt}; use rustc::traits; @@ -49,7 +49,7 @@ use std::fs; use std::io::{self, Write}; use std::iter; use std::path::{Path, PathBuf}; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{self, Lrc}; use std::sync::mpsc; use syntax::{self, ast, attr, diagnostics, visit}; use syntax::ext::base::ExtCtxt; @@ -64,6 +64,51 @@ use pretty::ReplaceBodyWithLoop; use profile; +#[cfg(not(parallel_queries))] +pub fn spawn_thread_pool R + sync::Send, R: sync::Send>( + opts: config::Options, + f: F +) -> R { + f(opts) +} + +#[cfg(parallel_queries)] +pub fn spawn_thread_pool R + sync::Send, R: sync::Send>( + opts: config::Options, + f: F +) -> R { + use syntax; + use syntax_pos; + use rayon::{ThreadPoolBuilder, ThreadPool}; + + let config = ThreadPoolBuilder::new().num_threads(Session::query_threads_from_opts(&opts)) + .stack_size(16 * 1024 * 1024); + + let with_pool = move |pool: &ThreadPool| { + pool.install(move || f(opts)) + }; + + syntax::GLOBALS.with(|syntax_globals| { + syntax_pos::GLOBALS.with(|syntax_pos_globals| { + // The main handler run for each Rayon worker thread and sets up + // the thread local rustc uses. syntax_globals and syntax_pos_globals are + // captured and set on the new threads. ty::tls::with_thread_locals sets up + // thread local callbacks from libsyntax + let main_handler = move |worker: &mut FnMut()| { + syntax::GLOBALS.set(syntax_globals, || { + syntax_pos::GLOBALS.set(syntax_pos_globals, || { + ty::tls::with_thread_locals(|| { + worker() + }) + }) + }) + }; + + ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap() + }) + }) +} + pub fn compile_input( trans: Box, sess: &Session, @@ -1047,7 +1092,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>( trans: &TransCrate, control: &CompileController, sess: &'tcx Session, - cstore: &'tcx CrateStore, + cstore: &'tcx CrateStoreDyn, hir_map: hir_map::Map<'tcx>, mut analysis: ty::CrateAnalysis, resolutions: Resolutions, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index a1052ca6c3ca9..148fbd73e9bd8 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -27,12 +27,15 @@ #![feature(rustc_stack_internals)] #![feature(no_debug)] +#![recursion_limit="256"] + extern crate arena; extern crate getopts; extern crate graphviz; extern crate env_logger; #[cfg(unix)] extern crate libc; +extern crate rustc_rayon as rayon; extern crate rustc; extern crate rustc_allocator; extern crate rustc_target; @@ -51,6 +54,7 @@ extern crate rustc_save_analysis; extern crate rustc_traits; extern crate rustc_trans_utils; extern crate rustc_typeck; +extern crate scoped_tls; extern crate serialize; #[macro_use] extern crate log; @@ -64,7 +68,7 @@ use pretty::{PpMode, UserIdentifiedItem}; use rustc_resolve as resolve; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{self, Lrc}; use rustc_data_structures::OnDrop; use rustc::session::{self, config, Session, build_session, CompileResult}; use rustc::session::CompileIncomplete; @@ -448,22 +452,33 @@ fn get_trans_sysroot(backend_name: &str) -> fn() -> Box { // See comments on CompilerCalls below for details about the callbacks argument. // The FileLoader provides a way to load files from sources other than the file system. pub fn run_compiler<'a>(args: &[String], - callbacks: &mut CompilerCalls<'a>, + callbacks: &mut (CompilerCalls<'a> + sync::Send), file_loader: Option>, emitter_dest: Option>) -> (CompileResult, Option) { syntax::with_globals(|| { - run_compiler_impl(args, callbacks, file_loader, emitter_dest) + let matches = match handle_options(args) { + Some(matches) => matches, + None => return (Ok(()), None), + }; + + let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); + + driver::spawn_thread_pool(sopts, |sopts| { + run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest) + }) }) } -fn run_compiler_impl<'a>(args: &[String], - callbacks: &mut CompilerCalls<'a>, - file_loader: Option>, - emitter_dest: Option>) - -> (CompileResult, Option) -{ +fn run_compiler_with_pool<'a>( + matches: getopts::Matches, + sopts: config::Options, + cfg: ast::CrateConfig, + callbacks: &mut (CompilerCalls<'a> + sync::Send), + file_loader: Option>, + emitter_dest: Option> +) -> (CompileResult, Option) { macro_rules! do_or_return {($expr: expr, $sess: expr) => { match $expr { Compilation::Stop => return (Ok(()), $sess), @@ -471,13 +486,6 @@ fn run_compiler_impl<'a>(args: &[String], } }} - let matches = match handle_options(args) { - Some(matches) => matches, - None => return (Ok(()), None), - }; - - let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); - let descriptions = diagnostics_registry(); do_or_return!(callbacks.early_callback(&matches, diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 70b73ebb8cdeb..108b47623383c 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -20,7 +20,7 @@ use {abort_on_err, driver}; use rustc::ty::{self, TyCtxt, Resolutions, AllArenas}; use rustc::cfg; use rustc::cfg::graphviz::LabelledCFG; -use rustc::middle::cstore::CrateStore; +use rustc::middle::cstore::CrateStoreDyn; use rustc::session::Session; use rustc::session::config::{Input, OutputFilenames}; use rustc_borrowck as borrowck; @@ -199,7 +199,7 @@ impl PpSourceMode { } fn call_with_pp_support_hir<'tcx, A, F>(&self, sess: &'tcx Session, - cstore: &'tcx CrateStore, + cstore: &'tcx CrateStoreDyn, hir_map: &hir_map::Map<'tcx>, analysis: &ty::CrateAnalysis, resolutions: &Resolutions, @@ -912,7 +912,7 @@ pub fn print_after_parsing(sess: &Session, } pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, - cstore: &'tcx CrateStore, + cstore: &'tcx CrateStoreDyn, hir_map: &hir_map::Map<'tcx>, analysis: &ty::CrateAnalysis, resolutions: &Resolutions, @@ -1068,7 +1068,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, // with a different callback than the standard driver, so that isn't easy. // Instead, we call that function ourselves. fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, - cstore: &'a CrateStore, + cstore: &'a CrateStoreDyn, hir_map: &hir_map::Map<'tcx>, analysis: &ty::CrateAnalysis, resolutions: &Resolutions, diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index d2ee3d8743c2c..7ae26e9e9798e 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -99,20 +99,25 @@ fn test_env(source_string: &str, where F: FnOnce(Env) { syntax::with_globals(|| { - test_env_impl(source_string, args, body) + let mut options = config::basic_options(); + options.debugging_opts.verbose = true; + options.unstable_features = UnstableFeatures::Allow; + + driver::spawn_thread_pool(options, |options| { + test_env_with_pool(options, source_string, args, body) + }) }); } -fn test_env_impl(source_string: &str, - (emitter, expected_err_count): (Box, usize), - body: F) +fn test_env_with_pool( + options: config::Options, + source_string: &str, + (emitter, expected_err_count): (Box, usize), + body: F +) where F: FnOnce(Env) { - let mut options = config::basic_options(); - options.debugging_opts.verbose = true; - options.unstable_features = UnstableFeatures::Allow; let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter); - let sess = session::build_session_(options, None, diagnostic_handler, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 0fb78b9f1b81d..c2dcbad8d2451 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -541,7 +541,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { if !ty.moves_by_default(cx.tcx, param_env, item.span) { return; } - if param_env.can_type_implement_copy(cx.tcx, ty, item.span).is_ok() { + if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() { cx.span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, "type could implement `Copy`; consider adding `impl \ @@ -1568,10 +1568,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExternCrate { if let Some(orig) = orig { err.span_suggestion(it.span, &help, - format!("{}use {} as {}", pub_, orig, it.name)); + format!("{}use {} as {};", pub_, orig, it.name)); } else { err.span_suggestion(it.span, &help, - format!("{}use {}", pub_, it.name)); + format!("{}use {};", pub_, it.name)); } } else { err.span_suggestion(it.span, "remove it", "".into()); diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 6708640379a54..4789e2e50ca54 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -114,7 +114,7 @@ impl<'a> AstValidator<'a> { } } - /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus), + /// matches '-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus), /// or path for ranges. /// /// FIXME: do we want to allow expr -> pattern conversion to create path expressions? diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 7ae4d990c8a4e..6cd8e267ec5c1 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -761,17 +761,6 @@ impl LayoutDetails { align, } } - - pub fn uninhabited(field_count: usize) -> Self { - let align = Align::from_bytes(1, 1).unwrap(); - LayoutDetails { - variants: Variants::Single { index: 0 }, - fields: FieldPlacement::Union(field_count), - abi: Abi::Uninhabited, - align, - size: Size::from_bytes(0) - } - } } /// The details of the layout of a type, alongside the type itself. @@ -826,10 +815,10 @@ impl<'a, Ty> TyLayout<'a, Ty> { /// Returns true if the type is a ZST and not unsized. pub fn is_zst(&self) -> bool { match self.abi { - Abi::Uninhabited => true, Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, + Abi::Uninhabited => self.size.bytes() == 0, Abi::Aggregate { sized } => sized && self.size.bytes() == 0 } } diff --git a/src/librustc_target/spec/aarch64_unknown_openbsd.rs b/src/librustc_target/spec/aarch64_unknown_openbsd.rs new file mode 100644 index 0000000000000..25817fce5ce6c --- /dev/null +++ b/src/librustc_target/spec/aarch64_unknown_openbsd.rs @@ -0,0 +1,31 @@ +// 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. + +use spec::{LinkerFlavor, Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::openbsd_base::opts(); + base.max_atomic_width = Some(128); + base.abi_blacklist = super::arm_base::abi_blacklist(); + + Ok(Target { + llvm_target: "aarch64-unknown-openbsd".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), + arch: "aarch64".to_string(), + target_os: "openbsd".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: base, + }) +} diff --git a/src/librustc_target/spec/i686_unknown_openbsd.rs b/src/librustc_target/spec/i686_unknown_openbsd.rs index 79c059c8f952d..f22bf2abe4501 100644 --- a/src/librustc_target/spec/i686_unknown_openbsd.rs +++ b/src/librustc_target/spec/i686_unknown_openbsd.rs @@ -15,6 +15,7 @@ pub fn target() -> TargetResult { base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-fuse-ld=lld".to_string()); base.stack_probes = true; Ok(Target { diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 708a3865b23b9..fb20fe9c8918f 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -313,6 +313,7 @@ supported_targets! { ("x86_64-unknown-bitrig", x86_64_unknown_bitrig), + ("aarch64-unknown-openbsd", aarch64_unknown_openbsd), ("i686-unknown-openbsd", i686_unknown_openbsd), ("x86_64-unknown-openbsd", x86_64_unknown_openbsd), diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 432ac44e0a566..d2bf83942968d 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -217,12 +217,9 @@ impl<'a, 'tcx> OperandRef<'tcx> { let offset = self.layout.fields.offset(i); let mut val = match (self.val, &self.layout.abi) { - // If we're uninhabited, or the field is ZST, it has no data. - _ if self.layout.abi == layout::Abi::Uninhabited || field.is_zst() => { - return OperandRef { - val: OperandValue::Immediate(C_undef(field.immediate_llvm_type(bx.cx))), - layout: field - }; + // If the field is ZST, it has no data. + _ if field.is_zst() => { + return OperandRef::new_zst(bx.cx, field); } // Newtype of a scalar, scalar pair or vector. diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index f736e81202a38..32d26052aff5d 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -213,10 +213,10 @@ pub trait LayoutLlvmExt<'tcx> { impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { fn is_llvm_immediate(&self) -> bool { match self.abi { - layout::Abi::Uninhabited | layout::Abi::Scalar(_) | layout::Abi::Vector { .. } => true, layout::Abi::ScalarPair(..) => false, + layout::Abi::Uninhabited | layout::Abi::Aggregate { .. } => self.is_zst() } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7b859635f60df..b9c035e1ca10e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3278,7 +3278,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span, variant: &'tcx ty::VariantDef, ast_fields: &'gcx [hir::Field], - check_completeness: bool) { + check_completeness: bool) -> bool { let tcx = self.tcx; let adt_ty_hint = @@ -3380,6 +3380,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { truncated_fields_error)) .emit(); } + error_happened } fn check_struct_fields_on_error(&self, @@ -3478,24 +3479,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span, variant, fields, - base_expr.is_none()); + let error_happened = self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span, + variant, fields, base_expr.is_none()); if let &Some(ref base_expr) = base_expr { - self.check_expr_has_type_or_error(base_expr, struct_ty); - match struct_ty.sty { - ty::TyAdt(adt, substs) if adt.is_struct() => { - let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| { - self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs)) - }).collect(); - - self.tables - .borrow_mut() - .fru_field_types_mut() - .insert(expr.hir_id, fru_field_types); - } - _ => { - span_err!(self.tcx.sess, base_expr.span, E0436, - "functional record update syntax requires a struct"); + // If check_expr_struct_fields hit an error, do not attempt to populate + // the fields with the base_expr. This could cause us to hit errors later + // when certain fields are assumed to exist that in fact do not. + if !error_happened { + self.check_expr_has_type_or_error(base_expr, struct_ty); + match struct_ty.sty { + ty::TyAdt(adt, substs) if adt.is_struct() => { + let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| { + self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs)) + }).collect(); + + self.tables + .borrow_mut() + .fru_field_types_mut() + .insert(expr.hir_id, fru_field_types); + } + _ => { + span_err!(self.tcx.sess, base_expr.span, E0436, + "functional record update syntax requires a struct"); + } } } } diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 3424a31e09df0..2f08a54e10f08 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -111,9 +111,9 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type); - match param_env.can_type_implement_copy(tcx, self_type, span) { + match param_env.can_type_implement_copy(tcx, self_type) { Ok(()) => {} - Err(CopyImplementationError::InfrigingField(field)) => { + Err(CopyImplementationError::InfrigingFields(fields)) => { let item = tcx.hir.expect_item(impl_node_id); let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node { tr.path.span @@ -121,14 +121,14 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span }; - struct_span_err!(tcx.sess, - span, - E0204, - "the trait `Copy` may not be implemented for this type") - .span_label( - tcx.def_span(field.did), - "this field does not implement `Copy`") - .emit() + let mut err = struct_span_err!(tcx.sess, + span, + E0204, + "the trait `Copy` may not be implemented for this type"); + for span in fields.iter().map(|f| tcx.def_span(f.did)) { + err.span_label(span, "this field does not implement `Copy`"); + } + err.emit() } Err(CopyImplementationError::NotAnAdt) => { let item = tcx.hir.expect_item(impl_node_id); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3ffdd5595a2d5..7d3ba79282938 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -697,7 +697,7 @@ impl<'a> FromIterator<&'a DocFragment> for String { pub struct Attributes { pub doc_strings: Vec, pub other_attrs: Vec, - pub cfg: Option>, + pub cfg: Option>, pub span: Option, /// map from Rust paths to resolved defs and potential URL fragments pub links: Vec<(String, Option, Option)>, @@ -848,7 +848,7 @@ impl Attributes { Attributes { doc_strings, other_attrs, - cfg: if cfg == Cfg::True { None } else { Some(Rc::new(cfg)) }, + cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }, span: sp, links: vec![], } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 61fb0b40c2315..6222edd5450f0 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -161,161 +161,162 @@ pub fn run_core(search_paths: SearchPaths, edition, ..config::basic_options().clone() }; - - let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping())); - let emitter: Box = match error_format { - ErrorOutputType::HumanReadable(color_config) => Box::new( - EmitterWriter::stderr( - color_config, - Some(codemap.clone()), - false, - sessopts.debugging_opts.teach, - ).ui_testing(sessopts.debugging_opts.ui_testing) - ), - ErrorOutputType::Json(pretty) => Box::new( - JsonEmitter::stderr( - None, - codemap.clone(), - pretty, - sessopts.debugging_opts.suggestion_applicability, - ).ui_testing(sessopts.debugging_opts.ui_testing) - ), - ErrorOutputType::Short(color_config) => Box::new( - EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false) - ), - }; - - let diagnostic_handler = errors::Handler::with_emitter_and_flags( - emitter, - errors::HandlerFlags { - can_emit_warnings: true, - treat_err_as_bug: false, - external_macro_backtrace: false, - ..Default::default() - }, - ); - - let mut sess = session::build_session_( - sessopts, cpath, diagnostic_handler, codemap, - ); - let trans = rustc_driver::get_trans(&sess); - let cstore = Rc::new(CStore::new(trans.metadata_loader())); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - - let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs)); - target_features::add_configuration(&mut cfg, &sess, &*trans); - sess.parse_sess.config = cfg; - - let control = &driver::CompileController::basic(); - - let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input)); - - let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input); - - let mut crate_loader = CrateLoader::new(&sess, &cstore, &name); - - let resolver_arenas = resolve::Resolver::arenas(); - let result = driver::phase_2_configure_and_expand_inner(&sess, - &cstore, - krate, - None, - &name, - None, - resolve::MakeGlobMap::No, - &resolver_arenas, - &mut crate_loader, - |_| Ok(())); - let driver::InnerExpansionResult { - mut hir_forest, - resolver, - .. - } = abort_on_err(result, &sess); - - // We need to hold on to the complete resolver, so we clone everything - // for the analysis passes to use. Suboptimal, but necessary in the - // current architecture. - let defs = resolver.definitions.clone(); - let resolutions = ty::Resolutions { - freevars: resolver.freevars.clone(), - export_map: resolver.export_map.clone(), - trait_map: resolver.trait_map.clone(), - maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(), - maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(), - }; - let analysis = ty::CrateAnalysis { - access_levels: Lrc::new(AccessLevels::default()), - name: name.to_string(), - glob_map: if resolver.make_glob_map { Some(resolver.glob_map.clone()) } else { None }, - }; - - let arenas = AllArenas::new(); - let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs); - let output_filenames = driver::build_output_filenames(&input, - &None, - &None, - &[], - &sess); - - let resolver = RefCell::new(resolver); - - abort_on_err(driver::phase_3_run_analysis_passes(&*trans, - control, - &sess, - &*cstore, - hir_map, - analysis, - resolutions, - &arenas, - &name, - &output_filenames, - |tcx, analysis, _, result| { - if let Err(_) = result { - sess.fatal("Compilation failed, aborting rustdoc"); - } - - let ty::CrateAnalysis { access_levels, .. } = analysis; - - // Convert from a NodeId set to a DefId set since we don't always have easy access - // to the map from defid -> nodeid - let access_levels = AccessLevels { - map: access_levels.map.iter() - .map(|(&k, &v)| (tcx.hir.local_def_id(k), v)) - .collect() + driver::spawn_thread_pool(sessopts, move |sessopts| { + let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping())); + let emitter: Box = match error_format { + ErrorOutputType::HumanReadable(color_config) => Box::new( + EmitterWriter::stderr( + color_config, + Some(codemap.clone()), + false, + sessopts.debugging_opts.teach, + ).ui_testing(sessopts.debugging_opts.ui_testing) + ), + ErrorOutputType::Json(pretty) => Box::new( + JsonEmitter::stderr( + None, + codemap.clone(), + pretty, + sessopts.debugging_opts.suggestion_applicability, + ).ui_testing(sessopts.debugging_opts.ui_testing) + ), + ErrorOutputType::Short(color_config) => Box::new( + EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false) + ), }; - let send_trait = if crate_name == Some("core".to_string()) { - clean::get_trait_def_id(&tcx, &["marker", "Send"], true) - } else { - clean::get_trait_def_id(&tcx, &["core", "marker", "Send"], false) + let diagnostic_handler = errors::Handler::with_emitter_and_flags( + emitter, + errors::HandlerFlags { + can_emit_warnings: true, + treat_err_as_bug: false, + external_macro_backtrace: false, + ..Default::default() + }, + ); + + let mut sess = session::build_session_( + sessopts, cpath, diagnostic_handler, codemap, + ); + let trans = rustc_driver::get_trans(&sess); + let cstore = Rc::new(CStore::new(trans.metadata_loader())); + rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + + let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs)); + target_features::add_configuration(&mut cfg, &sess, &*trans); + sess.parse_sess.config = cfg; + + let control = &driver::CompileController::basic(); + + let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input)); + + let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input); + + let mut crate_loader = CrateLoader::new(&sess, &cstore, &name); + + let resolver_arenas = resolve::Resolver::arenas(); + let result = driver::phase_2_configure_and_expand_inner(&sess, + &cstore, + krate, + None, + &name, + None, + resolve::MakeGlobMap::No, + &resolver_arenas, + &mut crate_loader, + |_| Ok(())); + let driver::InnerExpansionResult { + mut hir_forest, + resolver, + .. + } = abort_on_err(result, &sess); + + // We need to hold on to the complete resolver, so we clone everything + // for the analysis passes to use. Suboptimal, but necessary in the + // current architecture. + let defs = resolver.definitions.clone(); + let resolutions = ty::Resolutions { + freevars: resolver.freevars.clone(), + export_map: resolver.export_map.clone(), + trait_map: resolver.trait_map.clone(), + maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(), + maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(), }; - - let ctxt = DocContext { - tcx, - resolver: &resolver, - crate_name, - cstore: cstore.clone(), - populated_all_crate_impls: Cell::new(false), - access_levels: RefCell::new(access_levels), - external_traits: Default::default(), - active_extern_traits: Default::default(), - renderinfo: Default::default(), - ty_substs: Default::default(), - lt_substs: Default::default(), - impl_trait_bounds: Default::default(), - mod_ids: Default::default(), - send_trait: send_trait, - fake_def_ids: RefCell::new(FxHashMap()), - all_fake_def_ids: RefCell::new(FxHashSet()), - generated_synthetics: RefCell::new(FxHashSet()), - }; - debug!("crate: {:?}", tcx.hir.krate()); - - let krate = { - let mut v = RustdocVisitor::new(&*cstore, &ctxt); - v.visit(tcx.hir.krate()); - v.clean(&ctxt) + let analysis = ty::CrateAnalysis { + access_levels: Lrc::new(AccessLevels::default()), + name: name.to_string(), + glob_map: if resolver.make_glob_map { Some(resolver.glob_map.clone()) } else { None }, }; - (krate, ctxt.renderinfo.into_inner()) - }), &sess) + let arenas = AllArenas::new(); + let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs); + let output_filenames = driver::build_output_filenames(&input, + &None, + &None, + &[], + &sess); + + let resolver = RefCell::new(resolver); + + abort_on_err(driver::phase_3_run_analysis_passes(&*trans, + control, + &sess, + &*cstore, + hir_map, + analysis, + resolutions, + &arenas, + &name, + &output_filenames, + |tcx, analysis, _, result| { + if let Err(_) = result { + sess.fatal("Compilation failed, aborting rustdoc"); + } + + let ty::CrateAnalysis { access_levels, .. } = analysis; + + // Convert from a NodeId set to a DefId set since we don't always have easy access + // to the map from defid -> nodeid + let access_levels = AccessLevels { + map: access_levels.map.iter() + .map(|(&k, &v)| (tcx.hir.local_def_id(k), v)) + .collect() + }; + + let send_trait = if crate_name == Some("core".to_string()) { + clean::get_trait_def_id(&tcx, &["marker", "Send"], true) + } else { + clean::get_trait_def_id(&tcx, &["core", "marker", "Send"], false) + }; + + let ctxt = DocContext { + tcx, + resolver: &resolver, + crate_name, + cstore: cstore.clone(), + populated_all_crate_impls: Cell::new(false), + access_levels: RefCell::new(access_levels), + external_traits: Default::default(), + active_extern_traits: Default::default(), + renderinfo: Default::default(), + ty_substs: Default::default(), + lt_substs: Default::default(), + impl_trait_bounds: Default::default(), + mod_ids: Default::default(), + send_trait: send_trait, + fake_def_ids: RefCell::new(FxHashMap()), + all_fake_def_ids: RefCell::new(FxHashSet()), + generated_synthetics: RefCell::new(FxHashSet()), + }; + debug!("crate: {:?}", tcx.hir.krate()); + + let krate = { + let mut v = RustdocVisitor::new(&*cstore, &ctxt); + v.visit(tcx.hir.krate()); + v.clean(&ctxt) + }; + + (krate, ctxt.renderinfo.into_inner()) + }), &sess) + }) } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 059d41698953d..f2da09e16036e 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -26,6 +26,8 @@ #![feature(vec_remove_item)] #![feature(entry_and_modify)] +#![recursion_limit="256"] + extern crate arena; extern crate getopts; extern crate env_logger; diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 9e65fff5e2ac6..fc8abafd4d89b 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::rc::Rc; +use std::sync::Arc; use clean::{Crate, Item}; use clean::cfg::Cfg; @@ -20,7 +20,7 @@ pub fn propagate_doc_cfg(cr: Crate) -> PluginResult { } struct CfgPropagator { - parent_cfg: Option>, + parent_cfg: Option>, } impl DocFolder for CfgPropagator { @@ -31,8 +31,8 @@ impl DocFolder for CfgPropagator { (None, None) => None, (Some(rc), None) | (None, Some(rc)) => Some(rc), (Some(mut a), Some(b)) => { - let b = Rc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc)); - *Rc::make_mut(&mut a) &= b; + let b = Arc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc)); + *Arc::make_mut(&mut a) &= b; Some(a) } }; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index c4eaa48e49db6..7be7ce313fcff 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -85,77 +85,80 @@ pub fn run(input_path: &Path, edition, ..config::basic_options().clone() }; - - let codemap = Lrc::new(CodeMap::new(sessopts.file_path_mapping())); - let handler = - errors::Handler::with_tty_emitter(ColorConfig::Auto, - true, false, - Some(codemap.clone())); - - let mut sess = session::build_session_( - sessopts, Some(input_path.to_owned()), handler, codemap.clone(), - ); - let trans = rustc_driver::get_trans(&sess); - let cstore = CStore::new(trans.metadata_loader()); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - - let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); - target_features::add_configuration(&mut cfg, &sess, &*trans); - sess.parse_sess.config = cfg; - - let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(), - &sess, - &input)); - let driver::ExpansionResult { defs, mut hir_forest, .. } = { - phase_2_configure_and_expand( - &sess, - &cstore, - krate, - None, - "rustdoc-test", - None, - MakeGlobMap::No, - |_| Ok(()), - ).expect("phase_2_configure_and_expand aborted in rustdoc!") - }; - - let crate_name = crate_name.unwrap_or_else(|| { - ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input) - }); - let mut opts = scrape_test_config(hir_forest.krate()); - opts.display_warnings |= display_warnings; - let mut collector = Collector::new(crate_name, - cfgs, - libs, - cg, - externs, - false, - opts, - maybe_sysroot, - Some(codemap), - None, - linker, - edition); - - { - let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs); - let krate = map.krate(); - let mut hir_collector = HirCollector { - sess: &sess, - collector: &mut collector, - map: &map + driver::spawn_thread_pool(sessopts, |sessopts| { + let codemap = Lrc::new(CodeMap::new(sessopts.file_path_mapping())); + let handler = + errors::Handler::with_tty_emitter(ColorConfig::Auto, + true, false, + Some(codemap.clone())); + + let mut sess = session::build_session_( + sessopts, Some(input_path.to_owned()), handler, codemap.clone(), + ); + let trans = rustc_driver::get_trans(&sess); + let cstore = CStore::new(trans.metadata_loader()); + rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + + let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); + target_features::add_configuration(&mut cfg, &sess, &*trans); + sess.parse_sess.config = cfg; + + let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(), + &sess, + &input)); + let driver::ExpansionResult { defs, mut hir_forest, .. } = { + phase_2_configure_and_expand( + &sess, + &cstore, + krate, + None, + "rustdoc-test", + None, + MakeGlobMap::No, + |_| Ok(()), + ).expect("phase_2_configure_and_expand aborted in rustdoc!") }; - hir_collector.visit_testable("".to_string(), &krate.attrs, |this| { - intravisit::walk_crate(this, krate); + + let crate_name = crate_name.unwrap_or_else(|| { + ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input) }); - } + let mut opts = scrape_test_config(hir_forest.krate()); + opts.display_warnings |= display_warnings; + let mut collector = Collector::new( + crate_name, + cfgs, + libs, + cg, + externs, + false, + opts, + maybe_sysroot, + Some(codemap), + None, + linker, + edition + ); + + { + let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs); + let krate = map.krate(); + let mut hir_collector = HirCollector { + sess: &sess, + collector: &mut collector, + map: &map + }; + hir_collector.visit_testable("".to_string(), &krate.attrs, |this| { + intravisit::walk_crate(this, krate); + }); + } - test_args.insert(0, "rustdoctest".to_string()); + test_args.insert(0, "rustdoctest".to_string()); - testing::test_main(&test_args, - collector.tests.into_iter().collect(), - testing::Options::new().display_output(display_warnings)); - 0 + testing::test_main(&test_args, + collector.tests.into_iter().collect(), + testing::Options::new().display_output(display_warnings)); + 0 + }) } // Look for #![doc(test(no_crate_inject))], used by crates in the std facade @@ -229,102 +232,106 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, ..config::basic_options().clone() }; - // Shuffle around a few input and output handles here. We're going to pass - // an explicit handle into rustc to collect output messages, but we also - // want to catch the error message that rustc prints when it fails. - // - // We take our thread-local stderr (likely set by the test runner) and replace - // it with a sink that is also passed to rustc itself. When this function - // returns the output of the sink is copied onto the output of our own thread. - // - // The basic idea is to not use a default Handler for rustc, and then also - // not print things by default to the actual stderr. - struct Sink(Arc>>); - impl Write for Sink { - fn write(&mut self, data: &[u8]) -> io::Result { - Write::write(&mut *self.0.lock().unwrap(), data) + let (libdir, outdir) = driver::spawn_thread_pool(sessopts, |sessopts| { + // Shuffle around a few input and output handles here. We're going to pass + // an explicit handle into rustc to collect output messages, but we also + // want to catch the error message that rustc prints when it fails. + // + // We take our thread-local stderr (likely set by the test runner) and replace + // it with a sink that is also passed to rustc itself. When this function + // returns the output of the sink is copied onto the output of our own thread. + // + // The basic idea is to not use a default Handler for rustc, and then also + // not print things by default to the actual stderr. + struct Sink(Arc>>); + impl Write for Sink { + fn write(&mut self, data: &[u8]) -> io::Result { + Write::write(&mut *self.0.lock().unwrap(), data) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } } - fn flush(&mut self) -> io::Result<()> { Ok(()) } - } - struct Bomb(Arc>>, Box); - impl Drop for Bomb { - fn drop(&mut self) { - let _ = self.1.write_all(&self.0.lock().unwrap()); + struct Bomb(Arc>>, Box); + impl Drop for Bomb { + fn drop(&mut self) { + let _ = self.1.write_all(&self.0.lock().unwrap()); + } } - } - let data = Arc::new(Mutex::new(Vec::new())); - let codemap = Lrc::new(CodeMap::new_doctest( - sessopts.file_path_mapping(), filename.clone(), line as isize - line_offset as isize - )); - let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()), - Some(codemap.clone()), - false, - false); - let old = io::set_panic(Some(box Sink(data.clone()))); - let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout())); - - // Compile the code - let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter); - - let mut sess = session::build_session_( - sessopts, None, diagnostic_handler, codemap, - ); - let trans = rustc_driver::get_trans(&sess); - let cstore = CStore::new(trans.metadata_loader()); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - - let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir")); - let libdir = sess.target_filesearch(PathKind::All).get_lib_path(); - let mut control = driver::CompileController::basic(); - - let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); - target_features::add_configuration(&mut cfg, &sess, &*trans); - sess.parse_sess.config = cfg; - - let out = Some(outdir.lock().unwrap().path().to_path_buf()); - - if no_run { - control.after_analysis.stop = Compilation::Stop; - } - - let res = panic::catch_unwind(AssertUnwindSafe(|| { - driver::compile_input( - trans, - &sess, - &cstore, - &None, - &input, - &out, - &None, - None, - &control - ) - })); - - let compile_result = match res { - Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()), - Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(()) - }; - - match (compile_result, compile_fail) { - (Ok(()), true) => { - panic!("test compiled while it wasn't supposed to") + let data = Arc::new(Mutex::new(Vec::new())); + let codemap = Lrc::new(CodeMap::new_doctest( + sessopts.file_path_mapping(), filename.clone(), line as isize - line_offset as isize + )); + let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()), + Some(codemap.clone()), + false, + false); + let old = io::set_panic(Some(box Sink(data.clone()))); + let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout())); + + // Compile the code + let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter); + + let mut sess = session::build_session_( + sessopts, None, diagnostic_handler, codemap, + ); + let trans = rustc_driver::get_trans(&sess); + let cstore = CStore::new(trans.metadata_loader()); + rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + + let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir")); + let libdir = sess.target_filesearch(PathKind::All).get_lib_path(); + let mut control = driver::CompileController::basic(); + + let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); + target_features::add_configuration(&mut cfg, &sess, &*trans); + sess.parse_sess.config = cfg; + + let out = Some(outdir.lock().unwrap().path().to_path_buf()); + + if no_run { + control.after_analysis.stop = Compilation::Stop; } - (Ok(()), false) => {} - (Err(()), true) => { - if error_codes.len() > 0 { - let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap(); - error_codes.retain(|err| !out.contains(err)); + + let res = panic::catch_unwind(AssertUnwindSafe(|| { + driver::compile_input( + trans, + &sess, + &cstore, + &None, + &input, + &out, + &None, + None, + &control + ) + })); + + let compile_result = match res { + Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()), + Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(()) + }; + + match (compile_result, compile_fail) { + (Ok(()), true) => { + panic!("test compiled while it wasn't supposed to") + } + (Ok(()), false) => {} + (Err(()), true) => { + if error_codes.len() > 0 { + let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap(); + error_codes.retain(|err| !out.contains(err)); + } + } + (Err(()), false) => { + panic!("couldn't compile the test") } } - (Err(()), false) => { - panic!("couldn't compile the test") + + if error_codes.len() > 0 { + panic!("Some expected error codes were not found: {:?}", error_codes); } - } - if error_codes.len() > 0 { - panic!("Some expected error codes were not found: {:?}", error_codes); - } + (libdir, outdir) + }); if no_run { return } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index ace9904e0c021..fcda6ce9b164d 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -1348,7 +1348,7 @@ impl LitKind { Token::Ident(ident, false) if ident.name == "true" => Some(LitKind::Bool(true)), Token::Ident(ident, false) if ident.name == "false" => Some(LitKind::Bool(false)), Token::Interpolated(ref nt) => match nt.0 { - token::NtExpr(ref v) => match v.node { + token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node { ExprKind::Lit(ref lit) => Some(lit.node.clone()), _ => None, }, diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 71634ada89458..f0339b89839c1 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -735,6 +735,7 @@ fn may_begin_with(name: &str, token: &Token) -> bool { "expr" => token.can_begin_expr(), "ty" => token.can_begin_type(), "ident" => get_macro_ident(token).is_some(), + "literal" => token.can_begin_literal_or_bool(), "vis" => match *token { // The follow-set of :vis + "priv" keyword + interpolated Token::Comma | Token::Ident(..) | Token::Interpolated(_) => true, @@ -821,6 +822,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { }, "pat" => token::NtPat(panictry!(p.parse_pat())), "expr" => token::NtExpr(panictry!(p.parse_expr())), + "literal" => token::NtLiteral(panictry!(p.parse_literal_maybe_minus())), "ty" => token::NtTy(panictry!(p.parse_ty())), // this could be handled like a token, since it is one "ident" => if let Some((ident, is_raw)) = get_macro_ident(&p.token) { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index ffe68289d5224..1fc5aed7e7a23 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -647,7 +647,7 @@ fn check_matcher_core(sess: &ParseSess, let msg = format!("invalid fragment specifier `{}`", bad_frag); sess.span_diagnostic.struct_span_err(token.span(), &msg) .help("valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, \ - `pat`, `ty`, `path`, `meta`, `tt`, `item` and `vis`") + `pat`, `ty`, `literal`, `path`, `meta`, `tt`, `item` and `vis`") .emit(); // (This eliminates false positives and duplicates // from error messages.) @@ -784,6 +784,7 @@ fn frag_can_be_followed_by_any(frag: &str) -> bool { "item" | // always terminated by `}` or `;` "block" | // exactly one token tree "ident" | // exactly one token tree + "literal" | // exactly one token tree "meta" | // exactly one token tree "lifetime" | // exactly one token tree "tt" => // exactly one token tree @@ -850,6 +851,10 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result { + // literals may be of a single token, or two tokens (negative numbers) + Ok(true) + }, "meta" | "tt" => { // being either a single token or a delimited sequence, tt is // harmless @@ -873,7 +878,7 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result Err((format!("invalid fragment specifier `{}`", frag), "valid fragment specifiers are `ident`, `block`, \ `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, \ - `item` and `vis`")) + `literal`, `item` and `vis`")) } } } @@ -913,6 +918,18 @@ fn is_legal_fragment_specifier(sess: &ParseSess, } true }, + "literal" => { + if !features.macro_literal_matcher && + !attr::contains_name(attrs, "allow_internal_unstable") { + let explain = feature_gate::EXPLAIN_LITERAL_MATCHER; + emit_feature_err(sess, + "macro_literal_matcher", + frag_span, + GateIssue::Language, + explain); + } + true + }, "vis" => { if !features.macro_vis_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index b27568a61f85c..562705462e2a4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -463,6 +463,9 @@ declare_features! ( // Scoped attributes (active, tool_attributes, "1.25.0", Some(44690), None), + + // Allows use of the :literal macro fragment specifier (RFC 1576) + (active, macro_literal_matcher, "1.27.0", Some(35625), None), ); declare_features! ( @@ -1331,6 +1334,9 @@ pub const EXPLAIN_VIS_MATCHER: &'static str = pub const EXPLAIN_LIFETIME_MATCHER: &'static str = ":lifetime fragment specifier is experimental and subject to change"; +pub const EXPLAIN_LITERAL_MATCHER: &'static str = + ":literal fragment specifier is experimental and subject to change"; + pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str = "Unsized tuple coercion is not stable enough for use and is subject to change"; diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index a0cd831a9ba08..d67995761f627 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -635,6 +635,7 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)), token::NtIdent(ident, is_raw) => token::NtIdent(fld.fold_ident(ident), is_raw), token::NtLifetime(ident) => token::NtLifetime(fld.fold_ident(ident)), + token::NtLiteral(expr) => token::NtLiteral(fld.fold_expr(expr)), token::NtMeta(meta) => token::NtMeta(fld.fold_meta_item(meta)), token::NtPath(path) => token::NtPath(fld.fold_path(path)), token::NtTT(tt) => token::NtTT(fld.fold_tt(tt)), diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index f148aaf7267ee..90af3ba51ecad 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -73,7 +73,7 @@ macro_rules! unwrap_or { } } -struct Globals { +pub struct Globals { used_attrs: Lock>, known_attrs: Lock>, syntax_pos_globals: syntax_pos::Globals, @@ -98,7 +98,7 @@ pub fn with_globals(f: F) -> R }) } -scoped_thread_local!(static GLOBALS: Globals); +scoped_thread_local!(pub static GLOBALS: Globals); #[macro_use] pub mod diagnostics { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 49b30c6f460fe..3f0df6d055b76 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -115,7 +115,7 @@ macro_rules! maybe_whole_expr { ($p:expr) => { if let token::Interpolated(nt) = $p.token.clone() { match nt.0 { - token::NtExpr(ref e) => { + token::NtExpr(ref e) | token::NtLiteral(ref e) => { $p.bump(); return Ok((*e).clone()); } @@ -1823,7 +1823,7 @@ impl<'a> Parser<'a> { pub fn parse_lit_token(&mut self) -> PResult<'a, LitKind> { let out = match self.token { token::Interpolated(ref nt) => match nt.0 { - token::NtExpr(ref v) => match v.node { + token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node { ExprKind::Lit(ref lit) => { lit.node.clone() } _ => { return self.unexpected_last(&self.token); } }, @@ -1862,7 +1862,7 @@ impl<'a> Parser<'a> { } /// matches '-' lit | lit (cf. ast_validation::AstValidator::check_expr_within_pat) - pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P> { + pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { maybe_whole_expr!(self); let minus_lo = self.span; @@ -2407,10 +2407,10 @@ impl<'a> Parser<'a> { hi = pth.span; ex = ExprKind::Path(None, pth); } else { - match self.parse_lit() { - Ok(lit) => { - hi = lit.span; - ex = ExprKind::Lit(P(lit)); + match self.parse_literal_maybe_minus() { + Ok(expr) => { + hi = expr.span; + ex = expr.node.clone(); } Err(mut err) => { self.cancel(&mut err); @@ -3724,7 +3724,7 @@ impl<'a> Parser<'a> { let hi = self.prev_span; Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), ThinVec::new())) } else { - self.parse_pat_literal_maybe_minus() + self.parse_literal_maybe_minus() } } @@ -3914,7 +3914,7 @@ impl<'a> Parser<'a> { } } else { // Try to parse everything else as literal with optional minus - match self.parse_pat_literal_maybe_minus() { + match self.parse_literal_maybe_minus() { Ok(begin) => { if self.eat(&token::DotDotDot) { let end = self.parse_pat_range_end()?; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 938711ca1d495..6bcc1b0f02691 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -280,7 +280,12 @@ impl Token { Lifetime(..) | // labeled loop Pound => true, // expression attributes Interpolated(ref nt) => match nt.0 { - NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) | NtLifetime(..) => true, + NtLiteral(..) | + NtIdent(..) | + NtExpr(..) | + NtBlock(..) | + NtPath(..) | + NtLifetime(..) => true, _ => false, }, _ => false, @@ -324,6 +329,18 @@ impl Token { } } + /// Returns `true` if the token is any literal, a minus (which can follow a literal, + /// for example a '-42', or one of the boolean idents). + pub fn can_begin_literal_or_bool(&self) -> bool { + match *self { + Literal(..) => true, + BinOp(Minus) => true, + Ident(ident, false) if ident.name == keywords::True.name() => true, + Ident(ident, false) if ident.name == keywords::False.name() => true, + _ => false, + } + } + /// Returns an identifier if this token is an identifier. pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> { match *self { @@ -672,6 +689,7 @@ pub enum Nonterminal { NtTy(P), NtIdent(ast::Ident, /* is_raw */ bool), NtLifetime(ast::Ident), + NtLiteral(P), /// Stuff inside brackets for attributes NtMeta(ast::MetaItem), NtPath(ast::Path), @@ -713,6 +731,7 @@ impl fmt::Debug for Nonterminal { NtExpr(..) => f.pad("NtExpr(..)"), NtTy(..) => f.pad("NtTy(..)"), NtIdent(..) => f.pad("NtIdent(..)"), + NtLiteral(..) => f.pad("NtLiteral(..)"), NtMeta(..) => f.pad("NtMeta(..)"), NtPath(..) => f.pad("NtPath(..)"), NtTT(..) => f.pad("NtTT(..)"), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b8ddb063d9875..99a6fcf170dcb 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -273,6 +273,7 @@ pub fn token_to_string(tok: &Token) -> String { token::NtIdent(e, false) => ident_to_string(e), token::NtIdent(e, true) => format!("r#{}", ident_to_string(e)), token::NtLifetime(e) => ident_to_string(e), + token::NtLiteral(ref e) => expr_to_string(e), token::NtTT(ref tree) => tt_to_string(tree.clone()), token::NtArm(ref e) => arm_to_string(e), token::NtImplItem(ref e) => impl_item_to_string(e), diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index b84ff5697a4c8..2258ed12779e4 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -527,7 +527,7 @@ impl PartialOrd for InternedString { if self.symbol == other.symbol { return Some(Ordering::Equal); } - self.with(|self_str| other.with(|other_str| self_str.partial_cmp(&other_str))) + self.with(|self_str| other.with(|other_str| self_str.partial_cmp(other_str))) } } diff --git a/src/test/run-pass/issue-46845.rs b/src/test/run-pass/issue-46845.rs index 235d3982a9c0c..92f68dcfc349d 100644 --- a/src/test/run-pass/issue-46845.rs +++ b/src/test/run-pass/issue-46845.rs @@ -24,6 +24,7 @@ union Foo { } // If all the variants are uninhabited, however, the union should be uninhabited. +// NOTE(#49298) the union being uninhabited shouldn't change its size. union Bar { _a: (Never, u64), _b: (u64, Never) @@ -31,7 +32,8 @@ union Bar { fn main() { assert_eq!(mem::size_of::(), 8); - assert_eq!(mem::size_of::(), 0); + // See the note on `Bar`'s definition for why this isn't `0`. + assert_eq!(mem::size_of::(), 8); let f = [Foo { a: 42 }, Foo { a: 10 }]; println!("{}", unsafe { f[0].a }); diff --git a/src/test/run-pass/issue-49298.rs b/src/test/run-pass/issue-49298.rs new file mode 100644 index 0000000000000..0b2169c9476cd --- /dev/null +++ b/src/test/run-pass/issue-49298.rs @@ -0,0 +1,34 @@ +// 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. + +#![feature(test)] + +extern crate test; + +enum Void {} + +fn main() { + let mut x: (Void, usize); + let mut y = 42; + x.1 = 13; + + // Make sure `y` stays on the stack. + test::black_box(&mut y); + + // Check that the write to `x.1` did not overwrite `y`. + // Note that this doesn't fail with optimizations enabled, + // because we can't keep `x.1` on the stack, like we can `y`, + // as we can't borrow partially initialized variables. + assert_eq!(y.to_string(), "42"); + + // Check that `(Void, usize)` has space for the `usize` field. + assert_eq!(std::mem::size_of::<(Void, usize)>(), + std::mem::size_of::()); +} diff --git a/src/test/run-pass/issue-50442.rs b/src/test/run-pass/issue-50442.rs new file mode 100644 index 0000000000000..1e43bebf5c32c --- /dev/null +++ b/src/test/run-pass/issue-50442.rs @@ -0,0 +1,21 @@ +// 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. + +enum Void {} + +enum Foo { + A(i32), + B(Void), + C(i32) +} + +fn main() { + let _foo = Foo::A(0); +} diff --git a/src/test/run-pass/macro-literal.rs b/src/test/run-pass/macro-literal.rs new file mode 100644 index 0000000000000..0bcda7bc1447a --- /dev/null +++ b/src/test/run-pass/macro-literal.rs @@ -0,0 +1,143 @@ +// 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. + +#![feature(macro_literal_matcher)] + +macro_rules! mtester { + ($l:literal) => { + &format!("macro caught literal: {}", $l) + }; + ($e:expr) => { + &format!("macro caught expr: {}", $e) + }; +} + +macro_rules! two_negative_literals { + ($l1:literal $l2:literal) => { + &format!("macro caught literals: {}, {}", $l1, $l2) + }; +} + +macro_rules! only_expr { + ($e:expr) => { + &format!("macro caught expr: {}", $e) + }; +} + +macro_rules! mtester_dbg { + ($l:literal) => { + &format!("macro caught literal: {:?}", $l) + }; + ($e:expr) => { + &format!("macro caught expr: {:?}", $e) + }; +} + +macro_rules! catch_range { + ($s:literal ... $e:literal) => { + &format!("macro caught literal: {} ... {}", $s, $e) + }; + (($s:expr) ... ($e:expr)) => { // Must use ')' before '...' + &format!("macro caught expr: {} ... {}", $s, $e) + }; +} + +macro_rules! pat_match { + ($s:literal ... $e:literal) => { + match 3 { + $s ... $e => "literal, in range", + _ => "literal, other", + } + }; + ($s:pat) => { + match 3 { + $s => "pat, single", + _ => "pat, other", + } + }; +} + +macro_rules! match_attr { + (#[$attr:meta] $e:literal) => { + "attr matched literal" + }; + (#[$attr:meta] $e:expr) => { + "attr matched expr" + }; +} + +macro_rules! match_produced_attr { + ($lit: literal) => { + // Struct with doc comment passed via $literal + #[doc = $lit] + struct LiteralProduced; + }; + ($expr: expr) => { + struct ExprProduced; + }; +} + +macro_rules! test_user { + ($s:literal, $e:literal) => { + { + let mut v = Vec::new(); + for i in $s .. $e { + v.push(i); + } + "literal" + } + }; + ($s:expr, $e: expr) => { + { + let mut v = Vec::new(); + for i in $s .. $e { + v.push(i); + } + "expr" + } + }; +} + +pub fn main() { + // Cases where 'literal' catches + assert_eq!(mtester!("str"), "macro caught literal: str"); + assert_eq!(mtester!(2), "macro caught literal: 2"); + assert_eq!(mtester!(2.2), "macro caught literal: 2.2"); + assert_eq!(mtester!(1u32), "macro caught literal: 1"); + assert_eq!(mtester!(0x32), "macro caught literal: 50"); + assert_eq!(mtester!('c'), "macro caught literal: c"); + assert_eq!(mtester!(-1.2), "macro caught literal: -1.2"); + assert_eq!(two_negative_literals!(-2 -3), "macro caught literals: -2, -3"); + assert_eq!(catch_range!(2 ... 3), "macro caught literal: 2 ... 3"); + assert_eq!(match_attr!(#[attr] 1), "attr matched literal"); + assert_eq!(test_user!(10, 20), "literal"); + assert_eq!(mtester!(false), "macro caught literal: false"); + assert_eq!(mtester!(true), "macro caught literal: true"); + match_produced_attr!("a"); + let _a = LiteralProduced; + assert_eq!(pat_match!(1 ... 3), "literal, in range"); + assert_eq!(pat_match!(4 ... 6), "literal, other"); + + // Cases where 'expr' catches + assert_eq!(mtester!((-1.2)), "macro caught expr: -1.2"); + assert_eq!(only_expr!(-1.2), "macro caught expr: -1.2"); + assert_eq!(mtester!((1 + 3)), "macro caught expr: 4"); + assert_eq!(mtester_dbg!(()), "macro caught expr: ()"); + assert_eq!(catch_range!((1 + 1) ... (2 + 2)), "macro caught expr: 2 ... 4"); + assert_eq!(match_attr!(#[attr] (1 + 2)), "attr matched expr"); + assert_eq!(test_user!(10, (20 + 2)), "expr"); + + match_produced_attr!((3 + 2)); + let _b = ExprProduced; + + // Cases where 'pat' matched + assert_eq!(pat_match!(3), "pat, single"); + assert_eq!(pat_match!(6), "pat, other"); +} diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index a47f082b9c3ee..8f4613d6c373a 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -68,9 +68,15 @@ enum EnumSingle5 { A = 42 as u8, } -enum NicheFilledEnumWithInhabitedVariant { +enum EnumWithMaybeUninhabitedVariant { A(&'static ()), - B(&'static (), !), + B(&'static (), T), + C, +} + +enum NicheFilledEnumWithAbsentVariant { + A(&'static ()), + B((), !), C, } @@ -107,5 +113,7 @@ pub fn main() { assert_eq!(size_of::(), 1); assert_eq!(size_of::(), 1); - assert_eq!(size_of::(), size_of::<&'static ()>()); + assert_eq!(size_of::>(), + size_of::>()); + assert_eq!(size_of::(), size_of::<&'static ()>()); } diff --git a/src/test/ui-fulldeps/unnecessary-extern-crate.stderr b/src/test/ui-fulldeps/unnecessary-extern-crate.stderr index b0b56f527e64f..ab5457018eda6 100644 --- a/src/test/ui-fulldeps/unnecessary-extern-crate.stderr +++ b/src/test/ui-fulldeps/unnecessary-extern-crate.stderr @@ -14,55 +14,55 @@ error: `extern crate` is unnecessary in the new edition --> $DIR/unnecessary-extern-crate.rs:19:1 | LL | extern crate alloc as x; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;` error: `extern crate` is unnecessary in the new edition --> $DIR/unnecessary-extern-crate.rs:25:1 | LL | pub extern crate test as y; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y;` error: `extern crate` is unnecessary in the new edition --> $DIR/unnecessary-extern-crate.rs:28:1 | LL | pub extern crate libc; - | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc` + | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc;` error: `extern crate` is unnecessary in the new edition --> $DIR/unnecessary-extern-crate.rs:34:5 | LL | extern crate alloc; - | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc` + | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc;` error: `extern crate` is unnecessary in the new edition --> $DIR/unnecessary-extern-crate.rs:37:5 | LL | extern crate alloc as x; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;` error: `extern crate` is unnecessary in the new edition --> $DIR/unnecessary-extern-crate.rs:40:5 | LL | pub extern crate test; - | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test` + | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test;` error: `extern crate` is unnecessary in the new edition --> $DIR/unnecessary-extern-crate.rs:43:5 | LL | pub extern crate test as y; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y;` error: `extern crate` is unnecessary in the new edition --> $DIR/unnecessary-extern-crate.rs:47:9 | LL | extern crate alloc; - | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc` + | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc;` error: `extern crate` is unnecessary in the new edition --> $DIR/unnecessary-extern-crate.rs:50:9 | LL | extern crate alloc as x; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;` error: aborting due to 10 previous errors diff --git a/src/test/ui/feature-gate-macro-literal-matcher.rs b/src/test/ui/feature-gate-macro-literal-matcher.rs new file mode 100644 index 0000000000000..db5cca193ab4e --- /dev/null +++ b/src/test/ui/feature-gate-macro-literal-matcher.rs @@ -0,0 +1,19 @@ +// 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. + +// Test that the :lifetime macro fragment cannot be used when macro_lifetime_matcher +// feature gate is not used. + +macro_rules! m { ($lt:literal) => {} } +//~^ ERROR :literal fragment specifier is experimental and subject to change + +fn main() { + m!("some string literal"); +} diff --git a/src/test/ui/feature-gate-macro-literal-matcher.stderr b/src/test/ui/feature-gate-macro-literal-matcher.stderr new file mode 100644 index 0000000000000..f714b916966a1 --- /dev/null +++ b/src/test/ui/feature-gate-macro-literal-matcher.stderr @@ -0,0 +1,11 @@ +error[E0658]: :literal fragment specifier is experimental and subject to change (see issue #35625) + --> $DIR/feature-gate-macro-literal-matcher.rs:14:19 + | +LL | macro_rules! m { ($lt:literal) => {} } + | ^^^^^^^^^^^ + | + = help: add #![feature(macro_literal_matcher)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/issue-50480.rs b/src/test/ui/issue-50480.rs new file mode 100644 index 0000000000000..3427cf6bf9ca2 --- /dev/null +++ b/src/test/ui/issue-50480.rs @@ -0,0 +1,17 @@ +// 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. + +#[derive(Clone, Copy)] +//~^ ERROR the trait `Copy` may not be implemented for this type +struct Foo(NotDefined, ::Item, Vec, String); +//~^ ERROR cannot find type `NotDefined` in this scope +//~| ERROR the trait bound `i32: std::iter::Iterator` is not satisfied + +fn main() {} diff --git a/src/test/ui/issue-50480.stderr b/src/test/ui/issue-50480.stderr new file mode 100644 index 0000000000000..f5281fec4d1ea --- /dev/null +++ b/src/test/ui/issue-50480.stderr @@ -0,0 +1,29 @@ +error[E0412]: cannot find type `NotDefined` in this scope + --> $DIR/issue-50480.rs:13:12 + | +LL | struct Foo(NotDefined, ::Item, Vec, String); + | ^^^^^^^^^^ not found in this scope + +error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied + --> $DIR/issue-50480.rs:13:24 + | +LL | struct Foo(NotDefined, ::Item, Vec, String); + | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method + | + = help: the trait `std::iter::Iterator` is not implemented for `i32` + +error[E0204]: the trait `Copy` may not be implemented for this type + --> $DIR/issue-50480.rs:11:17 + | +LL | #[derive(Clone, Copy)] + | ^^^^ +LL | //~^ ERROR the trait `Copy` may not be implemented for this type +LL | struct Foo(NotDefined, ::Item, Vec, String); + | -------- ------ this field does not implement `Copy` + | | + | this field does not implement `Copy` + +error: aborting due to 3 previous errors + +Some errors occurred: E0204, E0277, E0412. +For more information about an error, try `rustc --explain E0204`. diff --git a/src/test/ui/issue-50618.rs b/src/test/ui/issue-50618.rs new file mode 100644 index 0000000000000..ed427c293df47 --- /dev/null +++ b/src/test/ui/issue-50618.rs @@ -0,0 +1,29 @@ +// Copyright 2017 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. + +struct Point { + pub x: u64, + pub y: u64, +} + +const TEMPLATE: Point = Point { + x: 0, + y: 0 +}; + +fn main() { + let _ = || { + Point { + nonexistent: 0, + //~^ ERROR struct `Point` has no field named `nonexistent` + ..TEMPLATE + } + }; +} diff --git a/src/test/ui/issue-50618.stderr b/src/test/ui/issue-50618.stderr new file mode 100644 index 0000000000000..07cc5a1318aa4 --- /dev/null +++ b/src/test/ui/issue-50618.stderr @@ -0,0 +1,11 @@ +error[E0560]: struct `Point` has no field named `nonexistent` + --> $DIR/issue-50618.rs:24:13 + | +LL | nonexistent: 0, + | ^^^^^^^^^^^ `Point` does not have this field + | + = note: available fields are: `x`, `y` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0560`. diff --git a/src/test/ui/macro-invalid-fragment-spec.stderr b/src/test/ui/macro-invalid-fragment-spec.stderr index bdb0e4a5c4044..765621f51d4fd 100644 --- a/src/test/ui/macro-invalid-fragment-spec.stderr +++ b/src/test/ui/macro-invalid-fragment-spec.stderr @@ -4,7 +4,7 @@ error: invalid fragment specifier `foo` LL | ($x:foo) => () | ^^^^^^ | - = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, `item` and `vis` + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `literal`, `path`, `meta`, `tt`, `item` and `vis` error: aborting due to previous error diff --git a/src/test/ui/suggestions/auxiliary/removing-extern-crate.rs b/src/test/ui/suggestions/auxiliary/removing-extern-crate.rs new file mode 100644 index 0000000000000..4275e80e7fe8b --- /dev/null +++ b/src/test/ui/suggestions/auxiliary/removing-extern-crate.rs @@ -0,0 +1,11 @@ +// 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. + +// intentionally blank diff --git a/src/test/ui/suggestions/removing-extern-crate.fixed b/src/test/ui/suggestions/removing-extern-crate.fixed new file mode 100644 index 0000000000000..723137f5db0c1 --- /dev/null +++ b/src/test/ui/suggestions/removing-extern-crate.fixed @@ -0,0 +1,27 @@ +// 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. + +// compile-flags: --edition 2018 +// aux-build:removing-extern-crate.rs +// run-rustfix +// compile-pass + +#![warn(rust_2018_idioms)] +#![allow(unused_imports)] + +use std as foo; + + +mod another { + use std as foo; + use std; +} + +fn main() {} diff --git a/src/test/ui/suggestions/removing-extern-crate.rs b/src/test/ui/suggestions/removing-extern-crate.rs new file mode 100644 index 0000000000000..29479086460e6 --- /dev/null +++ b/src/test/ui/suggestions/removing-extern-crate.rs @@ -0,0 +1,27 @@ +// 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. + +// compile-flags: --edition 2018 +// aux-build:removing-extern-crate.rs +// run-rustfix +// compile-pass + +#![warn(rust_2018_idioms)] +#![allow(unused_imports)] + +extern crate std as foo; +extern crate core; + +mod another { + extern crate std as foo; + extern crate std; +} + +fn main() {} diff --git a/src/test/ui/suggestions/removing-extern-crate.stderr b/src/test/ui/suggestions/removing-extern-crate.stderr new file mode 100644 index 0000000000000..317703d0caa52 --- /dev/null +++ b/src/test/ui/suggestions/removing-extern-crate.stderr @@ -0,0 +1,31 @@ +warning: `extern crate` is unnecessary in the new edition + --> $DIR/removing-extern-crate.rs:19:1 + | +LL | extern crate std as foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use std as foo;` + | +note: lint level defined here + --> $DIR/removing-extern-crate.rs:16:9 + | +LL | #![warn(rust_2018_idioms)] + | ^^^^^^^^^^^^^^^^ + = note: #[warn(unnecessary_extern_crate)] implied by #[warn(rust_2018_idioms)] + +warning: `extern crate` is unnecessary in the new edition + --> $DIR/removing-extern-crate.rs:20:1 + | +LL | extern crate core; + | ^^^^^^^^^^^^^^^^^^ help: remove it + +warning: `extern crate` is unnecessary in the new edition + --> $DIR/removing-extern-crate.rs:23:5 + | +LL | extern crate std as foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use std as foo;` + +warning: `extern crate` is unnecessary in the new edition + --> $DIR/removing-extern-crate.rs:24:5 + | +LL | extern crate std; + | ^^^^^^^^^^^^^^^^^ help: use `use`: `use std;` + diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 9a87fcb00d526..c34cf1bd5ec09 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -59,6 +59,7 @@ static WHITELIST_CRATES: &'static [CrateVersion] = &[ static WHITELIST: &'static [Crate] = &[ Crate("aho-corasick"), Crate("ar"), + Crate("arrayvec"), Crate("atty"), Crate("backtrace"), Crate("backtrace-sys"), @@ -67,6 +68,10 @@ static WHITELIST: &'static [Crate] = &[ Crate("cc"), Crate("cfg-if"), Crate("cmake"), + Crate("crossbeam-deque"), + Crate("crossbeam-epoch"), + Crate("crossbeam-utils"), + Crate("either"), Crate("ena"), Crate("env_logger"), Crate("filetime"), @@ -82,7 +87,9 @@ static WHITELIST: &'static [Crate] = &[ Crate("log"), Crate("log_settings"), Crate("memchr"), + Crate("memoffset"), Crate("miniz-sys"), + Crate("nodrop"), Crate("num_cpus"), Crate("owning_ref"), Crate("parking_lot"), @@ -95,7 +102,10 @@ static WHITELIST: &'static [Crate] = &[ Crate("regex-syntax"), Crate("remove_dir_all"), Crate("rustc-demangle"), + Crate("rustc-rayon"), + Crate("rustc-rayon-core"), Crate("scoped-tls"), + Crate("scopeguard"), Crate("smallvec"), Crate("stable_deref_trait"), Crate("tempdir"),