Auto merge of #50968 - kennytm:rollup, r=kennytm

Rollup of 15 pull requests

Successful merges:

 - #50846 (Add E0665)
 - #50849 (CheckLoopVisitor: also visit closure arguments)
 - #50863 (Make `[T]::len` and `str::len` const fn)
 - #50875 (rustdoc: use "short form" doc(cfg) printing even when combined with other conditionals)
 - #50913 (Fix typo in cell.rs)
 - #50914 (Issue #50636: Improve error diagnostic with missing commas after struct fields.)
 - #50931 (Inline `try_get`.)
 - #50932 (Optimize seen Predicate filtering.)
 - #50945 (Stabilize feature from_ref)
 - #50946 (rustc: Fix procedural macros generating lifetime tokens)
 - #50947 (rustdoc: set tab width in rust source blocks)
 - #50952 (Add the 2018 edition of the book to doc.rust-lang.org)
 - #50958 (Micro-optimization on PR#50697)
 - #50961 (Fix FileCheck finding with MSVC)
 - #50963 (Right-size the `VecDeque` in `coerce_unsized`.)

Failed merges:
This commit is contained in:
bors 2018-05-22 16:38:12 +00:00
commit e0635188ed
29 changed files with 349 additions and 67 deletions

View File

@ -272,6 +272,12 @@ impl Step for TheBook {
name: INTERNER.intern_string(format!("{}/second-edition", name)),
});
// build book 2018 edition
builder.ensure(Rustbook {
target,
name: INTERNER.intern_string(format!("{}/2018-edition", name)),
});
// build the version info page and CSS
builder.ensure(Standalone {
compiler,

View File

@ -592,12 +592,20 @@ impl Build {
Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target))
} else {
let base = self.llvm_out(self.config.build).join("build");
let exe = exe("FileCheck", &*target);
if !self.config.ninja && self.config.build.contains("msvc") {
base.join("Release/bin").join(exe)
let base = if !self.config.ninja && self.config.build.contains("msvc") {
if self.config.llvm_optimize {
if self.config.llvm_release_debuginfo {
base.join("RelWithDebInfo")
} else {
base.join("Release")
}
} else {
base.join("Debug")
}
} else {
base.join("bin").join(exe)
}
base
};
base.join("bin").join(exe("FileCheck", &*target))
}
}

@ -1 +1 @@
Subproject commit f51127530d46b9acbf4747c859da185e771cfcf3
Subproject commit 36d65d00164d1750f6fa7f8b0f52dabc3fea500b

View File

@ -119,8 +119,8 @@ pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
pub use core::slice::{RSplit, RSplitMut};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::slice::{from_raw_parts, from_raw_parts_mut};
#[unstable(feature = "from_ref", issue = "45703")]
pub use core::slice::{from_ref, from_ref_mut};
#[stable(feature = "from_ref", since = "1.28.0")]
pub use core::slice::{from_ref, from_mut};
#[unstable(feature = "slice_get_slice", issue = "35729")]
pub use core::slice::SliceIndex;
#[unstable(feature = "exact_chunks", issue = "47115")]

View File

@ -1257,7 +1257,7 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> {
/// To assist with proper design, the following scenarios are explicitly declared legal
/// for single-threaded code:
///
/// 1. A `&T` reference can be released to safe code and there it can co-exit with other `&T`
/// 1. A `&T` reference can be released to safe code and there it can co-exist with other `&T`
/// references, but not with a `&mut T`
///
/// 2. A `&mut T` reference may be released to safe code provided neither other `&mut T` nor `&T`

View File

@ -119,6 +119,9 @@
#![feature(powerpc_target_feature)]
#![feature(mips_target_feature)]
#![feature(aarch64_target_feature)]
#![feature(const_slice_len)]
#![feature(const_str_as_bytes)]
#![feature(const_str_len)]
#[prelude_import]
#[allow(unused)]

View File

@ -59,9 +59,16 @@ mod rotate;
mod sort;
#[repr(C)]
struct Repr<T> {
pub data: *const T,
pub len: usize,
union Repr<'a, T: 'a> {
rust: &'a [T],
rust_mut: &'a mut [T],
raw: FatPtr<T>,
}
#[repr(C)]
struct FatPtr<T> {
data: *const T,
len: usize,
}
//
@ -119,9 +126,10 @@ impl<T> [T] {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn len(&self) -> usize {
#[rustc_const_unstable(feature = "const_slice_len")]
pub const fn len(&self) -> usize {
unsafe {
mem::transmute::<&[T], Repr<T>>(self).len
Repr { rust: self }.raw.len
}
}
@ -135,7 +143,8 @@ impl<T> [T] {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_empty(&self) -> bool {
#[rustc_const_unstable(feature = "const_slice_len")]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
@ -418,7 +427,8 @@ impl<T> [T] {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn as_ptr(&self) -> *const T {
#[rustc_const_unstable(feature = "const_slice_as_ptr")]
pub const fn as_ptr(&self) -> *const T {
self as *const [T] as *const T
}
@ -3856,8 +3866,8 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] {
mem::transmute(Repr { data: p, len: len })
pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
Repr { raw: FatPtr { data, len } }.rust
}
/// Performs the same functionality as `from_raw_parts`, except that a mutable
@ -3869,12 +3879,12 @@ pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] {
/// `from_raw_parts`.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] {
mem::transmute(Repr { data: p, len: len })
pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
Repr { raw: FatPtr { data, len} }.rust_mut
}
/// Converts a reference to T into a slice of length 1 (without copying).
#[unstable(feature = "from_ref", issue = "45703")]
#[stable(feature = "from_ref", since = "1.28.0")]
pub fn from_ref<T>(s: &T) -> &[T] {
unsafe {
from_raw_parts(s, 1)
@ -3882,8 +3892,8 @@ pub fn from_ref<T>(s: &T) -> &[T] {
}
/// Converts a reference to T into a slice of length 1 (without copying).
#[unstable(feature = "from_ref", issue = "45703")]
pub fn from_ref_mut<T>(s: &mut T) -> &mut [T] {
#[stable(feature = "from_ref", since = "1.28.0")]
pub fn from_mut<T>(s: &mut T) -> &mut [T] {
unsafe {
from_raw_parts_mut(s, 1)
}

View File

@ -2166,7 +2166,8 @@ impl str {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn len(&self) -> usize {
#[rustc_const_unstable(feature = "const_str_len")]
pub const fn len(&self) -> usize {
self.as_bytes().len()
}
@ -2185,7 +2186,8 @@ impl str {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_empty(&self) -> bool {
#[rustc_const_unstable(feature = "const_str_len")]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
@ -2242,8 +2244,15 @@ impl str {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline(always)]
pub fn as_bytes(&self) -> &[u8] {
unsafe { &*(self as *const str as *const [u8]) }
#[rustc_const_unstable(feature="const_str_as_bytes")]
pub const fn as_bytes(&self) -> &[u8] {
unsafe {
union Slices<'a> {
str: &'a str,
slice: &'a [u8],
}
Slices { str: self }.slice
}
}
/// Converts a mutable string slice to a mutable byte slice. To convert the
@ -2303,7 +2312,8 @@ impl str {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn as_ptr(&self) -> *const u8 {
#[rustc_const_unstable(feature = "const_str_as_ptr")]
pub const fn as_ptr(&self) -> *const u8 {
self as *const str as *const u8
}

View File

@ -948,7 +948,7 @@ impl<'tcx> TerminatorKind<'tcx> {
Drop { target: ref mut t, unwind: Some(ref mut u), .. } |
Assert { target: ref mut t, cleanup: Some(ref mut u), .. } |
FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => {
Some(t).into_iter().chain(slice::from_ref_mut(u))
Some(t).into_iter().chain(slice::from_mut(u))
}
SwitchInt { ref mut targets, .. } => {
None.into_iter().chain(&mut targets[..])

View File

@ -3356,13 +3356,28 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
predicate: predicate.value
}))
}).collect();
// We are performing deduplication here to avoid exponential blowups
// (#38528) from happening, but the real cause of the duplication is
// unknown. What we know is that the deduplication avoids exponential
// amount of predicates being propogated when processing deeply nested
// amount of predicates being propagated when processing deeply nested
// types.
let mut seen = FxHashSet();
predicates.retain(|i| seen.insert(i.clone()));
//
// This code is hot enough that it's worth avoiding the allocation
// required for the FxHashSet when possible. Special-casing lengths 0,
// 1 and 2 covers roughly 75--80% of the cases.
if predicates.len() <= 1 {
// No possibility of duplicates.
} else if predicates.len() == 2 {
// Only two elements. Drop the second if they are equal.
if predicates[0] == predicates[1] {
predicates.truncate(1);
}
} else {
// Three or more elements. Use a general deduplication process.
let mut seen = FxHashSet();
predicates.retain(|i| seen.insert(i.clone()));
}
self.infcx().plug_leaks(skol_map, snapshot, predicates)
}
}

View File

@ -105,6 +105,10 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
/// start executing the query, or it returns with the result of the query.
/// If the query is executing elsewhere, this will wait for it.
/// If the query panicked, this will silently panic.
///
/// This function is inlined because that results in a noticeable speedup
/// for some compile-time benchmarks.
#[inline(always)]
pub(super) fn try_get(
tcx: TyCtxt<'a, 'tcx, '_>,
span: Span,

View File

@ -1853,6 +1853,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
for index in ii {
if flow_state.ever_inits.contains(index) {
self.used_mut.insert(*local);
break;
}
}
}

View File

@ -82,7 +82,8 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
hir::ExprLoop(ref b, _, source) => {
self.with_context(Loop(LoopKind::Loop(source)), |v| v.visit_block(&b));
}
hir::ExprClosure(.., b, _, _) => {
hir::ExprClosure(_, ref function_decl, b, _, _) => {
self.visit_fn_decl(&function_decl);
self.with_context(Closure, |v| v.visit_nested_body(b));
}
hir::ExprBlock(ref b, Some(_label)) => {

View File

@ -537,8 +537,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
let mut selcx = traits::SelectionContext::new(self);
// Use a FIFO queue for this custom fulfillment procedure.
let mut queue = VecDeque::new();
// Use a FIFO queue for this custom fulfillment procedure. (The maximum
// length is almost always 1.)
let mut queue = VecDeque::with_capacity(1);
// Create an obligation for `Source: CoerceUnsized<Target>`.
let cause = ObligationCause::misc(self.cause.span, self.body_id);

View File

@ -138,7 +138,7 @@ impl Cfg {
/// Renders the configuration for human display, as a short HTML description.
pub(crate) fn render_short_html(&self) -> String {
let mut msg = ShortHtml(self).to_string();
let mut msg = Html(self, true).to_string();
if self.should_capitalize_first_letter() {
if let Some(i) = msg.find(|c: char| c.is_ascii_alphanumeric()) {
msg[i .. i+1].make_ascii_uppercase();
@ -155,7 +155,7 @@ impl Cfg {
"on"
};
let mut msg = format!("This is supported {} <strong>{}</strong>", on, Html(self));
let mut msg = format!("This is supported {} <strong>{}</strong>", on, Html(self, false));
if self.should_append_only_to_description() {
msg.push_str(" only");
}
@ -265,7 +265,9 @@ impl ops::BitOr for Cfg {
}
}
struct Html<'a>(&'a Cfg);
/// Pretty-print wrapper for a `Cfg`. Also indicates whether the "short-form" rendering should be
/// used.
struct Html<'a>(&'a Cfg, bool);
fn write_with_opt_paren<T: fmt::Display>(
fmt: &mut fmt::Formatter,
@ -295,12 +297,12 @@ impl<'a> fmt::Display for Html<'a> {
};
for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
fmt.write_str(if i == 0 { "neither " } else { separator })?;
write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg))?;
write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg, self.1))?;
}
Ok(())
}
ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Html(simple)),
ref c => write!(fmt, "not ({})", Html(c)),
ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Html(simple, self.1)),
ref c => write!(fmt, "not ({})", Html(c, self.1)),
},
Cfg::Any(ref sub_cfgs) => {
@ -313,7 +315,7 @@ impl<'a> fmt::Display for Html<'a> {
if i != 0 {
fmt.write_str(separator)?;
}
write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg))?;
write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg, self.1))?;
}
Ok(())
},
@ -323,7 +325,7 @@ impl<'a> fmt::Display for Html<'a> {
if i != 0 {
fmt.write_str(" and ")?;
}
write_with_opt_paren(fmt, !sub_cfg.is_simple(), Html(sub_cfg))?;
write_with_opt_paren(fmt, !sub_cfg.is_simple(), Html(sub_cfg, self.1))?;
}
Ok(())
},
@ -390,7 +392,11 @@ impl<'a> fmt::Display for Html<'a> {
("target_endian", Some(endian)) => return write!(fmt, "{}-endian", endian),
("target_pointer_width", Some(bits)) => return write!(fmt, "{}-bit", bits),
("target_feature", Some(feat)) =>
return write!(fmt, "target feature <code>{}</code>", feat),
if self.1 {
return write!(fmt, "<code>{}</code>", feat);
} else {
return write!(fmt, "target feature <code>{}</code>", feat);
},
_ => "",
};
if !human_readable.is_empty() {
@ -405,19 +411,6 @@ impl<'a> fmt::Display for Html<'a> {
}
}
struct ShortHtml<'a>(&'a Cfg);
impl<'a> fmt::Display for ShortHtml<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self.0 {
Cfg::Cfg(ref name, Some(ref vendor)) if name == &"target_feature" => {
write!(fmt, "<code>{}</code>", vendor)
},
ref cfg => write!(fmt, "{}", Html(cfg)),
}
}
}
#[cfg(test)]
mod test {
use super::Cfg;
@ -740,6 +733,13 @@ mod test {
name_value_cfg("target_feature", "sse2").render_short_html(),
"<code>sse2</code>"
);
assert_eq!(
(
name_value_cfg("target_arch", "x86_64") &
name_value_cfg("target_feature", "sse2")
).render_short_html(),
"x86-64 and <code>sse2</code>"
);
})
}
@ -818,6 +818,14 @@ mod test {
name_value_cfg("target_feature", "sse2").render_long_html(),
"This is supported with <strong>target feature <code>sse2</code></strong> only."
);
assert_eq!(
(
name_value_cfg("target_arch", "x86_64") &
name_value_cfg("target_feature", "sse2")
).render_long_html(),
"This is supported on <strong>x86-64 and target feature \
<code>sse2</code></strong> only."
);
})
}
}

View File

@ -1010,6 +1010,8 @@ span.since {
pre.rust {
position: relative;
tab-width: 4;
-moz-tab-width: 4;
}
.search-failed {

View File

@ -5807,9 +5807,18 @@ impl<'a> Parser<'a> {
return Err(err);
}
}
_ => return Err(self.span_fatal_help(self.span,
&format!("expected `,`, or `}}`, found `{}`", self.this_token_to_string()),
"struct fields should be separated by commas")),
_ => {
let sp = self.sess.codemap().next_point(self.prev_span);
let mut err = self.struct_span_err(sp, &format!("expected `,`, or `}}`, found `{}`",
self.this_token_to_string()));
if self.token.is_ident() {
// This is likely another field; emit the diagnostic and keep going
err.span_suggestion(sp, "try adding a comma", ",".into());
err.emit();
} else {
return Err(err)
}
}
}
Ok(a_var)
}

View File

@ -22,6 +22,7 @@ use serialize::{Decodable, Decoder, Encodable, Encoder};
use symbol::keywords;
use syntax::parse::parse_stream_from_source_str;
use syntax_pos::{self, Span, FileName};
use syntax_pos::symbol::{self, Symbol};
use tokenstream::{TokenStream, TokenTree};
use tokenstream;
@ -478,7 +479,13 @@ impl Token {
_ => return None,
},
SingleQuote => match joint {
Ident(ident, false) => Lifetime(ident),
Ident(ident, false) => {
let name = Symbol::intern(&format!("'{}", ident));
Lifetime(symbol::Ident {
name,
span: ident.span,
})
}
_ => return None,
},

View File

@ -76,8 +76,8 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructur
}
}
StaticEnum(..) => {
cx.span_err(trait_span,
"`Default` cannot be derived for enums, only structs");
span_err_if_not_stage0!(cx, trait_span, E0665,
"`Default` cannot be derived for enums, only structs");
// let compilation continue
cx.expr_usize(trait_span, 0)
}

View File

@ -19,6 +19,17 @@ use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::Span;
macro_rules! span_err_if_not_stage0 {
($cx:expr, $sp:expr, $code:ident, $text:tt) => {
#[cfg(not(stage0))] {
span_err!($cx, $sp, $code, $text)
}
#[cfg(stage0)] {
$cx.span_err($sp, $text)
}
}
}
macro path_local($x:ident) {
generic::ty::Path::new_local(stringify!($x))
}

View File

@ -82,7 +82,7 @@ A clobber was surrounded by braces in the `asm` macro.
Erroneous code example:
```compile_fail,E0663
```compile_fail,E0664
asm!("mov $$0x200, %eax"
:
:
@ -94,4 +94,38 @@ Considering that this would be a long explanation, we instead recommend you to
take a look at the unstable book:
https://doc.rust-lang.org/unstable-book/language-features/asm.html
"##,
E0665: r##"
The `Default` trait was derived on an enum.
Erroneous code example:
```compile_fail,E0665
#[derive(Default)]
enum Food {
Sweet,
Salty,
}
```
The `Default` cannot be derived on an enum for the simple reason that the
compiler doesn't know which value to pick by default whereas it can for a
struct as long as all its fields implement the `Default` trait as well.
If you still want to implement `Default` on your enum, you'll have to do it "by
hand":
```
enum Food {
Sweet,
Salty,
}
impl Default for Food {
fn default() -> Food {
Food::Sweet
}
}
```
"##,
}

View File

@ -31,8 +31,12 @@ extern crate rustc_target;
mod diagnostics;
mod assert;
#[macro_use]
// for custom_derive
pub mod deriving;
mod asm;
mod assert;
mod cfg;
mod compile_error;
mod concat;
@ -46,8 +50,6 @@ mod trace_macros;
pub mod proc_macro_registrar;
// for custom_derive
pub mod deriving;
pub mod proc_macro_impl;

View File

@ -0,0 +1,35 @@
// 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.
// no-prefer-dynamic
#![crate_type = "proc-macro"]
#![feature(proc_macro)]
extern crate proc_macro;
use proc_macro::*;
#[proc_macro]
pub fn bar(_input: TokenStream) -> TokenStream {
let mut ret = Vec::<TokenTree>::new();
ret.push(Ident::new("static", Span::call_site()).into());
ret.push(Ident::new("FOO", Span::call_site()).into());
ret.push(Punct::new(':', Spacing::Alone).into());
ret.push(Punct::new('&', Spacing::Alone).into());
ret.push(Punct::new('\'', Spacing::Joint).into());
ret.push(Ident::new("static", Span::call_site()).into());
ret.push(Ident::new("i32", Span::call_site()).into());
ret.push(Punct::new('=', Spacing::Alone).into());
ret.push(Punct::new('&', Spacing::Alone).into());
ret.push(Literal::i32_unsuffixed(1).into());
ret.push(Punct::new(';', Spacing::Alone).into());
ret.into_iter().collect()
}

View File

@ -0,0 +1,22 @@
// 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.
// aux-build:gen-lifetime-token.rs
#![feature(proc_macro)]
extern crate gen_lifetime_token as bar;
bar::bar!();
fn main() {
let x: &'static i32 = FOO;
assert_eq!(*x, 1);
}

20
src/test/ui/E0665.rs Normal file
View File

@ -0,0 +1,20 @@
// 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-stage1
#[derive(Default)] //~ ERROR E0665
enum Food {
Sweet,
Salty,
}
fn main() {
}

9
src/test/ui/E0665.stderr Normal file
View File

@ -0,0 +1,9 @@
error[E0665]: `Default` cannot be derived for enums, only structs
--> $DIR/E0665.rs:13:10
|
LL | #[derive(Default)] //~ ERROR E0665
| ^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0665`.

View File

@ -0,0 +1,33 @@
// 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.
// run-pass
#![feature(const_str_len, const_str_as_bytes)]
const S: &str = "foo";
pub const B: &[u8] = S.as_bytes();
pub fn foo() -> [u8; S.len()] {
let mut buf = [0; S.len()];
for (i, &c) in S.as_bytes().iter().enumerate() {
buf[i] = c;
}
buf
}
fn main() {
assert_eq!(&foo()[..], b"foo");
assert_eq!(foo().len(), S.len());
const LEN: usize = S.len();
assert_eq!(LEN, S.len());
assert_eq!(B, foo());
assert_eq!(B, b"foo");
}

View File

@ -0,0 +1,23 @@
// 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.
// compile-flags: -Z parse-only
// Issue #50636
struct S {
foo: u32 //~ expected `,`, or `}`, found `bar`
// ~^ HELP try adding a comma: ','
bar: u32
}
fn main() {
let s = S { foo: 5, bar: 6 };
}

View File

@ -0,0 +1,8 @@
error: expected `,`, or `}`, found `bar`
--> $DIR/struct-missing-comma.rs:16:13
|
LL | foo: u32 //~ expected `,`, or `}`, found `bar`
| ^ help: try adding a comma: `,`
error: aborting due to previous error