Auto merge of #76231 - tmandry:rollup-ilvs9fq, r=tmandry

Rollup of 14 pull requests

Successful merges:

 - #74880 (Add trailing comma support to matches macro)
 - #76074 (Add new `-Z dump-mir-spanview` option)
 - #76088 (Add more examples to lexicographic cmp on Iterators.)
 - #76099 (Add info about `!` and `impl Trait`)
 - #76126 (Use "Fira Sans" for crate list font)
 - #76132 (Factor out StmtKind::MacCall fields into `MacCallStmt` struct)
 - #76143 (Give a better error message for duplicate built-in macros)
 - #76158 (Stabilise link-self-contained option)
 - #76201 (Move to intra-doc links for library/core/src/panic.rs)
 - #76206 (Make all methods of `std::net::Ipv6Addr` const)
 - #76207 (# Move to intra-doc links for library/core/src/clone.rs)
 - #76212 (Document lint missing_doc_code_examples is nightly-only)
 - #76218 (lexer: Tiny improvement to shebang detection)
 - #76221 (Clean up header in `iter` docs for `for` loops)

Failed merges:

r? @ghost
This commit is contained in:
bors 2020-09-02 01:29:28 +00:00
commit e36e4bd0f7
47 changed files with 1064 additions and 99 deletions

View File

@ -922,9 +922,13 @@ impl Stmt {
pub fn add_trailing_semicolon(mut self) -> Self {
self.kind = match self.kind {
StmtKind::Expr(expr) => StmtKind::Semi(expr),
StmtKind::MacCall(mac) => StmtKind::MacCall(
mac.map(|(mac, _style, attrs)| (mac, MacStmtStyle::Semicolon, attrs)),
),
StmtKind::MacCall(mac) => {
StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs }| MacCallStmt {
mac,
style: MacStmtStyle::Semicolon,
attrs,
}))
}
kind => kind,
};
self
@ -958,7 +962,14 @@ pub enum StmtKind {
/// Just a trailing semi-colon.
Empty,
/// Macro.
MacCall(P<(MacCall, MacStmtStyle, AttrVec)>),
MacCall(P<MacCallStmt>),
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct MacCallStmt {
pub mac: MacCall,
pub style: MacStmtStyle,
pub attrs: AttrVec,
}
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]

View File

@ -16,7 +16,6 @@ use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;
use std::iter;
use std::ops::DerefMut;
pub struct MarkedAttrs(GrowableBitSet<AttrId>);
@ -634,10 +633,7 @@ impl HasAttrs for StmtKind {
StmtKind::Local(ref local) => local.attrs(),
StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(),
StmtKind::Empty | StmtKind::Item(..) => &[],
StmtKind::MacCall(ref mac) => {
let (_, _, ref attrs) = **mac;
attrs.attrs()
}
StmtKind::MacCall(ref mac) => mac.attrs.attrs(),
}
}
@ -647,8 +643,7 @@ impl HasAttrs for StmtKind {
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
StmtKind::Empty | StmtKind::Item(..) => {}
StmtKind::MacCall(mac) => {
let (_mac, _style, attrs) = mac.deref_mut();
attrs.visit_attrs(f);
mac.attrs.visit_attrs(f);
}
}
}

View File

@ -1305,7 +1305,7 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(),
StmtKind::Empty => smallvec![StmtKind::Empty],
StmtKind::MacCall(mut mac) => {
let (mac_, _semi, attrs) = mac.deref_mut();
let MacCallStmt { mac: mac_, style: _, attrs } = mac.deref_mut();
vis.visit_mac(mac_);
visit_thin_attrs(attrs, vis);
smallvec![StmtKind::MacCall(mac)]

View File

@ -692,7 +692,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) {
StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => visitor.visit_expr(expr),
StmtKind::Empty => {}
StmtKind::MacCall(ref mac) => {
let (ref mac, _, ref attrs) = **mac;
let MacCallStmt { ref mac, style: _, ref attrs } = **mac;
visitor.visit_mac(mac);
for attr in attrs.iter() {
visitor.visit_attribute(attr);

View File

@ -1507,11 +1507,10 @@ impl<'a> State<'a> {
self.s.word(";");
}
ast::StmtKind::MacCall(ref mac) => {
let (ref mac, style, ref attrs) = **mac;
self.space_if_not_bol();
self.print_outer_attributes(attrs);
self.print_mac(mac);
if style == ast::MacStmtStyle::Semicolon {
self.print_outer_attributes(&mac.attrs);
self.print_mac(&mac.mac);
if mac.style == ast::MacStmtStyle::Semicolon {
self.s.word(";");
}
}

View File

@ -1084,7 +1084,7 @@ fn get_crt_libs_path(sess: &Session) -> Option<PathBuf> {
fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf {
// prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details
if sess.opts.debugging_opts.link_self_contained.is_none()
if sess.opts.cg.link_self_contained.is_none()
&& sess.target.target.llvm_target.contains("windows-gnu")
{
if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
@ -1289,7 +1289,7 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
/// Whether we link to our own CRT objects instead of relying on gcc to pull them.
/// We only provide such support for a very limited number of targets.
fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
if let Some(self_contained) = sess.opts.debugging_opts.link_self_contained {
if let Some(self_contained) = sess.opts.cg.link_self_contained {
return self_contained;
}
@ -1499,7 +1499,7 @@ fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<'
/// Add sysroot and other globally set directories to the directory search list.
fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) {
// Prefer system mingw-w64 libs, see get_crt_libs_path comment for more details.
if sess.opts.debugging_opts.link_self_contained.is_none()
if sess.opts.cg.link_self_contained.is_none()
&& cfg!(windows)
&& sess.target.target.llvm_target.contains("windows-gnu")
{

View File

@ -454,6 +454,7 @@ E0768: include_str!("./error_codes/E0768.md"),
E0769: include_str!("./error_codes/E0769.md"),
E0770: include_str!("./error_codes/E0770.md"),
E0771: include_str!("./error_codes/E0771.md"),
E0773: include_str!("./error_codes/E0773.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard

View File

@ -0,0 +1,38 @@
A builtin-macro was defined more than once.
Erroneous code example:
```compile_fail,E0773
#![feature(decl_macro)]
#![feature(rustc_attrs)]
#[rustc_builtin_macro]
pub macro test($item:item) {
/* compiler built-in */
}
mod inner {
#[rustc_builtin_macro]
pub macro test($item:item) {
/* compiler built-in */
}
}
```
To fix the issue, remove the duplicate declaration:
```
#![feature(decl_macro)]
#![feature(rustc_attrs)]
#[rustc_builtin_macro]
pub macro test($item:item) {
/* compiler built-in */
}
```
In very rare edge cases, this may happen when loading `core` or `std` twice,
once with `check` metadata and once with `build` metadata.
For more information, see [#75176].
[#75176]: https://github.com/rust-lang/rust/pull/75176#issuecomment-683234468

View File

@ -13,7 +13,7 @@ use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{self as ast, AttrItem, Block, LitKind, NodeId, PatKind, Path};
use rustc_ast::{ItemKind, MacArgs, MacStmtStyle, StmtKind};
use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind};
use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
use rustc_data_structures::map_in_place::MapInPlace;
@ -1363,7 +1363,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
}
if let StmtKind::MacCall(mac) = stmt.kind {
let (mac, style, attrs) = mac.into_inner();
let MacCallStmt { mac, style, attrs } = mac.into_inner();
self.check_attributes(&attrs);
let mut placeholder =
self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts();

View File

@ -92,7 +92,11 @@ pub fn placeholder(
AstFragment::Ty(P(ast::Ty { id, span, kind: ast::TyKind::MacCall(mac_placeholder()) }))
}
AstFragmentKind::Stmts => AstFragment::Stmts(smallvec![{
let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::AttrVec::new()));
let mac = P(ast::MacCallStmt {
mac: mac_placeholder(),
style: ast::MacStmtStyle::Braces,
attrs: ast::AttrVec::new(),
});
ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac) }
}]),
AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm {
@ -293,7 +297,7 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
let (style, mut stmts) = match stmt.kind {
ast::StmtKind::MacCall(mac) => (mac.1, self.remove(stmt.id).make_stmts()),
ast::StmtKind::MacCall(mac) => (mac.style, self.remove(stmt.id).make_stmts()),
_ => return noop_flat_map_stmt(stmt, self),
};

View File

@ -402,6 +402,7 @@ fn test_codegen_options_tracking_hash() {
// `link_arg` is omitted because it just forwards to `link_args`.
untracked!(link_args, vec![String::from("abc"), String::from("def")]);
untracked!(link_dead_code, Some(true));
untracked!(link_self_contained, Some(true));
untracked!(linker, Some(PathBuf::from("linker")));
untracked!(linker_flavor, Some(LinkerFlavor::Gcc));
untracked!(no_stack_check, true);

View File

@ -191,12 +191,16 @@ pub fn strip_shebang(input: &str) -> Option<usize> {
// For simplicity we consider any line starting with `#!` a shebang,
// regardless of restrictions put on shebangs by specific platforms.
if let Some(input_tail) = input.strip_prefix("#!") {
// Ok, this is a shebang but if the next non-whitespace token is `[` or maybe
// a doc comment (due to `TokenKind::(Line,Block)Comment` ambiguity at lexer level),
// Ok, this is a shebang but if the next non-whitespace token is `[`,
// then it may be valid Rust code, so consider it Rust code.
let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok|
!matches!(tok, TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. })
);
let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok| {
!matches!(
tok,
TokenKind::Whitespace
| TokenKind::LineComment { doc_style: None }
| TokenKind::BlockComment { doc_style: None, .. }
)
});
if next_non_whitespace_token != Some(TokenKind::OpenBracket) {
// No other choice than to consider this a shebang.
return Some(2 + input_tail.lines().next().unwrap_or_default().len());

View File

@ -9,6 +9,7 @@ mod alignment;
pub mod collect_writes;
mod graphviz;
pub(crate) mod pretty;
pub(crate) mod spanview;
pub use self::aggregate::expand_aggregate;
pub use self::alignment::is_disaligned;

View File

@ -6,6 +6,7 @@ use std::io::{self, Write};
use std::path::{Path, PathBuf};
use super::graphviz::write_mir_fn_graphviz;
use super::spanview::write_mir_fn_spanview;
use crate::transform::MirSource;
use either::Either;
use rustc_data_structures::fx::FxHashMap;
@ -147,6 +148,16 @@ fn dump_matched_mir_node<'tcx, F>(
write_mir_fn_graphviz(tcx, source.def_id(), body, false, &mut file)?;
};
}
if let Some(spanview) = tcx.sess.opts.debugging_opts.dump_mir_spanview {
let _: io::Result<()> = try {
let mut file =
create_dump_file(tcx, "html", pass_num, pass_name, disambiguator, source)?;
if source.def_id().is_local() {
write_mir_fn_spanview(tcx, source.def_id(), body, spanview, &mut file)?;
}
};
}
}
/// Returns the path to the filename where we should dump a given MIR.

View File

@ -0,0 +1,461 @@
use rustc_hir::def_id::DefId;
use rustc_middle::hir;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::MirSpanview;
use rustc_span::{BytePos, Pos, Span};
use std::io::{self, Write};
use std::iter::Peekable;
pub const TOOLTIP_INDENT: &str = " ";
const NEW_LINE_SPAN: &str = "</span>\n<span class=\"line\">";
const HEADER: &str = r#"<!DOCTYPE html>
<html>
<head>
<title>coverage_of_if_else - Code Regions</title>
<style>
.line {
counter-increment: line;
}
.line:before {
content: counter(line) ": ";
font-family: Menlo, Monaco, monospace;
font-style: italic;
width: 3.8em;
display: inline-block;
text-align: right;
filter: opacity(50%);
-webkit-user-select: none;
}
.code {
color: #dddddd;
background-color: #222222;
font-family: Menlo, Monaco, monospace;
line-height: 1.4em;
border-bottom: 2px solid #222222;
white-space: pre;
display: inline-block;
}
.odd {
background-color: #55bbff;
color: #223311;
}
.even {
background-color: #ee7756;
color: #551133;
}
.code {
--index: calc(var(--layer) - 1);
padding-top: calc(var(--index) * 0.15em);
filter:
hue-rotate(calc(var(--index) * 25deg))
saturate(calc(100% - (var(--index) * 2%)))
brightness(calc(100% - (var(--index) * 1.5%)));
}
.annotation {
color: #4444ff;
font-family: monospace;
font-style: italic;
display: none;
-webkit-user-select: none;
}
body:active .annotation {
/* requires holding mouse down anywhere on the page */
display: inline-block;
}
span:hover .annotation {
/* requires hover over a span ONLY on its first line */
display: inline-block;
}
</style>
</head>
<body>"#;
const FOOTER: &str = r#"
</body>
</html>"#;
/// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator.
pub struct SpanViewable {
pub span: Span,
pub title: String,
pub tooltip: String,
}
/// Write a spanview HTML+CSS file to analyze MIR element spans.
pub fn write_mir_fn_spanview<'tcx, W>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
body: &Body<'tcx>,
spanview: MirSpanview,
w: &mut W,
) -> io::Result<()>
where
W: Write,
{
let body_span = hir_body(tcx, def_id).value.span;
let mut span_viewables = Vec::new();
for (bb, data) in body.basic_blocks().iter_enumerated() {
match spanview {
MirSpanview::Statement => {
for (i, statement) in data.statements.iter().enumerate() {
if let Some(span_viewable) =
statement_span_viewable(tcx, body_span, bb, i, statement)
{
span_viewables.push(span_viewable);
}
}
if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) {
span_viewables.push(span_viewable);
}
}
MirSpanview::Terminator => {
if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) {
span_viewables.push(span_viewable);
}
}
MirSpanview::Block => {
if let Some(span_viewable) = block_span_viewable(tcx, body_span, bb, data) {
span_viewables.push(span_viewable);
}
}
}
}
write_spanview_document(tcx, def_id, span_viewables, w)?;
Ok(())
}
/// Generate a spanview HTML+CSS document for the given local function `def_id`, and a pre-generated
/// list `SpanViewable`s.
pub fn write_spanview_document<'tcx, W>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
mut span_viewables: Vec<SpanViewable>,
w: &mut W,
) -> io::Result<()>
where
W: Write,
{
let fn_span = fn_span(tcx, def_id);
writeln!(w, "{}", HEADER)?;
let mut next_pos = fn_span.lo();
let end_pos = fn_span.hi();
let source_map = tcx.sess.source_map();
let start = source_map.lookup_char_pos(next_pos);
write!(
w,
r#"<div class="code" style="counter-reset: line {}"><span class="line">{}"#,
start.line - 1,
" ".repeat(start.col.to_usize())
)?;
span_viewables.sort_unstable_by(|a, b| {
let a = a.span;
let b = b.span;
if a.lo() == b.lo() {
// Sort hi() in reverse order so shorter spans are attempted after longer spans.
// This should give shorter spans a higher "layer", so they are not covered by
// the longer spans.
b.hi().partial_cmp(&a.hi())
} else {
a.lo().partial_cmp(&b.lo())
}
.unwrap()
});
let mut ordered_span_viewables = span_viewables.iter().peekable();
let mut alt = false;
while ordered_span_viewables.peek().is_some() {
next_pos = write_span_viewables(tcx, next_pos, &mut ordered_span_viewables, false, 1, w)?;
alt = !alt;
}
if next_pos < end_pos {
write_coverage_gap(tcx, next_pos, end_pos, w)?;
}
write!(w, r#"</span></div>"#)?;
writeln!(w, "{}", FOOTER)?;
Ok(())
}
/// Format a string showing the start line and column, and end line and column within a file.
pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> String {
let source_map = tcx.sess.source_map();
let start = source_map.lookup_char_pos(span.lo());
let end = source_map.lookup_char_pos(span.hi());
format!("{}:{}-{}:{}", start.line, start.col.to_usize() + 1, end.line, end.col.to_usize() + 1)
}
pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
use StatementKind::*;
match statement.kind {
Assign(..) => "Assign",
FakeRead(..) => "FakeRead",
SetDiscriminant { .. } => "SetDiscriminant",
StorageLive(..) => "StorageLive",
StorageDead(..) => "StorageDead",
LlvmInlineAsm(..) => "LlvmInlineAsm",
Retag(..) => "Retag",
AscribeUserType(..) => "AscribeUserType",
Coverage(..) => "Coverage",
Nop => "Nop",
}
}
pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str {
use TerminatorKind::*;
match term.kind {
Goto { .. } => "Goto",
SwitchInt { .. } => "SwitchInt",
Resume => "Resume",
Abort => "Abort",
Return => "Return",
Unreachable => "Unreachable",
Drop { .. } => "Drop",
DropAndReplace { .. } => "DropAndReplace",
Call { .. } => "Call",
Assert { .. } => "Assert",
Yield { .. } => "Yield",
GeneratorDrop => "GeneratorDrop",
FalseEdge { .. } => "FalseEdge",
FalseUnwind { .. } => "FalseUnwind",
InlineAsm { .. } => "InlineAsm",
}
}
fn statement_span_viewable<'tcx>(
tcx: TyCtxt<'tcx>,
body_span: Span,
bb: BasicBlock,
i: usize,
statement: &Statement<'tcx>,
) -> Option<SpanViewable> {
let span = statement.source_info.span;
if !body_span.contains(span) {
return None;
}
let title = format!("bb{}[{}]", bb.index(), i);
let tooltip = tooltip(tcx, &title, span, vec![statement.clone()], &None);
Some(SpanViewable { span, title, tooltip })
}
fn terminator_span_viewable<'tcx>(
tcx: TyCtxt<'tcx>,
body_span: Span,
bb: BasicBlock,
data: &BasicBlockData<'tcx>,
) -> Option<SpanViewable> {
let term = data.terminator();
let span = term.source_info.span;
if !body_span.contains(span) {
return None;
}
let title = format!("bb{}`{}`", bb.index(), terminator_kind_name(term));
let tooltip = tooltip(tcx, &title, span, vec![], &data.terminator);
Some(SpanViewable { span, title, tooltip })
}
fn block_span_viewable<'tcx>(
tcx: TyCtxt<'tcx>,
body_span: Span,
bb: BasicBlock,
data: &BasicBlockData<'tcx>,
) -> Option<SpanViewable> {
let span = compute_block_span(data, body_span);
if !body_span.contains(span) {
return None;
}
let title = format!("bb{}", bb.index());
let tooltip = tooltip(tcx, &title, span, data.statements.clone(), &data.terminator);
Some(SpanViewable { span, title, tooltip })
}
fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Span {
let mut span = data.terminator().source_info.span;
for statement_span in data.statements.iter().map(|statement| statement.source_info.span) {
// Only combine Spans from the function's body_span.
if body_span.contains(statement_span) {
span = span.to(statement_span);
}
}
span
}
/// Recursively process each ordered span. Spans that overlap will have progressively varying
/// styles, such as increased padding for each overlap. Non-overlapping adjacent spans will
/// have alternating style choices, to help distinguish between them if, visually adjacent.
/// The `layer` is incremented for each overlap, and the `alt` bool alternates between true
/// and false, for each adjacent non-overlapping span. Source code between the spans (code
/// that is not in any coverage region) has neutral styling.
fn write_span_viewables<'tcx, 'b, W>(
tcx: TyCtxt<'tcx>,
next_pos: BytePos,
ordered_span_viewables: &mut Peekable<impl Iterator<Item = &'b SpanViewable>>,
alt: bool,
layer: usize,
w: &mut W,
) -> io::Result<BytePos>
where
W: Write,
{
let span_viewable =
ordered_span_viewables.next().expect("ordered_span_viewables should have some");
if next_pos < span_viewable.span.lo() {
write_coverage_gap(tcx, next_pos, span_viewable.span.lo(), w)?;
}
let mut remaining_span = span_viewable.span;
let mut subalt = false;
loop {
let next_span_viewable = match ordered_span_viewables.peek() {
None => break,
Some(span_viewable) => *span_viewable,
};
if !next_span_viewable.span.overlaps(remaining_span) {
break;
}
write_span(
tcx,
remaining_span.until(next_span_viewable.span),
Some(span_viewable),
alt,
layer,
w,
)?;
let next_pos = write_span_viewables(
tcx,
next_span_viewable.span.lo(),
ordered_span_viewables,
subalt,
layer + 1,
w,
)?;
subalt = !subalt;
if next_pos < remaining_span.hi() {
remaining_span = remaining_span.with_lo(next_pos);
} else {
return Ok(next_pos);
}
}
write_span(tcx, remaining_span, Some(span_viewable), alt, layer, w)
}
fn write_coverage_gap<'tcx, W>(
tcx: TyCtxt<'tcx>,
lo: BytePos,
hi: BytePos,
w: &mut W,
) -> io::Result<BytePos>
where
W: Write,
{
write_span(tcx, Span::with_root_ctxt(lo, hi), None, false, 0, w)
}
fn write_span<'tcx, W>(
tcx: TyCtxt<'tcx>,
span: Span,
span_viewable: Option<&SpanViewable>,
alt: bool,
layer: usize,
w: &mut W,
) -> io::Result<BytePos>
where
W: Write,
{
let source_map = tcx.sess.source_map();
let snippet = source_map
.span_to_snippet(span)
.unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err));
let labeled_snippet = if let Some(SpanViewable { title, .. }) = span_viewable {
if span.is_empty() {
format!(r#"<span class="annotation">@{}</span>"#, title)
} else {
format!(r#"<span class="annotation">@{}:</span> {}"#, title, escape_html(&snippet))
}
} else {
snippet
};
let maybe_alt = if layer > 0 {
if alt { " odd" } else { " even" }
} else {
""
};
let maybe_tooltip = if let Some(SpanViewable { tooltip, .. }) = span_viewable {
format!(" title=\"{}\"", escape_attr(tooltip))
} else {
"".to_owned()
};
if layer == 1 {
write!(w, "<span>")?;
}
for (i, line) in labeled_snippet.lines().enumerate() {
if i > 0 {
write!(w, "{}", NEW_LINE_SPAN)?;
}
write!(
w,
r#"<span class="code{}" style="--layer: {}"{}>{}</span>"#,
maybe_alt, layer, maybe_tooltip, line
)?;
}
if layer == 1 {
write!(w, "</span>")?;
}
Ok(span.hi())
}
fn tooltip<'tcx>(
tcx: TyCtxt<'tcx>,
title: &str,
span: Span,
statements: Vec<Statement<'tcx>>,
terminator: &Option<Terminator<'tcx>>,
) -> String {
let source_map = tcx.sess.source_map();
let mut text = Vec::new();
text.push(format!("{}: {}:", title, &source_map.span_to_string(span)));
for statement in statements {
let source_range = source_range_no_file(tcx, &statement.source_info.span);
text.push(format!(
"\n{}{}: {}: {}",
TOOLTIP_INDENT,
source_range,
statement_kind_name(&statement),
format!("{:?}", statement)
));
}
if let Some(term) = terminator {
let source_range = source_range_no_file(tcx, &term.source_info.span);
text.push(format!(
"\n{}{}: {}: {:?}",
TOOLTIP_INDENT,
source_range,
terminator_kind_name(term),
term.kind
));
}
text.join("")
}
fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span {
let hir_id =
tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local"));
tcx.hir().span(hir_id)
}
fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> {
let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
tcx.hir().body(fn_body_id)
}
fn escape_html(s: &str) -> String {
s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
}
fn escape_attr(s: &str) -> String {
s.replace("&", "&amp;")
.replace("\"", "&quot;")
.replace("'", "&#39;")
.replace("<", "&lt;")
.replace(">", "&gt;")
}

View File

@ -10,7 +10,7 @@ use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, TokenKind};
use rustc_ast::util::classify;
use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacStmtStyle};
use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacCallStmt, MacStmtStyle};
use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID};
use rustc_errors::{Applicability, PResult};
use rustc_span::source_map::{BytePos, Span};
@ -107,7 +107,7 @@ impl<'a> Parser<'a> {
let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof
{
StmtKind::MacCall(P((mac, style, attrs)))
StmtKind::MacCall(P(MacCallStmt { mac, style, attrs }))
} else {
// Since none of the above applied, this is an expression statement macro.
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new());

View File

@ -867,6 +867,12 @@ pub struct ExternPreludeEntry<'a> {
pub introduced_by_item: bool,
}
/// Used for better errors for E0773
enum BuiltinMacroState {
NotYetSeen(SyntaxExtension),
AlreadySeen(Span),
}
/// The main resolver class.
///
/// This is the visitor that walks the whole crate.
@ -960,7 +966,7 @@ pub struct Resolver<'a> {
crate_loader: CrateLoader<'a>,
macro_names: FxHashSet<Ident>,
builtin_macros: FxHashMap<Symbol, SyntaxExtension>,
builtin_macros: FxHashMap<Symbol, BuiltinMacroState>,
registered_attrs: FxHashSet<Ident>,
registered_tools: FxHashSet<Ident>,
macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>,

View File

@ -3,7 +3,7 @@
use crate::imports::ImportResolver;
use crate::Namespace::*;
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy};
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy};
use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
use rustc_ast::{self as ast, NodeId};
@ -11,6 +11,7 @@ use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_pretty::pprust;
use rustc_attr::StabilityLevel;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
@ -166,7 +167,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
}
fn register_builtin_macro(&mut self, ident: Ident, ext: SyntaxExtension) {
if self.builtin_macros.insert(ident.name, ext).is_some() {
if self.builtin_macros.insert(ident.name, BuiltinMacroState::NotYetSeen(ext)).is_some() {
self.session
.span_err(ident.span, &format!("built-in macro `{}` was already defined", ident));
}
@ -1076,10 +1077,23 @@ impl<'a> Resolver<'a> {
if result.is_builtin {
// The macro was marked with `#[rustc_builtin_macro]`.
if let Some(ext) = self.builtin_macros.remove(&item.ident.name) {
if let Some(builtin_macro) = self.builtin_macros.get_mut(&item.ident.name) {
// The macro is a built-in, replace its expander function
// while still taking everything else from the source code.
result.kind = ext.kind;
// If we already loaded this builtin macro, give a better error message than 'no such builtin macro'.
match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) {
BuiltinMacroState::NotYetSeen(ext) => result.kind = ext.kind,
BuiltinMacroState::AlreadySeen(span) => {
struct_span_err!(
self.session,
item.span,
E0773,
"attempted to define built-in macro more than once"
)
.span_note(span, "previously defined here")
.emit();
}
}
} else {
let msg = format!("cannot find a built-in macro with name `{}`", item.ident);
self.session.span_err(item.span, &msg);

View File

@ -163,6 +163,21 @@ pub enum LtoCli {
Unspecified,
}
/// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
/// document highlighting each span of every statement (including terminators). `Terminator` and
/// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
/// computed span for the block, representing the entire range, covering the block's terminator and
/// all of its statements.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum MirSpanview {
/// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
Statement,
/// `-Z dump_mir_spanview=terminator`
Terminator,
/// `-Z dump_mir_spanview=block`
Block,
}
#[derive(Clone, PartialEq, Hash)]
pub enum LinkerPluginLto {
LinkerPlugin(PathBuf),

View File

@ -255,6 +255,7 @@ macro_rules! options {
pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
pub const parse_optimization_fuel: &str = "crate=integer";
pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
pub const parse_unpretty: &str = "`string` or `string=string`";
pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0";
pub const parse_lto: &str =
@ -551,6 +552,36 @@ macro_rules! options {
}
}
fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool {
if v.is_some() {
let mut bool_arg = None;
if parse_opt_bool(&mut bool_arg, v) {
*slot = if bool_arg.unwrap() {
Some(MirSpanview::Statement)
} else {
None
};
return true
}
}
let v = match v {
None => {
*slot = Some(MirSpanview::Statement);
return true;
}
Some(v) => v,
};
*slot = Some(match v.trim_end_matches("s") {
"statement" | "stmt" => MirSpanview::Statement,
"terminator" | "term" => MirSpanview::Terminator,
"block" | "basicblock" => MirSpanview::Block,
_ => return false,
});
true
}
fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
match v {
Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
@ -719,6 +750,9 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
"extra arguments to append to the linker invocation (space separated)"),
link_dead_code: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
"keep dead code at link time (useful for code coverage) (default: no)"),
link_self_contained: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
"control whether to link Rust provided C objects/libraries or rely
on C toolchain installed in the system"),
linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"system linker to link outputs with"),
linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
@ -849,6 +883,11 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"exclude the pass number when dumping MIR (used in tests) (default: no)"),
dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
"in addition to `.mir` files, create graphviz `.dot` files (default: no)"),
dump_mir_spanview: Option<MirSpanview> = (None, parse_mir_spanview, [UNTRACKED],
"in addition to `.mir` files, create `.html` files to view spans for \
all `statement`s (including terminators), only `terminator` spans, or \
computed `block` spans (one span encompassing a block's terminator and \
all statements)."),
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
"emit a section containing stack size metadata (default: no)"),
fewer_names: bool = (false, parse_bool, [TRACKED],
@ -894,9 +933,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"keep hygiene data after analysis (default: no)"),
link_native_libraries: bool = (true, parse_bool, [UNTRACKED],
"link native libraries in the linker invocation (default: yes)"),
link_self_contained: Option<bool> = (None, parse_opt_bool, [TRACKED],
"control whether to link Rust provided C objects/libraries or rely
on C toolchain installed in the system"),
link_only: bool = (false, parse_bool, [TRACKED],
"link the `.rlink` file generated by `-Z no-link` (default: no)"),
llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],

View File

@ -7,11 +7,9 @@
//! contain owned boxes or implement [`Drop`]), so the compiler considers
//! them cheap and safe to copy. For other types copies must be made
//! explicitly, by convention implementing the [`Clone`] trait and calling
//! the [`clone`][clone] method.
//! the [`clone`] method.
//!
//! [`Clone`]: trait.Clone.html
//! [clone]: trait.Clone.html#tymethod.clone
//! [`Drop`]: ../../std/ops/trait.Drop.html
//! [`clone`]: Clone::clone
//!
//! Basic usage example:
//!
@ -51,7 +49,9 @@
/// ## Derivable
///
/// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d
/// implementation of [`clone`] calls [`clone`] on each field.
/// implementation of [`Clone`] calls [`clone`] on each field.
///
/// [`clone`]: Clone::clone
///
/// For a generic struct, `#[derive]` implements `Clone` conditionally by adding bound `Clone` on
/// generic parameters.
@ -74,9 +74,6 @@
/// An example is a generic struct holding a function pointer. In this case, the
/// implementation of `Clone` cannot be `derive`d, but can be implemented as:
///
/// [`Copy`]: ../../std/marker/trait.Copy.html
/// [`clone`]: trait.Clone.html#tymethod.clone
///
/// ```
/// struct Generate<T>(fn() -> T);
///

View File

@ -135,7 +135,7 @@
//! methods like `nth` and `fold` if an iterator can compute them more efficiently without calling
//! `next`.
//!
//! # for Loops and IntoIterator
//! # `for` loops and `IntoIterator`
//!
//! Rust's `for` loop syntax is actually sugar for iterators. Here's a basic
//! example of `for`:

View File

@ -3078,6 +3078,7 @@ pub trait Iterator {
/// assert_eq!([1].iter().lt([1].iter()), false);
/// assert_eq!([1].iter().lt([1, 2].iter()), true);
/// assert_eq!([1, 2].iter().lt([1].iter()), false);
/// assert_eq!([1, 2].iter().lt([1, 2].iter()), false);
/// ```
#[stable(feature = "iter_order", since = "1.5.0")]
fn lt<I>(self, other: I) -> bool
@ -3098,6 +3099,7 @@ pub trait Iterator {
/// assert_eq!([1].iter().le([1].iter()), true);
/// assert_eq!([1].iter().le([1, 2].iter()), true);
/// assert_eq!([1, 2].iter().le([1].iter()), false);
/// assert_eq!([1, 2].iter().le([1, 2].iter()), true);
/// ```
#[stable(feature = "iter_order", since = "1.5.0")]
fn le<I>(self, other: I) -> bool
@ -3118,6 +3120,7 @@ pub trait Iterator {
/// assert_eq!([1].iter().gt([1].iter()), false);
/// assert_eq!([1].iter().gt([1, 2].iter()), false);
/// assert_eq!([1, 2].iter().gt([1].iter()), true);
/// assert_eq!([1, 2].iter().gt([1, 2].iter()), false);
/// ```
#[stable(feature = "iter_order", since = "1.5.0")]
fn gt<I>(self, other: I) -> bool
@ -3138,6 +3141,7 @@ pub trait Iterator {
/// assert_eq!([1].iter().ge([1].iter()), true);
/// assert_eq!([1].iter().ge([1, 2].iter()), false);
/// assert_eq!([1, 2].iter().ge([1].iter()), true);
/// assert_eq!([1, 2].iter().ge([1, 2].iter()), true);
/// ```
#[stable(feature = "iter_order", since = "1.5.0")]
fn ge<I>(self, other: I) -> bool

View File

@ -242,7 +242,7 @@ macro_rules! debug_assert_ne {
#[macro_export]
#[stable(feature = "matches_macro", since = "1.42.0")]
macro_rules! matches {
($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )?) => {
($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => {
match $expression {
$( $pattern )|+ $( if $guard )? => true,
_ => false

View File

@ -92,8 +92,6 @@ impl<'a> PanicInfo<'a> {
/// If the `panic!` macro from the `core` crate (not from `std`)
/// was used with a formatting string and some additional arguments,
/// returns that message ready to be used for example with [`fmt::write`]
///
/// [`fmt::write`]: ../fmt/fn.write.html
#[unstable(feature = "panic_info_message", issue = "66745")]
pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
self.message
@ -105,8 +103,6 @@ impl<'a> PanicInfo<'a> {
/// This method will currently always return [`Some`], but this may change
/// in future versions.
///
/// [`Some`]: ../../std/option/enum.Option.html#variant.Some
///
/// # Examples
///
/// ```should_panic
@ -153,10 +149,7 @@ impl fmt::Display for PanicInfo<'_> {
/// A struct containing information about the location of a panic.
///
/// This structure is created by the [`location`] method of [`PanicInfo`].
///
/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location
/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html
/// This structure is created by [`PanicInfo::location()`].
///
/// # Examples
///

View File

@ -238,6 +238,7 @@
#![feature(concat_idents)]
#![feature(const_cstr_unchecked)]
#![feature(const_fn_transmute)]
#![feature(const_ipv6)]
#![feature(const_raw_ptr_deref)]
#![feature(container_error_extra)]
#![feature(core_intrinsics)]

View File

@ -1102,8 +1102,9 @@ impl Ipv6Addr {
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(),
/// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn segments(&self) -> [u16; 8] {
pub const fn segments(&self) -> [u16; 8] {
// All elements in `s6_addr` must be big endian.
// SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`.
let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) };
@ -1135,9 +1136,10 @@ impl Ipv6Addr {
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false);
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[stable(since = "1.7.0", feature = "ip_17")]
pub fn is_unspecified(&self) -> bool {
self.segments() == [0, 0, 0, 0, 0, 0, 0, 0]
pub const fn is_unspecified(&self) -> bool {
u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets())
}
/// Returns [`true`] if this is a loopback address (::1).
@ -1155,9 +1157,10 @@ impl Ipv6Addr {
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false);
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[stable(since = "1.7.0", feature = "ip_17")]
pub fn is_loopback(&self) -> bool {
self.segments() == [0, 0, 0, 0, 0, 0, 0, 1]
pub const fn is_loopback(&self) -> bool {
u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
}
/// Returns [`true`] if the address appears to be globally routable.
@ -1182,7 +1185,8 @@ impl Ipv6Addr {
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false);
/// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
/// ```
pub fn is_global(&self) -> bool {
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
pub const fn is_global(&self) -> bool {
match self.multicast_scope() {
Some(Ipv6MulticastScope::Global) => true,
None => self.is_unicast_global(),
@ -1208,7 +1212,8 @@ impl Ipv6Addr {
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false);
/// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
/// ```
pub fn is_unique_local(&self) -> bool {
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
pub const fn is_unique_local(&self) -> bool {
(self.segments()[0] & 0xfe00) == 0xfc00
}
@ -1263,7 +1268,8 @@ impl Ipv6Addr {
/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
/// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
/// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
pub fn is_unicast_link_local_strict(&self) -> bool {
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
pub const fn is_unicast_link_local_strict(&self) -> bool {
(self.segments()[0] & 0xffff) == 0xfe80
&& (self.segments()[1] & 0xffff) == 0
&& (self.segments()[2] & 0xffff) == 0
@ -1320,7 +1326,8 @@ impl Ipv6Addr {
///
/// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
/// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
pub fn is_unicast_link_local(&self) -> bool {
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
pub const fn is_unicast_link_local(&self) -> bool {
(self.segments()[0] & 0xffc0) == 0xfe80
}
@ -1359,7 +1366,8 @@ impl Ipv6Addr {
/// addresses.
///
/// [RFC 3879]: https://tools.ietf.org/html/rfc3879
pub fn is_unicast_site_local(&self) -> bool {
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
pub const fn is_unicast_site_local(&self) -> bool {
(self.segments()[0] & 0xffc0) == 0xfec0
}
@ -1381,7 +1389,8 @@ impl Ipv6Addr {
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false);
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
/// ```
pub fn is_documentation(&self) -> bool {
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
pub const fn is_documentation(&self) -> bool {
(self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
}
@ -1416,7 +1425,8 @@ impl Ipv6Addr {
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false);
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true);
/// ```
pub fn is_unicast_global(&self) -> bool {
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
pub const fn is_unicast_global(&self) -> bool {
!self.is_multicast()
&& !self.is_loopback()
&& !self.is_unicast_link_local()
@ -1440,7 +1450,8 @@ impl Ipv6Addr {
/// );
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
/// ```
pub fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
if self.is_multicast() {
match self.segments()[0] & 0x000f {
1 => Some(Ipv6MulticastScope::InterfaceLocal),
@ -1472,8 +1483,9 @@ impl Ipv6Addr {
/// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true);
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[stable(since = "1.7.0", feature = "ip_17")]
pub fn is_multicast(&self) -> bool {
pub const fn is_multicast(&self) -> bool {
(self.segments()[0] & 0xff00) == 0xff00
}
@ -1498,7 +1510,8 @@ impl Ipv6Addr {
/// Some(Ipv4Addr::new(192, 10, 2, 255)));
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
/// ```
pub fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
match self.octets() {
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
Some(Ipv4Addr::new(a, b, c, d))
@ -1525,8 +1538,9 @@ impl Ipv6Addr {
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(),
/// Some(Ipv4Addr::new(0, 0, 0, 1)));
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_ipv4(&self) -> Option<Ipv4Addr> {
pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() {
let [a, b] = ab.to_be_bytes();
let [c, d] = cd.to_be_bytes();

View File

@ -1,7 +1,6 @@
#[doc(primitive = "bool")]
#[doc(alias = "true")]
#[doc(alias = "false")]
//
/// The boolean type.
///
/// The `bool` represents a value, which could only be either `true` or `false`. If you cast
@ -12,8 +11,8 @@
/// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc.,
/// which allow us to perform boolean operations using `&`, `|` and `!`.
///
/// `if` always demands a `bool` value. [`assert!`], being an important macro in testing,
/// checks whether an expression returns `true`.
/// `if` always demands a `bool` value. [`assert!`], which is an important macro in testing,
/// checks whether an expression returns `true` and panics if it isn't.
///
/// ```
/// let bool_val = true & false | false;
@ -194,14 +193,48 @@ mod prim_bool {}
/// # `!` and traits
///
/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl`
/// which doesn't `panic!`. As it turns out, most traits can have an `impl` for `!`. Take [`Debug`]
/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` where `!`
/// does not have an `impl` of `Trait` cannot diverge as their only possible code path. In other
/// words, they can't return `!` from every code path. As an example, this code doesn't compile:
///
/// ```compile_fail
/// use core::ops::Add;
///
/// fn foo() -> impl Add<u32> {
/// unimplemented!()
/// }
/// ```
///
/// But this code does:
///
/// ```
/// use core::ops::Add;
///
/// fn foo() -> impl Add<u32> {
/// if true {
/// unimplemented!()
/// } else {
/// 0
/// }
/// }
/// ```
///
/// The reason is that, in the first example, there are many possible types that `!` could coerce
/// to, because many types implement `Add<u32>`. However, in the second example,
/// the `else` branch returns a `0`, which the compiler infers from the return type to be of type
/// `u32`. Since `u32` is a concrete type, `!` can and will be coerced to it. See issue [#36375]
/// for more information on this quirk of `!`.
///
/// [#36375]: https://github.com/rust-lang/rust/issues/36375
///
/// As it turns out, though, most traits can have an `impl` for `!`. Take [`Debug`]
/// for example:
///
/// ```
/// #![feature(never_type)]
/// # use std::fmt;
/// # trait Debug {
/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
/// # }
/// impl Debug for ! {
/// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {

View File

@ -44,13 +44,13 @@ incremental builds the default is 256 which allows caching to be more granular.
## control-flow-guard
This flag controls whether LLVM enables the Windows [Control Flow
Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard)
platform security feature. This flag is currently ignored for non-Windows targets.
This flag controls whether LLVM enables the Windows [Control Flow
Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard)
platform security feature. This flag is currently ignored for non-Windows targets.
It takes one of the following values:
* `y`, `yes`, `on`, `checks`, or no value: enable Control Flow Guard.
* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this
* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this
should only be used for testing purposes as it does not provide security enforcement).
* `n`, `no`, `off`: do not enable Control Flow Guard (the default).
@ -200,6 +200,18 @@ the following values:
An example of when this flag might be useful is when trying to construct code coverage
metrics.
## link-self-contained
On targets that support it this flag controls whether the linker will use libraries and objects
shipped with Rust instead or those in the system.
It takes one of the following values:
* no value: rustc will use heuristic to disable self-contained mode if system has necessary tools.
* `y`, `yes`, `on`: use only libraries/objects shipped with Rust.
* `n`, `no`, or `off`: rely on the user or the linker to provide non-Rust libraries/objects.
This allows overriding cases when detection fails or user wants to use shipped libraries.
## linker
This flag controls which linker `rustc` invokes to link your code. It takes a

View File

@ -51,7 +51,7 @@ warning: missing documentation for a function
## missing_doc_code_examples
This lint is **allowed by default**. It detects when a documentation block
This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block
is missing a code example. For example:
```rust

View File

@ -1062,12 +1062,13 @@ themePicker.onblur = handleThemeButtonsBlur;
let content = format!(
"<h1 class='fqn'>\
<span class='in-band'>List of all crates</span>\
</h1><ul class='mod'>{}</ul>",
</h1>\
<ul class='crate mod'>{}</ul>",
krates
.iter()
.map(|s| {
format!(
"<li><a class=\"mod\" href=\"{}index.html\">{}</a></li>",
"<li><a class=\"crate mod\" href=\"{}index.html\">{}</a></li>",
ensure_trailing_slash(s),
s
)

View File

@ -178,6 +178,9 @@ pre {
.content span.externcrate, .content span.mod, .content a.mod {
color: #acccf9;
}
.content ul.crate a.crate {
font: 16px/1.6 "Fira Sans";
}
.content span.struct, .content a.struct {
color: #ffa0a5;
}

View File

@ -0,0 +1,5 @@
// Test spanview block output
// compile-flags: -Z dump-mir-spanview=block
// EMIT_MIR spanview_block.main.mir_map.0.html
fn main() {}

View File

@ -0,0 +1,5 @@
// Test spanview output (the default value for `-Z dump-mir-spanview` is "statement")
// compile-flags: -Z dump-mir-spanview
// EMIT_MIR spanview_statement.main.mir_map.0.html
fn main() {}

View File

@ -0,0 +1,5 @@
// Test spanview terminator output
// compile-flags: -Z dump-mir-spanview=terminator
// EMIT_MIR spanview_terminator.main.mir_map.0.html
fn main() {}

View File

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html>
<head>
<title>coverage_of_if_else - Code Regions</title>
<style>
.line {
counter-increment: line;
}
.line:before {
content: counter(line) ": ";
font-family: Menlo, Monaco, monospace;
font-style: italic;
width: 3.8em;
display: inline-block;
text-align: right;
filter: opacity(50%);
-webkit-user-select: none;
}
.code {
color: #dddddd;
background-color: #222222;
font-family: Menlo, Monaco, monospace;
line-height: 1.4em;
border-bottom: 2px solid #222222;
white-space: pre;
display: inline-block;
}
.odd {
background-color: #55bbff;
color: #223311;
}
.even {
background-color: #ee7756;
color: #551133;
}
.code {
--index: calc(var(--layer) - 1);
padding-top: calc(var(--index) * 0.15em);
filter:
hue-rotate(calc(var(--index) * 25deg))
saturate(calc(100% - (var(--index) * 2%)))
brightness(calc(100% - (var(--index) * 1.5%)));
}
.annotation {
color: #4444ff;
font-family: monospace;
font-style: italic;
display: none;
-webkit-user-select: none;
}
body:active .annotation {
/* requires holding mouse down anywhere on the page */
display: inline-block;
}
span:hover .annotation {
/* requires hover over a span ONLY on its first line */
display: inline-block;
}
</style>
</head>
<body>
<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="bb0: $DIR/spanview-block.rs:5:11: 5:13:
5:11-5:13: Assign: _0 = const ()
5:13-5:13: Goto: goto -&gt; bb2"><span class="annotation">@bb0:</span> {}</span></span><span><span class="code even" style="--layer: 1" title="bb2: $DIR/spanview-block.rs:5:13: 5:13:
5:13-5:13: Return: return"><span class="annotation">@bb2</span></span></span></span></div>
</body>
</html>

View File

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html>
<head>
<title>coverage_of_if_else - Code Regions</title>
<style>
.line {
counter-increment: line;
}
.line:before {
content: counter(line) ": ";
font-family: Menlo, Monaco, monospace;
font-style: italic;
width: 3.8em;
display: inline-block;
text-align: right;
filter: opacity(50%);
-webkit-user-select: none;
}
.code {
color: #dddddd;
background-color: #222222;
font-family: Menlo, Monaco, monospace;
line-height: 1.4em;
border-bottom: 2px solid #222222;
white-space: pre;
display: inline-block;
}
.odd {
background-color: #55bbff;
color: #223311;
}
.even {
background-color: #ee7756;
color: #551133;
}
.code {
--index: calc(var(--layer) - 1);
padding-top: calc(var(--index) * 0.15em);
filter:
hue-rotate(calc(var(--index) * 25deg))
saturate(calc(100% - (var(--index) * 2%)))
brightness(calc(100% - (var(--index) * 1.5%)));
}
.annotation {
color: #4444ff;
font-family: monospace;
font-style: italic;
display: none;
-webkit-user-select: none;
}
body:active .annotation {
/* requires holding mouse down anywhere on the page */
display: inline-block;
}
span:hover .annotation {
/* requires hover over a span ONLY on its first line */
display: inline-block;
}
</style>
</head>
<body>
<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="bb0[0]: $DIR/spanview-statement.rs:5:11: 5:13:
5:11-5:13: Assign: _0 = const ()"><span class="annotation">@bb0[0]:</span> {}</span></span><span><span class="code even" style="--layer: 1" title="bb0`Goto`: $DIR/spanview-statement.rs:5:13: 5:13:
5:13-5:13: Goto: goto -&gt; bb2"><span class="annotation">@bb0`Goto`</span></span></span><span><span class="code even" style="--layer: 1" title="bb2`Return`: $DIR/spanview-statement.rs:5:13: 5:13:
5:13-5:13: Return: return"><span class="annotation">@bb2`Return`</span></span></span></span></div>
</body>
</html>

View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html>
<head>
<title>coverage_of_if_else - Code Regions</title>
<style>
.line {
counter-increment: line;
}
.line:before {
content: counter(line) ": ";
font-family: Menlo, Monaco, monospace;
font-style: italic;
width: 3.8em;
display: inline-block;
text-align: right;
filter: opacity(50%);
-webkit-user-select: none;
}
.code {
color: #dddddd;
background-color: #222222;
font-family: Menlo, Monaco, monospace;
line-height: 1.4em;
border-bottom: 2px solid #222222;
white-space: pre;
display: inline-block;
}
.odd {
background-color: #55bbff;
color: #223311;
}
.even {
background-color: #ee7756;
color: #551133;
}
.code {
--index: calc(var(--layer) - 1);
padding-top: calc(var(--index) * 0.15em);
filter:
hue-rotate(calc(var(--index) * 25deg))
saturate(calc(100% - (var(--index) * 2%)))
brightness(calc(100% - (var(--index) * 1.5%)));
}
.annotation {
color: #4444ff;
font-family: monospace;
font-style: italic;
display: none;
-webkit-user-select: none;
}
body:active .annotation {
/* requires holding mouse down anywhere on the page */
display: inline-block;
}
span:hover .annotation {
/* requires hover over a span ONLY on its first line */
display: inline-block;
}
</style>
</head>
<body>
<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() {}</span><span><span class="code even" style="--layer: 1" title="bb0`Goto`: $DIR/spanview-terminator.rs:5:13: 5:13:
5:13-5:13: Goto: goto -&gt; bb2"><span class="annotation">@bb0`Goto`</span></span></span><span><span class="code even" style="--layer: 1" title="bb2`Return`: $DIR/spanview-terminator.rs:5:13: 5:13:
5:13-5:13: Return: return"><span class="annotation">@bb2`Return`</span></span></span></span></div>
</body>
</html>

View File

@ -6,6 +6,6 @@
// @has foo/../index.html
// @has - '//span[@class="in-band"]' 'List of all crates'
// @has - '//ul[@class="mod"]//a[@href="foo/index.html"]' 'foo'
// @has - '//ul[@class="mod"]//a[@href="all_item_types/index.html"]' 'all_item_types'
// @has - '//ul[@class="crate mod"]//a[@href="foo/index.html"]' 'foo'
// @has - '//ul[@class="crate mod"]//a[@href="all_item_types/index.html"]' 'all_item_types'
pub struct Foo;

View File

@ -0,0 +1,53 @@
// run-pass
#![feature(ip)]
#![feature(const_ipv6)]
use std::net::{Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
fn main() {
const IP_ADDRESS : Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST);
const SEGMENTS : [u16; 8] = IP_ADDRESS.segments();
assert_eq!(SEGMENTS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 1]);
const OCTETS : [u8; 16] = IP_ADDRESS.octets();
assert_eq!(OCTETS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 0 ,0 ,0 ,0 ,0 ,0 ,0, 0, 1]);
const IS_UNSPECIFIED : bool = IP_ADDRESS.is_unspecified();
assert!(!IS_UNSPECIFIED);
const IS_LOOPBACK : bool = IP_ADDRESS.is_loopback();
assert!(IS_LOOPBACK);
const IS_GLOBAL : bool = IP_ADDRESS.is_global();
assert!(!IS_GLOBAL);
const IS_UNIQUE_LOCAL : bool = IP_ADDRESS.is_unique_local();
assert!(!IS_UNIQUE_LOCAL);
const IS_UNICAST_LINK_LOCAL_STRICT : bool = IP_ADDRESS.is_unicast_link_local_strict();
assert!(!IS_UNICAST_LINK_LOCAL_STRICT);
const IS_UNICAST_LINK_LOCAL : bool = IP_ADDRESS.is_unicast_link_local();
assert!(!IS_UNICAST_LINK_LOCAL);
const IS_UNICAST_SITE_LOCAL : bool = IP_ADDRESS.is_unicast_site_local();
assert!(!IS_UNICAST_SITE_LOCAL);
const IS_DOCUMENTATION : bool = IP_ADDRESS.is_documentation();
assert!(!IS_DOCUMENTATION);
const IS_UNICAST_GLOBAL : bool = IP_ADDRESS.is_unicast_global();
assert!(!IS_UNICAST_GLOBAL);
const MULTICAST_SCOPE : Option<Ipv6MulticastScope> = IP_ADDRESS.multicast_scope();
assert_eq!(MULTICAST_SCOPE, None);
const IS_MULTICAST : bool = IP_ADDRESS.is_multicast();
assert!(!IS_MULTICAST);
const IP_V4 : Option<Ipv4Addr> = IP_ADDRESS.to_ipv4();
assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1));
}

View File

@ -0,0 +1,17 @@
// compile-flags:--crate-type lib
#![feature(decl_macro)]
#![feature(rustc_attrs)]
#[rustc_builtin_macro]
pub macro test($item:item) {
//~^ NOTE previously defined
/* compiler built-in */
}
mod inner {
#[rustc_builtin_macro]
pub macro test($item:item) {
//~^ ERROR attempted to define built-in macro more than once [E0773]
/* compiler built-in */
}
}

View File

@ -0,0 +1,21 @@
error[E0773]: attempted to define built-in macro more than once
--> $DIR/duplicate-builtin.rs:13:5
|
LL | / pub macro test($item:item) {
LL | |
LL | | /* compiler built-in */
LL | | }
| |_____^
|
note: previously defined here
--> $DIR/duplicate-builtin.rs:6:1
|
LL | / pub macro test($item:item) {
LL | |
LL | | /* compiler built-in */
LL | | }
| |_^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0773`.

View File

@ -1,4 +1,4 @@
// error-pattern: cannot find a built-in macro with name `line`
// error-pattern: attempted to define built-in macro more than once
#![feature(rustc_attrs)]
@ -6,7 +6,7 @@
macro_rules! unknown { () => () } //~ ERROR cannot find a built-in macro with name `unknown`
#[rustc_builtin_macro]
macro_rules! line { () => () }
macro_rules! line { () => () } //~ NOTE previously defined here
fn main() {
line!();

View File

@ -4,7 +4,7 @@ error: cannot find a built-in macro with name `unknown`
LL | macro_rules! unknown { () => () }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: cannot find a built-in macro with name `line`
error[E0773]: attempted to define built-in macro more than once
--> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
LL | / macro_rules! line {
@ -13,6 +13,13 @@ LL | | /* compiler built-in */
LL | | };
LL | | }
| |_____^
|
note: previously defined here
--> $DIR/unknown-builtin.rs:9:1
|
LL | macro_rules! line { () => () }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0773`.

View File

@ -1,6 +1,3 @@
#!///bin/bash
[allow(unused_variables)]
//~^^ ERROR expected `[`, found doc comment
// Doc comment is misinterpreted as a whitespace (regular comment) during shebang detection.
// Even if it wasn't, it would still result in an error, just a different one.
//~^ ERROR expected item, found `[`

View File

@ -1,8 +1,8 @@
error: expected `[`, found doc comment `///bin/bash`
--> $DIR/shebang-doc-comment.rs:1:3
error: expected item, found `[`
--> $DIR/shebang-doc-comment.rs:2:1
|
LL | #!///bin/bash
| ^^^^^^^^^^^ expected `[`
LL | [allow(unused_variables)]
| ^ expected item
error: aborting due to previous error

View File

@ -191,7 +191,7 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool {
(Item(l), Item(r)) => eq_item(l, r, eq_item_kind),
(Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r),
(Empty, Empty) => true,
(MacCall(l), MacCall(r)) => l.1 == r.1 && eq_mac_call(&l.0, &r.0) && over(&l.2, &r.2, |l, r| eq_attr(l, r)),
(MacCall(l), MacCall(r)) => l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)),
_ => false,
}
}