Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
37 changes: 37 additions & 0 deletions compiler/rustc_abi/src/extern_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,43 @@ impl ExternAbi {
| Self::Swift => true,
}
}

/// Returns whether safe functions with this ABI implement the `Fn` traits.
/// `false` only for uncallable or internal ABIs.
pub fn is_fn_trait_compatible(self) -> bool {
match self {
ExternAbi::C { .. }
| ExternAbi::System { .. }
| ExternAbi::Rust
| ExternAbi::RustCold
| ExternAbi::RustPreserveNone
| ExternAbi::RustTail
| ExternAbi::EfiApi
| ExternAbi::Swift
| ExternAbi::Aapcs { .. }
| ExternAbi::CmseNonSecureCall
| ExternAbi::CmseNonSecureEntry
| ExternAbi::Cdecl { .. }
| ExternAbi::Stdcall { .. }
| ExternAbi::Fastcall { .. }
| ExternAbi::Thiscall { .. }
| ExternAbi::Vectorcall { .. }
| ExternAbi::SysV64 { .. }
| ExternAbi::Win64 { .. } => true,
ExternAbi::RustCall
| ExternAbi::RustInvalid
| ExternAbi::LlvmIntrinsic
| ExternAbi::Custom
| ExternAbi::GpuKernel
| ExternAbi::PtxKernel
| ExternAbi::AvrInterrupt
| ExternAbi::AvrNonBlockingInterrupt
| ExternAbi::Msp430Interrupt
| ExternAbi::RiscvInterruptM
| ExternAbi::RiscvInterruptS
| ExternAbi::X86Interrupt => false,
}
}
}

pub fn all_names() -> Vec<&'static str> {
Expand Down
59 changes: 35 additions & 24 deletions compiler/rustc_attr_parsing/src/attributes/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ use crate::diagnostics::{
DocAutoCfgHideShowExpectsList, DocAutoCfgHideShowNoIdentBeforeValues,
DocAutoCfgHideShowUnexpectedItem, DocAutoCfgHideShowUnexpectedItemAfterValues,
DocAutoCfgHideShowValuesMix, DocAutoCfgWrongLiteral, DocInlineConflict, DocInlineOnlyUse,
DocKeywordNotKeyword, DocTestLiteral, DocTestTakesList, DocTestUnknown, DocUnknownAny,
DocUnknownInclude, DocUnknownPasses, DocUnknownPlugins, DocUnknownSpotlight, ExpectedNameValue,
ExpectedNoArgs, IllFormedAttributeInput, MalformedDoc, UnusedDuplicate,
DocKeywordNotKeyword, DocReserved, DocTestLiteral, DocTestTakesList, DocTestUnknown,
DocUnknownAny, DocUnknownInclude, DocUnknownPasses, DocUnknownPlugins, DocUnknownSpotlight,
ExpectedNameValue, ExpectedNoArgs, IllFormedAttributeInput, MalformedDoc, UnusedDuplicate,
};
use crate::parser::{
ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser,
Expand Down Expand Up @@ -647,13 +647,11 @@ impl DocParser {
no_args_and_not_crate_level!(search_unbox)
}
Some(sym::rust_logo) => {
// FIXME: Only feature gated at the crate level (!!)
if cx.target == Target::Crate {
gated!(
rustdoc_internals,
"the `#[doc(rust_logo)]` attribute is used for Rust branding"
);
}
gated!(
rustdoc_internals,
"the `#[doc(rust_logo)]` attribute is used for Rust branding"
);

no_args_and_crate_level!(rust_logo)
}
Some(sym::auto_cfg) => {
Expand Down Expand Up @@ -688,18 +686,30 @@ impl DocParser {
let span = path.span();
cx.emit_lint(INVALID_DOC_ATTRIBUTES, DocUnknownSpotlight { sugg_span: span }, span);
}
Some(sym::include) if let Some(nv) = args.as_name_value() => {
let inner = match cx.attr_style {
AttrStyle::Outer => "",
AttrStyle::Inner => "!",
};
let value = nv.value_as_lit().symbol;
let span = path.span();
cx.emit_lint(
INVALID_DOC_ATTRIBUTES,
DocUnknownInclude { inner, value, sugg: (span, Applicability::MaybeIncorrect) },
span,
);
Some(sym::include) => {
if let Some(nv) = args.as_name_value() {
let inner = match cx.attr_style {
AttrStyle::Outer => "",
AttrStyle::Inner => "!",
};
let value = nv.value_as_lit().symbol;
let span = path.span();
cx.emit_lint(
INVALID_DOC_ATTRIBUTES,
DocUnknownInclude {
inner,
value,
sugg: (span, Applicability::MaybeIncorrect),
},
span,
);
} else {
cx.emit_lint(
INVALID_DOC_ATTRIBUTES,
DocUnknownAny { name: sym::include },
path.span(),
);
}
}
Some(name @ (sym::passes | sym::no_default_passes)) => {
let span = path.span();
Expand All @@ -714,13 +724,14 @@ impl DocParser {
cx.emit_lint(INVALID_DOC_ATTRIBUTES, DocUnknownPlugins { label_span: span }, span);
}
Some(name) => {
cx.emit_lint(INVALID_DOC_ATTRIBUTES, DocUnknownAny { name }, path.span());
cx.emit_err(DocReserved { name, span: path.span() });
}
None => {
let full_name =
path.segments().map(|s| s.as_str()).intersperse("::").collect::<String>();
let name = Symbol::intern(&full_name);
cx.emit_lint(INVALID_DOC_ATTRIBUTES, DocUnknownAny { name }, path.span());

cx.emit_err(DocReserved { name, span: path.span() });
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_attr_parsing/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,14 @@ pub(crate) struct DocUnknownAny {
pub name: Symbol,
}

#[derive(Diagnostic)]
#[diag("reserved `doc` attribute `{$name}`")]
pub(crate) struct DocReserved {
pub name: Symbol,
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("expected boolean for `#[doc(auto_cfg = ...)]`")]
pub(crate) struct DocAutoCfgWrongLiteral;
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_const_eval/src/check_consts/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,10 @@ impl<C> DebugWithContext<C> for State {

impl JoinSemiLattice for State {
fn join(&mut self, other: &Self) -> bool {
self.qualif.join(&other.qualif) || self.borrow.join(&other.borrow)
// `join` has a side-effect on `self` so make sure we always call it on both fields.
let a = self.qualif.join(&other.qualif);
let b = self.borrow.join(&other.borrow);
a || b
}
}

Expand Down
36 changes: 18 additions & 18 deletions compiler/rustc_error_codes/src/error_codes/E0373.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,48 @@ A captured variable in a closure may not live long enough.
Erroneous code example:

```compile_fail,E0373
fn foo() -> Box<dyn Fn(u32) -> u32> {
let x = 0u32;
Box::new(|y| x + y)
fn foo() -> Box<dyn Fn(usize) -> usize> {
let arr = [42_u32; 17];
Box::new(|y| arr.len() + y)
}
```

This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure as shown in the previous code example.

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be
unsafe.
Notice that `arr` is stack-allocated by `foo()`. Within the closure, it is used
by reference (as the receiver of the `.len()` call). This means that once
`foo()` returns, `arr` no longer exists. An attempt to access `list` within the
closure would thus be unsafe.

Another situation where this might be encountered is when spawning threads:

```compile_fail,E0373
fn foo() {
let x = 0u32;
let y = 1u32;
let arr = [42_u32; 17];
let y = 1usize;

let thr = std::thread::spawn(|| {
x + y
arr.len() + y
});
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behavior is safe, and so won't let us do it.
Since our new thread runs in parallel, the stack frame containing `arr` may well
have disappeared by the time we try to use them. Even if we call `thr.join()`
within foo (which blocks until `thr` has completed, ensuring the stack frame
won't disappear), we will not succeed: the compiler cannot prove that this
behavior is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<dyn Fn(u32) -> u32> {
let x = 0u32;
Box::new(move |y| x + y)
fn foo() -> Box<dyn Fn(usize) -> usize> {
let arr = [42_u32; 17];
Box::new(move |y| arr.len() + y)
}
```

Expand Down
Loading
Loading