Auto merge of #48653 - Manishearth:rollup2, r=Manishearth
Another rollup None
This commit is contained in:
commit
9cb18a92ad
42 changed files with 706 additions and 337 deletions
|
@ -188,7 +188,7 @@ matrix:
|
|||
script:
|
||||
MESSAGE_FILE=$(mktemp -t msg.XXXXXX);
|
||||
. src/ci/docker/x86_64-gnu-tools/repo.sh;
|
||||
commit_toolstate_change "$MESSAGE_FILE" "$TRAVIS_BUILD_DIR/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "$MESSAGE_FILE"
|
||||
commit_toolstate_change "$MESSAGE_FILE" "$TRAVIS_BUILD_DIR/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "$MESSAGE_FILE" "$TOOLSTATE_REPO_ACCESS_TOKEN";
|
||||
|
||||
env:
|
||||
global:
|
||||
|
|
|
@ -233,7 +233,7 @@ find out how various parts of the compiler work.
|
|||
[IRC]: https://en.wikipedia.org/wiki/Internet_Relay_Chat
|
||||
[#rust]: irc://irc.mozilla.org/rust
|
||||
[#rust-beginners]: irc://irc.mozilla.org/rust-beginners
|
||||
[rustc-guide]: https://rust-lang-nursery.github.io/rustc-guide/about-this-guide.html
|
||||
[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/about-this-guide.html
|
||||
|
||||
## License
|
||||
[license]: #license
|
||||
|
|
|
@ -231,7 +231,7 @@ pub struct ShouldRun<'a> {
|
|||
paths: BTreeSet<PathSet>,
|
||||
|
||||
// If this is a default rule, this is an additional constraint placed on
|
||||
// it's run. Generally something like compiler docs being enabled.
|
||||
// its run. Generally something like compiler docs being enabled.
|
||||
is_really_default: bool,
|
||||
}
|
||||
|
||||
|
@ -326,7 +326,9 @@ impl<'a> Builder<'a> {
|
|||
test::RunPassPretty, test::RunFailPretty, test::RunPassValgrindPretty,
|
||||
test::RunPassFullDepsPretty, test::RunFailFullDepsPretty, test::RunMake,
|
||||
test::Crate, test::CrateLibrustc, test::Rustdoc, test::Linkcheck, test::Cargotest,
|
||||
test::Cargo, test::Rls, test::Docs, test::ErrorIndex, test::Distcheck,
|
||||
test::Cargo, test::Rls, test::ErrorIndex, test::Distcheck,
|
||||
test::Nomicon, test::Reference, test::RustdocBook, test::RustByExample,
|
||||
test::TheBook, test::UnstableBook,
|
||||
test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme),
|
||||
Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
|
||||
Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
|
||||
|
|
|
@ -629,6 +629,8 @@ impl Step for CodegenBackend {
|
|||
.arg(build.src.join("src/librustc_trans/Cargo.toml"));
|
||||
rustc_cargo_env(build, &mut cargo);
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
|
||||
|
||||
match &*self.backend {
|
||||
"llvm" | "emscripten" => {
|
||||
// Build LLVM for our target. This will implicitly build the
|
||||
|
@ -642,7 +644,6 @@ impl Step for CodegenBackend {
|
|||
features.push_str(" emscripten");
|
||||
}
|
||||
|
||||
let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
|
||||
println!("Building stage{} codegen artifacts ({} -> {}, {})",
|
||||
compiler.stage, &compiler.host, target, self.backend);
|
||||
|
||||
|
|
|
@ -78,15 +78,17 @@ fn try_run(build: &Build, cmd: &mut Command) -> bool {
|
|||
true
|
||||
}
|
||||
|
||||
fn try_run_quiet(build: &Build, cmd: &mut Command) {
|
||||
fn try_run_quiet(build: &Build, cmd: &mut Command) -> bool {
|
||||
if !build.fail_fast {
|
||||
if !build.try_run_quiet(cmd) {
|
||||
let mut failures = build.delayed_failures.borrow_mut();
|
||||
failures.push(format!("{:?}", cmd));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
build.run_quiet(cmd);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -994,23 +996,19 @@ impl Step for Compiletest {
|
|||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Docs {
|
||||
struct DocTest {
|
||||
compiler: Compiler,
|
||||
path: &'static str,
|
||||
name: &'static str,
|
||||
is_ext_doc: bool,
|
||||
}
|
||||
|
||||
impl Step for Docs {
|
||||
impl Step for DocTest {
|
||||
type Output = ();
|
||||
const DEFAULT: bool = true;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun) -> ShouldRun {
|
||||
run.path("src/doc")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig) {
|
||||
run.builder.ensure(Docs {
|
||||
compiler: run.builder.compiler(run.builder.top_stage, run.host),
|
||||
});
|
||||
run.never()
|
||||
}
|
||||
|
||||
/// Run `rustdoc --test` for all documentation in `src/doc`.
|
||||
|
@ -1026,9 +1024,9 @@ impl Step for Docs {
|
|||
|
||||
// Do a breadth-first traversal of the `src/doc` directory and just run
|
||||
// tests for all files that end in `*.md`
|
||||
let mut stack = vec![build.src.join("src/doc")];
|
||||
let mut stack = vec![build.src.join(self.path)];
|
||||
let _time = util::timeit();
|
||||
let _folder = build.fold_output(|| "test_docs");
|
||||
let _folder = build.fold_output(|| format!("test_{}", self.name));
|
||||
|
||||
while let Some(p) = stack.pop() {
|
||||
if p.is_dir() {
|
||||
|
@ -1046,11 +1044,64 @@ impl Step for Docs {
|
|||
continue;
|
||||
}
|
||||
|
||||
markdown_test(builder, compiler, &p);
|
||||
let test_result = markdown_test(builder, compiler, &p);
|
||||
if self.is_ext_doc {
|
||||
let toolstate = if test_result {
|
||||
ToolState::TestPass
|
||||
} else {
|
||||
ToolState::TestFail
|
||||
};
|
||||
build.save_toolstate(self.name, toolstate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! test_book {
|
||||
($($name:ident, $path:expr, $book_name:expr, default=$default:expr;)+) => {
|
||||
$(
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct $name {
|
||||
compiler: Compiler,
|
||||
}
|
||||
|
||||
impl Step for $name {
|
||||
type Output = ();
|
||||
const DEFAULT: bool = $default;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun) -> ShouldRun {
|
||||
run.path($path)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig) {
|
||||
run.builder.ensure($name {
|
||||
compiler: run.builder.compiler(run.builder.top_stage, run.host),
|
||||
});
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder) {
|
||||
builder.ensure(DocTest {
|
||||
compiler: self.compiler,
|
||||
path: $path,
|
||||
name: $book_name,
|
||||
is_ext_doc: !$default,
|
||||
});
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
test_book!(
|
||||
Nomicon, "src/doc/nomicon", "nomicon", default=false;
|
||||
Reference, "src/doc/reference", "reference", default=false;
|
||||
RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
|
||||
RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false;
|
||||
TheBook, "src/doc/book", "book", default=false;
|
||||
UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
|
||||
);
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ErrorIndex {
|
||||
compiler: Compiler,
|
||||
|
@ -1101,13 +1152,13 @@ impl Step for ErrorIndex {
|
|||
}
|
||||
}
|
||||
|
||||
fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) {
|
||||
fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool {
|
||||
let build = builder.build;
|
||||
let mut file = t!(File::open(markdown));
|
||||
let mut contents = String::new();
|
||||
t!(file.read_to_string(&mut contents));
|
||||
if !contents.contains("```") {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
println!("doc tests for: {}", markdown.display());
|
||||
|
@ -1121,9 +1172,9 @@ fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) {
|
|||
cmd.arg("--test-args").arg(test_args);
|
||||
|
||||
if build.config.quiet_tests {
|
||||
try_run_quiet(build, &mut cmd);
|
||||
try_run_quiet(build, &mut cmd)
|
||||
} else {
|
||||
try_run(build, &mut cmd);
|
||||
try_run(build, &mut cmd)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
COPY x86_64-gnu-tools/checkregression.py /tmp/
|
||||
COPY x86_64-gnu-tools/checktools.sh /tmp/
|
||||
COPY x86_64-gnu-tools/repo.sh /tmp/
|
||||
|
||||
|
|
40
src/ci/docker/x86_64-gnu-tools/checkregression.py
Executable file
40
src/ci/docker/x86_64-gnu-tools/checkregression.py
Executable file
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
import sys
|
||||
import json
|
||||
|
||||
if __name__ == '__main__':
|
||||
os_name = sys.argv[1]
|
||||
toolstate_file = sys.argv[2]
|
||||
current_state = sys.argv[3]
|
||||
|
||||
with open(toolstate_file, 'r') as f:
|
||||
toolstate = json.load(f)
|
||||
with open(current_state, 'r') as f:
|
||||
current = json.load(f)
|
||||
|
||||
regressed = False
|
||||
for cur in current:
|
||||
tool = cur['tool']
|
||||
state = cur[os_name]
|
||||
new_state = toolstate.get(tool, '')
|
||||
if new_state < state:
|
||||
print(
|
||||
'Error: The state of "{}" has regressed from "{}" to "{}"'
|
||||
.format(tool, state, new_state)
|
||||
)
|
||||
regressed = True
|
||||
|
||||
if regressed:
|
||||
sys.exit(1)
|
|
@ -17,11 +17,18 @@ TOOLSTATE_FILE="$(realpath $2)"
|
|||
OS="$3"
|
||||
COMMIT="$(git rev-parse HEAD)"
|
||||
CHANGED_FILES="$(git diff --name-status HEAD HEAD^)"
|
||||
SIX_WEEK_CYCLE="$(( ($(date +%s) / 604800 - 3) % 6 ))"
|
||||
# ^ 1970 Jan 1st is a Thursday, and our release dates are also on Thursdays,
|
||||
# thus we could divide by 604800 (7 days in seconds) directly.
|
||||
|
||||
touch "$TOOLSTATE_FILE"
|
||||
|
||||
set +e
|
||||
python2.7 "$X_PY" test --no-fail-fast \
|
||||
src/doc/book \
|
||||
src/doc/nomicon \
|
||||
src/doc/reference \
|
||||
src/doc/rust-by-example \
|
||||
src/tools/rls \
|
||||
src/tools/rustfmt \
|
||||
src/tools/miri \
|
||||
|
@ -29,27 +36,38 @@ python2.7 "$X_PY" test --no-fail-fast \
|
|||
set -e
|
||||
|
||||
cat "$TOOLSTATE_FILE"
|
||||
echo
|
||||
|
||||
# If this PR is intended to update one of these tools, do not let the build pass
|
||||
# when they do not test-pass.
|
||||
for TOOL in rls rustfmt clippy; do
|
||||
echo "Verifying status of $TOOL..."
|
||||
if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]src/tools/$TOOL$"; then
|
||||
echo "This PR updated 'src/tools/$TOOL', verifying if status is 'test-pass'..."
|
||||
if grep -vq '"'"$TOOL"'[^"]*":"test-pass"' "$TOOLSTATE_FILE"; then
|
||||
verify_status() {
|
||||
echo "Verifying status of $1..."
|
||||
if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then
|
||||
echo "This PR updated '$2', verifying if status is 'test-pass'..."
|
||||
if grep -vq '"'"$1"'":"test-pass"' "$TOOLSTATE_FILE"; then
|
||||
echo
|
||||
echo "⚠️ We detected that this PR updated '$TOOL', but its tests failed."
|
||||
echo "⚠️ We detected that this PR updated '$1', but its tests failed."
|
||||
echo
|
||||
echo "If you do intend to update '$TOOL', please check the error messages above and"
|
||||
echo "If you do intend to update '$1', please check the error messages above and"
|
||||
echo "commit another update."
|
||||
echo
|
||||
echo "If you do NOT intend to update '$TOOL', please ensure you did not accidentally"
|
||||
echo "change the submodule at 'src/tools/$TOOL'. You may ask your reviewer for the"
|
||||
echo "If you do NOT intend to update '$1', please ensure you did not accidentally"
|
||||
echo "change the submodule at '$2'. You may ask your reviewer for the"
|
||||
echo "proper steps."
|
||||
exit 3
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# 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
|
||||
|
||||
if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then
|
||||
. "$(dirname $0)/repo.sh"
|
||||
|
@ -59,6 +77,11 @@ if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_s
|
|||
sed -i "1 a\\
|
||||
$COMMIT\t$(cat "$TOOLSTATE_FILE")
|
||||
" "history/$OS.tsv"
|
||||
# if we are at the last week in the 6-week release cycle, reject any kind of regression.
|
||||
if [ $SIX_WEEK_CYCLE -eq 5 ]; then
|
||||
python2.7 "$(dirname $0)/checkregression.py" \
|
||||
"$OS" "$TOOLSTATE_FILE" "rust-toolstate/_data/latest.json"
|
||||
fi
|
||||
rm -f "$MESSAGE_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
|
|
@ -2472,86 +2472,88 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
|
||||
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(p.id);
|
||||
let node = match p.node {
|
||||
PatKind::Wild => hir::PatKind::Wild,
|
||||
PatKind::Ident(ref binding_mode, pth1, ref sub) => {
|
||||
match self.resolver.get_resolution(p.id).map(|d| d.base_def()) {
|
||||
// `None` can occur in body-less function signatures
|
||||
def @ None | def @ Some(Def::Local(_)) => {
|
||||
let canonical_id = match def {
|
||||
Some(Def::Local(id)) => id,
|
||||
_ => p.id
|
||||
};
|
||||
hir::PatKind::Binding(self.lower_binding_mode(binding_mode),
|
||||
canonical_id,
|
||||
respan(pth1.span, pth1.node.name),
|
||||
sub.as_ref().map(|x| self.lower_pat(x)))
|
||||
}
|
||||
Some(def) => {
|
||||
hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path {
|
||||
span: pth1.span,
|
||||
def,
|
||||
segments: hir_vec![
|
||||
hir::PathSegment::from_name(pth1.node.name)
|
||||
],
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
|
||||
PatKind::TupleStruct(ref path, ref pats, ddpos) => {
|
||||
let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed);
|
||||
hir::PatKind::TupleStruct(qpath,
|
||||
pats.iter().map(|x| self.lower_pat(x)).collect(),
|
||||
ddpos)
|
||||
}
|
||||
PatKind::Path(ref qself, ref path) => {
|
||||
hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed))
|
||||
}
|
||||
PatKind::Struct(ref path, ref fields, etc) => {
|
||||
let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed);
|
||||
|
||||
let fs = fields.iter()
|
||||
.map(|f| {
|
||||
Spanned {
|
||||
span: f.span,
|
||||
node: hir::FieldPat {
|
||||
name: self.lower_ident(f.node.ident),
|
||||
pat: self.lower_pat(&f.node.pat),
|
||||
is_shorthand: f.node.is_shorthand,
|
||||
},
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
hir::PatKind::Struct(qpath, fs, etc)
|
||||
}
|
||||
PatKind::Tuple(ref elts, ddpos) => {
|
||||
hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
|
||||
}
|
||||
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
|
||||
PatKind::Ref(ref inner, mutbl) => {
|
||||
hir::PatKind::Ref(self.lower_pat(inner), self.lower_mutability(mutbl))
|
||||
}
|
||||
PatKind::Range(ref e1, ref e2, ref end) => {
|
||||
hir::PatKind::Range(P(self.lower_expr(e1)),
|
||||
P(self.lower_expr(e2)),
|
||||
self.lower_range_end(end))
|
||||
}
|
||||
PatKind::Slice(ref before, ref slice, ref after) => {
|
||||
hir::PatKind::Slice(before.iter().map(|x| self.lower_pat(x)).collect(),
|
||||
slice.as_ref().map(|x| self.lower_pat(x)),
|
||||
after.iter().map(|x| self.lower_pat(x)).collect())
|
||||
}
|
||||
PatKind::Paren(ref inner) => return self.lower_pat(inner),
|
||||
PatKind::Mac(_) => panic!("Shouldn't exist here"),
|
||||
};
|
||||
|
||||
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(p.id);
|
||||
P(hir::Pat {
|
||||
id: node_id,
|
||||
hir_id,
|
||||
node: match p.node {
|
||||
PatKind::Wild => hir::PatKind::Wild,
|
||||
PatKind::Ident(ref binding_mode, pth1, ref sub) => {
|
||||
match self.resolver.get_resolution(p.id).map(|d| d.base_def()) {
|
||||
// `None` can occur in body-less function signatures
|
||||
def @ None | def @ Some(Def::Local(_)) => {
|
||||
let canonical_id = match def {
|
||||
Some(Def::Local(id)) => id,
|
||||
_ => p.id
|
||||
};
|
||||
hir::PatKind::Binding(self.lower_binding_mode(binding_mode),
|
||||
canonical_id,
|
||||
respan(pth1.span, pth1.node.name),
|
||||
sub.as_ref().map(|x| self.lower_pat(x)))
|
||||
}
|
||||
Some(def) => {
|
||||
hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path {
|
||||
span: pth1.span,
|
||||
def,
|
||||
segments: hir_vec![
|
||||
hir::PathSegment::from_name(pth1.node.name)
|
||||
],
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
|
||||
PatKind::TupleStruct(ref path, ref pats, ddpos) => {
|
||||
let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed);
|
||||
hir::PatKind::TupleStruct(qpath,
|
||||
pats.iter().map(|x| self.lower_pat(x)).collect(),
|
||||
ddpos)
|
||||
}
|
||||
PatKind::Path(ref qself, ref path) => {
|
||||
hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed))
|
||||
}
|
||||
PatKind::Struct(ref path, ref fields, etc) => {
|
||||
let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed);
|
||||
|
||||
let fs = fields.iter()
|
||||
.map(|f| {
|
||||
Spanned {
|
||||
span: f.span,
|
||||
node: hir::FieldPat {
|
||||
name: self.lower_ident(f.node.ident),
|
||||
pat: self.lower_pat(&f.node.pat),
|
||||
is_shorthand: f.node.is_shorthand,
|
||||
},
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
hir::PatKind::Struct(qpath, fs, etc)
|
||||
}
|
||||
PatKind::Tuple(ref elts, ddpos) => {
|
||||
hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
|
||||
}
|
||||
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
|
||||
PatKind::Ref(ref inner, mutbl) => {
|
||||
hir::PatKind::Ref(self.lower_pat(inner), self.lower_mutability(mutbl))
|
||||
}
|
||||
PatKind::Range(ref e1, ref e2, ref end) => {
|
||||
hir::PatKind::Range(P(self.lower_expr(e1)),
|
||||
P(self.lower_expr(e2)),
|
||||
self.lower_range_end(end))
|
||||
}
|
||||
PatKind::Slice(ref before, ref slice, ref after) => {
|
||||
hir::PatKind::Slice(before.iter().map(|x| self.lower_pat(x)).collect(),
|
||||
slice.as_ref().map(|x| self.lower_pat(x)),
|
||||
after.iter().map(|x| self.lower_pat(x)).collect())
|
||||
}
|
||||
PatKind::Mac(_) => panic!("Shouldn't exist here"),
|
||||
},
|
||||
node,
|
||||
span: p.span,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -737,6 +737,7 @@ impl EarlyLintPass for IllegalFloatLiteralPattern {
|
|||
PatKind::TupleStruct(..) |
|
||||
PatKind::Ref(..) |
|
||||
PatKind::Box(..) |
|
||||
PatKind::Paren(..) |
|
||||
PatKind::Slice(..) => (),
|
||||
|
||||
// Extract the expressions and check them
|
||||
|
|
|
@ -542,7 +542,7 @@ fn foo<T, T>(s: T, u: T) {} // error: the name `T` is already used for a type
|
|||
// parameter in this type parameter list
|
||||
```
|
||||
|
||||
Please verify that none of the type parameterss are misspelled, and rename any
|
||||
Please verify that none of the type parameters are misspelled, and rename any
|
||||
clashing parameters. Example:
|
||||
|
||||
```
|
||||
|
@ -551,7 +551,8 @@ fn foo<T, Y>(s: T, u: Y) {} // ok!
|
|||
"##,
|
||||
|
||||
E0404: r##"
|
||||
You tried to implement something which was not a trait on an object.
|
||||
You tried to use something which is not a trait in a trait position, such as
|
||||
a bound or `impl`.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
@ -562,6 +563,14 @@ struct Bar;
|
|||
impl Foo for Bar {} // error: `Foo` is not a trait
|
||||
```
|
||||
|
||||
Another erroneous code example:
|
||||
|
||||
```compile_fail,E0404
|
||||
struct Foo;
|
||||
|
||||
fn bar<T: Foo>(t: T) {} // error: `Foo` is not a trait
|
||||
```
|
||||
|
||||
Please verify that you didn't misspell the trait's name or otherwise use the
|
||||
wrong identifier. Example:
|
||||
|
||||
|
@ -575,6 +584,17 @@ impl Foo for Bar { // ok!
|
|||
// functions implementation
|
||||
}
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
trait Foo {
|
||||
// some functions
|
||||
}
|
||||
|
||||
fn bar<T: Foo>(t: T) {} // ok!
|
||||
```
|
||||
|
||||
"##,
|
||||
|
||||
E0405: r##"
|
||||
|
|
|
@ -2163,6 +2163,7 @@ impl<'a> Resolver<'a> {
|
|||
result
|
||||
}
|
||||
|
||||
/// This is called to resolve a trait reference from an `impl` (i.e. `impl Trait for Foo`)
|
||||
fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
|
||||
where F: FnOnce(&mut Resolver, Option<DefId>) -> T
|
||||
{
|
||||
|
@ -2172,13 +2173,14 @@ impl<'a> Resolver<'a> {
|
|||
let path: Vec<_> = trait_ref.path.segments.iter()
|
||||
.map(|seg| respan(seg.span, seg.identifier))
|
||||
.collect();
|
||||
let def = self.smart_resolve_path_fragment(trait_ref.ref_id,
|
||||
None,
|
||||
&path,
|
||||
trait_ref.path.span,
|
||||
trait_ref.path.segments.last().unwrap().span,
|
||||
PathSource::Trait(AliasPossibility::No))
|
||||
.base_def();
|
||||
let def = self.smart_resolve_path_fragment(
|
||||
trait_ref.ref_id,
|
||||
None,
|
||||
&path,
|
||||
trait_ref.path.span,
|
||||
trait_ref.path.segments.last().unwrap().span,
|
||||
PathSource::Trait(AliasPossibility::No)
|
||||
).base_def();
|
||||
if def != Def::Err {
|
||||
new_id = Some(def.def_id());
|
||||
let span = trait_ref.path.span;
|
||||
|
|
|
@ -212,7 +212,7 @@ fn from_target_feature(
|
|||
let value = value.as_str();
|
||||
for feature in value.split(',') {
|
||||
if whitelist.contains(feature) {
|
||||
let llvm_feature = llvm_util::to_llvm_feature(feature);
|
||||
let llvm_feature = llvm_util::to_llvm_feature(&tcx.sess, feature);
|
||||
target_features.push(format!("+{}", llvm_feature));
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -81,7 +81,9 @@ unsafe fn configure_llvm(sess: &Session) {
|
|||
|
||||
const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];
|
||||
|
||||
const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"];
|
||||
const AARCH64_WHITELIST: &'static [&'static str] = &["fp", "neon", "sve", "crc", "crypto",
|
||||
"ras", "lse", "rdm", "fp16", "rcpc",
|
||||
"dotprod", "v8.1a", "v8.2a", "v8.3a"];
|
||||
|
||||
const X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw",
|
||||
"avx512cd", "avx512dq", "avx512er",
|
||||
|
@ -104,12 +106,18 @@ const POWERPC_WHITELIST: &'static [&'static str] = &["altivec",
|
|||
|
||||
const MIPS_WHITELIST: &'static [&'static str] = &["msa"];
|
||||
|
||||
pub fn to_llvm_feature(s: &str) -> &str {
|
||||
match s {
|
||||
"pclmulqdq" => "pclmul",
|
||||
"rdrand" => "rdrnd",
|
||||
"bmi1" => "bmi",
|
||||
s => s,
|
||||
pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
|
||||
let arch = if sess.target.target.arch == "x86_64" {
|
||||
"x86"
|
||||
} else {
|
||||
&*sess.target.target.arch
|
||||
};
|
||||
match (arch, s) {
|
||||
("x86", "pclmulqdq") => "pclmul",
|
||||
("x86", "rdrand") => "rdrnd",
|
||||
("x86", "bmi1") => "bmi",
|
||||
("aarch64", "fp16") => "fullfp16",
|
||||
(_, s) => s,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,7 +126,7 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
|
|||
target_feature_whitelist(sess)
|
||||
.iter()
|
||||
.filter(|feature| {
|
||||
let llvm_feature = to_llvm_feature(feature);
|
||||
let llvm_feature = to_llvm_feature(sess, feature);
|
||||
let cstr = CString::new(llvm_feature).unwrap();
|
||||
unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
|
||||
})
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use common::{C_i32, C_null};
|
||||
use libc::c_uint;
|
||||
use llvm::{self, ValueRef, BasicBlockRef};
|
||||
use llvm::debuginfo::DIScope;
|
||||
|
@ -23,6 +24,7 @@ use common::{CodegenCx, Funclet};
|
|||
use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
|
||||
use monomorphize::Instance;
|
||||
use abi::{ArgAttribute, FnType, PassMode};
|
||||
use type_::Type;
|
||||
|
||||
use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span};
|
||||
use syntax::symbol::keywords;
|
||||
|
@ -222,7 +224,7 @@ pub fn trans_mir<'a, 'tcx: 'a>(
|
|||
|
||||
// Compute debuginfo scopes from MIR scopes.
|
||||
let scopes = debuginfo::create_mir_scopes(cx, mir, &debug_context);
|
||||
let (landing_pads, funclets) = create_funclets(&bx, &cleanup_kinds, &block_bxs);
|
||||
let (landing_pads, funclets) = create_funclets(mir, &bx, &cleanup_kinds, &block_bxs);
|
||||
|
||||
let mut fx = FunctionCx {
|
||||
mir,
|
||||
|
@ -333,6 +335,7 @@ pub fn trans_mir<'a, 'tcx: 'a>(
|
|||
}
|
||||
|
||||
fn create_funclets<'a, 'tcx>(
|
||||
mir: &'a Mir<'tcx>,
|
||||
bx: &Builder<'a, 'tcx>,
|
||||
cleanup_kinds: &IndexVec<mir::BasicBlock, CleanupKind>,
|
||||
block_bxs: &IndexVec<mir::BasicBlock, BasicBlockRef>)
|
||||
|
@ -341,14 +344,59 @@ fn create_funclets<'a, 'tcx>(
|
|||
{
|
||||
block_bxs.iter_enumerated().zip(cleanup_kinds).map(|((bb, &llbb), cleanup_kind)| {
|
||||
match *cleanup_kind {
|
||||
CleanupKind::Funclet if base::wants_msvc_seh(bx.sess()) => {
|
||||
let cleanup_bx = bx.build_sibling_block(&format!("funclet_{:?}", bb));
|
||||
let cleanup = cleanup_bx.cleanup_pad(None, &[]);
|
||||
cleanup_bx.br(llbb);
|
||||
(Some(cleanup_bx.llbb()), Some(Funclet::new(cleanup)))
|
||||
}
|
||||
_ => (None, None)
|
||||
CleanupKind::Funclet if base::wants_msvc_seh(bx.sess()) => {}
|
||||
_ => return (None, None)
|
||||
}
|
||||
|
||||
let cleanup;
|
||||
let ret_llbb;
|
||||
match mir[bb].terminator.as_ref().map(|t| &t.kind) {
|
||||
// This is a basic block that we're aborting the program for,
|
||||
// notably in an `extern` function. These basic blocks are inserted
|
||||
// so that we assert that `extern` functions do indeed not panic,
|
||||
// and if they do we abort the process.
|
||||
//
|
||||
// On MSVC these are tricky though (where we're doing funclets). If
|
||||
// we were to do a cleanuppad (like below) the normal functions like
|
||||
// `longjmp` would trigger the abort logic, terminating the
|
||||
// program. Instead we insert the equivalent of `catch(...)` for C++
|
||||
// which magically doesn't trigger when `longjmp` files over this
|
||||
// frame.
|
||||
//
|
||||
// Lots more discussion can be found on #48251 but this codegen is
|
||||
// modeled after clang's for:
|
||||
//
|
||||
// try {
|
||||
// foo();
|
||||
// } catch (...) {
|
||||
// bar();
|
||||
// }
|
||||
Some(&mir::TerminatorKind::Abort) => {
|
||||
let cs_bx = bx.build_sibling_block(&format!("cs_funclet{:?}", bb));
|
||||
let cp_bx = bx.build_sibling_block(&format!("cp_funclet{:?}", bb));
|
||||
ret_llbb = cs_bx.llbb();
|
||||
|
||||
let cs = cs_bx.catch_switch(None, None, 1);
|
||||
cs_bx.add_handler(cs, cp_bx.llbb());
|
||||
|
||||
// The "null" here is actually a RTTI type descriptor for the
|
||||
// C++ personality function, but `catch (...)` has no type so
|
||||
// it's null. The 64 here is actually a bitfield which
|
||||
// represents that this is a catch-all block.
|
||||
let null = C_null(Type::i8p(bx.cx));
|
||||
let sixty_four = C_i32(bx.cx, 64);
|
||||
cleanup = cp_bx.catch_pad(cs, &[null, sixty_four, null]);
|
||||
cp_bx.br(llbb);
|
||||
}
|
||||
_ => {
|
||||
let cleanup_bx = bx.build_sibling_block(&format!("funclet_{:?}", bb));
|
||||
ret_llbb = cleanup_bx.llbb();
|
||||
cleanup = cleanup_bx.cleanup_pad(None, &[]);
|
||||
cleanup_bx.br(llbb);
|
||||
}
|
||||
};
|
||||
|
||||
(Some(ret_llbb), Some(Funclet::new(cleanup)))
|
||||
}).unzip()
|
||||
}
|
||||
|
||||
|
|
|
@ -312,7 +312,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
|
||||
/// Instantiates the path for the given trait reference, assuming that it's
|
||||
/// bound to a valid trait type. Returns the def_id for the defining trait.
|
||||
/// Fails if the type is a type other than a trait type.
|
||||
/// The type _cannot_ be a type other than a trait type.
|
||||
///
|
||||
/// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
|
||||
/// are disallowed. Otherwise, they are pushed onto the vector given.
|
||||
|
@ -330,6 +330,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
trait_ref.path.segments.last().unwrap())
|
||||
}
|
||||
|
||||
/// Get the DefId of the given trait ref. It _must_ actually be a trait.
|
||||
fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId {
|
||||
let path = &trait_ref.path;
|
||||
match path.def {
|
||||
|
@ -338,13 +339,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
Def::Err => {
|
||||
self.tcx().sess.fatal("cannot continue compilation due to previous error");
|
||||
}
|
||||
_ => {
|
||||
span_fatal!(self.tcx().sess, path.span, E0245, "`{}` is not a trait",
|
||||
self.tcx().hir.node_to_pretty_string(trait_ref.ref_id));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The given `trait_ref` must actually be trait.
|
||||
pub(super) fn instantiate_poly_trait_ref_inner(&self,
|
||||
trait_ref: &hir::TraitRef,
|
||||
self_ty: Ty<'tcx>,
|
||||
|
|
|
@ -4802,7 +4802,7 @@ register_diagnostics! {
|
|||
// E0240,
|
||||
// E0241,
|
||||
// E0242,
|
||||
E0245, // not a trait
|
||||
// E0245, // not a trait
|
||||
// E0246, // invalid recursive type
|
||||
// E0247,
|
||||
// E0248, // value used as a type, now reported earlier during resolution as E0412
|
||||
|
|
|
@ -17,7 +17,7 @@ use io::{self, Initializer, BufReader, LineWriter};
|
|||
use sync::{Arc, Mutex, MutexGuard};
|
||||
use sys::stdio;
|
||||
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
|
||||
use thread::{LocalKey, LocalKeyState};
|
||||
use thread::LocalKey;
|
||||
|
||||
/// Stdout used by print! and println! macros
|
||||
thread_local! {
|
||||
|
@ -663,29 +663,31 @@ pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
|
|||
///
|
||||
/// This function is used to print error messages, so it takes extra
|
||||
/// care to avoid causing a panic when `local_stream` is unusable.
|
||||
/// For instance, if the TLS key for the local stream is uninitialized
|
||||
/// or already destroyed, or if the local stream is locked by another
|
||||
/// For instance, if the TLS key for the local stream is
|
||||
/// already destroyed, or if the local stream is locked by another
|
||||
/// thread, it will just fall back to the global stream.
|
||||
///
|
||||
/// However, if the actual I/O causes an error, this function does panic.
|
||||
fn print_to<T>(args: fmt::Arguments,
|
||||
local_s: &'static LocalKey<RefCell<Option<Box<Write+Send>>>>,
|
||||
global_s: fn() -> T,
|
||||
label: &str) where T: Write {
|
||||
let result = match local_s.state() {
|
||||
LocalKeyState::Uninitialized |
|
||||
LocalKeyState::Destroyed => global_s().write_fmt(args),
|
||||
LocalKeyState::Valid => {
|
||||
local_s.with(|s| {
|
||||
if let Ok(mut borrowed) = s.try_borrow_mut() {
|
||||
if let Some(w) = borrowed.as_mut() {
|
||||
return w.write_fmt(args);
|
||||
}
|
||||
}
|
||||
global_s().write_fmt(args)
|
||||
})
|
||||
fn print_to<T>(
|
||||
args: fmt::Arguments,
|
||||
local_s: &'static LocalKey<RefCell<Option<Box<Write+Send>>>>,
|
||||
global_s: fn() -> T,
|
||||
label: &str,
|
||||
)
|
||||
where
|
||||
T: Write,
|
||||
{
|
||||
let result = local_s.try_with(|s| {
|
||||
if let Ok(mut borrowed) = s.try_borrow_mut() {
|
||||
if let Some(w) = borrowed.as_mut() {
|
||||
return w.write_fmt(args);
|
||||
}
|
||||
}
|
||||
};
|
||||
global_s().write_fmt(args)
|
||||
}).unwrap_or_else(|_| {
|
||||
global_s().write_fmt(args)
|
||||
});
|
||||
|
||||
if let Err(e) = result {
|
||||
panic!("failed printing to {}: {}", label, e);
|
||||
}
|
||||
|
|
|
@ -195,64 +195,20 @@ macro_rules! __thread_local_inner {
|
|||
}
|
||||
}
|
||||
|
||||
/// Indicator of the state of a thread local storage key.
|
||||
#[unstable(feature = "thread_local_state",
|
||||
reason = "state querying was recently added",
|
||||
issue = "27716")]
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||
pub enum LocalKeyState {
|
||||
/// All keys are in this state whenever a thread starts. Keys will
|
||||
/// transition to the `Valid` state once the first call to [`with`] happens
|
||||
/// and the initialization expression succeeds.
|
||||
///
|
||||
/// Keys in the `Uninitialized` state will yield a reference to the closure
|
||||
/// passed to [`with`] so long as the initialization routine does not panic.
|
||||
///
|
||||
/// [`with`]: ../../std/thread/struct.LocalKey.html#method.with
|
||||
Uninitialized,
|
||||
|
||||
/// Once a key has been accessed successfully, it will enter the `Valid`
|
||||
/// state. Keys in the `Valid` state will remain so until the thread exits,
|
||||
/// at which point the destructor will be run and the key will enter the
|
||||
/// `Destroyed` state.
|
||||
///
|
||||
/// Keys in the `Valid` state will be guaranteed to yield a reference to the
|
||||
/// closure passed to [`with`].
|
||||
///
|
||||
/// [`with`]: ../../std/thread/struct.LocalKey.html#method.with
|
||||
Valid,
|
||||
|
||||
/// When a thread exits, the destructors for keys will be run (if
|
||||
/// necessary). While a destructor is running, and possibly after a
|
||||
/// destructor has run, a key is in the `Destroyed` state.
|
||||
///
|
||||
/// Keys in the `Destroyed` states will trigger a panic when accessed via
|
||||
/// [`with`].
|
||||
///
|
||||
/// [`with`]: ../../std/thread/struct.LocalKey.html#method.with
|
||||
Destroyed,
|
||||
}
|
||||
|
||||
/// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with).
|
||||
#[unstable(feature = "thread_local_state",
|
||||
reason = "state querying was recently added",
|
||||
issue = "27716")]
|
||||
#[stable(feature = "thread_local_try_with", since = "1.26.0")]
|
||||
pub struct AccessError {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
#[unstable(feature = "thread_local_state",
|
||||
reason = "state querying was recently added",
|
||||
issue = "27716")]
|
||||
#[stable(feature = "thread_local_try_with", since = "1.26.0")]
|
||||
impl fmt::Debug for AccessError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("AccessError").finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "thread_local_state",
|
||||
reason = "state querying was recently added",
|
||||
issue = "27716")]
|
||||
#[stable(feature = "thread_local_try_with", since = "1.26.0")]
|
||||
impl fmt::Display for AccessError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt("already destroyed", f)
|
||||
|
@ -312,64 +268,21 @@ impl<T: 'static> LocalKey<T> {
|
|||
(*ptr).as_ref().unwrap()
|
||||
}
|
||||
|
||||
/// Query the current state of this key.
|
||||
///
|
||||
/// A key is initially in the `Uninitialized` state whenever a thread
|
||||
/// starts. It will remain in this state up until the first call to [`with`]
|
||||
/// within a thread has run the initialization expression successfully.
|
||||
///
|
||||
/// Once the initialization expression succeeds, the key transitions to the
|
||||
/// `Valid` state which will guarantee that future calls to [`with`] will
|
||||
/// succeed within the thread. Some keys might skip the `Uninitialized`
|
||||
/// state altogether and start in the `Valid` state as an optimization
|
||||
/// (e.g. keys initialized with a constant expression), but no guarantees
|
||||
/// are made.
|
||||
///
|
||||
/// When a thread exits, each key will be destroyed in turn, and as keys are
|
||||
/// destroyed they will enter the `Destroyed` state just before the
|
||||
/// destructor starts to run. Keys may remain in the `Destroyed` state after
|
||||
/// destruction has completed. Keys without destructors (e.g. with types
|
||||
/// that are [`Copy`]), may never enter the `Destroyed` state.
|
||||
///
|
||||
/// Keys in the `Uninitialized` state can be accessed so long as the
|
||||
/// initialization does not panic. Keys in the `Valid` state are guaranteed
|
||||
/// to be able to be accessed. Keys in the `Destroyed` state will panic on
|
||||
/// any call to [`with`].
|
||||
///
|
||||
/// [`with`]: ../../std/thread/struct.LocalKey.html#method.with
|
||||
/// [`Copy`]: ../../std/marker/trait.Copy.html
|
||||
#[unstable(feature = "thread_local_state",
|
||||
reason = "state querying was recently added",
|
||||
issue = "27716")]
|
||||
pub fn state(&'static self) -> LocalKeyState {
|
||||
unsafe {
|
||||
match (self.inner)() {
|
||||
Some(cell) => {
|
||||
match *cell.get() {
|
||||
Some(..) => LocalKeyState::Valid,
|
||||
None => LocalKeyState::Uninitialized,
|
||||
}
|
||||
}
|
||||
None => LocalKeyState::Destroyed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Acquires a reference to the value in this TLS key.
|
||||
///
|
||||
/// This will lazily initialize the value if this thread has not referenced
|
||||
/// this key yet. If the key has been destroyed (which may happen if this is called
|
||||
/// in a destructor), this function will return a ThreadLocalError.
|
||||
/// in a destructor), this function will return a `ThreadLocalError`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will still `panic!()` if the key is uninitialized and the
|
||||
/// key's initializer panics.
|
||||
#[unstable(feature = "thread_local_state",
|
||||
reason = "state querying was recently added",
|
||||
issue = "27716")]
|
||||
#[stable(feature = "thread_local_try_with", since = "1.26.0")]
|
||||
pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
|
||||
where F: FnOnce(&T) -> R {
|
||||
where
|
||||
F: FnOnce(&T) -> R,
|
||||
{
|
||||
unsafe {
|
||||
let slot = (self.inner)().ok_or(AccessError {
|
||||
_private: (),
|
||||
|
@ -530,7 +443,6 @@ pub mod os {
|
|||
mod tests {
|
||||
use sync::mpsc::{channel, Sender};
|
||||
use cell::{Cell, UnsafeCell};
|
||||
use super::LocalKeyState;
|
||||
use thread;
|
||||
|
||||
struct Foo(Sender<()>);
|
||||
|
@ -569,21 +481,13 @@ mod tests {
|
|||
struct Foo;
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
assert!(FOO.state() == LocalKeyState::Destroyed);
|
||||
assert!(FOO.try_with(|_| ()).is_err());
|
||||
}
|
||||
}
|
||||
fn foo() -> Foo {
|
||||
assert!(FOO.state() == LocalKeyState::Uninitialized);
|
||||
Foo
|
||||
}
|
||||
thread_local!(static FOO: Foo = foo());
|
||||
thread_local!(static FOO: Foo = Foo);
|
||||
|
||||
thread::spawn(|| {
|
||||
assert!(FOO.state() == LocalKeyState::Uninitialized);
|
||||
FOO.with(|_| {
|
||||
assert!(FOO.state() == LocalKeyState::Valid);
|
||||
});
|
||||
assert!(FOO.state() == LocalKeyState::Valid);
|
||||
assert!(FOO.try_with(|_| ()).is_ok());
|
||||
}).join().ok().unwrap();
|
||||
}
|
||||
|
||||
|
@ -613,7 +517,7 @@ mod tests {
|
|||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
HITS += 1;
|
||||
if K2.state() == LocalKeyState::Destroyed {
|
||||
if K2.try_with(|_| ()).is_err() {
|
||||
assert_eq!(HITS, 3);
|
||||
} else {
|
||||
if HITS == 1 {
|
||||
|
@ -629,7 +533,7 @@ mod tests {
|
|||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
HITS += 1;
|
||||
assert!(K1.state() != LocalKeyState::Destroyed);
|
||||
assert!(K1.try_with(|_| ()).is_ok());
|
||||
assert_eq!(HITS, 2);
|
||||
K1.with(|s| *s.get() = Some(S1));
|
||||
}
|
||||
|
@ -648,7 +552,7 @@ mod tests {
|
|||
|
||||
impl Drop for S1 {
|
||||
fn drop(&mut self) {
|
||||
assert!(K1.state() == LocalKeyState::Destroyed);
|
||||
assert!(K1.try_with(|_| ()).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -672,9 +576,7 @@ mod tests {
|
|||
fn drop(&mut self) {
|
||||
let S1(ref tx) = *self;
|
||||
unsafe {
|
||||
if K2.state() != LocalKeyState::Destroyed {
|
||||
K2.with(|s| *s.get() = Some(Foo(tx.clone())));
|
||||
}
|
||||
let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -191,7 +191,7 @@ use time::Duration;
|
|||
#[macro_use] mod local;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::local::{LocalKey, LocalKeyState, AccessError};
|
||||
pub use self::local::{LocalKey, AccessError};
|
||||
|
||||
// The types used by the thread_local! macro to access TLS keys. Note that there
|
||||
// are two types, the "OS" type and the "fast" type. The OS thread local key
|
||||
|
|
|
@ -562,7 +562,7 @@ impl Pat {
|
|||
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
|
||||
s.iter().all(|p| p.walk(it))
|
||||
}
|
||||
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
|
||||
PatKind::Box(ref s) | PatKind::Ref(ref s, _) | PatKind::Paren(ref s) => {
|
||||
s.walk(it)
|
||||
}
|
||||
PatKind::Slice(ref before, ref slice, ref after) => {
|
||||
|
@ -656,6 +656,8 @@ pub enum PatKind {
|
|||
/// `[a, b, ..i, y, z]` is represented as:
|
||||
/// `PatKind::Slice(box [a, b], Some(i), box [y, z])`
|
||||
Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
|
||||
/// Parentheses in patters used for grouping, i.e. `(PAT)`.
|
||||
Paren(P<Pat>),
|
||||
/// A macro pattern; pre-expansion
|
||||
Mac(Mac),
|
||||
}
|
||||
|
|
|
@ -705,17 +705,20 @@ impl CodeMap {
|
|||
};
|
||||
debug!("find_width_of_character_at_span: snippet=`{:?}`", snippet);
|
||||
|
||||
let file_start_pos = local_begin.fm.start_pos.to_usize();
|
||||
let file_end_pos = local_begin.fm.end_pos.to_usize();
|
||||
debug!("find_width_of_character_at_span: file_start_pos=`{:?}` file_end_pos=`{:?}`",
|
||||
file_start_pos, file_end_pos);
|
||||
|
||||
let mut target = if forwards { end_index + 1 } else { end_index - 1 };
|
||||
debug!("find_width_of_character_at_span: initial target=`{:?}`", target);
|
||||
|
||||
while !snippet.is_char_boundary(target - start_index)
|
||||
&& target >= file_start_pos && target <= file_end_pos {
|
||||
target = if forwards { target + 1 } else { target - 1 };
|
||||
while !snippet.is_char_boundary(target - start_index) && target < source_len {
|
||||
target = if forwards {
|
||||
target + 1
|
||||
} else {
|
||||
match target.checked_sub(1) {
|
||||
Some(target) => target,
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
debug!("find_width_of_character_at_span: target=`{:?}`", target);
|
||||
}
|
||||
debug!("find_width_of_character_at_span: final target=`{:?}`", target);
|
||||
|
|
|
@ -449,6 +449,9 @@ declare_features! (
|
|||
|
||||
// Multiple patterns with `|` in `if let` and `while let`
|
||||
(active, if_while_or_patterns, "1.26.0", Some(48215)),
|
||||
|
||||
// Parentheses in patterns
|
||||
(active, pattern_parentheses, "1.26.0", None),
|
||||
);
|
||||
|
||||
declare_features! (
|
||||
|
@ -1663,6 +1666,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
gate_feature_post!(&self, dotdoteq_in_patterns, pattern.span,
|
||||
"`..=` syntax in patterns is experimental");
|
||||
}
|
||||
PatKind::Paren(..) => {
|
||||
gate_feature_post!(&self, pattern_parentheses, pattern.span,
|
||||
"parentheses in patterns are unstable");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_pat(self, pattern)
|
||||
|
|
|
@ -1148,6 +1148,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
|
|||
slice.map(|x| folder.fold_pat(x)),
|
||||
after.move_map(|x| folder.fold_pat(x)))
|
||||
}
|
||||
PatKind::Paren(inner) => PatKind::Paren(folder.fold_pat(inner)),
|
||||
PatKind::Mac(mac) => PatKind::Mac(folder.fold_mac(mac))
|
||||
},
|
||||
span: folder.new_span(span)
|
||||
|
|
|
@ -3484,33 +3484,47 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
}
|
||||
|
||||
fn parse_pat_tuple_elements(&mut self, unary_needs_comma: bool)
|
||||
-> PResult<'a, (Vec<P<Pat>>, Option<usize>)> {
|
||||
let mut fields = vec![];
|
||||
let mut ddpos = None;
|
||||
// Parses a parenthesized list of patterns like
|
||||
// `()`, `(p)`, `(p,)`, `(p, q)`, or `(p, .., q)`. Returns:
|
||||
// - a vector of the patterns that were parsed
|
||||
// - an option indicating the index of the `..` element
|
||||
// - a boolean indicating whether a trailing comma was present.
|
||||
// Trailing commas are significant because (p) and (p,) are different patterns.
|
||||
fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
|
||||
self.expect(&token::OpenDelim(token::Paren))?;
|
||||
|
||||
while !self.check(&token::CloseDelim(token::Paren)) {
|
||||
if ddpos.is_none() && self.eat(&token::DotDot) {
|
||||
ddpos = Some(fields.len());
|
||||
if self.eat(&token::Comma) {
|
||||
// `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
|
||||
fields.push(self.parse_pat()?);
|
||||
let mut fields = Vec::new();
|
||||
let mut ddpos = None;
|
||||
let mut trailing_comma = false;
|
||||
loop {
|
||||
if self.eat(&token::DotDot) {
|
||||
if ddpos.is_none() {
|
||||
ddpos = Some(fields.len());
|
||||
} else {
|
||||
// Emit a friendly error, ignore `..` and continue parsing
|
||||
self.span_err(self.prev_span,
|
||||
"`..` can only be used once per tuple or tuple struct pattern");
|
||||
}
|
||||
} else if ddpos.is_some() && self.eat(&token::DotDot) {
|
||||
// Emit a friendly error, ignore `..` and continue parsing
|
||||
self.span_err(self.prev_span, "`..` can only be used once per \
|
||||
tuple or tuple struct pattern");
|
||||
} else {
|
||||
} else if !self.check(&token::CloseDelim(token::Paren)) {
|
||||
fields.push(self.parse_pat()?);
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if !self.check(&token::CloseDelim(token::Paren)) ||
|
||||
(unary_needs_comma && fields.len() == 1 && ddpos.is_none()) {
|
||||
self.expect(&token::Comma)?;
|
||||
trailing_comma = self.eat(&token::Comma);
|
||||
if !trailing_comma {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
Ok((fields, ddpos))
|
||||
if ddpos == Some(fields.len()) && trailing_comma {
|
||||
// `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
|
||||
self.span_err(self.prev_span, "trailing comma is not permitted after `..`");
|
||||
}
|
||||
|
||||
self.expect(&token::CloseDelim(token::Paren))?;
|
||||
|
||||
Ok((fields, ddpos, trailing_comma))
|
||||
}
|
||||
|
||||
fn parse_pat_vec_elements(
|
||||
|
@ -3714,10 +3728,12 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
token::OpenDelim(token::Paren) => {
|
||||
// Parse (pat,pat,pat,...) as tuple pattern
|
||||
self.bump();
|
||||
let (fields, ddpos) = self.parse_pat_tuple_elements(true)?;
|
||||
self.expect(&token::CloseDelim(token::Paren))?;
|
||||
pat = PatKind::Tuple(fields, ddpos);
|
||||
let (fields, ddpos, trailing_comma) = self.parse_parenthesized_pat_list()?;
|
||||
pat = if fields.len() == 1 && ddpos.is_none() && !trailing_comma {
|
||||
PatKind::Paren(fields.into_iter().nth(0).unwrap())
|
||||
} else {
|
||||
PatKind::Tuple(fields, ddpos)
|
||||
};
|
||||
}
|
||||
token::OpenDelim(token::Bracket) => {
|
||||
// Parse [pat,pat,...] as slice pattern
|
||||
|
@ -3807,9 +3823,7 @@ impl<'a> Parser<'a> {
|
|||
return Err(self.fatal("unexpected `(` after qualified path"));
|
||||
}
|
||||
// Parse tuple struct or enum pattern
|
||||
self.bump();
|
||||
let (fields, ddpos) = self.parse_pat_tuple_elements(false)?;
|
||||
self.expect(&token::CloseDelim(token::Paren))?;
|
||||
let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?;
|
||||
pat = PatKind::TupleStruct(path, fields, ddpos)
|
||||
}
|
||||
_ => pat = PatKind::Path(qself, path),
|
||||
|
|
|
@ -2659,6 +2659,11 @@ impl<'a> State<'a> {
|
|||
|s, p| s.print_pat(p))?;
|
||||
self.s.word("]")?;
|
||||
}
|
||||
PatKind::Paren(ref inner) => {
|
||||
self.popen()?;
|
||||
self.print_pat(inner)?;
|
||||
self.pclose()?;
|
||||
}
|
||||
PatKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
|
||||
}
|
||||
self.ann.post(self, NodePat(pat))
|
||||
|
|
|
@ -425,7 +425,8 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
|||
walk_list!(visitor, visit_pat, tuple_elements);
|
||||
}
|
||||
PatKind::Box(ref subpattern) |
|
||||
PatKind::Ref(ref subpattern, _) => {
|
||||
PatKind::Ref(ref subpattern, _) |
|
||||
PatKind::Paren(ref subpattern) => {
|
||||
visitor.visit_pat(subpattern)
|
||||
}
|
||||
PatKind::Ident(_, ref pth1, ref optional_subpattern) => {
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
|
||||
fn main() {
|
||||
match 0 {
|
||||
(pat, ..,) => {} //~ ERROR expected pattern, found `)`
|
||||
(pat, ..,) => {} //~ ERROR trailing comma is not permitted after `..`
|
||||
}
|
||||
}
|
||||
|
|
5
src/test/run-make/longjmp-across-rust/Makefile
Normal file
5
src/test/run-make/longjmp-across-rust/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
-include ../tools.mk
|
||||
|
||||
all: $(call NATIVE_STATICLIB,foo)
|
||||
$(RUSTC) main.rs
|
||||
$(call RUN,main)
|
28
src/test/run-make/longjmp-across-rust/foo.c
Normal file
28
src/test/run-make/longjmp-across-rust/foo.c
Normal file
|
@ -0,0 +1,28 @@
|
|||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#include <assert.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
static jmp_buf ENV;
|
||||
|
||||
extern void test_middle();
|
||||
|
||||
void test_start(void(*f)()) {
|
||||
if (setjmp(ENV) != 0)
|
||||
return;
|
||||
f();
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void test_end() {
|
||||
longjmp(ENV, 1);
|
||||
assert(0);
|
||||
}
|
40
src/test/run-make/longjmp-across-rust/main.rs
Normal file
40
src/test/run-make/longjmp-across-rust/main.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[link(name = "foo", kind = "static")]
|
||||
extern {
|
||||
fn test_start(f: extern fn());
|
||||
fn test_end();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
test_start(test_middle);
|
||||
}
|
||||
}
|
||||
|
||||
struct A;
|
||||
|
||||
impl Drop for A {
|
||||
fn drop(&mut self) {
|
||||
}
|
||||
}
|
||||
|
||||
extern fn test_middle() {
|
||||
let _a = A;
|
||||
foo();
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
let _a = A;
|
||||
unsafe {
|
||||
test_end();
|
||||
}
|
||||
}
|
16
src/test/run-pass/issue-48508-aux.rs
Normal file
16
src/test/run-pass/issue-48508-aux.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-test Not a test. Used by issue-48508.rs
|
||||
|
||||
pub fn other() -> f64 {
|
||||
let µ = 1.0;
|
||||
µ
|
||||
}
|
28
src/test/run-pass/issue-48508.rs
Normal file
28
src/test/run-pass/issue-48508.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Regression test for issue #48508:
|
||||
//
|
||||
// Confusion between global and local file offsets caused incorrect handling of multibyte character
|
||||
// spans when compiling multiple files. One visible effect was an ICE generating debug information
|
||||
// when a multibyte character is at the end of a scope. The problematic code is actually in
|
||||
// issue-48508-aux.rs
|
||||
|
||||
// compile-flags:-g
|
||||
// ignore-pretty issue #37195
|
||||
|
||||
#![feature(non_ascii_idents)]
|
||||
|
||||
#[path = "issue-48508-aux.rs"]
|
||||
mod other_file;
|
||||
|
||||
fn main() {
|
||||
other_file::other();
|
||||
}
|
43
src/test/run-pass/issue-48551.rs
Normal file
43
src/test/run-pass/issue-48551.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Regression test for #48551. Covers a case where duplicate candidates
|
||||
// arose during associated type projection.
|
||||
|
||||
use std::ops::{Mul, MulAssign};
|
||||
|
||||
pub trait ClosedMul<Right>: Sized + Mul<Right, Output = Self> + MulAssign<Right> {}
|
||||
impl<T, Right> ClosedMul<Right> for T
|
||||
where
|
||||
T: Mul<Right, Output = T> + MulAssign<Right>,
|
||||
{
|
||||
}
|
||||
|
||||
pub trait InnerSpace: ClosedMul<<Self as InnerSpace>::Real> {
|
||||
type Real;
|
||||
}
|
||||
|
||||
pub trait FiniteDimVectorSpace: ClosedMul<<Self as FiniteDimVectorSpace>::Field> {
|
||||
type Field;
|
||||
}
|
||||
|
||||
pub trait FiniteDimInnerSpace
|
||||
: InnerSpace + FiniteDimVectorSpace<Field = <Self as InnerSpace>::Real> {
|
||||
}
|
||||
|
||||
pub trait EuclideanSpace: ClosedMul<<Self as EuclideanSpace>::Real> {
|
||||
type Coordinates: FiniteDimInnerSpace<Real = Self::Real>
|
||||
+ Mul<Self::Real, Output = Self::Coordinates>
|
||||
+ MulAssign<Self::Real>;
|
||||
|
||||
type Real;
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -8,10 +8,10 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags: -Z parse-only
|
||||
#![feature(pattern_parentheses)]
|
||||
|
||||
fn main() {
|
||||
match 0 {
|
||||
(pat) => {} //~ ERROR expected one of `,` or `@`, found `)`
|
||||
(pat) => assert_eq!(pat, 0)
|
||||
}
|
||||
}
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
// ignore-emscripten no threads support
|
||||
|
||||
#![feature(thread_local_state)]
|
||||
#![feature(thread_local_try_with)]
|
||||
|
||||
use std::thread::{self, LocalKeyState};
|
||||
use std::thread;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
||||
|
||||
struct Foo { cnt: usize }
|
||||
|
@ -37,10 +37,8 @@ impl Drop for Foo {
|
|||
FOO.with(|foo| assert_eq!(foo.cnt, 0));
|
||||
} else {
|
||||
assert_eq!(self.cnt, 0);
|
||||
match FOO.state() {
|
||||
LocalKeyState::Valid => panic!("should not be in valid state"),
|
||||
LocalKeyState::Uninitialized |
|
||||
LocalKeyState::Destroyed => {}
|
||||
if FOO.try_with(|_| ()).is_ok() {
|
||||
panic!("should not be in valid state");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
// ignore-emscripten no threads support
|
||||
|
||||
#![feature(thread_local_state)]
|
||||
#![feature(thread_local_try_with)]
|
||||
|
||||
use std::thread;
|
||||
|
||||
|
|
|
@ -13,5 +13,6 @@ struct Bar;
|
|||
|
||||
impl Foo for Bar {} //~ ERROR E0404
|
||||
|
||||
fn main() {
|
||||
}
|
||||
fn main() {}
|
||||
|
||||
fn baz<T: Foo>(_: T) {} //~ ERROR E0404
|
||||
|
|
|
@ -4,6 +4,12 @@ error[E0404]: expected trait, found struct `Foo`
|
|||
LL | impl Foo for Bar {} //~ ERROR E0404
|
||||
| ^^^ not a trait
|
||||
|
||||
error[E0404]: expected trait, found struct `Foo`
|
||||
--> $DIR/E0404.rs:18:11
|
||||
|
|
||||
LL | fn baz<T: Foo>(_: T) {} //~ ERROR E0404
|
||||
| ^^^ not a trait
|
||||
|
||||
error: cannot continue compilation due to previous error
|
||||
|
||||
If you want more information on this error, try using "rustc --explain E0404"
|
||||
|
|
15
src/test/ui/feature-gate-pattern_parentheses.rs
Normal file
15
src/test/ui/feature-gate-pattern_parentheses.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
match 0 {
|
||||
(pat) => {} //~ ERROR parentheses in patterns are unstable
|
||||
}
|
||||
}
|
11
src/test/ui/feature-gate-pattern_parentheses.stderr
Normal file
11
src/test/ui/feature-gate-pattern_parentheses.stderr
Normal file
|
@ -0,0 +1,11 @@
|
|||
error[E0658]: parentheses in patterns are unstable
|
||||
--> $DIR/feature-gate-pattern_parentheses.rs:13:9
|
||||
|
|
||||
LL | (pat) => {} //~ ERROR parentheses in patterns are unstable
|
||||
| ^^^^^
|
||||
|
|
||||
= help: add #![feature(pattern_parentheses)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
If you want more information on this error, try using "rustc --explain E0658"
|
|
@ -17,6 +17,11 @@ import json
|
|||
import copy
|
||||
import datetime
|
||||
import collections
|
||||
import textwrap
|
||||
try:
|
||||
import urllib2
|
||||
except ImportError:
|
||||
import urllib.request as urllib2
|
||||
|
||||
# List of people to ping when the status of a tool changed.
|
||||
MAINTAINERS = {
|
||||
|
@ -24,6 +29,10 @@ MAINTAINERS = {
|
|||
'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk',
|
||||
'rls': '@nrc',
|
||||
'rustfmt': '@nrc',
|
||||
'book': '@carols10cents @steveklabnik',
|
||||
'nomicon': '@frewsxcv @Gankro',
|
||||
'reference': '@steveklabnik @Havvy @matthewjasper @alercah',
|
||||
'rust-by-example': '@steveklabnik @marioidival @projektir',
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,7 +47,12 @@ def read_current_status(current_commit, path):
|
|||
return {}
|
||||
|
||||
|
||||
def update_latest(current_commit, relevant_pr_number, current_datetime):
|
||||
def update_latest(
|
||||
current_commit,
|
||||
relevant_pr_number,
|
||||
relevant_pr_url,
|
||||
current_datetime
|
||||
):
|
||||
'''Updates `_data/latest.json` to match build result of the given commit.
|
||||
'''
|
||||
with open('_data/latest.json', 'rb+') as f:
|
||||
|
@ -50,8 +64,13 @@ def update_latest(current_commit, relevant_pr_number, current_datetime):
|
|||
}
|
||||
|
||||
slug = 'rust-lang/rust'
|
||||
message = '📣 Toolstate changed by {}!\n\nTested on commit {}@{}.\n\n' \
|
||||
.format(relevant_pr_number, slug, current_commit)
|
||||
message = textwrap.dedent('''\
|
||||
📣 Toolstate changed by {}!
|
||||
|
||||
Tested on commit {}@{}.
|
||||
Direct link to PR: <{}>
|
||||
|
||||
''').format(relevant_pr_number, slug, current_commit, relevant_pr_url)
|
||||
anything_changed = False
|
||||
for status in latest:
|
||||
tool = status['tool']
|
||||
|
@ -68,7 +87,7 @@ def update_latest(current_commit, relevant_pr_number, current_datetime):
|
|||
elif new < old:
|
||||
changed = True
|
||||
message += '💔 {} on {}: {} → {} (cc {}).\n' \
|
||||
.format(tool, os, old, new, MAINTAINERS[tool])
|
||||
.format(tool, os, old, new, MAINTAINERS.get(tool))
|
||||
|
||||
if changed:
|
||||
status['commit'] = current_commit
|
||||
|
@ -89,17 +108,41 @@ if __name__ == '__main__':
|
|||
cur_datetime = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
cur_commit_msg = sys.argv[2]
|
||||
save_message_to_path = sys.argv[3]
|
||||
github_token = sys.argv[4]
|
||||
|
||||
relevant_pr_match = re.search('#[0-9]+', cur_commit_msg)
|
||||
relevant_pr_match = re.search('#([0-9]+)', cur_commit_msg)
|
||||
if relevant_pr_match:
|
||||
relevant_pr_number = 'rust-lang/rust' + relevant_pr_match.group(0)
|
||||
number = relevant_pr_match.group(1)
|
||||
relevant_pr_number = 'rust-lang/rust#' + number
|
||||
relevant_pr_url = 'https://github.com/rust-lang/rust/pull/' + number
|
||||
else:
|
||||
number = '-1'
|
||||
relevant_pr_number = '<unknown PR>'
|
||||
relevant_pr_url = '<unknown>'
|
||||
|
||||
message = update_latest(cur_commit, relevant_pr_number, cur_datetime)
|
||||
if message:
|
||||
print(message)
|
||||
with open(save_message_to_path, 'w') as f:
|
||||
f.write(message)
|
||||
else:
|
||||
message = update_latest(
|
||||
cur_commit,
|
||||
relevant_pr_number,
|
||||
relevant_pr_url,
|
||||
cur_datetime
|
||||
)
|
||||
if not message:
|
||||
print('<Nothing changed>')
|
||||
sys.exit(0)
|
||||
|
||||
print(message)
|
||||
with open(save_message_to_path, 'w') as f:
|
||||
f.write(message)
|
||||
|
||||
# Write the toolstate comment on the PR as well.
|
||||
gh_url = 'https://api.github.com/repos/rust-lang/rust/issues/{}/comments' \
|
||||
.format(number)
|
||||
response = urllib2.urlopen(urllib2.Request(
|
||||
gh_url,
|
||||
json.dumps({'body': message}),
|
||||
{
|
||||
'Authorization': 'token ' + github_token,
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
))
|
||||
response.read()
|
||||
|
|
Loading…
Add table
Reference in a new issue