diff --git a/src/Cargo.lock b/src/Cargo.lock index 6a9488226b1bd..2719587f20e8a 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -270,7 +270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chalk-engine" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1898,7 +1898,7 @@ dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "fmt_macros 0.0.0", "graphviz 0.0.0", @@ -2434,7 +2434,7 @@ name = "rustc_traits" version = "0.0.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", @@ -3195,7 +3195,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1" "checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" -"checksum chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "25ce2f28f55ed544a2a3756b7acf41dd7d6f27acffb2086439950925506af7d0" +"checksum chalk-engine 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6749eb72e7d4355d944a99f15fbaea701b978c18c5e184a025fcde942b0c9779" "checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e" "checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" diff --git a/src/doc/unstable-book/src/language-features/cfg-attr-multi.md b/src/doc/unstable-book/src/language-features/cfg-attr-multi.md new file mode 100644 index 0000000000000..6365d3e71c616 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/cfg-attr-multi.md @@ -0,0 +1,20 @@ +# `cfg_attr_multi` + +The tracking issue for this feature is: [#54881] +The RFC for this feature is: [#2539] + +[#54881]: https://github.com/rust-lang/rust/issues/54881 +[#2539]: https://github.com/rust-lang/rfcs/pull/2539 + +------------------------ + +This feature flag lets you put multiple attributes into a `cfg_attr` attribute. + +Example: + +```rust,ignore +#[cfg_attr(all(), must_use, optimize)] +``` + +Because `cfg_attr` resolves before procedural macros, this does not affect +macro resolution at all. \ No newline at end of file diff --git a/src/doc/unstable-book/src/language-features/tool-lints.md b/src/doc/unstable-book/src/language-features/tool-lints.md deleted file mode 100644 index 5c0d33b5ab0c4..0000000000000 --- a/src/doc/unstable-book/src/language-features/tool-lints.md +++ /dev/null @@ -1,35 +0,0 @@ -# `tool_lints` - -The tracking issue for this feature is: [#44690] - -[#44690]: https://github.com/rust-lang/rust/issues/44690 - ------------------------- - -Tool lints let you use scoped lints, to `allow`, `warn`, `deny` or `forbid` lints of -certain tools. - -Currently `clippy` is the only available lint tool. - -It is recommended for lint tools to implement the scoped lints like this: - -- `#[_(TOOL_NAME::lintname)]`: for lint names -- `#[_(TOOL_NAME::lintgroup)]`: for groups of lints -- `#[_(TOOL_NAME::all)]`: for (almost[^1]) all lints - -## An example - -```rust -#![feature(tool_lints)] - -#![warn(clippy::pedantic)] - -#[allow(clippy::filter_map)] -fn main() { - let v = vec![0; 10]; - let _ = v.into_iter().filter(|&x| x < 1).map(|x| x + 1).collect::>(); - println!("No filter_map()!"); -} -``` - -[^1]: Some defined lint groups can be excluded here. diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 0255f7a0885ea..cf1c77041b91f 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -867,8 +867,6 @@ impl Option { /// # Examples /// /// ``` - /// #![feature(option_replace)] - /// /// let mut x = Some(2); /// let old = x.replace(5); /// assert_eq!(x, Some(5)); @@ -880,7 +878,7 @@ impl Option { /// assert_eq!(old, None); /// ``` #[inline] - #[unstable(feature = "option_replace", issue = "51998")] + #[stable(feature = "option_replace", since = "1.31.0")] pub fn replace(&mut self, value: T) -> Option { mem::replace(self, Some(value)) } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index ada61d8dfd873..0beb60a127097 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -39,7 +39,6 @@ #![feature(reverse_bits)] #![feature(inner_deref)] #![feature(slice_internals)] -#![feature(option_replace)] #![feature(slice_partition_dedup)] #![feature(copy_within)] diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 6c3b52196a3a2..d0ec8640ce9ef 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -31,7 +31,7 @@ syntax_pos = { path = "../libsyntax_pos" } backtrace = "0.3.3" parking_lot = "0.6" byteorder = { version = "1.1", features = ["i128"]} -chalk-engine = { version = "0.7.0", default-features=false } +chalk-engine = { version = "0.8.0", default-features=false } rustc_fs_util = { path = "../librustc_fs_util" } smallvec = { version = "0.6.5", features = ["union"] } diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index e8c89cb3e0e7e..f51a3e71d0741 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1370,7 +1370,7 @@ impl<'a, 'tcx> HashStable> for traits::Goal<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use traits::Goal::*; + use traits::GoalKind::*; mem::discriminant(self).hash_stable(hcx, hasher); match self { diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 87d33e473e7f6..950754a07ab09 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -18,11 +18,10 @@ use lint::context::CheckLintNameResult; use lint::{self, Lint, LintId, Level, LintSource}; use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher, StableHasherResult}; -use session::{config::nightly_options, Session}; +use session::Session; use syntax::ast; use syntax::attr; use syntax::source_map::MultiSpan; -use syntax::feature_gate; use syntax::symbol::Symbol; use util::nodemap::FxHashMap; @@ -228,18 +227,7 @@ impl<'a> LintLevelsBuilder<'a> { } }; let tool_name = if let Some(lint_tool) = word.is_scoped() { - let gate_feature = !self.sess.features_untracked().tool_lints; - let known_tool = attr::is_known_lint_tool(lint_tool); - if gate_feature { - feature_gate::emit_feature_err( - &sess.parse_sess, - "tool_lints", - word.span, - feature_gate::GateIssue::Language, - &format!("scoped lint `{}` is experimental", word.ident), - ); - } - if !known_tool { + if !attr::is_known_lint_tool(lint_tool) { span_err!( sess, lint_tool.span, @@ -247,9 +235,6 @@ impl<'a> LintLevelsBuilder<'a> { "an unknown tool name found in scoped lint: `{}`", word.ident ); - } - - if gate_feature || !known_tool { continue; } @@ -299,13 +284,7 @@ impl<'a> LintLevelsBuilder<'a> { "change it to", new_lint_name.to_string(), Applicability::MachineApplicable, - ); - - if nightly_options::is_nightly_build() { - err.emit(); - } else { - err.cancel(); - } + ).emit(); let src = LintSource::Node(Symbol::intern(&new_lint_name), li.span); for id in ids { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 286e35c5d4e95..6e4abee32c077 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -318,31 +318,33 @@ pub enum QuantifierKind { } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum Goal<'tcx> { - Implies(Clauses<'tcx>, &'tcx Goal<'tcx>), - And(&'tcx Goal<'tcx>, &'tcx Goal<'tcx>), - Not(&'tcx Goal<'tcx>), +pub enum GoalKind<'tcx> { + Implies(Clauses<'tcx>, Goal<'tcx>), + And(Goal<'tcx>, Goal<'tcx>), + Not(Goal<'tcx>), DomainGoal(DomainGoal<'tcx>), - Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>), + Quantified(QuantifierKind, ty::Binder>), CannotProve, } +pub type Goal<'tcx> = &'tcx GoalKind<'tcx>; + pub type Goals<'tcx> = &'tcx List>; impl<'tcx> DomainGoal<'tcx> { - pub fn into_goal(self) -> Goal<'tcx> { - Goal::DomainGoal(self) + pub fn into_goal(self) -> GoalKind<'tcx> { + GoalKind::DomainGoal(self) } } -impl<'tcx> Goal<'tcx> { +impl<'tcx> GoalKind<'tcx> { pub fn from_poly_domain_goal<'a>( domain_goal: PolyDomainGoal<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - ) -> Goal<'tcx> { + ) -> GoalKind<'tcx> { match domain_goal.no_late_bound_regions() { Some(p) => p.into_goal(), - None => Goal::Quantified( + None => GoalKind::Quantified( QuantifierKind::Universal, domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal())) ), diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 22e79fc2638ab..1524f89af291d 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -469,7 +469,7 @@ impl fmt::Display for traits::QuantifierKind { impl<'tcx> fmt::Display for traits::Goal<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use traits::Goal::*; + use traits::GoalKind::*; match self { Implies(hypotheses, goal) => { @@ -598,25 +598,25 @@ CloneTypeFoldableAndLiftImpls! { } EnumTypeFoldableImpl! { - impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> { - (traits::Goal::Implies)(hypotheses, goal), - (traits::Goal::And)(goal1, goal2), - (traits::Goal::Not)(goal), - (traits::Goal::DomainGoal)(domain_goal), - (traits::Goal::Quantified)(qkind, goal), - (traits::Goal::CannotProve), + impl<'tcx> TypeFoldable<'tcx> for traits::GoalKind<'tcx> { + (traits::GoalKind::Implies)(hypotheses, goal), + (traits::GoalKind::And)(goal1, goal2), + (traits::GoalKind::Not)(goal), + (traits::GoalKind::DomainGoal)(domain_goal), + (traits::GoalKind::Quantified)(qkind, goal), + (traits::GoalKind::CannotProve), } } EnumLiftImpl! { - impl<'a, 'tcx> Lift<'tcx> for traits::Goal<'a> { - type Lifted = traits::Goal<'tcx>; - (traits::Goal::Implies)(hypotheses, goal), - (traits::Goal::And)(goal1, goal2), - (traits::Goal::Not)(goal), - (traits::Goal::DomainGoal)(domain_goal), - (traits::Goal::Quantified)(kind, goal), - (traits::Goal::CannotProve), + impl<'a, 'tcx> Lift<'tcx> for traits::GoalKind<'a> { + type Lifted = traits::GoalKind<'tcx>; + (traits::GoalKind::Implies)(hypotheses, goal), + (traits::GoalKind::And)(goal1, goal2), + (traits::GoalKind::Not)(goal), + (traits::GoalKind::DomainGoal)(domain_goal), + (traits::GoalKind::Quantified)(kind, goal), + (traits::GoalKind::CannotProve), } } @@ -633,7 +633,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx traits::Goal<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let v = (**self).fold_with(folder); folder.tcx().mk_goal(v) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 46ba5f5ef362d..3d4ae572d0b81 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -36,7 +36,7 @@ use mir::interpret::Allocation; use ty::subst::{CanonicalSubsts, Kind, Substs, Subst}; use ty::ReprOptions; use traits; -use traits::{Clause, Clauses, Goal, Goals}; +use traits::{Clause, Clauses, GoalKind, Goal, Goals}; use ty::{self, Ty, TypeAndMut}; use ty::{TyS, TyKind, List}; use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const}; @@ -143,7 +143,8 @@ pub struct CtxtInterners<'tcx> { predicates: InternedSet<'tcx, List>>, const_: InternedSet<'tcx, Const<'tcx>>, clauses: InternedSet<'tcx, List>>, - goals: InternedSet<'tcx, List>>, + goal: InternedSet<'tcx, GoalKind<'tcx>>, + goal_list: InternedSet<'tcx, List>>, } impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { @@ -159,7 +160,8 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { predicates: Default::default(), const_: Default::default(), clauses: Default::default(), - goals: Default::default(), + goal: Default::default(), + goal_list: Default::default(), } } @@ -1731,9 +1733,9 @@ impl<'a, 'tcx> Lift<'tcx> for Region<'a> { } } -impl<'a, 'tcx> Lift<'tcx> for &'a Goal<'a> { - type Lifted = &'tcx Goal<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Goal<'tcx>> { +impl<'a, 'tcx> Lift<'tcx> for Goal<'a> { + type Lifted = Goal<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { if tcx.interners.arena.in_arena(*self as *const _) { return Some(unsafe { mem::transmute(*self) }); } @@ -2304,6 +2306,12 @@ impl<'tcx> Borrow for Interned<'tcx, RegionKind> { } } +impl<'tcx: 'lcx, 'lcx> Borrow> for Interned<'tcx, GoalKind<'tcx>> { + fn borrow<'a>(&'a self) -> &'a GoalKind<'lcx> { + &self.0 + } +} + impl<'tcx: 'lcx, 'lcx> Borrow<[ExistentialPredicate<'lcx>]> for Interned<'tcx, List>> { fn borrow<'a>(&'a self) -> &'a [ExistentialPredicate<'lcx>] { @@ -2419,7 +2427,8 @@ pub fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { direct_interners!('tcx, region: mk_region(|r: &RegionKind| r.keep_in_local_tcx()) -> RegionKind, - const_: mk_const(|c: &Const<'_>| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx> + const_: mk_const(|c: &Const<'_>| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx>, + goal: mk_goal(|c: &GoalKind<'_>| keep_local(c)) -> GoalKind<'tcx> ); macro_rules! slice_interners { @@ -2438,7 +2447,7 @@ slice_interners!( type_list: _intern_type_list(Ty), substs: _intern_substs(Kind), clauses: _intern_clauses(Clause), - goals: _intern_goals(Goal) + goal_list: _intern_goals(Goal) ); // This isn't a perfect fit: CanonicalVarInfo slices are always @@ -2818,10 +2827,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { iter.intern_with(|xs| self.intern_goals(xs)) } - pub fn mk_goal(self, goal: Goal<'tcx>) -> &'tcx Goal<'_> { - &self.intern_goals(&[goal])[0] - } - pub fn lint_hir>(self, lint: &'static Lint, hir_id: HirId, diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index c3d41873009a7..10a90dfc8a8cf 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -148,7 +148,10 @@ impl FlagComputation { self.add_projection_ty(data); } - &ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + &ty::UnnormalizedProjection(ref data) => { + self.add_flags(TypeFlags::HAS_PROJECTION); + self.add_projection_ty(data); + }, &ty::Opaque(_, substs) => { self.add_flags(TypeFlags::HAS_PROJECTION); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 4405c0aef9023..0514bd20c985a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -21,7 +21,6 @@ #![feature(box_syntax)] #![cfg_attr(unix, feature(libc))] #![feature(nll)] -#![feature(option_replace)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index e55469436abf0..307112f8ba16a 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -13,8 +13,10 @@ use borrow_check::error_reporting::UseSpans; use borrow_check::nll::region_infer::Cause; use borrow_check::{Context, MirBorrowckCtxt, WriteKind}; use rustc::ty::{self, Region, TyCtxt}; -use rustc::mir::{FakeReadCause, Local, Location, Mir, Operand}; -use rustc::mir::{Place, StatementKind, TerminatorKind}; +use rustc::mir::{ + CastKind, FakeReadCause, Local, Location, Mir, Operand, Place, Projection, ProjectionElem, + Rvalue, Statement, StatementKind, TerminatorKind +}; use rustc_errors::DiagnosticBuilder; use syntax_pos::Span; @@ -34,6 +36,7 @@ pub(in borrow_check) enum BorrowExplanation<'tcx> { #[derive(Clone, Copy)] pub(in borrow_check) enum LaterUseKind { + TraitCapture, ClosureCapture, Call, FakeLetRead, @@ -51,6 +54,7 @@ impl<'tcx> BorrowExplanation<'tcx> { match *self { BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => { let message = match later_use_kind { + LaterUseKind::TraitCapture => "borrow later captured here by trait object", LaterUseKind::ClosureCapture => "borrow later captured here by closure", LaterUseKind::Call => "borrow later used by call", LaterUseKind::FakeLetRead => "borrow later stored here", @@ -60,9 +64,10 @@ impl<'tcx> BorrowExplanation<'tcx> { }, BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => { let message = match later_use_kind { - LaterUseKind::ClosureCapture => { - "borrow captured here by closure, in later iteration of loop" - }, + LaterUseKind::TraitCapture => + "borrow captured here by trait object, in later iteration of loop", + LaterUseKind::ClosureCapture => + "borrow captured here by closure, in later iteration of loop", LaterUseKind::Call => "borrow used by call, in later iteration of loop", LaterUseKind::FakeLetRead => "borrow later stored here", LaterUseKind::Other => "borrow used here, in later iteration of loop", @@ -200,13 +205,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { .or_else(|| self.borrow_spans(span, location)); if self.is_borrow_location_in_loop(context.loc) { - let later_use = self.later_use_kind(spans, location); + let later_use = self.later_use_kind(borrow, spans, location); BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1) } else { // Check if the location represents a `FakeRead`, and adapt the error // message to the `FakeReadCause` it is from: in particular, // the ones inserted in optimized `let var = ` patterns. - let later_use = self.later_use_kind(spans, location); + let later_use = self.later_use_kind(borrow, spans, location); BorrowExplanation::UsedLater(later_use.0, later_use.1) } } @@ -316,42 +321,184 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { false } - fn later_use_kind(&self, use_spans: UseSpans, location: Location) -> (LaterUseKind, Span) { - use self::LaterUseKind::*; - - let block = &self.mir.basic_blocks()[location.block]; + /// Determine how the borrow was later used. + fn later_use_kind( + &self, + borrow: &BorrowData<'tcx>, + use_spans: UseSpans, + location: Location + ) -> (LaterUseKind, Span) { match use_spans { - UseSpans::ClosureUse { var_span, .. } => (LaterUseKind::ClosureCapture, var_span), + UseSpans::ClosureUse { var_span, .. } => { + // Used in a closure. + (LaterUseKind::ClosureCapture, var_span) + }, UseSpans::OtherUse(span) => { - (if let Some(stmt) = block.statements.get(location.statement_index) { - match stmt.kind { - StatementKind::FakeRead(FakeReadCause::ForLet, _) => FakeLetRead, - _ => Other, + let block = &self.mir.basic_blocks()[location.block]; + + let kind = if let Some(&Statement { + kind: StatementKind::FakeRead(FakeReadCause::ForLet, _), + .. + }) = block.statements.get(location.statement_index) { + LaterUseKind::FakeLetRead + } else if self.was_captured_by_trait_object(borrow) { + LaterUseKind::TraitCapture + } else if location.statement_index == block.statements.len() { + if let TerminatorKind::Call { + ref func, from_hir_call: true, .. + } = block.terminator().kind { + // Just point to the function, to reduce the chance of overlapping spans. + let function_span = match func { + Operand::Constant(c) => c.span, + Operand::Copy(Place::Local(l)) | Operand::Move(Place::Local(l)) => { + let local_decl = &self.mir.local_decls[*l]; + if local_decl.name.is_none() { + local_decl.source_info.span + } else { + span + } + }, + _ => span, + }; + return (LaterUseKind::Call, function_span); + } else { + LaterUseKind::Other } } else { - assert_eq!(location.statement_index, block.statements.len()); - match block.terminator().kind { - TerminatorKind::Call { ref func, from_hir_call: true, .. } => { - // Just point to the function, to reduce the chance - // of overlapping spans. - let function_span = match func { - Operand::Constant(c) => c.span, - Operand::Copy(Place::Local(l)) | Operand::Move(Place::Local(l)) => { - let local_decl = &self.mir.local_decls[*l]; - if local_decl.name.is_none() { - local_decl.source_info.span - } else { - span - } - }, - _ => span, - }; - return (Call, function_span); + LaterUseKind::Other + }; + + (kind, span) + } + } + } + + /// Check if a borrowed value was captured by a trait object. We do this by + /// looking forward in the MIR from the reserve location and checking if we see + /// a unsized cast to a trait object on our data. + fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool { + // Start at the reserve location, find the place that we want to see cast to a trait object. + let location = borrow.reserve_location; + let block = &self.mir[location.block]; + let stmt = block.statements.get(location.statement_index); + debug!("was_captured_by_trait_object: location={:?} stmt={:?}", location, stmt); + + // We make a `queue` vector that has the locations we want to visit. As of writing, this + // will only ever have one item at any given time, but by using a vector, we can pop from + // it which simplifies the termination logic. + let mut queue = vec![location]; + let mut target = if let Some(&Statement { + kind: StatementKind::Assign(Place::Local(local), _), + .. + }) = stmt { + local + } else { + return false; + }; + + debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue); + while let Some(current_location) = queue.pop() { + debug!("was_captured_by_trait: target={:?}", target); + let block = &self.mir[current_location.block]; + // We need to check the current location to find out if it is a terminator. + let is_terminator = current_location.statement_index == block.statements.len(); + if !is_terminator { + let stmt = &block.statements[current_location.statement_index]; + debug!("was_captured_by_trait_object: stmt={:?}", stmt); + + // The only kind of statement that we care about is assignments... + if let StatementKind::Assign( + place, + box rvalue, + ) = &stmt.kind { + let into = match place { + Place::Local(into) => into, + Place::Projection(box Projection { + base: Place::Local(into), + elem: ProjectionElem::Deref, + }) => into, + _ => { + // Continue at the next location. + queue.push(current_location.successor_within_block()); + continue; }, - _ => Other, + }; + + match rvalue { + // If we see a use, we should check whether it is our data, and if so + // update the place that we're looking for to that new place. + Rvalue::Use(operand) => match operand { + Operand::Copy(Place::Local(from)) | + Operand::Move(Place::Local(from)) if *from == target => { + target = *into; + }, + _ => {}, + }, + // If we see a unsized cast, then if it is our data we should check + // whether it is being cast to a trait object. + Rvalue::Cast(CastKind::Unsize, operand, ty) => match operand { + Operand::Copy(Place::Local(from)) | + Operand::Move(Place::Local(from)) if *from == target => { + debug!("was_captured_by_trait_object: ty={:?}", ty); + // Check the type for a trait object. + match ty.sty { + // `&dyn Trait` + ty::TyKind::Ref(_, ty, _) if ty.is_trait() => return true, + // `Box` + _ if ty.is_box() && ty.boxed_ty().is_trait() => + return true, + // `dyn Trait` + _ if ty.is_trait() => return true, + // Anything else. + _ => return false, + } + }, + _ => return false, + }, + _ => {}, } - }, span) + } + + // Continue at the next location. + queue.push(current_location.successor_within_block()); + } else { + // The only thing we need to do for terminators is progress to the next block. + let terminator = block.terminator(); + debug!("was_captured_by_trait_object: terminator={:?}", terminator); + + match &terminator.kind { + TerminatorKind::Call { + destination: Some((Place::Local(dest), block)), + args, + .. + } => { + debug!( + "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", + target, dest, args + ); + // Check if one of the arguments to this function is the target place. + let found_target = args.iter().any(|arg| { + if let Operand::Move(Place::Local(potential)) = arg { + *potential == target + } else { + false + } + }); + + // If it is, follow this to the next block and update the target. + if found_target { + target = *dest; + queue.push(block.start_location()); + } + }, + _ => {}, + } } + + debug!("was_captured_by_trait: queue={:?}", queue); } + + // We didn't find anything and ran out of locations to check. + false } } diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml index cd21ee601a7d2..16f0f11757a12 100644 --- a/src/librustc_traits/Cargo.toml +++ b/src/librustc_traits/Cargo.toml @@ -16,5 +16,5 @@ rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -chalk-engine = { version = "0.7.0", default-features=false } +chalk-engine = { version = "0.8.0", default-features=false } smallvec = { version = "0.6.5", features = ["union"] } diff --git a/src/librustc_traits/chalk_context.rs b/src/librustc_traits/chalk_context.rs index 4c28df97bdf50..dea3aa4372a33 100644 --- a/src/librustc_traits/chalk_context.rs +++ b/src/librustc_traits/chalk_context.rs @@ -19,6 +19,7 @@ use rustc::traits::{ ExClauseFold, ExClauseLift, Goal, + GoalKind, ProgramClause, QuantifierKind }; @@ -92,7 +93,7 @@ impl context::Context for ChalkArenas<'tcx> { type DomainGoal = DomainGoal<'tcx>; - type BindersGoal = ty::Binder<&'tcx Goal<'tcx>>; + type BindersGoal = ty::Binder>; type Parameter = Kind<'tcx>; @@ -102,14 +103,6 @@ impl context::Context for ChalkArenas<'tcx> { type UnificationResult = InferOk<'tcx, ()>; - fn into_goal(domain_goal: DomainGoal<'tcx>) -> Goal<'tcx> { - Goal::DomainGoal(domain_goal) - } - - fn cannot_prove() -> Goal<'tcx> { - Goal::CannotProve - } - fn goal_in_environment( env: &ty::ParamEnv<'tcx>, goal: Goal<'tcx>, @@ -251,15 +244,23 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { impl context::InferenceTable, ChalkArenas<'tcx>> for ChalkInferenceContext<'cx, 'gcx, 'tcx> { + fn into_goal(&self, domain_goal: DomainGoal<'tcx>) -> Goal<'tcx> { + self.infcx.tcx.mk_goal(GoalKind::DomainGoal(domain_goal)) + } + + fn cannot_prove(&self) -> Goal<'tcx> { + self.infcx.tcx.mk_goal(GoalKind::CannotProve) + } + fn into_hh_goal(&mut self, goal: Goal<'tcx>) -> ChalkHhGoal<'tcx> { - match goal { - Goal::Implies(..) => panic!("FIXME rust-lang-nursery/chalk#94"), - Goal::And(left, right) => HhGoal::And(*left, *right), - Goal::Not(subgoal) => HhGoal::Not(*subgoal), - Goal::DomainGoal(d) => HhGoal::DomainGoal(d), - Goal::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder), - Goal::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder), - Goal::CannotProve => HhGoal::CannotProve, + match *goal { + GoalKind::Implies(..) => panic!("FIXME rust-lang-nursery/chalk#94"), + GoalKind::And(left, right) => HhGoal::And(left, right), + GoalKind::Not(subgoal) => HhGoal::Not(subgoal), + GoalKind::DomainGoal(d) => HhGoal::DomainGoal(d), + GoalKind::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder), + GoalKind::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder), + GoalKind::CannotProve => HhGoal::CannotProve, } } @@ -363,21 +364,21 @@ impl context::UnificationOps, ChalkArenas<'tcx>> fn instantiate_binders_universally( &mut self, - _arg: &ty::Binder<&'tcx Goal<'tcx>>, + _arg: &ty::Binder>, ) -> Goal<'tcx> { panic!("FIXME -- universal instantiation needs sgrif's branch") } fn instantiate_binders_existentially( &mut self, - arg: &ty::Binder<&'tcx Goal<'tcx>>, + arg: &ty::Binder>, ) -> Goal<'tcx> { let (value, _map) = self.infcx.replace_late_bound_regions_with_fresh_var( DUMMY_SP, LateBoundRegionConversionTime::HigherRankedType, arg, ); - *value + value } fn debug_ex_clause(&mut self, value: &'v ChalkExClause<'tcx>) -> Box { diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index ad724babe49fb..181106d3f84bf 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -13,7 +13,14 @@ use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::hir::map::definitions::DefPathData; use rustc::hir::{self, ImplPolarity}; use rustc::traits::{ - Clause, Clauses, DomainGoal, FromEnv, Goal, PolyDomainGoal, ProgramClause, WellFormed, + Clause, + Clauses, + DomainGoal, + FromEnv, + GoalKind, + PolyDomainGoal, + ProgramClause, + WellFormed, WhereClause, }; use rustc::ty::query::Providers; @@ -249,7 +256,7 @@ fn program_clauses_for_trait<'a, 'tcx>( let impl_trait: DomainGoal = trait_pred.lower(); // `FromEnv(Self: Trait)` - let from_env_goal = impl_trait.into_from_env_goal().into_goal(); + let from_env_goal = tcx.mk_goal(impl_trait.into_from_env_goal().into_goal()); let hypotheses = tcx.intern_goals(&[from_env_goal]); // `Implemented(Self: Trait) :- FromEnv(Self: Trait)` @@ -308,7 +315,7 @@ fn program_clauses_for_trait<'a, 'tcx>( let wf_clause = ProgramClause { goal: DomainGoal::WellFormed(WellFormed::Trait(trait_pred)), hypotheses: tcx.mk_goals( - wf_conditions.map(|wc| Goal::from_poly_domain_goal(wc, tcx)), + wf_conditions.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))), ), }; let wf_clause = iter::once(Clause::ForAll(ty::Binder::dummy(wf_clause))); @@ -352,10 +359,10 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId hypotheses: tcx.mk_goals( where_clauses .into_iter() - .map(|wc| Goal::from_poly_domain_goal(wc, tcx)), + .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))), ), }; - tcx.intern_clauses(&[Clause::ForAll(ty::Binder::dummy(clause))]) + tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))) } pub fn program_clauses_for_type_def<'a, 'tcx>( @@ -388,7 +395,7 @@ pub fn program_clauses_for_type_def<'a, 'tcx>( where_clauses .iter() .cloned() - .map(|wc| Goal::from_poly_domain_goal(wc, tcx)), + .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))), ), }; @@ -404,7 +411,7 @@ pub fn program_clauses_for_type_def<'a, 'tcx>( // ``` // `FromEnv(Ty<...>)` - let from_env_goal = DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal(); + let from_env_goal = tcx.mk_goal(DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal()); let hypotheses = tcx.intern_goals(&[from_env_goal]); // For each where clause `WC`: @@ -423,10 +430,86 @@ pub fn program_clauses_for_type_def<'a, 'tcx>( } pub fn program_clauses_for_associated_type_def<'a, 'tcx>( - _tcx: TyCtxt<'a, 'tcx, 'tcx>, - _item_id: DefId, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + item_id: DefId, ) -> Clauses<'tcx> { - unimplemented!() + // Rule ProjectionEq-Skolemize + // + // ``` + // trait Trait { + // type AssocType; + // } + // ``` + // + // `ProjectionEq` can succeed by skolemizing, see "associated type" + // chapter for more: + // ``` + // forall { + // ProjectionEq( + // >::AssocType = + // (Trait::AssocType) + // ) + // } + // ``` + + let item = tcx.associated_item(item_id); + debug_assert_eq!(item.kind, ty::AssociatedKind::Type); + let trait_id = match item.container { + ty::AssociatedItemContainer::TraitContainer(trait_id) => trait_id, + _ => bug!("not an trait container"), + }; + let trait_ref = ty::TraitRef::identity(tcx, trait_id); + + let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident); + let placeholder_ty = tcx.mk_ty(ty::UnnormalizedProjection(projection_ty)); + let projection_eq = WhereClause::ProjectionEq(ty::ProjectionPredicate { + projection_ty, + ty: placeholder_ty, + }); + + let projection_eq_clause = ProgramClause { + goal: DomainGoal::Holds(projection_eq), + hypotheses: &ty::List::empty(), + }; + + // Rule WellFormed-AssocTy + // ``` + // forall { + // WellFormed((Trait::AssocType)) + // :- Implemented(Self: Trait) + // } + // ``` + + let trait_predicate = ty::TraitPredicate { trait_ref }; + let hypothesis = tcx.mk_goal( + DomainGoal::Holds(WhereClause::Implemented(trait_predicate)).into_goal() + ); + let wf_clause = ProgramClause { + goal: DomainGoal::WellFormed(WellFormed::Ty(placeholder_ty)), + hypotheses: tcx.mk_goals(iter::once(hypothesis)), + }; + + // Rule Implied-Trait-From-AssocTy + // ``` + // forall { + // FromEnv(Self: Trait) + // :- FromEnv((Trait::AssocType)) + // } + // ``` + + let hypothesis = tcx.mk_goal( + DomainGoal::FromEnv(FromEnv::Ty(placeholder_ty)).into_goal() + ); + let from_env_clause = ProgramClause { + goal: DomainGoal::FromEnv(FromEnv::Trait(trait_predicate)), + hypotheses: tcx.mk_goals(iter::once(hypothesis)), + }; + + let clauses = iter::once(projection_eq_clause) + .chain(iter::once(wf_clause)) + .chain(iter::once(from_env_clause)); + let clauses = clauses.map(|clause| Clause::ForAll(ty::Binder::dummy(clause))); + tcx.mk_clauses(clauses) } pub fn program_clauses_for_associated_type_value<'a, 'tcx>( @@ -435,10 +518,11 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>( ) -> Clauses<'tcx> { // Rule Normalize-From-Impl (see rustc guide) // - // ```impl Trait for A0 - // { + // ``` + // impl Trait for A0 { // type AssocType = T; - // }``` + // } + // ``` // // FIXME: For the moment, we don't account for where clauses written on the associated // ty definition (i.e. in the trait def, as in `type AssocType where T: Sized`). @@ -482,10 +566,10 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>( hypotheses: tcx.mk_goals( hypotheses .into_iter() - .map(|wc| Goal::from_poly_domain_goal(wc, tcx)), + .map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))), ), }; - tcx.intern_clauses(&[Clause::ForAll(ty::Binder::dummy(clause))]) + tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))) } pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index a9ce236557779..e611eb86dc1b3 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -9,7 +9,14 @@ // except according to those terms. use attr::HasAttrs; -use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; +use feature_gate::{ + feature_err, + EXPLAIN_STMT_ATTR_SYNTAX, + Features, + get_features, + GateIssue, + emit_feature_err, +}; use {fold, attr}; use ast; use source_map::Spanned; @@ -73,49 +80,103 @@ impl<'a> StripUnconfigured<'a> { if self.in_cfg(node.attrs()) { Some(node) } else { None } } + /// Parse and expand all `cfg_attr` attributes into a list of attributes + /// that are within each `cfg_attr` that has a true configuration predicate. + /// + /// Gives compiler warnigns if any `cfg_attr` does not contain any + /// attributes and is in the original source code. Gives compiler errors if + /// the syntax of any `cfg_attr` is incorrect. pub fn process_cfg_attrs(&mut self, node: T) -> T { node.map_attrs(|attrs| { - attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect() + attrs.into_iter().flat_map(|attr| self.process_cfg_attr(attr)).collect() }) } - fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option { + /// Parse and expand a single `cfg_attr` attribute into a list of attributes + /// when the configuration predicate is true, or otherwise expand into an + /// empty list of attributes. + /// + /// Gives a compiler warning when the `cfg_attr` contains no attribtes and + /// is in the original source file. Gives a compiler error if the syntax of + /// the attribute is incorrect + fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { if !attr.check_name("cfg_attr") { - return Some(attr); + return vec![attr]; } - let (cfg, path, tokens, span) = match attr.parse(self.sess, |parser| { + let gate_cfg_attr_multi = if let Some(ref features) = self.features { + !features.cfg_attr_multi + } else { + false + }; + let cfg_attr_span = attr.span; + + let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| { parser.expect(&token::OpenDelim(token::Paren))?; - let cfg = parser.parse_meta_item()?; + + let cfg_predicate = parser.parse_meta_item()?; parser.expect(&token::Comma)?; - let lo = parser.span.lo(); - let (path, tokens) = parser.parse_meta_item_unrestricted()?; - parser.eat(&token::Comma); // Optional trailing comma + + // Presumably, the majority of the time there will only be one attr. + let mut expanded_attrs = Vec::with_capacity(1); + + while !parser.check(&token::CloseDelim(token::Paren)) { + let lo = parser.span.lo(); + let (path, tokens) = parser.parse_meta_item_unrestricted()?; + expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo))); + parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?; + } + parser.expect(&token::CloseDelim(token::Paren))?; - Ok((cfg, path, tokens, parser.prev_span.with_lo(lo))) + Ok((cfg_predicate, expanded_attrs)) }) { Ok(result) => result, Err(mut e) => { e.emit(); - return None; + return Vec::new(); } }; - if attr::cfg_matches(&cfg, self.sess, self.features) { - self.process_cfg_attr(ast::Attribute { + // Check feature gate and lint on zero attributes in source. Even if the feature is gated, + // we still compute as if it wasn't, since the emitted error will stop compilation futher + // along the compilation. + match (expanded_attrs.len(), gate_cfg_attr_multi) { + (0, false) => { + // FIXME: Emit unused attribute lint here. + }, + (1, _) => {}, + (_, true) => { + emit_feature_err( + self.sess, + "cfg_attr_multi", + cfg_attr_span, + GateIssue::Language, + "cfg_attr with zero or more than one attributes is experimental", + ); + }, + (_, false) => {} + } + + if attr::cfg_matches(&cfg_predicate, self.sess, self.features) { + // We call `process_cfg_attr` recursively in case there's a + // `cfg_attr` inside of another `cfg_attr`. E.g. + // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. + expanded_attrs.into_iter() + .flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute { id: attr::mk_attr_id(), style: attr.style, path, tokens, is_sugared_doc: false, span, - }) + })) + .collect() } else { - None + Vec::new() } } - // Determine if a node with the given attributes should be included in this configuration. + /// Determine if a node with the given attributes should be included in this configuration. pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { attrs.iter().all(|attr| { if !is_cfg(attr) { @@ -165,7 +226,7 @@ impl<'a> StripUnconfigured<'a> { }) } - // Visit attributes on expression and statements (but not attributes on items in blocks). + /// Visit attributes on expression and statements (but not attributes on items in blocks). fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) { // flag the offending attributes for attr in attrs.iter() { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 24ee24640558e..b86b92fb29e60 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -433,9 +433,6 @@ declare_features! ( // #[doc(alias = "...")] (active, doc_alias, "1.27.0", Some(50146), None), - // Scoped lints - (active, tool_lints, "1.28.0", Some(44690), None), - // Allows irrefutable patterns in if-let and while-let statements (RFC 2086) (active, irrefutable_let_patterns, "1.27.0", Some(44495), None), @@ -499,6 +496,9 @@ declare_features! ( // Allows `impl Trait` in bindings (`let`, `const`, `static`) (active, impl_trait_in_bindings, "1.30.0", Some(34511), None), + + // #[cfg_attr(predicate, multiple, attributes, here)] + (active, cfg_attr_multi, "1.31.0", Some(54881), None), ); declare_features! ( @@ -679,6 +679,8 @@ declare_features! ( (accepted, pattern_parentheses, "1.31.0", Some(51087), None), // Allows the definition of `const fn` functions. (accepted, min_const_fn, "1.31.0", Some(53555), None), + // Scoped lints + (accepted, tool_lints, "1.31.0", Some(44690), None), ); // If you change this, please modify src/doc/unstable-book as well. You must diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d653ed819fddd..3099b2a3e8e9b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -678,7 +678,7 @@ impl<'a> Parser<'a> { /// Expect next token to be edible or inedible token. If edible, /// then consume it; if inedible, then return without consuming /// anything. Signal a fatal error if next token is unexpected. - fn expect_one_of(&mut self, + pub fn expect_one_of(&mut self, edible: &[token::Token], inedible: &[token::Token]) -> PResult<'a, ()>{ fn tokens_to_string(tokens: &[TokenType]) -> String { @@ -3866,6 +3866,9 @@ impl<'a> Parser<'a> { // check that a comma comes after every field if !ate_comma { let err = self.struct_span_err(self.prev_span, "expected `,`"); + if let Some(mut delayed) = delayed_err { + delayed.emit(); + } return Err(err); } ate_comma = false; diff --git a/src/test/run-pass/tool_lints.rs b/src/test/run-pass/tool_lints.rs index 24ec43b12f60e..2705c03598a0d 100644 --- a/src/test/run-pass/tool_lints.rs +++ b/src/test/run-pass/tool_lints.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tool_lints)] + #![deny(unknown_lints)] #[allow(clippy::almost_swapped)] diff --git a/src/test/run-pass/tool_lints_2018_preview.rs b/src/test/run-pass/tool_lints_2018_preview.rs index 6cd57eaa19595..57df3e072a8dc 100644 --- a/src/test/run-pass/tool_lints_2018_preview.rs +++ b/src/test/run-pass/tool_lints_2018_preview.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tool_lints)] + #![feature(rust_2018_preview)] #![deny(unknown_lints)] diff --git a/src/test/ui-fulldeps/lint_tool_test.rs b/src/test/ui-fulldeps/lint_tool_test.rs index ebe10b3714f20..11b70d1d7809c 100644 --- a/src/test/ui-fulldeps/lint_tool_test.rs +++ b/src/test/ui-fulldeps/lint_tool_test.rs @@ -11,8 +11,8 @@ // aux-build:lint_tool_test.rs // ignore-stage1 // compile-flags: --cfg foo + #![feature(plugin)] -#![feature(tool_lints)] #![plugin(lint_tool_test)] #![allow(dead_code)] #![cfg_attr(foo, warn(test_lint))] diff --git a/src/test/ui/cfg-attr-trailing-comma.rs b/src/test/ui/cfg-attr-trailing-comma.rs deleted file mode 100644 index 21e00544ca00b..0000000000000 --- a/src/test/ui/cfg-attr-trailing-comma.rs +++ /dev/null @@ -1,13 +0,0 @@ -// compile-flags: --cfg TRUE - -#[cfg_attr(TRUE, inline,)] // OK -fn f() {} - -#[cfg_attr(FALSE, inline,)] // OK -fn g() {} - -#[cfg_attr(TRUE, inline,,)] //~ ERROR expected `)`, found `,` -fn h() {} - -#[cfg_attr(FALSE, inline,,)] //~ ERROR expected `)`, found `,` -fn i() {} diff --git a/src/test/ui/cfg-attr-trailing-comma.stderr b/src/test/ui/cfg-attr-trailing-comma.stderr deleted file mode 100644 index 76a470417e9ed..0000000000000 --- a/src/test/ui/cfg-attr-trailing-comma.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: expected `)`, found `,` - --> $DIR/cfg-attr-trailing-comma.rs:9:25 - | -LL | #[cfg_attr(TRUE, inline,,)] //~ ERROR expected `)`, found `,` - | ^ expected `)` - -error: expected `)`, found `,` - --> $DIR/cfg-attr-trailing-comma.rs:12:26 - | -LL | #[cfg_attr(FALSE, inline,,)] //~ ERROR expected `)`, found `,` - | ^ expected `)` - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/chalkify/lower_trait.rs b/src/test/ui/chalkify/lower_trait.rs index c5ba5beeca7a5..ba7d4ff0d9bf5 100644 --- a/src/test/ui/chalkify/lower_trait.rs +++ b/src/test/ui/chalkify/lower_trait.rs @@ -10,11 +10,12 @@ #![feature(rustc_attrs)] +trait Bar { } + #[rustc_dump_program_clauses] //~ ERROR program clause dump -trait Foo { - fn s(_: S) -> S; - fn t(_: T) -> T; - fn u(_: U) -> U; +trait Foo { + #[rustc_dump_program_clauses] //~ ERROR program clause dump + type Assoc: Bar + ?Sized; } fn main() { diff --git a/src/test/ui/chalkify/lower_trait.stderr b/src/test/ui/chalkify/lower_trait.stderr index c4e768415d60b..dc2375277e734 100644 --- a/src/test/ui/chalkify/lower_trait.stderr +++ b/src/test/ui/chalkify/lower_trait.stderr @@ -1,14 +1,23 @@ error: program clause dump - --> $DIR/lower_trait.rs:13:1 + --> $DIR/lower_trait.rs:15:1 | LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo). - = note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo). - = note: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo). - = note: Implemented(Self: Foo) :- FromEnv(Self: Foo). - = note: WellFormed(Self: Foo) :- Implemented(Self: Foo), WellFormed(S: std::marker::Sized), WellFormed(T: std::marker::Sized), WellFormed(U: std::marker::Sized). + = note: FromEnv(>::Assoc: Bar) :- FromEnv(Self: Foo). + = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo). + = note: Implemented(Self: Foo) :- FromEnv(Self: Foo). + = note: WellFormed(Self: Foo) :- Implemented(Self: Foo), WellFormed(S: std::marker::Sized), WellFormed(>::Assoc: Bar). -error: aborting due to previous error +error: program clause dump + --> $DIR/lower_trait.rs:17:5 + | +LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: FromEnv(Self: Foo) :- FromEnv(Unnormalized(>::Assoc)). + = note: ProjectionEq(>::Assoc == Unnormalized(>::Assoc)). + = note: WellFormed(Unnormalized(>::Assoc)) :- Implemented(Self: Foo). + +error: aborting due to 2 previous errors diff --git a/src/test/ui/auxiliary/namespaced_enums.rs b/src/test/ui/conditional-compilation/auxiliary/namespaced_enums.rs similarity index 100% rename from src/test/ui/auxiliary/namespaced_enums.rs rename to src/test/ui/conditional-compilation/auxiliary/namespaced_enums.rs diff --git a/src/test/ui/cfg-arg-invalid-1.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs similarity index 100% rename from src/test/ui/cfg-arg-invalid-1.rs rename to src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs diff --git a/src/test/ui/cfg-arg-invalid-2.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-2.rs similarity index 100% rename from src/test/ui/cfg-arg-invalid-2.rs rename to src/test/ui/conditional-compilation/cfg-arg-invalid-2.rs diff --git a/src/test/ui/cfg-arg-invalid-3.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-3.rs similarity index 100% rename from src/test/ui/cfg-arg-invalid-3.rs rename to src/test/ui/conditional-compilation/cfg-arg-invalid-3.rs diff --git a/src/test/ui/cfg-arg-invalid-4.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-4.rs similarity index 100% rename from src/test/ui/cfg-arg-invalid-4.rs rename to src/test/ui/conditional-compilation/cfg-arg-invalid-4.rs diff --git a/src/test/ui/cfg-arg-invalid-5.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-5.rs similarity index 100% rename from src/test/ui/cfg-arg-invalid-5.rs rename to src/test/ui/conditional-compilation/cfg-arg-invalid-5.rs diff --git a/src/test/ui/cfg-attr-cfg-2.rs b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.rs similarity index 100% rename from src/test/ui/cfg-attr-cfg-2.rs rename to src/test/ui/conditional-compilation/cfg-attr-cfg-2.rs diff --git a/src/test/ui/cfg-attr-cfg-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr similarity index 100% rename from src/test/ui/cfg-attr-cfg-2.stderr rename to src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr diff --git a/src/test/ui/cfg-attr-crate-2.rs b/src/test/ui/conditional-compilation/cfg-attr-crate-2.rs similarity index 100% rename from src/test/ui/cfg-attr-crate-2.rs rename to src/test/ui/conditional-compilation/cfg-attr-crate-2.rs diff --git a/src/test/ui/cfg-attr-crate-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr similarity index 91% rename from src/test/ui/cfg-attr-crate-2.stderr rename to src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr index 7b66c8f5e40f0..a730473f66315 100644 --- a/src/test/ui/cfg-attr-crate-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr @@ -2,7 +2,7 @@ error[E0658]: no_core is experimental (see issue #29639) --> $DIR/cfg-attr-crate-2.rs:15:21 | LL | #![cfg_attr(broken, no_core)] //~ ERROR no_core is experimental - | ^^^^^^^^ + | ^^^^^^^ | = help: add #![feature(no_core)] to the crate attributes to enable diff --git a/src/test/ui/cfg-attr-invalid-predicate.rs b/src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.rs similarity index 100% rename from src/test/ui/cfg-attr-invalid-predicate.rs rename to src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.rs diff --git a/src/test/ui/cfg-attr-invalid-predicate.stderr b/src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.stderr similarity index 100% rename from src/test/ui/cfg-attr-invalid-predicate.stderr rename to src/test/ui/conditional-compilation/cfg-attr-invalid-predicate.stderr diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs new file mode 100644 index 0000000000000..84bd33fc0e7d3 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-false.rs @@ -0,0 +1,20 @@ +// Test that cfg_attr doesn't emit any attributes when the +// configuation variable is false. This mirrors `cfg-attr-multi-true.rs` + +// compile-pass + +#![warn(unused_must_use)] +#![feature(cfg_attr_multi)] + +#[cfg_attr(any(), deprecated, must_use)] +struct Struct {} + +impl Struct { + fn new() -> Struct { + Struct {} + } +} + +fn main() { + Struct::new(); +} diff --git a/src/test/ui/feature-gates/feature-gate-tool_lints-fail.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs similarity index 65% rename from src/test/ui/feature-gates/feature-gate-tool_lints-fail.rs rename to src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs index c311eb7ed7ae1..d4c3186a6ebbb 100644 --- a/src/test/ui/feature-gates/feature-gate-tool_lints-fail.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs @@ -1,4 +1,4 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -7,6 +7,10 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// +// compile-flags: --cfg broken + +#![feature(cfg_attr_multi)] +#![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental -#[warn(clippy::assign_ops)] //~ ERROR scoped lint `clippy::assign_ops` is experimental -fn main() {} +fn main() { } diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr new file mode 100644 index 0000000000000..bf68d92cc0bbd --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr @@ -0,0 +1,11 @@ +error[E0658]: no_core is experimental (see issue #29639) + --> $DIR/cfg-attr-multi-invalid-1.rs:14:21 + | +LL | #![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental + | ^^^^^^^ + | + = help: add #![feature(no_core)] 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/conditional-compilation/cfg-attr-multi-invalid-2.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs new file mode 100644 index 0000000000000..bee6b7d4886bd --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs @@ -0,0 +1,16 @@ +// Copyright 2015 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: --cfg broken + +#![feature(cfg_attr_multi)] +#![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental + +fn main() { } diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr new file mode 100644 index 0000000000000..5c72a400e0bae --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr @@ -0,0 +1,11 @@ +error[E0658]: no_core is experimental (see issue #29639) + --> $DIR/cfg-attr-multi-invalid-2.rs:14:29 + | +LL | #![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental + | ^^^^^^^ + | + = help: add #![feature(no_core)] 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/conditional-compilation/cfg-attr-multi-true.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-true.rs new file mode 100644 index 0000000000000..a31dde00c7cf5 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-true.rs @@ -0,0 +1,22 @@ +// Test that cfg_attr with multiple attributes actually emits both attributes. +// This is done by emitting two attributes that cause new warnings, and then +// triggering those warnings. + +// compile-pass + +#![warn(unused_must_use)] +#![feature(cfg_attr_multi)] + +#[cfg_attr(all(), deprecated, must_use)] +struct MustUseDeprecated {} + +impl MustUseDeprecated { //~ warning: use of deprecated item + fn new() -> MustUseDeprecated { //~ warning: use of deprecated item + MustUseDeprecated {} //~ warning: use of deprecated item + } +} + +fn main() { + MustUseDeprecated::new(); //~ warning: use of deprecated item + //| warning: unused `MustUseDeprecated` which must be used +} diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr new file mode 100644 index 0000000000000..37cb3de06c04f --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-true.stderr @@ -0,0 +1,38 @@ +warning: use of deprecated item 'MustUseDeprecated' + --> $DIR/cfg-attr-multi-true.rs:13:6 + | +LL | impl MustUseDeprecated { //~ warning: use of deprecated item + | ^^^^^^^^^^^^^^^^^ + | + = note: #[warn(deprecated)] on by default + +warning: use of deprecated item 'MustUseDeprecated' + --> $DIR/cfg-attr-multi-true.rs:20:5 + | +LL | MustUseDeprecated::new(); //~ warning: use of deprecated item + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated item 'MustUseDeprecated' + --> $DIR/cfg-attr-multi-true.rs:14:17 + | +LL | fn new() -> MustUseDeprecated { //~ warning: use of deprecated item + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated item 'MustUseDeprecated' + --> $DIR/cfg-attr-multi-true.rs:15:9 + | +LL | MustUseDeprecated {} //~ warning: use of deprecated item + | ^^^^^^^^^^^^^^^^^ + +warning: unused `MustUseDeprecated` which must be used + --> $DIR/cfg-attr-multi-true.rs:20:5 + | +LL | MustUseDeprecated::new(); //~ warning: use of deprecated item + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/cfg-attr-multi-true.rs:7:9 + | +LL | #![warn(unused_must_use)] + | ^^^^^^^^^^^^^^^ + diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.rs b/src/test/ui/conditional-compilation/cfg-attr-parse.rs new file mode 100644 index 0000000000000..eec0e8faca877 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-parse.rs @@ -0,0 +1,45 @@ +// Parse `cfg_attr` with varying numbers of attributes and trailing commas + +#![feature(cfg_attr_multi)] + +// Completely empty `cfg_attr` input +#[cfg_attr()] //~ error: expected identifier, found `)` +struct NoConfigurationPredicate; + +// Zero attributes, zero trailing comma (comma manatory here) +#[cfg_attr(all())] //~ error: expected `,`, found `)` +struct A0C0; + +// Zero attributes, one trailing comma +#[cfg_attr(all(),)] // Ok +struct A0C1; + +// Zero attributes, two trailing commas +#[cfg_attr(all(),,)] //~ ERROR expected identifier +struct A0C2; + +// One attribute, no trailing comma +#[cfg_attr(all(), must_use)] // Ok +struct A1C0; + +// One attribute, one trailing comma +#[cfg_attr(all(), must_use,)] // Ok +struct A1C1; + +// One attribute, two trailing commas +#[cfg_attr(all(), must_use,,)] //~ ERROR expected identifier +struct A1C2; + +// Two attributes, no trailing comma +#[cfg_attr(all(), must_use, deprecated)] // Ok +struct A2C0; + +// Two attributes, one trailing comma +#[cfg_attr(all(), must_use, deprecated,)] // Ok +struct A2C1; + +// Two attributes, two trailing commas +#[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier +struct A2C2; + +fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr new file mode 100644 index 0000000000000..553406b6dd83d --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr @@ -0,0 +1,32 @@ +error: expected identifier, found `)` + --> $DIR/cfg-attr-parse.rs:6:12 + | +LL | #[cfg_attr()] //~ error: expected identifier, found `)` + | ^ expected identifier + +error: expected `,`, found `)` + --> $DIR/cfg-attr-parse.rs:10:17 + | +LL | #[cfg_attr(all())] //~ error: expected `,`, found `)` + | ^ expected `,` + +error: expected identifier, found `,` + --> $DIR/cfg-attr-parse.rs:18:18 + | +LL | #[cfg_attr(all(),,)] //~ ERROR expected identifier + | ^ expected identifier + +error: expected identifier, found `,` + --> $DIR/cfg-attr-parse.rs:30:28 + | +LL | #[cfg_attr(all(), must_use,,)] //~ ERROR expected identifier + | ^ expected identifier + +error: expected identifier, found `,` + --> $DIR/cfg-attr-parse.rs:42:40 + | +LL | #[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier + | ^ expected identifier + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/cfg-attr-syntax-validation.rs b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs similarity index 100% rename from src/test/ui/cfg-attr-syntax-validation.rs rename to src/test/ui/conditional-compilation/cfg-attr-syntax-validation.rs diff --git a/src/test/ui/cfg-attr-syntax-validation.stderr b/src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr similarity index 100% rename from src/test/ui/cfg-attr-syntax-validation.stderr rename to src/test/ui/conditional-compilation/cfg-attr-syntax-validation.stderr diff --git a/src/test/ui/cfg-attr-unknown-attribute-macro-expansion.rs b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs similarity index 100% rename from src/test/ui/cfg-attr-unknown-attribute-macro-expansion.rs rename to src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.rs diff --git a/src/test/ui/cfg-attr-unknown-attribute-macro-expansion.stderr b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr similarity index 100% rename from src/test/ui/cfg-attr-unknown-attribute-macro-expansion.stderr rename to src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr diff --git a/src/test/ui/cfg-empty-codemap.rs b/src/test/ui/conditional-compilation/cfg-empty-codemap.rs similarity index 100% rename from src/test/ui/cfg-empty-codemap.rs rename to src/test/ui/conditional-compilation/cfg-empty-codemap.rs diff --git a/src/test/ui/cfg-in-crate-1.rs b/src/test/ui/conditional-compilation/cfg-in-crate-1.rs similarity index 100% rename from src/test/ui/cfg-in-crate-1.rs rename to src/test/ui/conditional-compilation/cfg-in-crate-1.rs diff --git a/src/test/ui/cfg-in-crate-1.stderr b/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr similarity index 100% rename from src/test/ui/cfg-in-crate-1.stderr rename to src/test/ui/conditional-compilation/cfg-in-crate-1.stderr diff --git a/src/test/ui/cfg-non-opt-expr.rs b/src/test/ui/conditional-compilation/cfg-non-opt-expr.rs similarity index 100% rename from src/test/ui/cfg-non-opt-expr.rs rename to src/test/ui/conditional-compilation/cfg-non-opt-expr.rs diff --git a/src/test/ui/cfg-non-opt-expr.stderr b/src/test/ui/conditional-compilation/cfg-non-opt-expr.stderr similarity index 100% rename from src/test/ui/cfg-non-opt-expr.stderr rename to src/test/ui/conditional-compilation/cfg-non-opt-expr.stderr diff --git a/src/test/ui/cfg_attr_path.rs b/src/test/ui/conditional-compilation/cfg_attr_path.rs similarity index 100% rename from src/test/ui/cfg_attr_path.rs rename to src/test/ui/conditional-compilation/cfg_attr_path.rs diff --git a/src/test/ui/cfg_attr_path.stderr b/src/test/ui/conditional-compilation/cfg_attr_path.stderr similarity index 100% rename from src/test/ui/cfg_attr_path.stderr rename to src/test/ui/conditional-compilation/cfg_attr_path.stderr diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.rs b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.rs new file mode 100644 index 0000000000000..9515380bc2856 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.rs @@ -0,0 +1,5 @@ +// gate-test-cfg_attr_multi + +#![cfg_attr(all(), warn(nonstandard_style), allow(unused_attributes))] +//~^ ERROR cfg_attr with zero or more than one attributes is experimental +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr new file mode 100644 index 0000000000000..088e6df1a1ac1 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-1.stderr @@ -0,0 +1,11 @@ +error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #54881) + --> $DIR/feature-gate-cfg-attr-multi-1.rs:3:1 + | +LL | #![cfg_attr(all(), warn(nonstandard_style), allow(unused_attributes))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(cfg_attr_multi)] 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/feature-gates/feature-gate-cfg-attr-multi-2.rs b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.rs new file mode 100644 index 0000000000000..cf02432274b1e --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.rs @@ -0,0 +1,3 @@ +#![cfg_attr(all(),)] +//~^ ERROR cfg_attr with zero or more than one attributes is experimental +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr new file mode 100644 index 0000000000000..a01876114dde8 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-2.stderr @@ -0,0 +1,11 @@ +error[E0658]: cfg_attr with zero or more than one attributes is experimental (see issue #54881) + --> $DIR/feature-gate-cfg-attr-multi-2.rs:1:1 + | +LL | #![cfg_attr(all(),)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(cfg_attr_multi)] 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/feature-gates/feature-gate-cfg-attr-multi-bootstrap-1.rs b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-1.rs new file mode 100644 index 0000000000000..e4737926e7a22 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-1.rs @@ -0,0 +1,7 @@ +// Test that settingt the featute gate while using its functionality doesn't error. + +// compile-pass + +#![cfg_attr(all(), feature(cfg_attr_multi), crate_type="bin")] + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-2.rs b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-2.rs new file mode 100644 index 0000000000000..df740541f5543 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-attr-multi-bootstrap-2.rs @@ -0,0 +1,9 @@ +// Test that settingt the featute gate while using its functionality doesn't error. +// Specifically, if there's a cfg-attr *before* the feature gate. + +// compile-pass + +#![cfg_attr(all(),)] +#![cfg_attr(all(), feature(cfg_attr_multi), crate_type="bin")] + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-tool_lints-fail.stderr b/src/test/ui/feature-gates/feature-gate-tool_lints-fail.stderr deleted file mode 100644 index 33ee79cd2011a..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-tool_lints-fail.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: scoped lint `clippy::assign_ops` is experimental (see issue #44690) - --> $DIR/feature-gate-tool_lints-fail.rs:11:8 - | -LL | #[warn(clippy::assign_ops)] //~ ERROR scoped lint `clippy::assign_ops` is experimental - | ^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(tool_lints)] 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/feature-gates/feature-gate-tool_lints.stderr b/src/test/ui/feature-gates/feature-gate-tool_lints.stderr deleted file mode 100644 index 8019b1e6a28f6..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-tool_lints.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: scoped lint `clippy::decimal_literal_representation` is experimental (see issue #44690) - --> $DIR/feature-gate-tool_lints.rs:11:8 - | -LL | #[warn(clippy::decimal_literal_representation)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(tool_lints)] 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/nll/issue-52663-trait-object.rs b/src/test/ui/nll/issue-52663-trait-object.rs new file mode 100644 index 0000000000000..65d73eeae67c4 --- /dev/null +++ b/src/test/ui/nll/issue-52663-trait-object.rs @@ -0,0 +1,27 @@ +// Copyright 2014 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(box_syntax)] +#![feature(nll)] + +trait Foo { fn get(&self); } + +impl Foo for A { + fn get(&self) { } +} + +fn main() { + let _ = { + let tmp0 = 3; + let tmp1 = &tmp0; + box tmp1 as Box + }; + //~^^^ ERROR `tmp0` does not live long enough +} diff --git a/src/test/ui/nll/issue-52663-trait-object.stderr b/src/test/ui/nll/issue-52663-trait-object.stderr new file mode 100644 index 0000000000000..035422f245825 --- /dev/null +++ b/src/test/ui/nll/issue-52663-trait-object.stderr @@ -0,0 +1,13 @@ +error[E0597]: `tmp0` does not live long enough + --> $DIR/issue-52663-trait-object.rs:23:20 + | +LL | let tmp1 = &tmp0; + | ^^^^^ borrowed value does not live long enough +LL | box tmp1 as Box + | ------------------------- borrow later captured here by trait object +LL | }; + | - `tmp0` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/feature-gates/feature-gate-tool_lints.rs b/src/test/ui/resolve/issue-54379.rs similarity index 74% rename from src/test/ui/feature-gates/feature-gate-tool_lints.rs rename to src/test/ui/resolve/issue-54379.rs index 3ef67982be9a4..24aa758ea6c23 100644 --- a/src/test/ui/feature-gates/feature-gate-tool_lints.rs +++ b/src/test/ui/resolve/issue-54379.rs @@ -7,9 +7,15 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +struct MyStruct { + pub s1: Option, +} -#[warn(clippy::decimal_literal_representation)] -//~^ ERROR scoped lint `clippy::decimal_literal_representation` is experimental fn main() { - let a = 65_535; + let thing = MyStruct { s1: None }; + + match thing { + MyStruct { .., Some(_) } => {}, + _ => {} + } } diff --git a/src/test/ui/resolve/issue-54379.stderr b/src/test/ui/resolve/issue-54379.stderr new file mode 100644 index 0000000000000..d1d693a3817b9 --- /dev/null +++ b/src/test/ui/resolve/issue-54379.stderr @@ -0,0 +1,24 @@ +error: expected `}`, found `,` + --> $DIR/issue-54379.rs:18:22 + | +LL | MyStruct { .., Some(_) } => {}, + | --^ + | | | + | | expected `}` + | `..` must be at the end and cannot have a trailing comma + +error: expected `,` + --> $DIR/issue-54379.rs:18:24 + | +LL | MyStruct { .., Some(_) } => {}, + | ^^^^ + +error[E0027]: pattern does not mention field `s1` + --> $DIR/issue-54379.rs:18:9 + | +LL | MyStruct { .., Some(_) } => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^^ missing field `s1` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr index f8e5e3914eb3c..11fa447b5489a 100644 --- a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr +++ b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr @@ -4,7 +4,7 @@ error[E0597]: `tmp0` does not live long enough LL | let tmp1 = &tmp0; | ^^^^^ borrowed value does not live long enough LL | repeater3(tmp1) - | --------------- borrow later used here + | --------------- borrow later captured here by trait object LL | }; | - `tmp0` dropped here while still borrowed diff --git a/src/test/ui/tool_lints-fail.rs b/src/test/ui/tool_lints-fail.rs index ea1efab4cb6f8..4134fca1ce6ca 100644 --- a/src/test/ui/tool_lints-fail.rs +++ b/src/test/ui/tool_lints-fail.rs @@ -10,7 +10,7 @@ // Don't allow tool_lints, which aren't scoped -#![feature(tool_lints)] + #![deny(unknown_lints)] #![deny(clippy)] //~ ERROR: unknown lint: `clippy` diff --git a/src/test/ui/tool_lints.rs b/src/test/ui/tool_lints.rs index 71f90b17c18fc..001f2f11e5cb3 100644 --- a/src/test/ui/tool_lints.rs +++ b/src/test/ui/tool_lints.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tool_lints)] + #[warn(foo::bar)] //~^ ERROR an unknown tool name found in scoped lint: `foo::bar` diff --git a/src/test/ui/unknown-lint-tool-name.rs b/src/test/ui/unknown-lint-tool-name.rs index 78b736edcebe6..a1d6c27e518e5 100644 --- a/src/test/ui/unknown-lint-tool-name.rs +++ b/src/test/ui/unknown-lint-tool-name.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(tool_lints)] + #![deny(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar`