Auto merge of #48653 - Manishearth:rollup2, r=Manishearth

Another rollup

None
This commit is contained in:
bors 2018-03-02 06:08:15 +00:00
commit 9cb18a92ad
42 changed files with 706 additions and 337 deletions

View file

@ -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:

View file

@ -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

View file

@ -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,

View file

@ -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);

View file

@ -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)
}
}

View file

@ -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/

View 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)

View file

@ -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

View file

@ -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,
})
}

View file

@ -737,6 +737,7 @@ impl EarlyLintPass for IllegalFloatLiteralPattern {
PatKind::TupleStruct(..) |
PatKind::Ref(..) |
PatKind::Box(..) |
PatKind::Paren(..) |
PatKind::Slice(..) => (),
// Extract the expressions and check them

View file

@ -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##"

View file

@ -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;

View file

@ -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
}

View file

@ -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()) }
})

View file

@ -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()
}

View file

@ -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>,

View file

@ -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

View file

@ -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);
}

View file

@ -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())));
}
}
}

View file

@ -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

View file

@ -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),
}

View file

@ -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);

View file

@ -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)

View file

@ -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)

View file

@ -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),

View file

@ -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))

View file

@ -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) => {

View file

@ -12,6 +12,6 @@
fn main() {
match 0 {
(pat, ..,) => {} //~ ERROR expected pattern, found `)`
(pat, ..,) => {} //~ ERROR trailing comma is not permitted after `..`
}
}

View file

@ -0,0 +1,5 @@
-include ../tools.mk
all: $(call NATIVE_STATICLIB,foo)
$(RUSTC) main.rs
$(call RUN,main)

View 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);
}

View 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();
}
}

View 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;
µ
}

View 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();
}

View 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() {}

View file

@ -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)
}
}

View file

@ -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");
}
}
}

View file

@ -10,7 +10,7 @@
// ignore-emscripten no threads support
#![feature(thread_local_state)]
#![feature(thread_local_try_with)]
use std::thread;

View file

@ -13,5 +13,6 @@ struct Bar;
impl Foo for Bar {} //~ ERROR E0404
fn main() {
}
fn main() {}
fn baz<T: Foo>(_: T) {} //~ ERROR E0404

View file

@ -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"

View 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
}
}

View 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"

View file

@ -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()