diff --git a/src/librustc_error_codes/error_codes/E0744.md b/src/librustc_error_codes/error_codes/E0744.md index b299102fd6934..602fbc50a7153 100644 --- a/src/librustc_error_codes/error_codes/E0744.md +++ b/src/librustc_error_codes/error_codes/E0744.md @@ -3,7 +3,7 @@ Control-flow expressions are not allowed inside a const context. At the moment, `if` and `match`, as well as the looping constructs `for`, `while`, and `loop`, are forbidden inside a `const`, `static`, or `const fn`. -```compile_fail,E0744 +```compile_fail,E0658 const _: i32 = { let mut x = 0; loop { diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 98213b890f953..7985f944b89ac 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -52,6 +52,17 @@ macro_rules! declare_features { pub fn walk_feature_fields(&self, mut f: impl FnMut(&str, bool)) { $(f(stringify!($feature), self.$feature);)+ } + + /// Is the given feature enabled? + /// + /// Panics if the symbol doesn't correspond to a declared feature. + pub fn enabled(&self, feature: Symbol) -> bool { + match feature { + $( sym::$feature => self.$feature, )* + + _ => panic!("`{}` was not listed in `declare_features`", feature), + } + } } }; } @@ -522,6 +533,9 @@ declare_features! ( /// Allows using `&mut` in constant functions. (active, const_mut_refs, "1.41.0", Some(57349), None), + /// Allows the use of `loop` and `while` in constants. + (active, const_loop, "1.41.0", Some(52000), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 10b00d35d9bca..798aa3fec1a70 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -295,6 +295,10 @@ pub struct MissingDoc { impl_lint_pass!(MissingDoc => [MISSING_DOCS]); fn has_doc(attr: &ast::Attribute) -> bool { + if attr.is_doc_comment() { + return true; + } + if !attr.check_name(sym::doc) { return false; } @@ -751,7 +755,7 @@ impl UnusedDocComment { let span = sugared_span.take().unwrap_or_else(|| attr.span); - if attr.check_name(sym::doc) { + if attr.is_doc_comment() || attr.check_name(sym::doc) { let mut err = cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, "unused doc comment"); err.span_label( diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index e6f39cca6dc3a..39bdb7aa92e10 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -296,6 +296,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { fn check_attribute(&mut self, cx: &LateContext<'_, '_>, attr: &ast::Attribute) { debug!("checking attribute: {:?}", attr); + if attr.is_doc_comment() { + return; + } + let attr_info = attr.ident().and_then(|ident| self.builtin_attributes.get(&ident.name)); if let Some(&&(name, ty, ..)) = attr_info { diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index 393ae9442a17e..3df60993d9ad5 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -170,6 +170,10 @@ impl NonConstOp for LiveDrop { #[derive(Debug)] pub struct Loop; impl NonConstOp for Loop { + fn feature_gate(tcx: TyCtxt<'_>) -> Option { + Some(tcx.features().const_loop) + } + fn emit_error(&self, item: &Item<'_, '_>, span: Span) { // This should be caught by the HIR const-checker. item.tcx.sess.delay_span_bug( diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 1c95155e7ff1c..e2530795749a9 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -390,8 +390,12 @@ fn check_terminator( cleanup: _, } => check_operand(tcx, cond, span, def_id, body), + | TerminatorKind::FalseUnwind { .. } + if feature_allowed(tcx, def_id, sym::const_loop) + => Ok(()), + TerminatorKind::FalseUnwind { .. } => { Err((span, "loops are not allowed in const fn".into())) - }, + } } } diff --git a/src/librustc_parse/validate_attr.rs b/src/librustc_parse/validate_attr.rs index 94d3fe7b55167..ac59592bdfed4 100644 --- a/src/librustc_parse/validate_attr.rs +++ b/src/librustc_parse/validate_attr.rs @@ -4,14 +4,17 @@ use crate::parse_in; use rustc_errors::{PResult, Applicability}; use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP}; -use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MacDelimiter, MetaItem, MetaItemKind}; -use syntax::attr::mk_name_value_item_str; +use syntax::ast::{self, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind}; use syntax::early_buffered_lints::ILL_FORMED_ATTRIBUTE_INPUT; use syntax::tokenstream::DelimSpan; use syntax::sess::ParseSess; use syntax_pos::{Symbol, sym}; pub fn check_meta(sess: &ParseSess, attr: &Attribute) { + if attr.is_doc_comment() { + return; + } + let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a); @@ -28,25 +31,21 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) { } pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> { - Ok(match attr.kind { - AttrKind::Normal(ref item) => MetaItem { - span: attr.span, - path: item.path.clone(), - kind: match &attr.get_normal_item().args { - MacArgs::Empty => MetaItemKind::Word, - MacArgs::Eq(_, t) => { - let v = parse_in(sess, t.clone(), "name value", |p| p.parse_unsuffixed_lit())?; - MetaItemKind::NameValue(v) - } - MacArgs::Delimited(dspan, delim, t) => { - check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters"); - let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?; - MetaItemKind::List(nmis) - } + let item = attr.get_normal_item(); + Ok(MetaItem { + span: attr.span, + path: item.path.clone(), + kind: match &item.args { + MacArgs::Empty => MetaItemKind::Word, + MacArgs::Eq(_, t) => { + let v = parse_in(sess, t.clone(), "name value", |p| p.parse_unsuffixed_lit())?; + MetaItemKind::NameValue(v) + } + MacArgs::Delimited(dspan, delim, t) => { + check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters"); + let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?; + MetaItemKind::List(nmis) } - }, - AttrKind::DocComment(comment) => { - mk_name_value_item_str(Ident::new(sym::doc, attr.span), comment, attr.span) } }) } diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs index 63c6e60de7954..725a742382e02 100644 --- a/src/librustc_passes/check_const.rs +++ b/src/librustc_passes/check_const.rs @@ -13,11 +13,11 @@ use rustc::hir::map::Map; use rustc::hir; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; -use rustc_feature::Features; +use rustc::session::config::nightly_options; use syntax::ast::Mutability; use syntax::feature_gate::feature_err; use syntax::span_err; -use syntax_pos::{sym, Span}; +use syntax_pos::{sym, Span, Symbol}; use rustc_error_codes::*; use std::fmt; @@ -37,18 +37,31 @@ impl NonConstExpr { } } - /// Returns `true` if all feature gates required to enable this expression are turned on, or - /// `None` if there is no feature gate corresponding to this expression. - fn is_feature_gate_enabled(self, features: &Features) -> Option { + fn required_feature_gates(self) -> Option<&'static [Symbol]> { use hir::MatchSource::*; - match self { + use hir::LoopSource::*; + + let gates: &[_] = match self { | Self::Match(Normal) | Self::Match(IfDesugar { .. }) | Self::Match(IfLetDesugar { .. }) - => Some(features.const_if_match), + => &[sym::const_if_match], - _ => None, - } + | Self::Loop(Loop) + => &[sym::const_loop], + + | Self::Loop(While) + | Self::Loop(WhileLet) + | Self::Match(WhileDesugar) + | Self::Match(WhileLetDesugar) + => &[sym::const_loop, sym::const_if_match], + + // A `for` loop's desugaring contains a call to `IntoIterator::into_iter`, + // so they are not yet allowed with `#![feature(const_loop)]`. + _ => return None, + }; + + Some(gates) } } @@ -120,11 +133,15 @@ impl<'tcx> CheckConstVisitor<'tcx> { /// Emits an error when an unsupported expression is found in a const context. fn const_check_violated(&self, expr: NonConstExpr, span: Span) { - match expr.is_feature_gate_enabled(self.tcx.features()) { + let features = self.tcx.features(); + let required_gates = expr.required_feature_gates(); + match required_gates { // Don't emit an error if the user has enabled the requisite feature gates. - Some(true) => return, + Some(gates) if gates.iter().all(|&g| features.enabled(g)) => return, - // Users of `-Zunleash-the-miri-inside-of-you` must use feature gates when possible. + // `-Zunleash-the-miri-inside-of-you` only works for expressions that don't have a + // corresponding feature gate. This encourages nightly users to use feature gates when + // possible. None if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => { self.tcx.sess.span_warn(span, "skipping const checks"); return; @@ -135,15 +152,47 @@ impl<'tcx> CheckConstVisitor<'tcx> { let const_kind = self.const_kind .expect("`const_check_violated` may only be called inside a const context"); - let msg = format!("`{}` is not allowed in a `{}`", expr.name(), const_kind); - match expr { - | NonConstExpr::Match(hir::MatchSource::Normal) - | NonConstExpr::Match(hir::MatchSource::IfDesugar { .. }) - | NonConstExpr::Match(hir::MatchSource::IfLetDesugar { .. }) - => feature_err(&self.tcx.sess.parse_sess, sym::const_if_match, span, &msg).emit(), - _ => span_err!(self.tcx.sess, span, E0744, "{}", msg), + let required_gates = required_gates.unwrap_or(&[]); + let missing_gates: Vec<_> = required_gates + .iter() + .copied() + .filter(|&g| !features.enabled(g)) + .collect(); + + match missing_gates.as_slice() { + &[] => span_err!(self.tcx.sess, span, E0744, "{}", msg), + + // If the user enabled `#![feature(const_loop)]` but not `#![feature(const_if_match)]`, + // explain why their `while` loop is being rejected. + &[gate @ sym::const_if_match] if required_gates.contains(&sym::const_loop) => { + feature_err(&self.tcx.sess.parse_sess, gate, span, &msg) + .note("`#![feature(const_loop)]` alone is not sufficient, \ + since this loop expression contains an implicit conditional") + .emit(); + } + + &[missing_primary, ref missing_secondary @ ..] => { + let mut err = feature_err(&self.tcx.sess.parse_sess, missing_primary, span, &msg); + + // If multiple feature gates would be required to enable this expression, include + // them as help messages. Don't emit a separate error for each missing feature gate. + // + // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This + // is a pretty narrow case, however. + if nightly_options::is_nightly_build() { + for gate in missing_secondary { + let note = format!( + "add `#![feature({})]` to the crate attributes to enable", + gate, + ); + err.help(¬e); + } + } + + err.emit(); + } } } diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 81f06a14d95f5..f01867f32c67b 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -8,6 +8,7 @@ #![feature(in_band_lifetimes)] #![feature(nll)] +#![feature(slice_patterns)] #![recursion_limit="256"] diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 424d57c8fe7fa..bfc870e0513d6 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -883,15 +883,15 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { let mut result = String::new(); for attr in attrs { - if attr.check_name(sym::doc) { - if let Some(val) = attr.value_str() { - if attr.is_doc_comment() { - result.push_str(&strip_doc_comment_decoration(&val.as_str())); - } else { - result.push_str(&val.as_str()); - } - result.push('\n'); - } else if let Some(meta_list) = attr.meta_item_list() { + if let Some(val) = attr.doc_str() { + if attr.is_doc_comment() { + result.push_str(&strip_doc_comment_decoration(&val.as_str())); + } else { + result.push_str(&val.as_str()); + } + result.push('\n'); + } else if attr.check_name(sym::doc) { + if let Some(meta_list) = attr.meta_item_list() { meta_list.into_iter() .filter(|it| it.check_name(sym::include)) .filter_map(|it| it.meta_item_list().map(|l| l.to_owned())) diff --git a/src/librustc_target/spec/i686_unknown_dragonfly.rs b/src/librustc_target/spec/i686_unknown_dragonfly.rs deleted file mode 100644 index 20315e7145c73..0000000000000 --- a/src/librustc_target/spec/i686_unknown_dragonfly.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; - -pub fn target() -> TargetResult { - let mut base = super::dragonfly_base::opts(); - base.cpu = "pentium4".to_string(); - base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); - base.stack_probes = true; - - Ok(Target { - llvm_target: "i686-unknown-dragonfly".to_string(), - target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), - target_c_int_width: "32".to_string(), - data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(), - arch: "x86".to_string(), - target_os: "dragonfly".to_string(), - target_env: String::new(), - target_vendor: "unknown".to_string(), - linker_flavor: LinkerFlavor::Gcc, - options: base, - }) -} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 693cf75e8fd64..34b321d38f0f6 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -398,7 +398,6 @@ supported_targets! { ("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd), ("x86_64-unknown-freebsd", x86_64_unknown_freebsd), - ("i686-unknown-dragonfly", i686_unknown_dragonfly), ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly), ("aarch64-unknown-openbsd", aarch64_unknown_openbsd), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index bd3f2a3690a27..1b20d20e65b68 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -17,9 +17,9 @@ use rustc::ty::layout::VariantIdx; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_index::vec::IndexVec; use rustc_target::spec::abi::Abi; -use syntax::ast::{self, Attribute, AttrStyle, AttrKind, Ident}; +use syntax::ast::{self, AttrStyle, Ident}; use syntax::attr; -use syntax::util::comments; +use syntax::util::comments::strip_doc_comment_decoration; use syntax::source_map::DUMMY_SP; use syntax_pos::hygiene::MacroKind; use syntax_pos::symbol::{Symbol, sym}; @@ -507,51 +507,26 @@ impl Attributes { let mut cfg = Cfg::True; let mut doc_line = 0; - /// If `attr` is a doc comment, strips the leading and (if present) - /// trailing comments symbols, e.g. `///`, `/**`, and `*/`. Otherwise, - /// returns `attr` unchanged. - pub fn with_doc_comment_markers_stripped( - attr: &Attribute, - f: impl FnOnce(&Attribute) -> T, - ) -> T { - match attr.kind { - AttrKind::Normal(_) => { - f(attr) - } - AttrKind::DocComment(comment) => { - let comment = - Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str())); - f(&Attribute { - kind: AttrKind::DocComment(comment), - id: attr.id, - style: attr.style, - span: attr.span, - }) - } - } - } - let other_attrs = attrs.iter().filter_map(|attr| { - with_doc_comment_markers_stripped(attr, |attr| { - if attr.check_name(sym::doc) { - if let Some(mi) = attr.meta() { - if let Some(value) = mi.value_str() { - // Extracted #[doc = "..."] - let value = value.to_string(); - let line = doc_line; - doc_line += value.lines().count(); + if let Some(value) = attr.doc_str() { + let (value, mk_fragment): (_, fn(_, _, _) -> _) = if attr.is_doc_comment() { + (strip_doc_comment_decoration(&value.as_str()), DocFragment::SugaredDoc) + } else { + (value.to_string(), DocFragment::RawDoc) + }; - if attr.is_doc_comment() { - doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value)); - } else { - doc_strings.push(DocFragment::RawDoc(line, attr.span, value)); - } + let line = doc_line; + doc_line += value.lines().count(); + doc_strings.push(mk_fragment(line, attr.span, value)); - if sp.is_none() { - sp = Some(attr.span); - } - return None; - } else if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { + if sp.is_none() { + sp = Some(attr.span); + } + None + } else { + if attr.check_name(sym::doc) { + if let Some(mi) = attr.meta() { + if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { // Extracted #[doc(cfg(...))] match Cfg::parse(cfg_mi) { Ok(new_cfg) => cfg &= new_cfg, @@ -570,7 +545,7 @@ impl Attributes { } } Some(attr.clone()) - }) + } }).collect(); // treat #[target_feature(enable = "feat")] attributes as if they were @@ -589,7 +564,7 @@ impl Attributes { } let inner_docs = attrs.iter() - .filter(|a| a.check_name(sym::doc)) + .filter(|a| a.doc_str().is_some()) .next() .map_or(true, |a| a.style == AttrStyle::Inner); diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index a109e38e1e3bc..01e57ec0ab941 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -936,7 +936,7 @@ impl OpenOptions { /// ```no_run /// use std::fs::OpenOptions; /// - /// let file = OpenOptions::new().open("foo.txt"); + /// let file = OpenOptions::new().read(true).open("foo.txt"); /// ``` /// /// [`ErrorKind`]: ../io/enum.ErrorKind.html diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index fad092e35c3e6..04bfdf67e12d2 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -364,7 +364,7 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let (dir, file) = open_parent(path, wasi::RIGHTS_PATH_OPEN)?; + let (dir, file) = open_parent(path)?; open_at(&dir, &file, opts) } @@ -452,7 +452,7 @@ impl DirBuilder { } pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_CREATE_DIRECTORY)?; + let (dir, file) = open_parent(p)?; dir.create_directory(osstr2str(file.as_ref())?) } } @@ -478,13 +478,13 @@ pub fn readdir(p: &Path) -> io::Result { } pub fn unlink(p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_UNLINK_FILE)?; + let (dir, file) = open_parent(p)?; dir.unlink_file(osstr2str(file.as_ref())?) } pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let (old, old_file) = open_parent(old, wasi::RIGHTS_PATH_RENAME_SOURCE)?; - let (new, new_file) = open_parent(new, wasi::RIGHTS_PATH_RENAME_TARGET)?; + let (old, old_file) = open_parent(old)?; + let (new, new_file) = open_parent(new)?; old.rename(osstr2str(old_file.as_ref())?, &new, osstr2str(new_file.as_ref())?) } @@ -495,12 +495,12 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { } pub fn rmdir(p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_REMOVE_DIRECTORY)?; + let (dir, file) = open_parent(p)?; dir.remove_directory(osstr2str(file.as_ref())?) } pub fn readlink(p: &Path) -> io::Result { - let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_READLINK)?; + let (dir, file) = open_parent(p)?; read_link(&dir, &file) } @@ -536,13 +536,13 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result { } pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let (dst, dst_file) = open_parent(dst, wasi::RIGHTS_PATH_SYMLINK)?; + let (dst, dst_file) = open_parent(dst)?; dst.symlink(osstr2str(src.as_ref())?, osstr2str(dst_file.as_ref())?) } pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let (src, src_file) = open_parent(src, wasi::RIGHTS_PATH_LINK_SOURCE)?; - let (dst, dst_file) = open_parent(dst, wasi::RIGHTS_PATH_LINK_TARGET)?; + let (src, src_file) = open_parent(src)?; + let (dst, dst_file) = open_parent(dst)?; src.link( wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, osstr2str(src_file.as_ref())?, @@ -552,12 +552,12 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { } pub fn stat(p: &Path) -> io::Result { - let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_FILESTAT_GET)?; + let (dir, file) = open_parent(p)?; metadata_at(&dir, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, &file) } pub fn lstat(p: &Path) -> io::Result { - let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_FILESTAT_GET)?; + let (dir, file) = open_parent(p)?; metadata_at(&dir, 0, &file) } @@ -611,11 +611,11 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result { /// /// Note that this can fail if `p` doesn't look like it can be opened relative /// to any preopened file descriptor. -fn open_parent(p: &Path, rights: wasi::Rights) -> io::Result<(ManuallyDrop, PathBuf)> { +fn open_parent(p: &Path) -> io::Result<(ManuallyDrop, PathBuf)> { let p = CString::new(p.as_os_str().as_bytes())?; unsafe { let mut ret = ptr::null(); - let fd = libc::__wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret); + let fd = __wasilibc_find_relpath(p.as_ptr(), &mut ret); if fd == -1 { let msg = format!( "failed to find a preopened file descriptor \ @@ -635,6 +635,13 @@ fn open_parent(p: &Path, rights: wasi::Rights) -> io::Result<(ManuallyDrop libc::c_int; + } } pub fn osstr2str(f: &OsStr) -> io::Result<&str> { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 92ba071a03d68..7d58d8d614380 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2362,10 +2362,6 @@ pub enum AttrKind { /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal` /// variant (which is much less compact and thus more expensive). - /// - /// Note: `self.has_name(sym::doc)` and `self.check_name(sym::doc)` succeed - /// for this variant, but this may change in the future. - /// ``` DocComment(Symbol), } diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index a37b27f67bcbd..2f81005a3f67e 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -16,6 +16,7 @@ use rustc_macros::HashStable_Generic; use rustc_error_codes::*; pub fn is_builtin_attr(attr: &Attribute) -> bool { + attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some() } diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 079a0f6fafa2c..29713dc8dd435 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -144,7 +144,7 @@ impl Attribute { pub fn has_name(&self, name: Symbol) -> bool { match self.kind { AttrKind::Normal(ref item) => item.path == name, - AttrKind::DocComment(_) => name == sym::doc, + AttrKind::DocComment(_) => false, } } @@ -168,7 +168,7 @@ impl Attribute { None } } - AttrKind::DocComment(_) => Some(Ident::new(sym::doc, self.span)), + AttrKind::DocComment(_) => None, } } pub fn name_or_empty(&self) -> Symbol { @@ -180,7 +180,7 @@ impl Attribute { AttrKind::Normal(ref item) => { item.meta(self.span).and_then(|meta| meta.value_str()) } - AttrKind::DocComment(comment) => Some(comment), + AttrKind::DocComment(..) => None, } } @@ -294,17 +294,26 @@ impl Attribute { } } + pub fn doc_str(&self) -> Option { + match self.kind { + AttrKind::DocComment(symbol) => Some(symbol), + AttrKind::Normal(ref item) if item.path == sym::doc => + item.meta(self.span).and_then(|meta| meta.value_str()), + _ => None, + } + } + pub fn get_normal_item(&self) -> &AttrItem { match self.kind { AttrKind::Normal(ref item) => item, - AttrKind::DocComment(_) => panic!("unexpected sugared doc"), + AttrKind::DocComment(_) => panic!("unexpected doc comment"), } } pub fn unwrap_normal_item(self) -> AttrItem { match self.kind { AttrKind::Normal(item) => item, - AttrKind::DocComment(_) => panic!("unexpected sugared doc"), + AttrKind::DocComment(_) => panic!("unexpected doc comment"), } } @@ -312,8 +321,7 @@ impl Attribute { pub fn meta(&self) -> Option { match self.kind { AttrKind::Normal(ref item) => item.meta(self.span), - AttrKind::DocComment(comment) => - Some(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span)), + AttrKind::DocComment(..) => None, } } } diff --git a/src/libsyntax_expand/parse/tests.rs b/src/libsyntax_expand/parse/tests.rs index 30e83c151e255..ba79a76c7fefa 100644 --- a/src/libsyntax_expand/parse/tests.rs +++ b/src/libsyntax_expand/parse/tests.rs @@ -2,13 +2,12 @@ use crate::tests::{matches_codepattern, string_to_stream, with_error_checking_pa use rustc_parse::new_parser_from_source_str; use syntax::ast::{self, Name, PatKind}; -use syntax::attr::first_attr_value_str_by_name; use syntax::sess::ParseSess; use syntax::token::{self, Token}; use syntax::print::pprust::item_to_string; use syntax::ptr::P; use syntax::source_map::FilePathMapping; -use syntax::symbol::{kw, sym}; +use syntax::symbol::{kw, sym, Symbol}; use syntax::tokenstream::{DelimSpan, TokenTree, TokenStream}; use syntax::visit; use syntax::with_default_globals; @@ -238,22 +237,21 @@ let mut fflags: c_int = wb(); let source = "/// doc comment\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_1, source, &sess) .unwrap().unwrap(); - let doc = first_attr_value_str_by_name(&item.attrs, sym::doc).unwrap(); + let doc = item.attrs.iter().filter_map(|at| at.doc_str()).next().unwrap(); assert_eq!(doc.as_str(), "/// doc comment"); let name_2 = FileName::Custom("crlf_source_2".to_string()); let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_2, source, &sess) .unwrap().unwrap(); - let docs = item.attrs.iter().filter(|a| a.has_name(sym::doc)) - .map(|a| a.value_str().unwrap().to_string()).collect::>(); - let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; + let docs = item.attrs.iter().filter_map(|at| at.doc_str()).collect::>(); + let b: &[_] = &[Symbol::intern("/// doc comment"), Symbol::intern("/// line 2")]; assert_eq!(&docs[..], b); let name_3 = FileName::Custom("clrf_source_3".to_string()); let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_3, source, &sess).unwrap().unwrap(); - let doc = first_attr_value_str_by_name(&item.attrs, sym::doc).unwrap(); + let doc = item.attrs.iter().filter_map(|at| at.doc_str()).next().unwrap(); assert_eq!(doc.as_str(), "/** doc comment\n * with CRLF */"); }); } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index c7e4182de6b73..ae34064c9267b 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -213,6 +213,7 @@ symbols! { const_indexing, const_in_array_repeat_expressions, const_let, + const_loop, const_mut_refs, const_panic, const_raw_ptr_deref, diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr index b4b40336aa926..4d13a80e4ccdd 100644 --- a/src/test/ui/closures/issue-52437.stderr +++ b/src/test/ui/closures/issue-52437.stderr @@ -4,11 +4,14 @@ error: invalid label name `'static` LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] | ^^^^^^^ -error[E0744]: `loop` is not allowed in a `const` +error[E0658]: `loop` is not allowed in a `const` --> $DIR/issue-52437.rs:2:13 | LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable error[E0282]: type annotations needed --> $DIR/issue-52437.rs:2:30 @@ -18,5 +21,5 @@ LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] error: aborting due to 3 previous errors -Some errors have detailed explanations: E0282, E0744. +Some errors have detailed explanations: E0282, E0658. For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr index de2624d7f7acf..ed3c66db2cd39 100644 --- a/src/test/ui/consts/const-eval/infinite_loop.stderr +++ b/src/test/ui/consts/const-eval/infinite_loop.stderr @@ -1,4 +1,4 @@ -error[E0744]: `while` is not allowed in a `const` +error[E0658]: `while` is not allowed in a `const` --> $DIR/infinite_loop.rs:7:9 | LL | / while n != 0 { @@ -8,6 +8,10 @@ LL | | LL | | LL | | } | |_________^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable + = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0658]: `if` is not allowed in a `const` --> $DIR/infinite_loop.rs:9:17 @@ -39,5 +43,5 @@ LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0080, E0658, E0744. +Some errors have detailed explanations: E0080, E0658. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/issue-52442.stderr b/src/test/ui/consts/const-eval/issue-52442.stderr index fa2272f8d634d..c8ac4b1a7629d 100644 --- a/src/test/ui/consts/const-eval/issue-52442.stderr +++ b/src/test/ui/consts/const-eval/issue-52442.stderr @@ -1,8 +1,11 @@ -error[E0744]: `loop` is not allowed in a `const` +error[E0658]: `loop` is not allowed in a `const` --> $DIR/issue-52442.rs:2:14 | LL | [(); { &loop { break } as *const _ as usize } ]; | ^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constants is unstable --> $DIR/issue-52442.rs:2:13 @@ -21,5 +24,5 @@ LL | [(); { &loop { break } as *const _ as usize } ]; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0080, E0658, E0744. +Some errors have detailed explanations: E0080, E0658. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/issue-52475.stderr b/src/test/ui/consts/const-eval/issue-52475.stderr index b8267f495de94..7c0c735f9a49a 100644 --- a/src/test/ui/consts/const-eval/issue-52475.stderr +++ b/src/test/ui/consts/const-eval/issue-52475.stderr @@ -1,4 +1,4 @@ -error[E0744]: `while` is not allowed in a `const` +error[E0658]: `while` is not allowed in a `const` --> $DIR/issue-52475.rs:6:9 | LL | / while n < 5 { @@ -7,6 +7,10 @@ LL | | n = (n + 1) % 5; LL | | x = &0; // Materialize a new AllocId LL | | } | |_________^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable + = help: add `#![feature(const_if_match)]` to the crate attributes to enable warning: Constant evaluating a complex constant, this might take some time --> $DIR/issue-52475.rs:2:18 @@ -29,5 +33,5 @@ LL | n = (n + 1) % 5; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0080, E0744. +Some errors have detailed explanations: E0080, E0658. For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/issue-62272.stderr b/src/test/ui/consts/const-eval/issue-62272.stderr index 573d04f5e4786..a02bbe557cf97 100644 --- a/src/test/ui/consts/const-eval/issue-62272.stderr +++ b/src/test/ui/consts/const-eval/issue-62272.stderr @@ -1,15 +1,21 @@ -error[E0744]: `loop` is not allowed in a `const` +error[E0658]: `loop` is not allowed in a `const` --> $DIR/issue-62272.rs:7:17 | LL | const FOO: () = loop { break; }; | ^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `const` +error[E0658]: `loop` is not allowed in a `const` --> $DIR/issue-62272.rs:10:20 | LL | [FOO; { let x; loop { x = 5; break; } x }]; | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0744`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-labeled-break.stderr b/src/test/ui/consts/const-labeled-break.stderr index ec32386439fdc..1282008fb637a 100644 --- a/src/test/ui/consts/const-labeled-break.stderr +++ b/src/test/ui/consts/const-labeled-break.stderr @@ -1,9 +1,13 @@ -error[E0744]: `while` is not allowed in a `const` +error[E0658]: `while` is not allowed in a `const` --> $DIR/const-labeled-break.rs:10:19 | LL | const CRASH: () = 'a: while break 'a {}; | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable + = help: add `#![feature(const_if_match)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0744`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/control-flow/basics.rs b/src/test/ui/consts/control-flow/basics.rs index b9ff040915863..a53293743d522 100644 --- a/src/test/ui/consts/control-flow/basics.rs +++ b/src/test/ui/consts/control-flow/basics.rs @@ -1,9 +1,10 @@ -// Test basic functionality of `if` and `match` in a const context. +// Test basic functionality of control flow in a const context. // run-pass #![feature(const_panic)] #![feature(const_if_match)] +#![feature(const_loop)] #![feature(const_fn)] const X: u32 = 4; @@ -30,15 +31,57 @@ const fn gcd(a: u32, b: u32) -> u32 { gcd(b, a % b) } +const fn fib(n: u64) -> u64 { + if n == 0 { + return 0; + } + + let mut fib = (0, 1); + let mut i = 1; + while i < n { + fib = (fib.1, fib.0 + fib.1); + i += 1; + } + + fib.1 +} + +const fn is_prime(n: u64) -> bool { + if n % 2 == 0 { + return false; + } + + let mut div = 3; + loop { + if n % div == 0 { + return false; + } + + if div * div > n { + return true; + } + + div += 2; + } +} + +macro_rules! const_assert { + ($expr:expr) => { + const _: () = assert!($expr); + assert!($expr); + } +} + fn main() { - const _: () = assert!(abs_diff(4, 5) == abs_diff(5, 4)); - assert_eq!(abs_diff(4, 5), abs_diff(5, 4)); + const_assert!(abs_diff(4, 5) == abs_diff(5, 4)); + const_assert!(ABS_DIFF == abs_diff(5, 4)); + + const_assert!(gcd(48, 18) == 6); + const_assert!(gcd(18, 48) == 6); - const _: () = assert!(ABS_DIFF == abs_diff(5, 4)); - assert_eq!(ABS_DIFF, abs_diff(5, 4)); + const_assert!(fib(2) == 1); + const_assert!(fib(8) == 21); - const _: () = assert!(gcd(48, 18) == 6); - const _: () = assert!(gcd(18, 48) == 6); - assert_eq!(gcd(48, 18), 6); - assert_eq!(gcd(18, 48), 6); + const_assert!(is_prime(113)); + const_assert!(!is_prime(117)); } diff --git a/src/test/ui/consts/control-flow/drop-failure.rs b/src/test/ui/consts/control-flow/drop-failure.rs index c6bea89e6e6f7..9da5546976c75 100644 --- a/src/test/ui/consts/control-flow/drop-failure.rs +++ b/src/test/ui/consts/control-flow/drop-failure.rs @@ -1,4 +1,5 @@ #![feature(const_if_match)] +#![feature(const_loop)] // `x` is *not* always moved into the final value may be dropped inside the initializer. const _: Option> = { @@ -32,4 +33,29 @@ const _: Vec = { } }; +const _: Option> = { + let mut some = Some(Vec::new()); + let mut tmp = None; + //~^ ERROR destructors cannot be evaluated at compile-time + + let mut i = 0; + while i < 10 { + tmp = some; + some = None; + + // We can escape the loop with `Some` still in `tmp`, + // which would require that it be dropped at the end of the block. + if i > 100 { + break; + } + + some = tmp; + tmp = None; + + i += 1; + } + + some +}; + fn main() {} diff --git a/src/test/ui/consts/control-flow/drop-failure.stderr b/src/test/ui/consts/control-flow/drop-failure.stderr index 35ceb3b277084..3eec3a929a07f 100644 --- a/src/test/ui/consts/control-flow/drop-failure.stderr +++ b/src/test/ui/consts/control-flow/drop-failure.stderr @@ -1,21 +1,27 @@ error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/drop-failure.rs:6:9 + --> $DIR/drop-failure.rs:7:9 | LL | let x = Some(Vec::new()); | ^ constants cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/drop-failure.rs:19:9 + --> $DIR/drop-failure.rs:20:9 | LL | let vec_tuple = (Vec::new(),); | ^^^^^^^^^ constants cannot evaluate destructors error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/drop-failure.rs:27:9 + --> $DIR/drop-failure.rs:28:9 | LL | let x: Result<_, Vec> = Ok(Vec::new()); | ^ constants cannot evaluate destructors -error: aborting due to 3 previous errors +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/drop-failure.rs:38:9 + | +LL | let mut tmp = None; + | ^^^^^^^ constants cannot evaluate destructors + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/control-flow/drop-success.rs b/src/test/ui/consts/control-flow/drop-success.rs index 92b3f6ec92eb5..185d6b639962b 100644 --- a/src/test/ui/consts/control-flow/drop-success.rs +++ b/src/test/ui/consts/control-flow/drop-success.rs @@ -1,6 +1,7 @@ // run-pass #![feature(const_if_match)] +#![feature(const_loop)] // `x` is always moved into the final value and is not dropped inside the initializer. const _: Option> = { @@ -21,4 +22,24 @@ const _: Option> = { } }; +const _: Option> = { + let mut some = Some(Vec::new()); + let mut tmp = None; + + let mut i = 0; + while i < 10 { + tmp = some; + some = None; + + // We can never exit the loop with `Some` in `tmp`. + + some = tmp; + tmp = None; + + i += 1; + } + + some +}; + fn main() {} diff --git a/src/test/ui/consts/control-flow/interior-mutability.rs b/src/test/ui/consts/control-flow/interior-mutability.rs index fcced75fcb047..c2439f4a7bff3 100644 --- a/src/test/ui/consts/control-flow/interior-mutability.rs +++ b/src/test/ui/consts/control-flow/interior-mutability.rs @@ -2,6 +2,7 @@ // disqualifies it from promotion. #![feature(const_if_match)] +#![feature(const_loop)] use std::cell::Cell; @@ -21,7 +22,26 @@ const Y: Option> = { y }; +const Z: Option> = { + let mut z = None; + let mut i = 0; + while i < 10 { + if i == 8 { + z = Some(Cell::new(4)); + } + + if i == 9 { + z = None; + } + + i += 1; + } + z +}; + + fn main() { let x: &'static _ = &X; //~ ERROR temporary value dropped while borrowed let y: &'static _ = &Y; //~ ERROR temporary value dropped while borrowed + let z: &'static _ = &Z; //~ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/control-flow/interior-mutability.stderr b/src/test/ui/consts/control-flow/interior-mutability.stderr index 49e8ea3ade7ba..0977c84d12d8a 100644 --- a/src/test/ui/consts/control-flow/interior-mutability.stderr +++ b/src/test/ui/consts/control-flow/interior-mutability.stderr @@ -1,24 +1,35 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/interior-mutability.rs:25:26 + --> $DIR/interior-mutability.rs:44:26 | LL | let x: &'static _ = &X; | ---------- ^ creates a temporary which is freed while still in use | | | type annotation requires that borrow lasts for `'static` -LL | let y: &'static _ = &Y; +... LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/interior-mutability.rs:26:26 + --> $DIR/interior-mutability.rs:45:26 | LL | let y: &'static _ = &Y; | ---------- ^ creates a temporary which is freed while still in use | | | type annotation requires that borrow lasts for `'static` +LL | let z: &'static _ = &Z; +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/interior-mutability.rs:46:26 + | +LL | let z: &'static _ = &Z; + | ---------- ^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` LL | } | - temporary value is freed at the end of this statement -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/control-flow/loop.both.stderr b/src/test/ui/consts/control-flow/loop.both.stderr new file mode 100644 index 0000000000000..71d96b216f974 --- /dev/null +++ b/src/test/ui/consts/control-flow/loop.both.stderr @@ -0,0 +1,19 @@ +error[E0744]: `for` is not allowed in a `const` + --> $DIR/loop.rs:63:5 + | +LL | / for i in 0..4 { +LL | | x += i; +LL | | } + | |_____^ + +error[E0744]: `for` is not allowed in a `const` + --> $DIR/loop.rs:67:5 + | +LL | / for i in 0..4 { +LL | | x += i; +LL | | } + | |_____^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0744`. diff --git a/src/test/ui/consts/control-flow/loop.if_match.stderr b/src/test/ui/consts/control-flow/loop.if_match.stderr index 15b9eb028611e..e01081638ec22 100644 --- a/src/test/ui/consts/control-flow/loop.if_match.stderr +++ b/src/test/ui/consts/control-flow/loop.if_match.stderr @@ -1,51 +1,72 @@ -error[E0744]: `loop` is not allowed in a `const` - --> $DIR/loop.rs:8:15 +error[E0658]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:10:15 | LL | const _: () = loop {}; | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `static` - --> $DIR/loop.rs:10:19 +error[E0658]: `loop` is not allowed in a `static` + --> $DIR/loop.rs:12:19 | LL | static FOO: i32 = loop { break 4; }; | ^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `const fn` - --> $DIR/loop.rs:13:5 +error[E0658]: `loop` is not allowed in a `const fn` + --> $DIR/loop.rs:15:5 | LL | loop {} | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `const fn` - --> $DIR/loop.rs:26:9 +error[E0658]: `loop` is not allowed in a `const fn` + --> $DIR/loop.rs:28:9 | LL | loop {} | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `while` is not allowed in a `const` - --> $DIR/loop.rs:38:9 +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:40:9 | LL | while false {} | ^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `while` is not allowed in a `const` - --> $DIR/loop.rs:47:5 +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:49:5 | LL | / while x < 4 { LL | | x += 1; LL | | } | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `while` is not allowed in a `const` - --> $DIR/loop.rs:51:5 +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:53:5 | LL | / while x < 8 { LL | | x += 1; LL | | } | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable error[E0744]: `for` is not allowed in a `const` - --> $DIR/loop.rs:61:5 + --> $DIR/loop.rs:63:5 | LL | / for i in 0..4 { LL | | x += i; @@ -53,15 +74,15 @@ LL | | } | |_____^ error[E0744]: `for` is not allowed in a `const` - --> $DIR/loop.rs:65:5 + --> $DIR/loop.rs:67:5 | LL | / for i in 0..4 { LL | | x += i; LL | | } | |_____^ -error[E0744]: `loop` is not allowed in a `const` - --> $DIR/loop.rs:75:5 +error[E0658]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:77:5 | LL | / loop { LL | | x += 1; @@ -70,9 +91,12 @@ LL | | break; LL | | } LL | | } | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `const` - --> $DIR/loop.rs:82:5 +error[E0658]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:84:5 | LL | / loop { LL | | x += 1; @@ -81,31 +105,47 @@ LL | | break; LL | | } LL | | } | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `while` is not allowed in a `const` - --> $DIR/loop.rs:94:5 +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:96:5 | LL | while let None = Some(x) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `while` is not allowed in a `const` - --> $DIR/loop.rs:95:5 +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:97:5 | LL | while let None = Some(x) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `const` - --> $DIR/loop.rs:17:22 +error[E0658]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:19:22 | LL | const BAR: i32 = loop { break 4; }; | ^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `const` - --> $DIR/loop.rs:21:22 +error[E0658]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:23:22 | LL | const BAR: i32 = loop { break 4; }; | ^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable error: aborting due to 15 previous errors -For more information about this error, try `rustc --explain E0744`. +Some errors have detailed explanations: E0658, E0744. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/control-flow/loop.loop_.stderr b/src/test/ui/consts/control-flow/loop.loop_.stderr new file mode 100644 index 0000000000000..cf871c9a78c41 --- /dev/null +++ b/src/test/ui/consts/control-flow/loop.loop_.stderr @@ -0,0 +1,96 @@ +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:40:9 + | +LL | while false {} + | ^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional + +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:49:5 + | +LL | / while x < 4 { +LL | | x += 1; +LL | | } + | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional + +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:53:5 + | +LL | / while x < 8 { +LL | | x += 1; +LL | | } + | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional + +error[E0744]: `for` is not allowed in a `const` + --> $DIR/loop.rs:63:5 + | +LL | / for i in 0..4 { +LL | | x += i; +LL | | } + | |_____^ + +error[E0744]: `for` is not allowed in a `const` + --> $DIR/loop.rs:67:5 + | +LL | / for i in 0..4 { +LL | | x += i; +LL | | } + | |_____^ + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/loop.rs:79:9 + | +LL | / if x == 4 { +LL | | break; +LL | | } + | |_________^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `if` is not allowed in a `const` + --> $DIR/loop.rs:86:9 + | +LL | / if x == 8 { +LL | | break; +LL | | } + | |_________^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:96:5 + | +LL | while let None = Some(x) { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional + +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:97:5 + | +LL | while let None = Some(x) { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/49146 + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0658, E0744. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/control-flow/loop.rs b/src/test/ui/consts/control-flow/loop.rs index 4be341f2d3846..bc57f7568a70a 100644 --- a/src/test/ui/consts/control-flow/loop.rs +++ b/src/test/ui/consts/control-flow/loop.rs @@ -1,9 +1,11 @@ -// Ensure that all loops are forbidden in a const context, even if `#![feature(const_if_match)]` is -// enabled. +// Ensure that loops are forbidden in a const context unless `#![feature(const_loop)]` is enabled. +// `while` loops require `#![feature(const_if_match)]` to be enabled as well. -// revisions: stock if_match +// gate-test-const_loop +// revisions: stock if_match loop_ both -#![cfg_attr(if_match, feature(const_if_match))] +#![cfg_attr(any(both, if_match), feature(const_if_match))] +#![cfg_attr(any(both, loop_), feature(const_loop))] const _: () = loop {}; //[stock,if_match]~ ERROR `loop` is not allowed in a `const` @@ -36,7 +38,7 @@ const fn const_outside() { fn main() { let x = [0; { while false {} - //[stock,if_match]~^ ERROR `while` is not allowed in a `const` + //[stock,if_match,loop_]~^ ERROR `while` is not allowed in a `const` 4 }]; } @@ -44,11 +46,11 @@ fn main() { const _: i32 = { let mut x = 0; - while x < 4 { //[stock,if_match]~ ERROR `while` is not allowed in a `const` + while x < 4 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const` x += 1; } - while x < 8 { //[stock,if_match]~ ERROR `while` is not allowed in a `const` + while x < 8 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const` x += 1; } @@ -58,11 +60,11 @@ const _: i32 = { const _: i32 = { let mut x = 0; - for i in 0..4 { //[stock,if_match]~ ERROR `for` is not allowed in a `const` + for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const` x += i; } - for i in 0..4 { //[stock,if_match]~ ERROR `for` is not allowed in a `const` + for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const` x += i; } @@ -74,14 +76,14 @@ const _: i32 = { loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const` x += 1; - if x == 4 { //[stock]~ ERROR `if` is not allowed in a `const` + if x == 4 { //[stock,loop_]~ ERROR `if` is not allowed in a `const` break; } } loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const` x += 1; - if x == 8 { //[stock]~ ERROR `if` is not allowed in a `const` + if x == 8 { //[stock,loop_]~ ERROR `if` is not allowed in a `const` break; } } @@ -91,7 +93,7 @@ const _: i32 = { const _: i32 = { let mut x = 0; - while let None = Some(x) { } //[stock,if_match]~ ERROR `while` is not allowed in a `const` - while let None = Some(x) { } //[stock,if_match]~ ERROR `while` is not allowed in a `const` + while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const` + while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const` x }; diff --git a/src/test/ui/consts/control-flow/loop.stock.stderr b/src/test/ui/consts/control-flow/loop.stock.stderr index bb651d23179f7..e3687cf12acc7 100644 --- a/src/test/ui/consts/control-flow/loop.stock.stderr +++ b/src/test/ui/consts/control-flow/loop.stock.stderr @@ -1,51 +1,75 @@ -error[E0744]: `loop` is not allowed in a `const` - --> $DIR/loop.rs:8:15 +error[E0658]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:10:15 | LL | const _: () = loop {}; | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `static` - --> $DIR/loop.rs:10:19 +error[E0658]: `loop` is not allowed in a `static` + --> $DIR/loop.rs:12:19 | LL | static FOO: i32 = loop { break 4; }; | ^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `const fn` - --> $DIR/loop.rs:13:5 +error[E0658]: `loop` is not allowed in a `const fn` + --> $DIR/loop.rs:15:5 | LL | loop {} | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `const fn` - --> $DIR/loop.rs:26:9 +error[E0658]: `loop` is not allowed in a `const fn` + --> $DIR/loop.rs:28:9 | LL | loop {} | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `while` is not allowed in a `const` - --> $DIR/loop.rs:38:9 +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:40:9 | LL | while false {} | ^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable + = help: add `#![feature(const_if_match)]` to the crate attributes to enable -error[E0744]: `while` is not allowed in a `const` - --> $DIR/loop.rs:47:5 +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:49:5 | LL | / while x < 4 { LL | | x += 1; LL | | } | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable + = help: add `#![feature(const_if_match)]` to the crate attributes to enable -error[E0744]: `while` is not allowed in a `const` - --> $DIR/loop.rs:51:5 +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:53:5 | LL | / while x < 8 { LL | | x += 1; LL | | } | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable + = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0744]: `for` is not allowed in a `const` - --> $DIR/loop.rs:61:5 + --> $DIR/loop.rs:63:5 | LL | / for i in 0..4 { LL | | x += i; @@ -53,15 +77,15 @@ LL | | } | |_____^ error[E0744]: `for` is not allowed in a `const` - --> $DIR/loop.rs:65:5 + --> $DIR/loop.rs:67:5 | LL | / for i in 0..4 { LL | | x += i; LL | | } | |_____^ -error[E0744]: `loop` is not allowed in a `const` - --> $DIR/loop.rs:75:5 +error[E0658]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:77:5 | LL | / loop { LL | | x += 1; @@ -70,9 +94,12 @@ LL | | break; LL | | } LL | | } | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable error[E0658]: `if` is not allowed in a `const` - --> $DIR/loop.rs:77:9 + --> $DIR/loop.rs:79:9 | LL | / if x == 4 { LL | | break; @@ -82,8 +109,8 @@ LL | | } = note: for more information, see https://github.com/rust-lang/rust/issues/49146 = help: add `#![feature(const_if_match)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `const` - --> $DIR/loop.rs:82:5 +error[E0658]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:84:5 | LL | / loop { LL | | x += 1; @@ -92,9 +119,12 @@ LL | | break; LL | | } LL | | } | |_____^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable error[E0658]: `if` is not allowed in a `const` - --> $DIR/loop.rs:84:9 + --> $DIR/loop.rs:86:9 | LL | / if x == 8 { LL | | break; @@ -104,29 +134,43 @@ LL | | } = note: for more information, see https://github.com/rust-lang/rust/issues/49146 = help: add `#![feature(const_if_match)]` to the crate attributes to enable -error[E0744]: `while` is not allowed in a `const` - --> $DIR/loop.rs:94:5 +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:96:5 | LL | while let None = Some(x) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable + = help: add `#![feature(const_if_match)]` to the crate attributes to enable -error[E0744]: `while` is not allowed in a `const` - --> $DIR/loop.rs:95:5 +error[E0658]: `while` is not allowed in a `const` + --> $DIR/loop.rs:97:5 | LL | while let None = Some(x) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable + = help: add `#![feature(const_if_match)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `const` - --> $DIR/loop.rs:17:22 +error[E0658]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:19:22 | LL | const BAR: i32 = loop { break 4; }; | ^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable -error[E0744]: `loop` is not allowed in a `const` - --> $DIR/loop.rs:21:22 +error[E0658]: `loop` is not allowed in a `const` + --> $DIR/loop.rs:23:22 | LL | const BAR: i32 = loop { break 4; }; | ^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable error: aborting due to 17 previous errors diff --git a/src/test/ui/consts/min_const_fn/loop_ice.stderr b/src/test/ui/consts/min_const_fn/loop_ice.stderr index 87db65fbb7dac..58d1d4211334c 100644 --- a/src/test/ui/consts/min_const_fn/loop_ice.stderr +++ b/src/test/ui/consts/min_const_fn/loop_ice.stderr @@ -1,9 +1,12 @@ -error[E0744]: `loop` is not allowed in a `const fn` +error[E0658]: `loop` is not allowed in a `const fn` --> $DIR/loop_ice.rs:2:5 | LL | loop {} | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0744`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/issues/issue-51714.stderr b/src/test/ui/issues/issue-51714.stderr index 001928c3b2f31..c3b880200f851 100644 --- a/src/test/ui/issues/issue-51714.stderr +++ b/src/test/ui/issues/issue-51714.stderr @@ -1,8 +1,12 @@ -error[E0744]: `while` is not allowed in a `const` +error[E0658]: `while` is not allowed in a `const` --> $DIR/issue-51714.rs:11:17 | LL | [(); return while let Some(n) = Some(0) {}]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/52000 + = help: add `#![feature(const_loop)]` to the crate attributes to enable + = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0572]: return statement outside of function body --> $DIR/issue-51714.rs:2:14 @@ -30,5 +34,5 @@ LL | [(); return while let Some(n) = Some(0) {}]; error: aborting due to 5 previous errors -Some errors have detailed explanations: E0572, E0744. +Some errors have detailed explanations: E0572, E0658. For more information about an error, try `rustc --explain E0572`.