diff options
| -rw-r--r-- | compiler/rustc_attr/src/builtin.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_lexer/src/tests.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 11 | ||||
| -rw-r--r-- | library/core/src/cmp.rs | 5 | ||||
| -rw-r--r-- | library/core/src/iter/adapters/by_ref_sized.rs | 42 | ||||
| -rw-r--r-- | library/core/src/iter/adapters/mod.rs | 3 | ||||
| -rw-r--r-- | library/core/src/iter/mod.rs | 2 | ||||
| -rw-r--r-- | library/core/src/iter/traits/iterator.rs | 3 | ||||
| -rw-r--r-- | library/core/tests/cmp.rs | 13 | ||||
| -rw-r--r-- | library/core/tests/iter/traits/iterator.rs | 24 | ||||
| -rw-r--r-- | library/std/src/sys/unix/process/process_unix.rs | 6 | ||||
| -rw-r--r-- | src/bootstrap/test.rs | 58 | ||||
| -rw-r--r-- | src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 10 | ||||
| -rw-r--r-- | src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version | 1 | ||||
| -rwxr-xr-x | src/ci/scripts/should-skip-this.sh | 1 | ||||
| -rw-r--r-- | src/test/ui/cfg/cfg-path-error.rs | 19 | ||||
| -rw-r--r-- | src/test/ui/cfg/cfg-path-error.stderr | 26 |
17 files changed, 218 insertions, 35 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 613320087d2..8a134bf7f96 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -603,10 +603,18 @@ pub fn eval_condition( match cfg.name_or_empty() { sym::any => mis .iter() - .any(|mi| eval_condition(mi.meta_item().unwrap(), sess, features, eval)), + // We don't use any() here, because we want to evaluate all cfg condition + // as eval_condition can (and does) extra checks + .fold(false, |res, mi| { + res | eval_condition(mi.meta_item().unwrap(), sess, features, eval) + }), sym::all => mis .iter() - .all(|mi| eval_condition(mi.meta_item().unwrap(), sess, features, eval)), + // We don't use all() here, because we want to evaluate all cfg condition + // as eval_condition can (and does) extra checks + .fold(true, |res, mi| { + res & eval_condition(mi.meta_item().unwrap(), sess, features, eval) + }), sym::not => { if mis.len() != 1 { struct_span_err!( diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs index 94017b7b286..548de67449a 100644 --- a/compiler/rustc_lexer/src/tests.rs +++ b/compiler/rustc_lexer/src/tests.rs @@ -67,6 +67,23 @@ fn test_unterminated_no_pound() { } #[test] +fn test_too_many_hashes() { + let max_count = u16::MAX; + let mut hashes: String = "#".repeat(max_count.into()); + + // Valid number of hashes (65535 = 2^16 - 1), but invalid string. + check_raw_str(&hashes, max_count, Some(RawStrError::InvalidStarter { bad_char: '\u{0}' })); + + // One more hash sign (65536 = 2^16) becomes too many. + hashes.push('#'); + check_raw_str( + &hashes, + 0, + Some(RawStrError::TooManyDelimiters { found: usize::from(max_count) + 1 }), + ); +} + +#[test] fn test_valid_shebang() { // https://github.com/rust-lang/rust/issues/70528 let input = "#!/usr/bin/rustrun\nlet x = 5;"; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index ef006d5fcda..a907f50a11b 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,9 +1,10 @@ +use super::diagnostics::SnapshotParser; use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ - AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, TokenType, + AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, + SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken, }; -use super::{SemiColonMode, SeqSep, TokenExpectType, TrailingToken}; use crate::maybe_recover_from_interpolated_ty_qpath; use ast::token::DelimToken; @@ -1105,7 +1106,7 @@ impl<'a> Parser<'a> { let snapshot = if self.token.kind == token::OpenDelim(token::Paren) && self.look_ahead_type_ascription_as_field() { - Some((self.clone(), fun.kind.clone())) + Some((self.create_snapshot_for_diagnostic(), fun.kind.clone())) } else { None }; @@ -1130,7 +1131,7 @@ impl<'a> Parser<'a> { lo: Span, open_paren: Span, seq: &mut PResult<'a, P<Expr>>, - snapshot: Option<(Self, ExprKind)>, + snapshot: Option<(SnapshotParser<'a>, ExprKind)>, ) -> Option<P<Expr>> { match (seq.as_mut(), snapshot) { (Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => { @@ -1140,7 +1141,7 @@ impl<'a> Parser<'a> { Ok((fields, ..)) if snapshot.eat(&token::CloseDelim(token::Paren)) => { // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`. - *self = snapshot; + self.restore_snapshot(snapshot); let close_paren = self.prev_token.span; let span = lo.to(self.prev_token.span); if !fields.is_empty() { diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index ddaeb9eca97..74328a3607d 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -333,7 +333,7 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> { /// let result = 2.cmp(&1); /// assert_eq!(Ordering::Greater, result); /// ``` -#[derive(Clone, Copy, PartialEq, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] #[repr(i8)] pub enum Ordering { @@ -862,9 +862,6 @@ pub macro Ord($item:item) { } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Ordering {} - -#[stable(feature = "rust1", since = "1.0.0")] impl Ord for Ordering { #[inline] fn cmp(&self, other: &Ordering) -> Ordering { diff --git a/library/core/src/iter/adapters/by_ref_sized.rs b/library/core/src/iter/adapters/by_ref_sized.rs new file mode 100644 index 00000000000..0b5e2a89ef3 --- /dev/null +++ b/library/core/src/iter/adapters/by_ref_sized.rs @@ -0,0 +1,42 @@ +use crate::ops::Try; + +/// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics. +/// +/// Ideally this will no longer be required, eventually, but as can be seen in +/// the benchmarks (as of Feb 2022 at least) `by_ref` can have performance cost. +pub(crate) struct ByRefSized<'a, I>(pub &'a mut I); + +impl<I: Iterator> Iterator for ByRefSized<'_, I> { + type Item = I::Item; + + fn next(&mut self) -> Option<Self::Item> { + self.0.next() + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } + + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.0.advance_by(n) + } + + fn nth(&mut self, n: usize) -> Option<Self::Item> { + self.0.nth(n) + } + + fn fold<B, F>(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.0.fold(init, f) + } + + fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + self.0.try_fold(init, f) + } +} diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 2ae92e89d63..d82fde47520 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,6 +1,7 @@ use crate::iter::{InPlaceIterable, Iterator}; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try}; +mod by_ref_sized; mod chain; mod cloned; mod copied; @@ -31,6 +32,8 @@ pub use self::{ scan::Scan, skip::Skip, skip_while::SkipWhile, take::Take, take_while::TakeWhile, zip::Zip, }; +pub(crate) use self::by_ref_sized::ByRefSized; + #[stable(feature = "iter_cloned", since = "1.1.0")] pub use self::cloned::Cloned; diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 5a987733134..145c5ee109d 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -417,7 +417,7 @@ pub use self::adapters::{ #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub use self::adapters::{Intersperse, IntersperseWith}; -pub(crate) use self::adapters::try_process; +pub(crate) use self::adapters::{try_process, ByRefSized}; mod adapters; mod range; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d980f593081..b62e8dfe1d6 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2,6 +2,7 @@ use crate::cmp::{self, Ordering}; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; use super::super::try_process; +use super::super::ByRefSized; use super::super::TrustedRandomAccessNoCoerce; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; @@ -1861,7 +1862,7 @@ pub trait Iterator { <<Self as Iterator>::Item as Try>::Residual: Residual<B>, B: FromIterator<<Self::Item as Try>::Output>, { - try_process(self, |i| i.collect()) + try_process(ByRefSized(self), |i| i.collect()) } /// Collects all the items from an iterator into a collection. diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs index 2b234de6795..8d0e59d5a49 100644 --- a/library/core/tests/cmp.rs +++ b/library/core/tests/cmp.rs @@ -134,6 +134,19 @@ fn ordering_const() { } #[test] +fn ordering_structural_eq() { + // test that consts of type `Ordering` are usable in patterns + + const ORDERING: Ordering = Greater; + + const REVERSE: Ordering = ORDERING.reverse(); + match Ordering::Less { + REVERSE => {} + _ => unreachable!(), + }; +} + +#[test] fn cmp_default() { // Test default methods in PartialOrd and PartialEq diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs index 32bd68e3d25..731b1592d41 100644 --- a/library/core/tests/iter/traits/iterator.rs +++ b/library/core/tests/iter/traits/iterator.rs @@ -551,6 +551,30 @@ fn test_collect_into() { assert!(a == b); } +#[test] +fn iter_try_collect_uses_try_fold_not_next() { + // This makes sure it picks up optimizations, and doesn't use the `&mut I` impl. + struct PanicOnNext<I>(I); + impl<I: Iterator> Iterator for PanicOnNext<I> { + type Item = I::Item; + fn next(&mut self) -> Option<Self::Item> { + panic!("Iterator::next should not be called!") + } + fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: std::ops::Try<Output = B>, + { + self.0.try_fold(init, f) + } + } + + let it = (0..10).map(Some); + let _ = PanicOnNext(it).try_collect::<Vec<_>>(); + // validation is just that it didn't panic. +} + // just tests by whether or not this compiles fn _empty_impl_all_auto_traits<T>() { use std::panic::{RefUnwindSafe, UnwindSafe}; diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 9c477e5addc..9d2803b40c4 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -648,11 +648,11 @@ impl ExitStatus { } pub fn code(&self) -> Option<i32> { - if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None } + self.exited().then(|| libc::WEXITSTATUS(self.0)) } pub fn signal(&self) -> Option<i32> { - if libc::WIFSIGNALED(self.0) { Some(libc::WTERMSIG(self.0)) } else { None } + libc::WIFSIGNALED(self.0).then(|| libc::WTERMSIG(self.0)) } pub fn core_dumped(&self) -> bool { @@ -660,7 +660,7 @@ impl ExitStatus { } pub fn stopped_signal(&self) -> Option<i32> { - if libc::WIFSTOPPED(self.0) { Some(libc::WSTOPSIG(self.0)) } else { None } + libc::WIFSTOPPED(self.0).then(|| libc::WSTOPSIG(self.0)) } pub fn continued(&self) -> bool { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 58b73ebed50..c8b76809aba 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -836,9 +836,9 @@ impl Step for RustdocJSNotStd { } } -fn check_if_browser_ui_test_is_installed_global(npm: &Path, global: bool) -> bool { +fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> { let mut command = Command::new(&npm); - command.arg("list").arg("--depth=0"); + command.arg("list").arg("--parseable").arg("--long").arg("--depth=0"); if global { command.arg("--global"); } @@ -846,12 +846,29 @@ fn check_if_browser_ui_test_is_installed_global(npm: &Path, global: bool) -> boo .output() .map(|output| String::from_utf8_lossy(&output.stdout).into_owned()) .unwrap_or(String::new()); - lines.contains(&" browser-ui-test@") + lines.lines().find_map(|l| l.split(":browser-ui-test@").skip(1).next()).map(|v| v.to_owned()) } -fn check_if_browser_ui_test_is_installed(npm: &Path) -> bool { - check_if_browser_ui_test_is_installed_global(npm, false) - || check_if_browser_ui_test_is_installed_global(npm, true) +fn get_browser_ui_test_version(npm: &Path) -> Option<String> { + get_browser_ui_test_version_inner(npm, false) + .or_else(|| get_browser_ui_test_version_inner(npm, true)) +} + +fn compare_browser_ui_test_version(installed_version: &str, src: &Path) { + match fs::read_to_string( + src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"), + ) { + Ok(v) => { + if v.trim() != installed_version { + eprintln!( + "⚠️ Installed version of browser-ui-test (`{}`) is different than the \ + one used in the CI (`{}`)", + installed_version, v + ); + } + } + Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e), + } } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -874,7 +891,7 @@ impl Step for RustdocGUI { .config .npm .as_ref() - .map(|p| check_if_browser_ui_test_is_installed(p)) + .map(|p| get_browser_ui_test_version(p).is_some()) .unwrap_or(false) })) } @@ -892,16 +909,23 @@ impl Step for RustdocGUI { // The goal here is to check if the necessary packages are installed, and if not, we // panic. - if !check_if_browser_ui_test_is_installed(&npm) { - eprintln!( - "error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \ - dependency is missing", - ); - eprintln!( - "If you want to install the `{0}` dependency, run `npm install {0}`", - "browser-ui-test", - ); - panic!("Cannot run rustdoc-gui tests"); + match get_browser_ui_test_version(&npm) { + Some(version) => { + // We also check the version currently used in CI and emit a warning if it's not the + // same one. + compare_browser_ui_test_version(&version, &builder.build.src); + } + None => { + eprintln!( + "error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \ + dependency is missing", + ); + eprintln!( + "If you want to install the `{0}` dependency, run `npm install {0}`", + "browser-ui-test", + ); + panic!("Cannot run rustdoc-gui tests"); + } } let out_dir = builder.test_out(self.target).join("rustdoc-gui"); diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index d78fc6d2083..2358091a6df 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -65,14 +65,20 @@ RUN /scripts/cmake.sh COPY host-x86_64/x86_64-gnu-tools/checktools.sh /tmp/ RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ -ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" +ENV NODE_FOLDER=/node-v14.4.0-linux-x64/bin +ENV PATH="$NODE_FOLDER:${PATH}" + +COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/ # For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries # to create a new folder. For reference: # https://github.com/puppeteer/puppeteer/issues/375 # # We also specify the version in case we need to update it to go around cache limitations. -RUN npm install -g browser-ui-test@0.8.3 --unsafe-perm=true +# +# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case +# the local version of the package is different than the one used by the CI. +RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version new file mode 100644 index 00000000000..fab77af2a1a --- /dev/null +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -0,0 +1 @@ +0.8.3 \ No newline at end of file diff --git a/src/ci/scripts/should-skip-this.sh b/src/ci/scripts/should-skip-this.sh index c046a6c8a26..c863f1b68c7 100755 --- a/src/ci/scripts/should-skip-this.sh +++ b/src/ci/scripts/should-skip-this.sh @@ -26,6 +26,7 @@ if [[ -n "${CI_ONLY_WHEN_SUBMODULES_CHANGED-}" ]]; then src/test/rustdoc-gui \ src/librustdoc \ src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile \ + src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version \ src/tools/rustdoc-gui); then # There was a change in either rustdoc or in its GUI tests. echo "Rustdoc was updated" diff --git a/src/test/ui/cfg/cfg-path-error.rs b/src/test/ui/cfg/cfg-path-error.rs new file mode 100644 index 00000000000..5bf80bd74b8 --- /dev/null +++ b/src/test/ui/cfg/cfg-path-error.rs @@ -0,0 +1,19 @@ +// check-fail + +#[cfg(any(foo, foo::bar))] +//~^ERROR `cfg` predicate key must be an identifier +fn foo1() {} + +#[cfg(any(foo::bar, foo))] +//~^ERROR `cfg` predicate key must be an identifier +fn foo2() {} + +#[cfg(all(foo, foo::bar))] +//~^ERROR `cfg` predicate key must be an identifier +fn foo3() {} + +#[cfg(all(foo::bar, foo))] +//~^ERROR `cfg` predicate key must be an identifier +fn foo4() {} + +fn main() {} diff --git a/src/test/ui/cfg/cfg-path-error.stderr b/src/test/ui/cfg/cfg-path-error.stderr new file mode 100644 index 00000000000..84b44b2b0c2 --- /dev/null +++ b/src/test/ui/cfg/cfg-path-error.stderr @@ -0,0 +1,26 @@ +error: `cfg` predicate key must be an identifier + --> $DIR/cfg-path-error.rs:3:16 + | +LL | #[cfg(any(foo, foo::bar))] + | ^^^^^^^^ + +error: `cfg` predicate key must be an identifier + --> $DIR/cfg-path-error.rs:7:11 + | +LL | #[cfg(any(foo::bar, foo))] + | ^^^^^^^^ + +error: `cfg` predicate key must be an identifier + --> $DIR/cfg-path-error.rs:11:16 + | +LL | #[cfg(all(foo, foo::bar))] + | ^^^^^^^^ + +error: `cfg` predicate key must be an identifier + --> $DIR/cfg-path-error.rs:15:11 + | +LL | #[cfg(all(foo::bar, foo))] + | ^^^^^^^^ + +error: aborting due to 4 previous errors + |
