Skip to content

Rollup of 14 pull requests #45261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 44 commits into from
Oct 13, 2017
Merged
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
5451b72
Expand the introduction to the ffi module.
federicomenaquintero Sep 22, 2017
8da694a
Overhaul the ffi::CString docs
federicomenaquintero Sep 23, 2017
2cb2a06
Overhaul the ffi::CStr documentation.
federicomenaquintero Sep 25, 2017
3c5e18f
Point from the error structs back to the method that created them, li…
federicomenaquintero Sep 25, 2017
155b4b1
Module overview for std::os::windows:ffi
federicomenaquintero Sep 25, 2017
91f6445
Overhaul the documentation for OsString / OsStr
federicomenaquintero Sep 25, 2017
4143422
os_str: Fix too-long lines
federicomenaquintero Sep 26, 2017
9854e83
Remove the implication that CString contains UTF-8 data.
federicomenaquintero Oct 2, 2017
50505aa
Clarify the ffi module's toplevel docs, per @clarcharr's comments
federicomenaquintero Oct 2, 2017
d989cd0
Fix broken links in documentation
federicomenaquintero Oct 2, 2017
35545b3
Improve newtype_index macro to handle description and constants consi…
Nashenas88 Oct 8, 2017
a28b246
usize index message for vec
GuillaumeGomez Oct 9, 2017
843dc60
Add suggestions for misspelled labels
Oct 9, 2017
72cfd20
Add error for comma after base struct field
Badel2 Oct 10, 2017
db91b00
output compiler message updated
jean-lourenco Oct 8, 2017
a2aba79
rustc: Update LLVM with a ThinLTO fix
alexcrichton Oct 11, 2017
90d58a3
rustbuild: Make openssl download more reliable.
kennytm Oct 11, 2017
d5bdfbc
ffi/c_str.rs: Make all descriptions have a single-sentence summary at…
federicomenaquintero Oct 11, 2017
a9a4ce6
ffi/c_str.rs: Fix method/function confusion
federicomenaquintero Oct 11, 2017
0264510
ffi/c_str.rs: Use only one space after a period ending a sentence
federicomenaquintero Oct 11, 2017
c8e232d
ffi/mod.rs: Keep the one-sentence summary at the beginning of the module
federicomenaquintero Oct 11, 2017
fab6a10
Point at immutable outer variable
estebank Oct 11, 2017
5fb8e3d
ffi/mod.rs: Use only one space after a period ending a sentence
federicomenaquintero Oct 11, 2017
9423bee
Move const qualifier from brackets to constant values and remove comm…
Nashenas88 Oct 12, 2017
97fe353
Split lines longer than 100 columns
Nashenas88 Oct 12, 2017
e6da40c
rustbuild: Prevent spurious rebuilds of the RLS
alexcrichton Oct 12, 2017
6cae080
rustc: Handle `#[linkage]` anywhere in a crate
alexcrichton Oct 10, 2017
9da9c3b
Small improvement for the sidebar on mobile devices
GuillaumeGomez Oct 12, 2017
16ec7b9
Increase padding between consecutive impls
Oct 12, 2017
11775ab
Clarify how needs_drop is conservative
Gankra Oct 13, 2017
6c43bd3
Rollup merge of #44855 - federicomenaquintero:master, r=steveklabnik
kennytm Oct 13, 2017
82f2c28
Rollup merge of #45110 - Nashenas88:master, r=arielb1
kennytm Oct 13, 2017
9eab4ec
Rollup merge of #45122 - jean-lourenco:master, r=nikomatsakis
kennytm Oct 13, 2017
b290568
Rollup merge of #45133 - GuillaumeGomez:usize-index-msg, r=dtolnay
kennytm Oct 13, 2017
46d86d3
Rollup merge of #45173 - laumann:suggest-misspelled-labels, r=petroch…
kennytm Oct 13, 2017
e6a6d98
Rollup merge of #45178 - Badel2:comma-after-struct, r=petrochenkov
kennytm Oct 13, 2017
a481d7c
Rollup merge of #45189 - alexcrichton:thinlto-allocators, r=michaelwo…
kennytm Oct 13, 2017
64cc5ec
Rollup merge of #45203 - alexcrichton:update-llvm, r=michaelwoerister
kennytm Oct 13, 2017
9b128e4
Rollup merge of #45209 - kennytm:treat-checksum-error-as-download-err…
kennytm Oct 13, 2017
2a6a4e7
Rollup merge of #45221 - estebank:issue-41790, r=nikomatsakis
kennytm Oct 13, 2017
4ed348e
Rollup merge of #45236 - alexcrichton:build-less, r=Mark-Simulacrum
kennytm Oct 13, 2017
f43c54e
Rollup merge of #45240 - GuillaumeGomez:mobile-sidebar-improvements, …
kennytm Oct 13, 2017
fb98e3e
Rollup merge of #45245 - stjepang:more-padding-between-impls, r=Quiet…
kennytm Oct 13, 2017
8ea6790
Rollup merge of #45253 - Gankro:drop_docs, r=kennytm
kennytm Oct 13, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/bootstrap/check.rs
Original file line number Diff line number Diff line change
@@ -246,8 +246,11 @@ impl Step for Rls {
let compiler = builder.compiler(stage, host);

builder.ensure(tool::Rls { compiler, target: self.host });
let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
cargo.arg("--manifest-path").arg(build.src.join("src/tools/rls/Cargo.toml"));
let mut cargo = tool::prepare_tool_cargo(builder,
compiler,
host,
"test",
"src/tools/rls");

// Don't build tests dynamically, just a pain to work with
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
@@ -291,8 +294,11 @@ impl Step for Rustfmt {
let compiler = builder.compiler(stage, host);

builder.ensure(tool::Rustfmt { compiler, target: self.host });
let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
cargo.arg("--manifest-path").arg(build.src.join("src/tools/rustfmt/Cargo.toml"));
let mut cargo = tool::prepare_tool_cargo(builder,
compiler,
host,
"test",
"src/tools/rustfmt");

// Don't build tests dynamically, just a pain to work with
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
57 changes: 37 additions & 20 deletions src/bootstrap/native.rs
Original file line number Diff line number Diff line change
@@ -352,34 +352,51 @@ impl Step for Openssl {
// originally from https://www.openssl.org/source/...
let url = format!("https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/{}",
name);
let mut ok = false;
let mut last_error = None;
for _ in 0..3 {
let status = Command::new("curl")
.arg("-o").arg(&tmp)
.arg("-f") // make curl fail if the URL does not return HTTP 200
.arg(&url)
.status()
.expect("failed to spawn curl");
if status.success() {
ok = true;
break

// Retry if download failed.
if !status.success() {
last_error = Some(status.to_string());
continue;
}

// Ensure the hash is correct.
let mut shasum = if target.contains("apple") || build.build.contains("netbsd") {
let mut cmd = Command::new("shasum");
cmd.arg("-a").arg("256");
cmd
} else {
Command::new("sha256sum")
};
let output = output(&mut shasum.arg(&tmp));
let found = output.split_whitespace().next().unwrap();

// If the hash is wrong, probably the download is incomplete or S3 served an error
// page. In any case, retry.
if found != OPENSSL_SHA256 {
last_error = Some(format!(
"downloaded openssl sha256 different\n\
expected: {}\n\
found: {}\n",
OPENSSL_SHA256,
found
));
continue;
}

// Everything is fine, so exit the retry loop.
last_error = None;
break;
}
if !ok {
panic!("failed to download openssl source")
}
let mut shasum = if target.contains("apple") || build.build.contains("netbsd") {
let mut cmd = Command::new("shasum");
cmd.arg("-a").arg("256");
cmd
} else {
Command::new("sha256sum")
};
let output = output(&mut shasum.arg(&tmp));
let found = output.split_whitespace().next().unwrap();
if found != OPENSSL_SHA256 {
panic!("downloaded openssl sha256 different\n\
expected: {}\n\
found: {}\n", OPENSSL_SHA256, found);
if let Some(error) = last_error {
panic!("failed to download openssl source: {}", error);
}
t!(fs::rename(&tmp, &tarball));
}
1 change: 1 addition & 0 deletions src/liballoc/lib.rs
Original file line number Diff line number Diff line change
@@ -121,6 +121,7 @@
#![feature(unique)]
#![feature(unsize)]
#![feature(allocator_internals)]
#![feature(on_unimplemented)]

#![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol, swap_with_slice, i128))]
#![cfg_attr(test, feature(test, box_heap))]
25 changes: 24 additions & 1 deletion src/liballoc/vec.rs
Original file line number Diff line number Diff line change
@@ -1543,6 +1543,7 @@ impl<T: Hash> Hash for Vec<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> Index<usize> for Vec<T> {
type Output = T;

@@ -1554,6 +1555,7 @@ impl<T> Index<usize> for Vec<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> IndexMut<usize> for Vec<T> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut T {
@@ -1562,8 +1564,8 @@ impl<T> IndexMut<usize> for Vec<T> {
}
}


#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> ops::Index<ops::Range<usize>> for Vec<T> {
type Output = [T];

@@ -1572,7 +1574,9 @@ impl<T> ops::Index<ops::Range<usize>> for Vec<T> {
Index::index(&**self, index)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> ops::Index<ops::RangeTo<usize>> for Vec<T> {
type Output = [T];

@@ -1581,7 +1585,9 @@ impl<T> ops::Index<ops::RangeTo<usize>> for Vec<T> {
Index::index(&**self, index)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> ops::Index<ops::RangeFrom<usize>> for Vec<T> {
type Output = [T];

@@ -1590,7 +1596,9 @@ impl<T> ops::Index<ops::RangeFrom<usize>> for Vec<T> {
Index::index(&**self, index)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> ops::Index<ops::RangeFull> for Vec<T> {
type Output = [T];

@@ -1599,7 +1607,9 @@ impl<T> ops::Index<ops::RangeFull> for Vec<T> {
self
}
}

#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> ops::Index<ops::RangeInclusive<usize>> for Vec<T> {
type Output = [T];

@@ -1608,7 +1618,9 @@ impl<T> ops::Index<ops::RangeInclusive<usize>> for Vec<T> {
Index::index(&**self, index)
}
}

#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> ops::Index<ops::RangeToInclusive<usize>> for Vec<T> {
type Output = [T];

@@ -1619,41 +1631,52 @@ impl<T> ops::Index<ops::RangeToInclusive<usize>> for Vec<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> ops::IndexMut<ops::Range<usize>> for Vec<T> {
#[inline]
fn index_mut(&mut self, index: ops::Range<usize>) -> &mut [T] {
IndexMut::index_mut(&mut **self, index)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> ops::IndexMut<ops::RangeTo<usize>> for Vec<T> {
#[inline]
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] {
IndexMut::index_mut(&mut **self, index)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> ops::IndexMut<ops::RangeFrom<usize>> for Vec<T> {
#[inline]
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [T] {
IndexMut::index_mut(&mut **self, index)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> ops::IndexMut<ops::RangeFull> for Vec<T> {
#[inline]
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut [T] {
self
}
}

#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for Vec<T> {
#[inline]
fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut [T] {
IndexMut::index_mut(&mut **self, index)
}
}

#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for Vec<T> {
#[inline]
fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut [T] {
8 changes: 5 additions & 3 deletions src/libcore/mem.rs
Original file line number Diff line number Diff line change
@@ -429,9 +429,11 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {

/// Returns whether dropping values of type `T` matters.
///
/// This is purely an optimization hint, and may be implemented conservatively.
/// For instance, always returning `true` would be a valid implementation of
/// this function.
/// This is purely an optimization hint, and may be implemented conservatively:
/// it may return `true` for types that don't actually need to be dropped.
/// As such always returning `true` would be a valid implementation of
/// this function. However if this function actually returns `false`, then you
/// can be certain dropping `T` has no side effect.
///
/// Low level implementations of things like collections, which need to manually
/// drop their data, should use this function to avoid unnecessarily
6 changes: 6 additions & 0 deletions src/librustc/middle/reachable.rs
Original file line number Diff line number Diff line change
@@ -336,6 +336,12 @@ struct CollectPrivateImplItemsVisitor<'a, 'tcx: 'a> {

impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
// Anything which has custom linkage gets thrown on the worklist no
// matter where it is in the crate.
if attr::contains_name(&item.attrs, "linkage") {
self.worklist.push(item.id);
}

// We need only trait impls here, not inherent impls, and only non-exported ones
if let hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_item_refs) = item.node {
if !self.access_levels.is_reachable(item.id) {
21 changes: 13 additions & 8 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -415,9 +415,11 @@ pub enum BorrowKind {
///////////////////////////////////////////////////////////////////////////
// Variables and temps

newtype_index!(Local, "_");

pub const RETURN_POINTER: Local = Local(0);
newtype_index!(Local
{
DEBUG_NAME = "_",
const RETURN_POINTER = 0,
});

/// Classifies locals into categories. See `Mir::local_kind`.
#[derive(PartialEq, Eq, Debug)]
@@ -551,7 +553,7 @@ pub struct UpvarDecl {
///////////////////////////////////////////////////////////////////////////
// BasicBlock

newtype_index!(BasicBlock, "bb");
newtype_index!(BasicBlock { DEBUG_NAME = "bb" });

///////////////////////////////////////////////////////////////////////////
// BasicBlockData and Terminator
@@ -1131,7 +1133,7 @@ pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Local, Ty<'tcx>
/// and the index is a local.
pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>;

newtype_index!(Field, "field");
newtype_index!(Field { DEBUG_NAME = "field" });

impl<'tcx> Lvalue<'tcx> {
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> {
@@ -1196,8 +1198,11 @@ impl<'tcx> Debug for Lvalue<'tcx> {
///////////////////////////////////////////////////////////////////////////
// Scopes

newtype_index!(VisibilityScope, "scope");
pub const ARGUMENT_VISIBILITY_SCOPE : VisibilityScope = VisibilityScope(0);
newtype_index!(VisibilityScope
{
DEBUG_NAME = "scope",
const ARGUMENT_VISIBILITY_SCOPE = 0,
});

#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct VisibilityScopeData {
@@ -1522,7 +1527,7 @@ pub struct Constant<'tcx> {
pub literal: Literal<'tcx>,
}

newtype_index!(Promoted, "promoted");
newtype_index!(Promoted { DEBUG_NAME = "promoted" });

#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum Literal<'tcx> {
16 changes: 15 additions & 1 deletion src/librustc_borrowck/borrowck/mod.rs
Original file line number Diff line number Diff line change
@@ -759,7 +759,21 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {

let mut db = match err.cause {
MutabilityViolation => {
self.cannot_assign(error_span, &descr, Origin::Ast)
let mut db = self.cannot_assign(error_span, &descr, Origin::Ast);
if let mc::NoteClosureEnv(upvar_id) = err.cmt.note {
let node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id);
let sp = self.tcx.hir.span(node_id);
match self.tcx.sess.codemap().span_to_snippet(sp) {
Ok(snippet) => {
let msg = &format!("consider making `{}` mutable", snippet);
db.span_suggestion(sp, msg, format!("mut {}", snippet));
}
_ => {
db.span_help(sp, "consider making this binding mutable");
}
}
}
db
}
BorrowViolation(euv::ClosureCapture(_)) => {
struct_span_err!(self.tcx.sess, error_span, E0595,
75 changes: 58 additions & 17 deletions src/librustc_data_structures/indexed_vec.rs
Original file line number Diff line number Diff line change
@@ -40,39 +40,80 @@ impl Idx for u32 {

#[macro_export]
macro_rules! newtype_index {
// ---- public rules ----

// Use default constants
($name:ident) => (
newtype_index!($name, unsafe { ::std::intrinsics::type_name::<$name>() });
newtype_index!(
@type[$name]
@max[::std::u32::MAX]
@debug_name[unsafe {::std::intrinsics::type_name::<$name>() }]);
);

// Define any constants
($name:ident { $($tokens:tt)+ }) => (
newtype_index!(
@type[$name]
@max[::std::u32::MAX]
@debug_name[unsafe {::std::intrinsics::type_name::<$name>() }]
$($tokens)+);
);

($name:ident, $debug_name:expr) => (
// ---- private rules ----

// Base case, user-defined constants (if any) have already been defined
(@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr]) => (
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
RustcEncodable, RustcDecodable)]
pub struct $name(u32);

impl $name {
// HACK use for constants
#[allow(unused)]
const fn const_new(x: u32) -> Self {
$name(x)
}
}
RustcEncodable, RustcDecodable)]
pub struct $type(u32);

impl Idx for $name {
impl Idx for $type {
fn new(value: usize) -> Self {
assert!(value < (::std::u32::MAX) as usize);
$name(value as u32)
assert!(value < ($max) as usize);
$type(value as u32)
}
fn index(self) -> usize {
self.0 as usize
}
}

impl ::std::fmt::Debug for $name {
impl ::std::fmt::Debug for $type {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(fmt, "{}{}", $debug_name, self.0)
}
}
)
);

// Rewrite final without comma to one that includes comma
(@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr]
$name:ident = $constant:expr) => (
newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $name = $constant,);
);

// Rewrite final const without comma to one that includes comma
(@type[$type:ident] @max[$_max:expr] @debug_name[$debug_name:expr]
const $name:ident = $constant:expr) => (
newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] const $name = $constant,);
);

// Replace existing default for max
(@type[$type:ident] @max[$_max:expr] @debug_name[$debug_name:expr]
MAX = $max:expr, $($tokens:tt)*) => (
newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $(tokens)*);
);

// Replace existing default for debug_name
(@type[$type:ident] @max[$max:expr] @debug_name[$_debug_name:expr]
DEBUG_NAME = $debug_name:expr, $($tokens:tt)*) => (
newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*);
);

// Assign a user-defined constant (as final param)
(@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr]
const $name:ident = $constant:expr, $($tokens:tt)*) => (
pub const $name: $type = $type($constant);
newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*);
);
}

#[derive(Clone, PartialEq, Eq)]
36 changes: 26 additions & 10 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
@@ -137,7 +137,7 @@ enum ResolutionError<'a> {
/// error E0416: identifier is bound more than once in the same pattern
IdentifierBoundMoreThanOnceInSamePattern(&'a str),
/// error E0426: use of undeclared label
UndeclaredLabel(&'a str),
UndeclaredLabel(&'a str, Option<Name>),
/// error E0429: `self` imports are only allowed within a { } list
SelfImportsOnlyAllowedWithin,
/// error E0430: `self` import can only appear once in the list
@@ -263,13 +263,17 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
err.span_label(span, "used in a pattern more than once");
err
}
ResolutionError::UndeclaredLabel(name) => {
ResolutionError::UndeclaredLabel(name, lev_candidate) => {
let mut err = struct_span_err!(resolver.session,
span,
E0426,
"use of undeclared label `{}`",
name);
err.span_label(span, format!("undeclared label `{}`", name));
if let Some(lev_candidate) = lev_candidate {
err.span_label(span, format!("did you mean `{}`?", lev_candidate));
} else {
err.span_label(span, format!("undeclared label `{}`", name));
}
err
}
ResolutionError::SelfImportsOnlyAllowedWithin => {
@@ -1790,9 +1794,13 @@ impl<'a> Resolver<'a> {
}
}

/// Searches the current set of local scopes for labels.
/// Searches the current set of local scopes for labels. Returns the first non-None label that
/// is returned by the given predicate function
///
/// Stops after meeting a closure.
fn search_label(&self, mut ident: Ident) -> Option<Def> {
fn search_label<P, R>(&self, mut ident: Ident, pred: P) -> Option<R>
where P: Fn(&Rib, Ident) -> Option<R>
{
for rib in self.label_ribs.iter().rev() {
match rib.kind {
NormalRibKind => {}
@@ -1808,9 +1816,9 @@ impl<'a> Resolver<'a> {
return None;
}
}
let result = rib.bindings.get(&ident).cloned();
if result.is_some() {
return result;
let r = pred(rib, ident);
if r.is_some() {
return r;
}
}
None
@@ -3202,12 +3210,20 @@ impl<'a> Resolver<'a> {
}

ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
match self.search_label(label.node) {
match self.search_label(label.node, |rib, id| rib.bindings.get(&id).cloned()) {
None => {
// Search again for close matches...
// Picks the first label that is "close enough", which is not necessarily
// the closest match
let close_match = self.search_label(label.node, |rib, ident| {
let names = rib.bindings.iter().map(|(id, _)| &id.name);
find_best_match_for_name(names, &*ident.name.as_str(), None)
});
self.record_def(expr.id, err_path_resolution());
resolve_error(self,
label.span,
ResolutionError::UndeclaredLabel(&label.node.name.as_str()));
ResolutionError::UndeclaredLabel(&label.node.name.as_str(),
close_match));
}
Some(def @ Def::Label(_)) => {
// Since this def is a label, it is never read.
14 changes: 8 additions & 6 deletions src/librustdoc/html/static/rustdoc.css
Original file line number Diff line number Diff line change
@@ -394,7 +394,7 @@ h4 > code, h3 > code, .invisible > code {
padding: 0;
}

.content .item-list li { margin-bottom: 3px; }
.content .item-list li { margin-bottom: 1em; }

.content .multi-column {
-moz-column-count: 5;
@@ -773,17 +773,19 @@ span.since {
}

.sidebar {
height: 40px;
height: 45px;
min-height: 40px;
width: 100%;
margin: 0px;
padding: 0px;
width: calc(100% + 30px);
margin: 0;
margin-left: -15px;
padding: 0 15px;
position: static;
}

.sidebar .location {
float: right;
margin: 0px;
margin-top: 2px;
padding: 3px 10px 1px 10px;
min-height: 39px;
background: inherit;
@@ -798,7 +800,7 @@ span.since {
.sidebar img {
width: 35px;
margin-top: 5px;
margin-bottom: 0px;
margin-bottom: 5px;
float: left;
}

251 changes: 186 additions & 65 deletions src/libstd/ffi/c_str.rs

Large diffs are not rendered by default.

151 changes: 151 additions & 0 deletions src/libstd/ffi/mod.rs
Original file line number Diff line number Diff line change
@@ -9,6 +9,157 @@
// except according to those terms.

//! Utilities related to FFI bindings.
//!
//! This module provides utilities to handle data across non-Rust
//! interfaces, like other programming languages and the underlying
//! operating system. It is mainly of use for FFI (Foreign Function
//! Interface) bindings and code that needs to exchange C-like strings
//! with other languages.
//!
//! # Overview
//!
//! Rust represents owned strings with the [`String`] type, and
//! borrowed slices of strings with the [`str`] primitive. Both are
//! always in UTF-8 encoding, and may contain nul bytes in the middle,
//! i.e. if you look at the bytes that make up the string, there may
//! be a `\0` among them. Both `String` and `str` store their length
//! explicitly; there are no nul terminators at the end of strings
//! like in C.
//!
//! C strings are different from Rust strings:
//!
//! * **Encodings** - Rust strings are UTF-8, but C strings may use
//! other encodings. If you are using a string from C, you should
//! check its encoding explicitly, rather than just assuming that it
//! is UTF-8 like you can do in Rust.
//!
//! * **Character size** - C strings may use `char` or `wchar_t`-sized
//! characters; please **note** that C's `char` is different from Rust's.
//! The C standard leaves the actual sizes of those types open to
//! interpretation, but defines different APIs for strings made up of
//! each character type. Rust strings are always UTF-8, so different
//! Unicode characters will be encoded in a variable number of bytes
//! each. The Rust type [`char`] represents a '[Unicode scalar
//! value]', which is similar to, but not the same as, a '[Unicode
//! code point]'.
//!
//! * **Nul terminators and implicit string lengths** - Often, C
//! strings are nul-terminated, i.e. they have a `\0` character at the
//! end. The length of a string buffer is not stored, but has to be
//! calculated; to compute the length of a string, C code must
//! manually call a function like `strlen()` for `char`-based strings,
//! or `wcslen()` for `wchar_t`-based ones. Those functions return
//! the number of characters in the string excluding the nul
//! terminator, so the buffer length is really `len+1` characters.
//! Rust strings don't have a nul terminator; their length is always
//! stored and does not need to be calculated. While in Rust
//! accessing a string's length is a O(1) operation (becasue the
//! length is stored); in C it is an O(length) operation because the
//! length needs to be computed by scanning the string for the nul
//! terminator.
//!
//! * **Internal nul characters** - When C strings have a nul
//! terminator character, this usually means that they cannot have nul
//! characters in the middle — a nul character would essentially
//! truncate the string. Rust strings *can* have nul characters in
//! the middle, because nul does not have to mark the end of the
//! string in Rust.
//!
//! # Representations of non-Rust strings
//!
//! [`CString`] and [`CStr`] are useful when you need to transfer
//! UTF-8 strings to and from languages with a C ABI, like Python.
//!
//! * **From Rust to C:** [`CString`] represents an owned, C-friendly
//! string: it is nul-terminated, and has no internal nul characters.
//! Rust code can create a `CString` out of a normal string (provided
//! that the string doesn't have nul characters in the middle), and
//! then use a variety of methods to obtain a raw `*mut u8` that can
//! then be passed as an argument to functions which use the C
//! conventions for strings.
//!
//! * **From C to Rust:** [`CStr`] represents a borrowed C string; it
//! is what you would use to wrap a raw `*const u8` that you got from
//! a C function. A `CStr` is guaranteed to be a nul-terminated array
//! of bytes. Once you have a `CStr`, you can convert it to a Rust
//! `&str` if it's valid UTF-8, or lossily convert it by adding
//! replacement characters.
//!
//! [`OsString`] and [`OsStr`] are useful when you need to transfer
//! strings to and from the operating system itself, or when capturing
//! the output of external commands. Conversions between `OsString`,
//! `OsStr` and Rust strings work similarly to those for [`CString`]
//! and [`CStr`].
//!
//! * [`OsString`] represents an owned string in whatever
//! representation the operating system prefers. In the Rust standard
//! library, various APIs that transfer strings to/from the operating
//! system use `OsString` instead of plain strings. For example,
//! [`env::var_os()`] is used to query environment variables; it
//! returns an `Option<OsString>`. If the environment variable exists
//! you will get a `Some(os_string)`, which you can *then* try to
//! convert to a Rust string. This yields a [`Result<>`], so that
//! your code can detect errors in case the environment variable did
//! not in fact contain valid Unicode data.
//!
//! * [`OsStr`] represents a borrowed reference to a string in a
//! format that can be passed to the operating system. It can be
//! converted into an UTF-8 Rust string slice in a similar way to
//! `OsString`.
//!
//! # Conversions
//!
//! ## On Unix
//!
//! On Unix, [`OsStr`] implements the
//! `std::os::unix:ffi::`[`OsStrExt`][unix.OsStrExt] trait, which
//! augments it with two methods, [`from_bytes`] and [`as_bytes`].
//! These do inexpensive conversions from and to UTF-8 byte slices.
//!
//! Additionally, on Unix [`OsString`] implements the
//! `std::os::unix:ffi::`[`OsStringExt`][unix.OsStringExt] trait,
//! which provides [`from_vec`] and [`into_vec`] methods that consume
//! their arguments, and take or produce vectors of [`u8`].
//!
//! ## On Windows
//!
//! On Windows, [`OsStr`] implements the
//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait,
//! which provides an [`encode_wide`] method. This provides an
//! iterator that can be [`collect`]ed into a vector of [`u16`].
//!
//! Additionally, on Windows [`OsString`] implements the
//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt]
//! trait, which provides a [`from_wide`] method. The result of this
//! method is an `OsString` which can be round-tripped to a Windows
//! string losslessly.
//!
//! [`String`]: ../string/struct.String.html
//! [`str`]: ../primitive.str.html
//! [`char`]: ../primitive.char.html
//! [`u8`]: ../primitive.u8.html
//! [`u16`]: ../primitive.u16.html
//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value
//! [Unicode code point]: http://www.unicode.org/glossary/#code_point
//! [`CString`]: struct.CString.html
//! [`CStr`]: struct.CStr.html
//! [`OsString`]: struct.OsString.html
//! [`OsStr`]: struct.OsStr.html
//! [`env::set_var()`]: ../env/fn.set_var.html
//! [`env::var_os()`]: ../env/fn.var_os.html
//! [`Result<>`]: ../result/enum.Result.html
//! [unix.OsStringExt]: ../os/unix/ffi/trait.OsStringExt.html
//! [`from_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.from_vec
//! [`into_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.into_vec
//! [unix.OsStrExt]: ../os/unix/ffi/trait.OsStrExt.html
//! [`from_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.from_bytes
//! [`as_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.as_bytes
//! [`OsStrExt`]: ../os/unix/ffi/trait.OsStrExt.html
//! [windows.OsStrExt]: ../os/windows/ffi/trait.OsStrExt.html
//! [`encode_wide`]: ../os/windows/ffi/trait.OsStrExt.html#tymethod.encode_wide
//! [`collect`]: ../iter/trait.Iterator.html#method.collect
//! [windows.OsStringExt]: ../os/windows/ffi/trait.OsStringExt.html
//! [`from_wide`]: ../os/windows/ffi/trait.OsStringExt.html#tymethod.from_wide
#![stable(feature = "rust1", since = "1.0.0")]

51 changes: 49 additions & 2 deletions src/libstd/ffi/os_str.rs
Original file line number Diff line number Diff line change
@@ -32,18 +32,65 @@ use sys_common::{AsInner, IntoInner, FromInner};
///
/// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust
/// and platform-native string values, and in particular allowing a Rust string
/// to be converted into an "OS" string with no cost.
/// to be converted into an "OS" string with no cost if possible.
///
/// `OsString` is to [`OsStr`] as [`String`] is to [`&str`]: the former
/// in each pair are owned strings; the latter are borrowed
/// references.
///
/// # Creating an `OsString`
///
/// **From a Rust string**: `OsString` implements
/// [`From`]`<`[`String`]`>`, so you can use `my_string.`[`from`] to
/// create an `OsString` from a normal Rust string.
///
/// **From slices:** Just like you can start with an empty Rust
/// [`String`] and then [`push_str`][String.push_str] `&str`
/// sub-string slices into it, you can create an empty `OsString` with
/// the [`new`] method and then push string slices into it with the
/// [`push`] method.
///
/// # Extracting a borrowed reference to the whole OS string
///
/// You can use the [`as_os_str`] method to get an `&`[`OsStr`] from
/// an `OsString`; this is effectively a borrowed reference to the
/// whole string.
///
/// # Conversions
///
/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
/// the traits which `OsString` implements for conversions from/to native representations.
///
/// [`OsStr`]: struct.OsStr.html
/// [`From`]: ../convert/trait.From.html
/// [`from`]: ../convert/trait.From.html#tymethod.from
/// [`String`]: ../string/struct.String.html
/// [`&str`]: ../primitive.str.html
/// [`u8`]: ../primitive.u8.html
/// [`u16`]: ../primitive.u16.html
/// [String.push_str]: ../string/struct.String.html#method.push_str
/// [`new`]: #method.new
/// [`push`]: #method.push
/// [`as_os_str`]: #method.as_os_str
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct OsString {
inner: Buf
}

/// Slices into OS strings (see [`OsString`]).
/// Borrowed reference to an OS string (see [`OsString`]).
///
/// This type represents a borrowed reference to a string in the operating system's preferred
/// representation.
///
/// `OsStr` is to [`OsString`] as [`String`] is to [`&str`]: the former in each pair are borrowed
/// references; the latter are owned strings.
///
/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
/// the traits which `OsStr` implements for conversions from/to native representations.
///
/// [`OsString`]: struct.OsString.html
/// [conversions]: index.html#conversions
#[stable(feature = "rust1", since = "1.0.0")]
pub struct OsStr {
inner: Slice
56 changes: 56 additions & 0 deletions src/libstd/sys/windows/ext/ffi.rs
Original file line number Diff line number Diff line change
@@ -9,6 +9,62 @@
// except according to those terms.

//! Windows-specific extensions to the primitives in the `std::ffi` module.
//!
//! # Overview
//!
//! For historical reasons, the Windows API uses a form of potentially
//! ill-formed UTF-16 encoding for strings. Specifically, the 16-bit
//! code units in Windows strings may contain [isolated surrogate code
//! points which are not paired together][ill-formed-utf-16]. The
//! Unicode standard requires that surrogate code points (those in the
//! range U+D800 to U+DFFF) always be *paired*, because in the UTF-16
//! encoding a *surrogate code unit pair* is used to encode a single
//! character. For compatibility with code that does not enforce
//! these pairings, Windows does not enforce them, either.
//!
//! While it is not always possible to convert such a string losslessly into
//! a valid UTF-16 string (or even UTF-8), it is often desirable to be
//! able to round-trip such a string from and to Windows APIs
//! losslessly. For example, some Rust code may be "bridging" some
//! Windows APIs together, just passing `WCHAR` strings among those
//! APIs without ever really looking into the strings.
//!
//! If Rust code *does* need to look into those strings, it can
//! convert them to valid UTF-8, possibly lossily, by substituting
//! invalid sequences with U+FFFD REPLACEMENT CHARACTER, as is
//! conventionally done in other Rust APIs that deal with string
//! encodings.
//!
//! # `OsStringExt` and `OsStrExt`
//!
//! [`OsString`] is the Rust wrapper for owned strings in the
//! preferred representation of the operating system. On Windows,
//! this struct gets augmented with an implementation of the
//! [`OsStringExt`] trait, which has a [`from_wide`] method. This
//! lets you create an [`OsString`] from a `&[u16]` slice; presumably
//! you get such a slice out of a `WCHAR` Windows API.
//!
//! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from
//! preferred representation of the operating system. On Windows, the
//! [`OsStrExt`] trait provides the [`encode_wide`] method, which
//! outputs an [`EncodeWide`] iterator. You can [`collect`] this
//! iterator, for example, to obtain a `Vec<u16>`; you can later get a
//! pointer to this vector's contents and feed it to Windows APIs.
//!
//! These traits, along with [`OsString`] and [`OsStr`], work in
//! conjunction so that it is possible to **round-trip** strings from
//! Windows and back, with no loss of data, even if the strings are
//! ill-formed UTF-16.
//!
//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16
//! [`OsString`]: ../../../ffi/struct.OsString.html
//! [`OsStr`]: ../../../ffi/struct.OsStr.html
//! [`OsStringExt`]: trait.OsStringExt.html
//! [`OsStrExt`]: trait.OsStrExt.html
//! [`EncodeWide`]: struct.EncodeWide.html
//! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide
//! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide
//! [`collect`]: ../../../iter/trait.Iterator.html#method.collect
#![stable(feature = "rust1", since = "1.0.0")]

12 changes: 12 additions & 0 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
@@ -2314,6 +2314,7 @@ impl<'a> Parser<'a> {

while self.token != token::CloseDelim(token::Brace) {
if self.eat(&token::DotDot) {
let exp_span = self.prev_span;
match self.parse_expr() {
Ok(e) => {
base = Some(e);
@@ -2323,6 +2324,16 @@ impl<'a> Parser<'a> {
self.recover_stmt();
}
}
if self.token == token::Comma {
let mut err = self.sess.span_diagnostic.mut_span_err(
exp_span.to(self.prev_span),
"cannot use a comma after the base struct",
);
err.span_suggestion_short(self.span, "remove this comma", "".to_owned());
err.note("the base struct must always be the last field");
err.emit();
self.recover_stmt();
}
break;
}

@@ -2960,6 +2971,7 @@ impl<'a> Parser<'a> {
{ // Foo<Bar<Baz<Qux, ()>>>
err.help(
"use `::<...>` instead of `<...>` if you meant to specify type arguments");
err.help("or use `(...)` if you meant to specify fn arguments");
}
err.emit();
}
15 changes: 15 additions & 0 deletions src/test/compile-fail/index-help.rs
Original file line number Diff line number Diff line change
@@ -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() {
let x = vec![1];
x[0i32]; //~ ERROR E0277
//~| NOTE vector indices are of type `usize` or ranges of `usize`
}
3 changes: 2 additions & 1 deletion src/test/parse-fail/require-parens-for-chained-comparison.rs
Original file line number Diff line number Diff line change
@@ -21,5 +21,6 @@ fn main() {

f<X>();
//~^ ERROR: chained comparison operators require parentheses
//~^^ HELP: use `::<...>` instead of `<...>`
//~| HELP: use `::<...>` instead of `<...>`
//~| HELP: or use `(...)`
}
41 changes: 0 additions & 41 deletions src/test/run-pass/smallest-hello-world.rs

This file was deleted.

19 changes: 19 additions & 0 deletions src/test/run-pass/thin-lto-global-allocator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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.

// compile-flags: -Z thinlto -C codegen-units=2
// min-llvm-version 4.0

#![feature(allocator_api, global_allocator)]

#[global_allocator]
static A: std::heap::System = std::heap::System;

fn main() {}
4 changes: 4 additions & 0 deletions src/test/ui/did_you_mean/issue-40396.stderr
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ error: chained comparison operators require parentheses
| ^^^^^^^^
|
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments
= help: or use `(...)` if you meant to specify fn arguments

error: chained comparison operators require parentheses
--> $DIR/issue-40396.rs:16:25
@@ -13,6 +14,7 @@ error: chained comparison operators require parentheses
| ^^^^^^^
|
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments
= help: or use `(...)` if you meant to specify fn arguments

error: chained comparison operators require parentheses
--> $DIR/issue-40396.rs:20:37
@@ -21,6 +23,7 @@ error: chained comparison operators require parentheses
| ^^^^^^^^
|
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments
= help: or use `(...)` if you meant to specify fn arguments

error: chained comparison operators require parentheses
--> $DIR/issue-40396.rs:20:41
@@ -29,6 +32,7 @@ error: chained comparison operators require parentheses
| ^^^^^^
|
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments
= help: or use `(...)` if you meant to specify fn arguments

error: aborting due to 4 previous errors

27 changes: 27 additions & 0 deletions src/test/ui/struct-field-init-syntax.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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.

// compile-flags: -Z parse-only

// issue #41834

fn main() {
let foo = Foo {
one: 111,
..Foo::default(),
//~^ ERROR cannot use a comma after struct expansion
};

let foo = Foo {
..Foo::default(),
//~^ ERROR cannot use a comma after struct expansion
one: 111,
};
}
18 changes: 18 additions & 0 deletions src/test/ui/struct-field-init-syntax.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error: cannot use a comma after the base struct
--> $DIR/struct-field-init-syntax.rs:18:9
|
18 | ..Foo::default(),
| ^^^^^^^^^^^^^^^^- help: remove this comma
|
= note: the base struct must always be the last field

error: cannot use a comma after the base struct
--> $DIR/struct-field-init-syntax.rs:23:9
|
23 | ..Foo::default(),
| ^^^^^^^^^^^^^^^^- help: remove this comma
|
= note: the base struct must always be the last field

error: aborting due to 2 previous errors

20 changes: 20 additions & 0 deletions src/test/ui/suggestions/closure-immutable-outer-variable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// 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.

// Point at the captured immutable outer variable

fn foo(mut f: Box<FnMut()>) {
f();
}

fn main() {
let y = true;
foo(Box::new(move || y = false) as Box<_>);
}
10 changes: 10 additions & 0 deletions src/test/ui/suggestions/closure-immutable-outer-variable.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error[E0594]: cannot assign to captured outer variable in an `FnMut` closure
--> $DIR/closure-immutable-outer-variable.rs:19:26
|
18 | let y = true;
| - help: consider making `y` mutable: `mut y`
19 | foo(Box::new(move || y = false) as Box<_>);
| ^^^^^^^^^

error: aborting due to previous error

26 changes: 26 additions & 0 deletions src/test/ui/suggestions/suggest-labels.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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.

#[allow(unreachable_code)]
fn main() {
'foo: loop {
break 'fo;
}

'bar: loop {
continue 'bor;
}

'longlabel: loop {
'longlabel1: loop {
break 'longlable;
}
}
}
20 changes: 20 additions & 0 deletions src/test/ui/suggestions/suggest-labels.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0426]: use of undeclared label `'fo`
--> $DIR/suggest-labels.rs:14:15
|
14 | break 'fo;
| ^^^ did you mean `'foo`?

error[E0426]: use of undeclared label `'bor`
--> $DIR/suggest-labels.rs:18:18
|
18 | continue 'bor;
| ^^^^ did you mean `'bar`?

error[E0426]: use of undeclared label `'longlable`
--> $DIR/suggest-labels.rs:23:19
|
23 | break 'longlable;
| ^^^^^^^^^^ did you mean `'longlabel1`?

error: aborting due to 3 previous errors