Auto merge of #126655 - jieyouxu:rollup-z7k1k6l, r=jieyouxu

Rollup of 10 pull requests

Successful merges:

 - #124135 (delegation: Implement glob delegation)
 - #125078 (fix: break inside async closure has incorrect span for enclosing closure)
 - #125293 (Place tail expression behind terminating scope)
 - #126422 (Suggest using a standalone doctest for non-local impl defs)
 - #126493 (safe transmute: support non-ZST, variantful, uninhabited enums)
 - #126504 (Sync fuchsia test runner with clang test runner)
 - #126558 (hir_typeck: be more conservative in making "note caller chooses ty param" note)
 - #126586 (Add `@badboy` and `@BlackHoleFox` as Mac Catalyst maintainers)
 - #126615 (Add `rustc-ice*` to `.gitignore`)
 - #126632 (Replace `move||` with `move ||`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-06-19 01:49:20 +00:00
commit a1ca449981
76 changed files with 2188 additions and 654 deletions

1
.gitignore vendored
View File

@ -52,6 +52,7 @@ build/
/src/tools/x/target
# Created by default with `src/ci/docker/run.sh`
/obj/
/rustc-ice*
## Temporary files
*~

View File

@ -3161,13 +3161,16 @@ pub struct Delegation {
pub path: Path,
pub rename: Option<Ident>,
pub body: Option<P<Block>>,
/// The item was expanded from a glob delegation item.
pub from_glob: bool,
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct DelegationMac {
pub qself: Option<P<QSelf>>,
pub prefix: Path,
pub suffixes: ThinVec<(Ident, Option<Ident>)>,
// Some for list delegation, and None for glob delegation.
pub suffixes: Option<ThinVec<(Ident, Option<Ident>)>>,
pub body: Option<P<Block>>,
}
@ -3294,7 +3297,7 @@ pub enum ItemKind {
///
/// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
Delegation(Box<Delegation>),
/// A list delegation item (`reuse prefix::{a, b, c}`).
/// A list or glob delegation item (`reuse prefix::{a, b, c}`, `reuse prefix::*`).
/// Treated similarly to a macro call and expanded early.
DelegationMac(Box<DelegationMac>),
}
@ -3375,7 +3378,7 @@ pub enum AssocItemKind {
MacCall(P<MacCall>),
/// An associated delegation item.
Delegation(Box<Delegation>),
/// An associated delegation item list.
/// An associated list or glob delegation item.
DelegationMac(Box<DelegationMac>),
}

View File

@ -1162,7 +1162,14 @@ impl NoopVisitItemKind for ItemKind {
}
ItemKind::MacCall(m) => vis.visit_mac_call(m),
ItemKind::MacroDef(def) => vis.visit_macro_def(def),
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
ItemKind::Delegation(box Delegation {
id,
qself,
path,
rename,
body,
from_glob: _,
}) => {
vis.visit_id(id);
vis.visit_qself(qself);
vis.visit_path(path);
@ -1176,12 +1183,14 @@ impl NoopVisitItemKind for ItemKind {
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
vis.visit_qself(qself);
vis.visit_path(prefix);
if let Some(suffixes) = suffixes {
for (ident, rename) in suffixes {
vis.visit_ident(ident);
if let Some(rename) = rename {
vis.visit_ident(rename);
}
}
}
if let Some(body) = body {
vis.visit_block(body);
}
@ -1218,7 +1227,14 @@ impl NoopVisitItemKind for AssocItemKind {
visit_opt(ty, |ty| visitor.visit_ty(ty));
}
AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
AssocItemKind::Delegation(box Delegation {
id,
qself,
path,
rename,
body,
from_glob: _,
}) => {
visitor.visit_id(id);
visitor.visit_qself(qself);
visitor.visit_path(path);
@ -1232,12 +1248,14 @@ impl NoopVisitItemKind for AssocItemKind {
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
visitor.visit_qself(qself);
visitor.visit_path(prefix);
if let Some(suffixes) = suffixes {
for (ident, rename) in suffixes {
visitor.visit_ident(ident);
if let Some(rename) = rename {
visitor.visit_ident(rename);
}
}
}
if let Some(body) = body {
visitor.visit_block(body);
}

View File

@ -408,7 +408,14 @@ impl WalkItemKind for ItemKind {
}
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)),
ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
ItemKind::Delegation(box Delegation {
id,
qself,
path,
rename,
body,
from_glob: _,
}) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
@ -421,12 +428,14 @@ impl WalkItemKind for ItemKind {
try_visit!(visitor.visit_ty(&qself.ty));
}
try_visit!(visitor.visit_path(prefix, item.id));
if let Some(suffixes) = suffixes {
for (ident, rename) in suffixes {
visitor.visit_ident(*ident);
if let Some(rename) = rename {
visitor.visit_ident(*rename);
}
}
}
visit_opt!(visitor, visit_block, body);
}
}
@ -837,7 +846,14 @@ impl WalkItemKind for AssocItemKind {
AssocItemKind::MacCall(mac) => {
try_visit!(visitor.visit_mac_call(mac));
}
AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => {
AssocItemKind::Delegation(box Delegation {
id,
qself,
path,
rename,
body,
from_glob: _,
}) => {
if let Some(qself) = qself {
try_visit!(visitor.visit_ty(&qself.ty));
}
@ -850,12 +866,14 @@ impl WalkItemKind for AssocItemKind {
try_visit!(visitor.visit_ty(&qself.ty));
}
try_visit!(visitor.visit_path(prefix, item.id));
if let Some(suffixes) = suffixes {
for (ident, rename) in suffixes {
visitor.visit_ident(*ident);
if let Some(rename) = rename {
visitor.visit_ident(*rename);
}
}
}
visit_opt!(visitor, visit_block, body);
}
}

View File

@ -1716,24 +1716,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `mut iter => { ... }`
let iter_arm = self.arm(iter_pat, loop_expr);
let into_iter_expr = match loop_kind {
let match_expr = match loop_kind {
ForLoopKind::For => {
// `::std::iter::IntoIterator::into_iter(<head>)`
self.expr_call_lang_item_fn(
let into_iter_expr = self.expr_call_lang_item_fn(
head_span,
hir::LangItem::IntoIterIntoIter,
arena_vec![self; head],
)
}
// ` unsafe { Pin::new_unchecked(&mut into_async_iter(<head>)) }`
ForLoopKind::ForAwait => {
// `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)`
let iter = self.expr_call_lang_item_fn(
head_span,
hir::LangItem::IntoAsyncIterIntoIter,
arena_vec![self; head],
);
let iter = self.expr_mut_addr_of(head_span, iter);
self.arena.alloc(self.expr_match(
for_span,
into_iter_expr,
arena_vec![self; iter_arm],
hir::MatchSource::ForLoopDesugar,
))
}
// `match into_async_iter(<head>) { ref mut iter => match unsafe { Pin::new_unchecked(iter) } { ... } }`
ForLoopKind::ForAwait => {
let iter_ident = iter;
let (async_iter_pat, async_iter_pat_id) =
self.pat_ident_binding_mode(head_span, iter_ident, hir::BindingMode::REF_MUT);
let iter = self.expr_ident_mut(head_span, iter_ident, async_iter_pat_id);
// `Pin::new_unchecked(...)`
let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut(
head_span,
@ -1742,17 +1746,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
));
// `unsafe { ... }`
let iter = self.arena.alloc(self.expr_unsafe(iter));
iter
}
};
let match_expr = self.arena.alloc(self.expr_match(
let inner_match_expr = self.arena.alloc(self.expr_match(
for_span,
into_iter_expr,
iter,
arena_vec![self; iter_arm],
hir::MatchSource::ForLoopDesugar,
));
// `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)`
let iter = self.expr_call_lang_item_fn(
head_span,
hir::LangItem::IntoAsyncIterIntoIter,
arena_vec![self; head],
);
let iter_arm = self.arm(async_iter_pat, inner_match_expr);
self.arena.alloc(self.expr_match(
for_span,
iter,
arena_vec![self; iter_arm],
hir::MatchSource::ForLoopDesugar,
))
}
};
// This is effectively `{ let _result = ...; _result }`.
// The construct was introduced in #21984 and is necessary to make sure that
// temporaries in the `head` expression are dropped and do not leak to the

View File

@ -1319,6 +1319,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
};
let closure_id = coroutine_kind.closure_id();
let span = if let FnRetTy::Default(span) = decl.output
&& matches!(coroutine_source, rustc_hir::CoroutineSource::Closure)
{
body_span.with_lo(span.lo())
} else {
body_span
};
let coroutine_expr = self.make_desugared_coroutine_expr(
// The default capture mode here is by-ref. Later on during upvar analysis,
// we will force the captured arguments to by-move, but for async closures,
@ -1327,7 +1335,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
CaptureBy::Ref,
closure_id,
None,
body_span,
span,
desugaring_kind,
coroutine_source,
mkbody,

View File

@ -9,6 +9,12 @@ use rustc_ast::ptr::P;
use rustc_ast::ModKind;
use rustc_span::symbol::Ident;
enum DelegationKind<'a> {
Single,
List(&'a [(Ident, Option<Ident>)]),
Glob,
}
fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
}
@ -387,7 +393,7 @@ impl<'a> State<'a> {
&item.vis,
&deleg.qself,
&deleg.path,
None,
DelegationKind::Single,
&deleg.body,
),
ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
@ -395,7 +401,7 @@ impl<'a> State<'a> {
&item.vis,
&deleg.qself,
&deleg.prefix,
Some(&deleg.suffixes),
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
&deleg.body,
),
}
@ -579,7 +585,7 @@ impl<'a> State<'a> {
vis,
&deleg.qself,
&deleg.path,
None,
DelegationKind::Single,
&deleg.body,
),
ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
@ -587,20 +593,20 @@ impl<'a> State<'a> {
vis,
&deleg.qself,
&deleg.prefix,
Some(&deleg.suffixes),
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
&deleg.body,
),
}
self.ann.post(self, AnnNode::SubItem(id))
}
pub(crate) fn print_delegation(
fn print_delegation(
&mut self,
attrs: &[ast::Attribute],
vis: &ast::Visibility,
qself: &Option<P<ast::QSelf>>,
path: &ast::Path,
suffixes: Option<&[(Ident, Option<Ident>)]>,
kind: DelegationKind<'_>,
body: &Option<P<ast::Block>>,
) {
if body.is_some() {
@ -614,7 +620,9 @@ impl<'a> State<'a> {
} else {
self.print_path(path, false, 0);
}
if let Some(suffixes) = suffixes {
match kind {
DelegationKind::Single => {}
DelegationKind::List(suffixes) => {
self.word("::");
self.word("{");
for (i, (ident, rename)) in suffixes.iter().enumerate() {
@ -630,6 +638,11 @@ impl<'a> State<'a> {
}
self.word("}");
}
DelegationKind::Glob => {
self.word("::");
self.word("*");
}
}
if let Some(body) = body {
self.nbsp();
self.print_block_with_attrs(body, attrs);

View File

@ -241,7 +241,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
variant_index: VariantIdx,
) -> InterpResult<'tcx, Option<(ScalarInt, usize)>> {
match self.layout_of(ty)?.variants {
abi::Variants::Single { .. } => Ok(None),
abi::Variants::Single { .. } => {
// The tag of a `Single` enum is like the tag of the niched
// variant: there's no tag as the discriminant is encoded
// entirely implicitly. If `write_discriminant` ever hits this
// case, we do a "validation read" to ensure the the right
// discriminant is encoded implicitly, so any attempt to write
// the wrong discriminant for a `Single` enum will reliably
// result in UB.
Ok(None)
}
abi::Variants::Multiple {
tag_encoding: TagEncoding::Direct,

View File

@ -35,8 +35,8 @@ expand_duplicate_matcher_binding = duplicate matcher binding
.label = duplicate binding
.label2 = previous binding
expand_empty_delegation_list =
empty list delegation is not supported
expand_empty_delegation_mac =
empty {$kind} delegation is not supported
expand_expected_paren_or_brace =
expected `(` or `{"{"}`, found `{$token}`
@ -58,6 +58,9 @@ expand_feature_removed =
.label = feature has been removed
.reason = {$reason}
expand_glob_delegation_outside_impls =
glob delegation is only supported in impls
expand_helper_attribute_name_invalid =
`{$name}` cannot be a name of derive helper attribute

View File

@ -357,6 +357,10 @@ where
}
}
pub trait GlobDelegationExpander {
fn expand(&self, ecx: &mut ExtCtxt<'_>) -> ExpandResult<Vec<(Ident, Option<Ident>)>, ()>;
}
// Use a macro because forwarding to a simple function has type system issues
macro_rules! make_stmts_default {
($me:expr) => {
@ -714,6 +718,9 @@ pub enum SyntaxExtensionKind {
/// The produced AST fragment is appended to the input AST fragment.
Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>,
),
/// A glob delegation.
GlobDelegation(Box<dyn GlobDelegationExpander + sync::DynSync + sync::DynSend>),
}
/// A struct representing a macro definition in "lowered" form ready for expansion.
@ -748,7 +755,9 @@ impl SyntaxExtension {
/// Returns which kind of macro calls this syntax extension.
pub fn macro_kind(&self) -> MacroKind {
match self.kind {
SyntaxExtensionKind::Bang(..) | SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang,
SyntaxExtensionKind::Bang(..)
| SyntaxExtensionKind::LegacyBang(..)
| SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang,
SyntaxExtensionKind::Attr(..)
| SyntaxExtensionKind::LegacyAttr(..)
| SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
@ -922,6 +931,32 @@ impl SyntaxExtension {
SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr, edition)
}
pub fn glob_delegation(
trait_def_id: DefId,
impl_def_id: LocalDefId,
edition: Edition,
) -> SyntaxExtension {
struct GlobDelegationExpanderImpl {
trait_def_id: DefId,
impl_def_id: LocalDefId,
}
impl GlobDelegationExpander for GlobDelegationExpanderImpl {
fn expand(
&self,
ecx: &mut ExtCtxt<'_>,
) -> ExpandResult<Vec<(Ident, Option<Ident>)>, ()> {
match ecx.resolver.glob_delegation_suffixes(self.trait_def_id, self.impl_def_id) {
Ok(suffixes) => ExpandResult::Ready(suffixes),
Err(Indeterminate) if ecx.force_mode => ExpandResult::Ready(Vec::new()),
Err(Indeterminate) => ExpandResult::Retry(()),
}
}
}
let expander = GlobDelegationExpanderImpl { trait_def_id, impl_def_id };
SyntaxExtension::default(SyntaxExtensionKind::GlobDelegation(Box::new(expander)), edition)
}
pub fn expn_data(
&self,
parent: LocalExpnId,
@ -1030,6 +1065,16 @@ pub trait ResolverExpand {
/// Tools registered with `#![register_tool]` and used by tool attributes and lints.
fn registered_tools(&self) -> &RegisteredTools;
/// Mark this invocation id as a glob delegation.
fn register_glob_delegation(&mut self, invoc_id: LocalExpnId);
/// Names of specific methods to which glob delegation expands.
fn glob_delegation_suffixes(
&mut self,
trait_def_id: DefId,
impl_def_id: LocalDefId,
) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate>;
}
pub trait LintStoreExpand {

View File

@ -435,8 +435,16 @@ pub struct ExpectedParenOrBrace<'a> {
}
#[derive(Diagnostic)]
#[diag(expand_empty_delegation_list)]
pub(crate) struct EmptyDelegationList {
#[diag(expand_empty_delegation_mac)]
pub(crate) struct EmptyDelegationMac {
#[primary_span]
pub span: Span,
pub kind: String,
}
#[derive(Diagnostic)]
#[diag(expand_glob_delegation_outside_impls)]
pub(crate) struct GlobDelegationOutsideImpls {
#[primary_span]
pub span: Span,
}

View File

@ -1,8 +1,8 @@
use crate::base::*;
use crate::config::StripUnconfigured;
use crate::errors::{
EmptyDelegationList, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported,
RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind,
EmptyDelegationMac, GlobDelegationOutsideImpls, IncompleteParse, RecursionLimitReached,
RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind,
};
use crate::mbe::diagnostics::annotate_err_with_kind;
use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
@ -343,6 +343,9 @@ pub enum InvocationKind {
is_const: bool,
item: Annotatable,
},
GlobDelegation {
item: P<ast::AssocItem>,
},
}
impl InvocationKind {
@ -370,6 +373,7 @@ impl Invocation {
InvocationKind::Bang { span, .. } => *span,
InvocationKind::Attr { attr, .. } => attr.span,
InvocationKind::Derive { path, .. } => path.span,
InvocationKind::GlobDelegation { item } => item.span,
}
}
@ -378,6 +382,7 @@ impl Invocation {
InvocationKind::Bang { span, .. } => span,
InvocationKind::Attr { attr, .. } => &mut attr.span,
InvocationKind::Derive { path, .. } => &mut path.span,
InvocationKind::GlobDelegation { item } => &mut item.span,
}
}
}
@ -800,6 +805,36 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
_ => unreachable!(),
},
InvocationKind::GlobDelegation { item } => {
let AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() };
let suffixes = match ext {
SyntaxExtensionKind::GlobDelegation(expander) => match expander.expand(self.cx)
{
ExpandResult::Ready(suffixes) => suffixes,
ExpandResult::Retry(()) => {
// Reassemble the original invocation for retrying.
return ExpandResult::Retry(Invocation {
kind: InvocationKind::GlobDelegation { item },
..invoc
});
}
},
SyntaxExtensionKind::LegacyBang(..) => {
let msg = "expanded a dummy glob delegation";
let guar = self.cx.dcx().span_delayed_bug(span, msg);
return ExpandResult::Ready(fragment_kind.dummy(span, guar));
}
_ => unreachable!(),
};
type Node = AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>;
let single_delegations = build_single_delegations::<Node>(
self.cx, deleg, &item, &suffixes, item.span, true,
);
fragment_kind.expect_from_annotatables(
single_delegations.map(|item| Annotatable::ImplItem(P(item))),
)
}
})
}
@ -1067,7 +1102,7 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
unreachable!()
}
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
None
}
fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind {
@ -1126,7 +1161,7 @@ impl InvocationCollectorNode for P<ast::Item> {
_ => unreachable!(),
}
}
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
match &self.kind {
ItemKind::DelegationMac(deleg) => Some((deleg, self)),
_ => None,
@ -1270,7 +1305,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
_ => unreachable!(),
}
}
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
match &self.wrapped.kind {
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
_ => None,
@ -1311,7 +1346,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
_ => unreachable!(),
}
}
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
match &self.wrapped.kind {
AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
_ => None,
@ -1487,7 +1522,7 @@ impl InvocationCollectorNode for ast::Stmt {
};
(mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No })
}
fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
match &self.kind {
StmtKind::Item(item) => match &item.kind {
ItemKind::DelegationMac(deleg) => Some((deleg, item)),
@ -1684,6 +1719,44 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag>
}
}
fn build_single_delegations<'a, Node: InvocationCollectorNode>(
ecx: &ExtCtxt<'_>,
deleg: &'a ast::DelegationMac,
item: &'a ast::Item<Node::ItemKind>,
suffixes: &'a [(Ident, Option<Ident>)],
item_span: Span,
from_glob: bool,
) -> impl Iterator<Item = ast::Item<Node::ItemKind>> + 'a {
if suffixes.is_empty() {
// Report an error for now, to avoid keeping stem for resolution and
// stability checks.
let kind = String::from(if from_glob { "glob" } else { "list" });
ecx.dcx().emit_err(EmptyDelegationMac { span: item.span, kind });
}
suffixes.iter().map(move |&(ident, rename)| {
let mut path = deleg.prefix.clone();
path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args: None });
ast::Item {
attrs: item.attrs.clone(),
id: ast::DUMMY_NODE_ID,
span: if from_glob { item_span } else { ident.span },
vis: item.vis.clone(),
ident: rename.unwrap_or(ident),
kind: Node::delegation_item_kind(Box::new(ast::Delegation {
id: ast::DUMMY_NODE_ID,
qself: deleg.qself.clone(),
path,
rename,
body: deleg.body.clone(),
from_glob,
})),
tokens: None,
}
})
}
struct InvocationCollector<'a, 'b> {
cx: &'a mut ExtCtxt<'b>,
invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>,
@ -1702,6 +1775,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
let expn_id = LocalExpnId::fresh_empty();
if matches!(kind, InvocationKind::GlobDelegation { .. }) {
// In resolver we need to know which invocation ids are delegations early,
// before their `ExpnData` is filled.
self.cx.resolver.register_glob_delegation(expn_id);
}
let vis = kind.placeholder_visibility();
self.invocations.push((
Invocation {
@ -1734,6 +1812,14 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
self.collect(kind, InvocationKind::Attr { attr, pos, item, derives })
}
fn collect_glob_delegation(
&mut self,
item: P<ast::AssocItem>,
kind: AstFragmentKind,
) -> AstFragment {
self.collect(kind, InvocationKind::GlobDelegation { item })
}
/// If `item` is an attribute invocation, remove the attribute and return it together with
/// its position and derives following it. We have to collect the derives in order to resolve
/// legacy derive helpers (helpers written before derives that introduce them).
@ -1901,37 +1987,27 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
Node::post_flat_map_node_collect_bang(&mut res, add_semicolon);
res
}
None if let Some((deleg, item)) = node.delegation_list() => {
if deleg.suffixes.is_empty() {
// Report an error for now, to avoid keeping stem for resolution and
// stability checks.
self.cx.dcx().emit_err(EmptyDelegationList { span: item.span });
None if let Some((deleg, item)) = node.delegation() => {
let Some(suffixes) = &deleg.suffixes else {
let item = match node.to_annotatable() {
Annotatable::ImplItem(item) => item,
ann @ (Annotatable::Item(_)
| Annotatable::TraitItem(_)
| Annotatable::Stmt(_)) => {
let span = ann.span();
self.cx.dcx().emit_err(GlobDelegationOutsideImpls { span });
return Default::default();
}
_ => unreachable!(),
};
return self.collect_glob_delegation(item, Node::KIND).make_ast::<Node>();
};
Node::flatten_outputs(deleg.suffixes.iter().map(|&(ident, rename)| {
let mut path = deleg.prefix.clone();
path.segments.push(ast::PathSegment {
ident,
id: ast::DUMMY_NODE_ID,
args: None,
});
let mut item = Node::from_item(ast::Item {
attrs: item.attrs.clone(),
id: ast::DUMMY_NODE_ID,
span: ident.span,
vis: item.vis.clone(),
ident: rename.unwrap_or(ident),
kind: Node::delegation_item_kind(Box::new(ast::Delegation {
id: ast::DUMMY_NODE_ID,
qself: deleg.qself.clone(),
path,
rename,
body: deleg.body.clone(),
})),
tokens: None,
});
let single_delegations = build_single_delegations::<Node>(
self.cx, deleg, item, suffixes, item.span, false,
);
Node::flatten_outputs(single_delegations.map(|item| {
let mut item = Node::from_item(item);
assign_id!(self, item.node_id_mut(), || item.noop_flat_map(self))
}))
}
@ -1983,7 +2059,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
self.collect_bang(mac, Node::KIND).make_ast::<Node>()
})
}
None if node.delegation_list().is_some() => unreachable!(),
None if node.delegation().is_some() => unreachable!(),
None => {
assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
}

View File

@ -588,6 +588,8 @@ declare_features! (
(incomplete, return_type_notation, "1.70.0", Some(109417)),
/// Allows `extern "rust-cold"`.
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
/// Shortern the tail expression lifetime
(unstable, shorter_tail_lifetimes, "1.79.0", Some(123739)),
/// Allows the use of SIMD types in functions declared in `extern` blocks.
(unstable, simd_ffi, "1.0.0", Some(27731)),
/// Allows specialization of implementations (RFC 1210).

View File

@ -6,7 +6,6 @@
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
use rustc_ast::visit::visit_opt;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@ -168,7 +167,14 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement),
}
}
visit_opt!(visitor, visit_expr, &blk.expr);
if let Some(tail_expr) = blk.expr {
if visitor.tcx.features().shorter_tail_lifetimes
&& blk.span.edition().at_least_rust_2024()
{
visitor.terminating_scopes.insert(tail_expr.hir_id.local_id);
}
visitor.visit_expr(tail_expr);
}
}
visitor.cx = prev_cx;

View File

@ -859,10 +859,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
// Only point to return type if the expected type is the return type, as if they
// are not, the expectation must have been caused by something else.
debug!("return type {:?}", hir_ty);
debug!(?hir_ty, "return type");
let ty = self.lowerer().lower_ty(hir_ty);
debug!("return type {:?}", ty);
debug!("expected type {:?}", expected);
debug!(?ty, "return type (lowered)");
debug!(?expected, "expected type");
let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into());
let ty = Binder::bind_with_vars(ty, bound_vars);
let ty = self.normalize(hir_ty.span, ty);
@ -873,7 +873,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected,
});
self.try_suggest_return_impl_trait(err, expected, found, fn_id);
self.note_caller_chooses_ty_for_ty_param(err, expected, found);
self.try_note_caller_chooses_ty_for_ty_param(err, expected, found);
return true;
}
}
@ -883,19 +883,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
fn note_caller_chooses_ty_for_ty_param(
fn try_note_caller_chooses_ty_for_ty_param(
&self,
diag: &mut Diag<'_>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
) {
if let ty::Param(expected_ty_as_param) = expected.kind() {
// Only show the note if:
// 1. `expected` ty is a type parameter;
// 2. The `expected` type parameter does *not* occur in the return expression type. This can
// happen for e.g. `fn foo<T>(t: &T) -> T { t }`, where `expected` is `T` but `found` is
// `&T`. Saying "the caller chooses a type for `T` which can be different from `&T`" is
// "well duh" and is only confusing and not helpful.
let ty::Param(expected_ty_as_param) = expected.kind() else {
return;
};
if found.contains(expected) {
return;
}
diag.subdiagnostic(errors::NoteCallerChoosesTyForTyParam {
ty_param_name: expected_ty_as_param.name,
found_ty: found,
});
}
}
/// check whether the return type is a generic type with a trait bound
/// only suggest this if the generic param is not present in the arguments

View File

@ -22,7 +22,7 @@ use std::ops::Deref;
/// e.g. closures defined within the function. For example:
/// ```ignore (illustrative)
/// fn foo() {
/// bar(move|| { ... })
/// bar(move || { ... })
/// }
/// ```
/// Here, the function `foo()` and the closure passed to

View File

@ -549,6 +549,7 @@ lint_non_local_definitions_impl = non-local `impl` definition, `impl` blocks sho
.without_trait = methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl`
.with_trait = an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl`
.bounds = `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type
.doctest = make this doc-test a standalone test with its own `fn main() {"{"} ... {"}"}`
.exception = items in an anonymous const item (`const _: () = {"{"} ... {"}"}`) are treated as in the same scope as the anonymous const's declaration
.const_anon = use a const-anon item to suppress this lint
.macro_to_change = the {$macro_kind} `{$macro_to_change}` defines the non-local `impl`, and may need to be changed

View File

@ -1358,6 +1358,7 @@ pub enum NonLocalDefinitionsDiag {
cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>,
const_anon: Option<Option<Span>>,
move_to: Option<(Span, Vec<Span>)>,
doctest: bool,
may_remove: Option<(Span, String)>,
has_trait: bool,
self_ty_str: String,
@ -1368,8 +1369,7 @@ pub enum NonLocalDefinitionsDiag {
depth: u32,
body_kind_descr: &'static str,
body_name: String,
help: Option<()>,
doctest_help: Option<()>,
doctest: bool,
cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>,
},
}
@ -1384,6 +1384,7 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
cargo_update,
const_anon,
move_to,
doctest,
may_remove,
has_trait,
self_ty_str,
@ -1422,6 +1423,9 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
}
diag.span_help(ms, fluent::lint_non_local_definitions_impl_move_help);
}
if doctest {
diag.help(fluent::lint_doctest);
}
if let Some((span, part)) = may_remove {
diag.arg("may_remove_part", part);
@ -1451,8 +1455,7 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
depth,
body_kind_descr,
body_name,
help,
doctest_help,
doctest,
cargo_update,
} => {
diag.primary_message(fluent::lint_non_local_definitions_macro_rules);
@ -1460,11 +1463,10 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
diag.arg("body_kind_descr", body_kind_descr);
diag.arg("body_name", body_name);
if let Some(()) = help {
diag.help(fluent::lint_help);
}
if let Some(()) = doctest_help {
if doctest {
diag.help(fluent::lint_help_doctest);
} else {
diag.help(fluent::lint_help);
}
diag.note(fluent::lint_non_local);

View File

@ -111,6 +111,12 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
}
};
// determining if we are in a doctest context can't currently be determined
// by the code itself (there are no specific attributes), but fortunately rustdoc
// sets a perma-unstable env var for libtest so we just reuse that for now
let is_at_toplevel_doctest =
|| self.body_depth == 2 && std::env::var("UNSTABLE_RUSTDOC_TEST_PATH").is_ok();
match item.kind {
ItemKind::Impl(impl_) => {
// The RFC states:
@ -191,29 +197,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
None
};
let mut collector = PathCollector { paths: Vec::new() };
collector.visit_ty(&impl_.self_ty);
if let Some(of_trait) = &impl_.of_trait {
collector.visit_trait_ref(of_trait);
}
collector.visit_generics(&impl_.generics);
let mut may_move: Vec<Span> = collector
.paths
.into_iter()
.filter_map(|path| {
if let Some(did) = path.res.opt_def_id()
&& did_has_local_parent(did, cx.tcx, parent, parent_parent)
{
Some(cx.tcx.def_span(did))
} else {
None
}
})
.collect();
may_move.sort();
may_move.dedup();
let const_anon = matches!(parent_def_kind, DefKind::Const | DefKind::Static { .. })
.then_some(span_for_const_anon_suggestion);
@ -248,6 +231,33 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
} else {
None
};
let (doctest, move_to) = if is_at_toplevel_doctest() {
(true, None)
} else {
let mut collector = PathCollector { paths: Vec::new() };
collector.visit_ty(&impl_.self_ty);
if let Some(of_trait) = &impl_.of_trait {
collector.visit_trait_ref(of_trait);
}
collector.visit_generics(&impl_.generics);
let mut may_move: Vec<Span> = collector
.paths
.into_iter()
.filter_map(|path| {
if let Some(did) = path.res.opt_def_id()
&& did_has_local_parent(did, cx.tcx, parent, parent_parent)
{
Some(cx.tcx.def_span(did))
} else {
None
}
})
.collect();
may_move.sort();
may_move.dedup();
let move_to = if may_move.is_empty() {
ms.push_span_label(
cx.tcx.def_span(parent),
@ -258,6 +268,9 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
Some((cx.tcx.def_span(parent), may_move))
};
(false, move_to)
};
let macro_to_change =
if let ExpnKind::Macro(kind, name) = item.span.ctxt().outer_expn_data().kind {
Some((name.to_string(), kind.descr()))
@ -279,6 +292,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
self_ty_str,
of_trait_str,
move_to,
doctest,
may_remove,
has_trait: impl_.of_trait.is_some(),
macro_to_change,
@ -288,12 +302,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
ItemKind::Macro(_macro, MacroKind::Bang)
if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) =>
{
// determining we if are in a doctest context can't currently be determined
// by the code it-self (no specific attrs), but fortunatly rustdoc sets a
// perma-unstable env for libtest so we just re-use that env for now
let is_at_toplevel_doctest =
self.body_depth == 2 && std::env::var("UNSTABLE_RUSTDOC_TEST_PATH").is_ok();
cx.emit_span_lint(
NON_LOCAL_DEFINITIONS,
item.span,
@ -304,8 +312,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
.map(|s| s.to_ident_string())
.unwrap_or_else(|| "<unnameable>".to_string()),
cargo_update: cargo_update(),
help: (!is_at_toplevel_doctest).then_some(()),
doctest_help: is_at_toplevel_doctest.then_some(()),
doctest: is_at_toplevel_doctest(),
},
)
}

View File

@ -2699,12 +2699,13 @@ pub(crate) struct SingleColonImportPath {
#[derive(Diagnostic)]
#[diag(parse_bad_item_kind)]
#[help]
pub(crate) struct BadItemKind {
#[primary_span]
pub span: Span,
pub descr: &'static str,
pub ctx: &'static str,
#[help]
pub help: Option<()>,
}
#[derive(Diagnostic)]

View File

@ -707,15 +707,25 @@ impl<'a> Parser<'a> {
};
let (ident, item_kind) = if self.eat(&token::PathSep) {
let (suffixes, _) = self.parse_delim_comma_seq(Delimiter::Brace, |p| {
Ok((p.parse_path_segment_ident()?, rename(p)?))
})?;
let suffixes = if self.eat(&token::BinOp(token::Star)) {
None
} else {
let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?));
Some(self.parse_delim_comma_seq(Delimiter::Brace, parse_suffix)?.0)
};
let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? };
(Ident::empty(), ItemKind::DelegationMac(Box::new(deleg)))
} else {
let rename = rename(self)?;
let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);
let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body: body(self)? };
let deleg = Delegation {
id: DUMMY_NODE_ID,
qself,
path,
rename,
body: body(self)?,
from_glob: false,
};
(ident, ItemKind::Delegation(Box::new(deleg)))
};
@ -1237,7 +1247,11 @@ impl<'a> Parser<'a> {
// FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`)
let span = self.psess.source_map().guess_head_span(span);
let descr = kind.descr();
self.dcx().emit_err(errors::BadItemKind { span, descr, ctx });
let help = match kind {
ItemKind::DelegationMac(deleg) if deleg.suffixes.is_none() => None,
_ => Some(()),
};
self.dcx().emit_err(errors::BadItemKind { span, descr, ctx, help });
None
}

View File

@ -19,6 +19,7 @@ use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
use rustc_attr as attr;
use rustc_data_structures::sync::Lrc;
use rustc_expand::base::ResolverExpand;
use rustc_expand::expand::AstFragment;
use rustc_hir::def::{self, *};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
@ -1358,6 +1359,14 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
self.visit_invoc_in_module(item.id);
}
AssocCtxt::Impl => {
let invoc_id = item.id.placeholder_to_expn_id();
if !self.r.glob_delegation_invoc_ids.contains(&invoc_id) {
self.r
.impl_unexpanded_invocations
.entry(self.r.invocation_parent(invoc_id))
.or_default()
.insert(invoc_id);
}
self.visit_invoc(item.id);
}
}
@ -1379,18 +1388,21 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
self.r.feed_visibility(feed, vis);
}
if ctxt == AssocCtxt::Trait {
let ns = match item.kind {
AssocItemKind::Const(..)
| AssocItemKind::Delegation(..)
| AssocItemKind::Fn(..) => ValueNS,
AssocItemKind::Const(..) | AssocItemKind::Delegation(..) | AssocItemKind::Fn(..) => {
ValueNS
}
AssocItemKind::Type(..) => TypeNS,
AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above
};
if ctxt == AssocCtxt::Trait {
let parent = self.parent_scope.module;
let expansion = self.parent_scope.expansion;
self.r.define(parent, item.ident, ns, (self.res(def_id), vis, item.span, expansion));
} else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) {
let impl_def_id = self.r.tcx.local_parent(local_def_id);
let key = BindingKey::new(item.ident.normalize_to_macros_2_0(), ns);
self.r.impl_binding_keys.entry(impl_def_id).or_default().insert(key);
}
visit::walk_assoc_item(self, item, ctxt);

View File

@ -144,8 +144,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
}
ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
ItemKind::Use(..) => return visit::walk_item(self, i),
ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
ItemKind::DelegationMac(..) => unreachable!(),
ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
return self.visit_macro_invoc(i.id);
}
};
let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span);
@ -294,8 +295,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
AssocItemKind::Fn(..) | AssocItemKind::Delegation(..) => DefKind::AssocFn,
AssocItemKind::Const(..) => DefKind::AssocConst,
AssocItemKind::Type(..) => DefKind::AssocTy,
AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
AssocItemKind::DelegationMac(..) => unreachable!(),
AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
return self.visit_macro_invoc(i.id);
}
};
let def = self.create_def(i.id, i.ident.name, def_kind, i.span);

View File

@ -1089,7 +1089,7 @@ pub struct Resolver<'a, 'tcx> {
single_segment_macro_resolutions:
Vec<(Ident, MacroKind, ParentScope<'a>, Option<NameBinding<'a>>)>,
multi_segment_macro_resolutions:
Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>, Option<Res>)>,
Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>, Option<Res>, Namespace)>,
builtin_attrs: Vec<(Ident, ParentScope<'a>)>,
/// `derive(Copy)` marks items they are applied to so they are treated specially later.
/// Derive macros cannot modify the item themselves and have to store the markers in the global
@ -1163,6 +1163,15 @@ pub struct Resolver<'a, 'tcx> {
doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>,
doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>,
all_macro_rules: FxHashMap<Symbol, Res>,
/// Invocation ids of all glob delegations.
glob_delegation_invoc_ids: FxHashSet<LocalExpnId>,
/// Analogue of module `unexpanded_invocations` but in trait impls, excluding glob delegations.
/// Needed because glob delegations wait for all other neighboring macros to expand.
impl_unexpanded_invocations: FxHashMap<LocalDefId, FxHashSet<LocalExpnId>>,
/// Simplified analogue of module `resolutions` but in trait impls, excluding glob delegations.
/// Needed because glob delegations exclude explicitly defined names.
impl_binding_keys: FxHashMap<LocalDefId, FxHashSet<BindingKey>>,
}
/// Nothing really interesting here; it just provides memory for the rest of the crate.
@ -1504,6 +1513,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
doc_link_traits_in_scope: Default::default(),
all_macro_rules: Default::default(),
delegation_fn_sigs: Default::default(),
glob_delegation_invoc_ids: Default::default(),
impl_unexpanded_invocations: Default::default(),
impl_binding_keys: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);

View File

@ -5,7 +5,7 @@ use crate::errors::CannotDetermineMacroResolution;
use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope};
use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive};
use crate::Namespace::*;
use crate::{BuiltinMacroState, Determinacy, MacroData, Used};
use crate::{BindingKey, BuiltinMacroState, Determinacy, MacroData, Used};
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
use rustc_ast::expand::StrippedCfgItem;
@ -198,6 +198,11 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope);
parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
if let Some(unexpanded_invocations) =
self.impl_unexpanded_invocations.get_mut(&self.invocation_parent(expansion))
{
unexpanded_invocations.remove(&expansion);
}
}
fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind) {
@ -262,15 +267,21 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
}
};
let (path, kind, inner_attr, derives) = match invoc.kind {
InvocationKind::Attr { ref attr, ref derives, .. } => (
&attr.get_normal_item().path,
MacroKind::Attr,
attr.style == ast::AttrStyle::Inner,
self.arenas.alloc_ast_paths(derives),
),
InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, false, &[][..]),
InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, false, &[][..]),
let (mut derives, mut inner_attr, mut deleg_impl) = (&[][..], false, None);
let (path, kind) = match invoc.kind {
InvocationKind::Attr { ref attr, derives: ref attr_derives, .. } => {
derives = self.arenas.alloc_ast_paths(attr_derives);
inner_attr = attr.style == ast::AttrStyle::Inner;
(&attr.get_normal_item().path, MacroKind::Attr)
}
InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang),
InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive),
InvocationKind::GlobDelegation { ref item } => {
let ast::AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() };
deleg_impl = Some(self.invocation_parent(invoc_id));
// It is sufficient to consider glob delegation a bang macro for now.
(&deleg.prefix, MacroKind::Bang)
}
};
// Derives are not included when `invocations` are collected, so we have to add them here.
@ -286,10 +297,11 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
node_id,
force,
soft_custom_inner_attributes_gate(path, invoc),
deleg_impl,
)?;
let span = invoc.span();
let def_id = res.opt_def_id();
let def_id = if deleg_impl.is_some() { None } else { res.opt_def_id() };
invoc_id.set_expn_data(
ext.expn_data(
parent_scope.expansion,
@ -452,6 +464,45 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
fn registered_tools(&self) -> &RegisteredTools {
self.registered_tools
}
fn register_glob_delegation(&mut self, invoc_id: LocalExpnId) {
self.glob_delegation_invoc_ids.insert(invoc_id);
}
fn glob_delegation_suffixes(
&mut self,
trait_def_id: DefId,
impl_def_id: LocalDefId,
) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate> {
let target_trait = self.expect_module(trait_def_id);
if !target_trait.unexpanded_invocations.borrow().is_empty() {
return Err(Indeterminate);
}
// FIXME: Instead of waiting try generating all trait methods, and pruning
// the shadowed ones a bit later, e.g. when all macro expansion completes.
// Pros: expansion will be stuck less (but only in exotic cases), the implementation may be
// less hacky.
// Cons: More code is generated just to be deleted later, deleting already created `DefId`s
// may be nontrivial.
if let Some(unexpanded_invocations) = self.impl_unexpanded_invocations.get(&impl_def_id)
&& !unexpanded_invocations.is_empty()
{
return Err(Indeterminate);
}
let mut idents = Vec::new();
target_trait.for_each_child(self, |this, ident, ns, _binding| {
// FIXME: Adjust hygiene for idents from globs, like for glob imports.
if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id)
&& overriding_keys.contains(&BindingKey::new(ident.normalize_to_macros_2_0(), ns))
{
// The name is overridden, do not produce it from the glob delegation.
} else {
idents.push((ident, None));
}
});
Ok(idents)
}
}
impl<'a, 'tcx> Resolver<'a, 'tcx> {
@ -468,15 +519,40 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
node_id: NodeId,
force: bool,
soft_custom_inner_attributes_gate: bool,
deleg_impl: Option<LocalDefId>,
) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
{
let (ext, res) = match self.resolve_macro_or_delegation_path(
path,
Some(kind),
parent_scope,
true,
force,
deleg_impl,
) {
Ok((Some(ext), res)) => (ext, res),
Ok((None, res)) => (self.dummy_ext(kind), res),
Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
Err(Determinacy::Undetermined) => return Err(Indeterminate),
};
// Everything below is irrelevant to glob delegation, take a shortcut.
if deleg_impl.is_some() {
if !matches!(res, Res::Err | Res::Def(DefKind::Trait, _)) {
self.dcx().emit_err(MacroExpectedFound {
span: path.span,
expected: "trait",
article: "a",
found: res.descr(),
macro_path: &pprust::path_to_string(path),
remove_surrounding_derive: None,
add_as_non_derive: None,
});
return Ok((self.dummy_ext(kind), Res::Err));
}
return Ok((ext, res));
}
// Report errors for the resolved macro.
for segment in &path.segments {
if let Some(args) = &segment.args {
@ -605,12 +681,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope: &ParentScope<'a>,
trace: bool,
force: bool,
) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
self.resolve_macro_or_delegation_path(path, kind, parent_scope, trace, force, None)
}
fn resolve_macro_or_delegation_path(
&mut self,
path: &ast::Path,
kind: Option<MacroKind>,
parent_scope: &ParentScope<'a>,
trace: bool,
force: bool,
deleg_impl: Option<LocalDefId>,
) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
let path_span = path.span;
let mut path = Segment::from_path(path);
// Possibly apply the macro helper hack
if kind == Some(MacroKind::Bang)
if deleg_impl.is_none()
&& kind == Some(MacroKind::Bang)
&& path.len() == 1
&& path[0].ident.span.ctxt().outer_expn_data().local_inner_macros
{
@ -618,13 +707,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
path.insert(0, Segment::from_ident(root));
}
let res = if path.len() > 1 {
let res = match self.maybe_resolve_path(&path, Some(MacroNS), parent_scope) {
let res = if deleg_impl.is_some() || path.len() > 1 {
let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS };
let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope) {
PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res),
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
PathResult::NonModule(..)
| PathResult::Indeterminate
| PathResult::Failed { .. } => Err(Determinacy::Determined),
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
Ok(module.res().unwrap())
}
PathResult::Module(..) => unreachable!(),
};
@ -636,6 +729,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
kind,
*parent_scope,
res.ok(),
ns,
));
}
@ -670,7 +764,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
res
};
res.map(|res| (self.get_macro(res).map(|macro_data| macro_data.ext.clone()), res))
let res = res?;
let ext = match deleg_impl {
Some(impl_def_id) => match res {
def::Res::Def(DefKind::Trait, def_id) => {
let edition = self.tcx.sess.edition();
Some(Lrc::new(SyntaxExtension::glob_delegation(def_id, impl_def_id, edition)))
}
_ => None,
},
None => self.get_macro(res).map(|macro_data| macro_data.ext.clone()),
};
Ok((ext, res))
}
pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) {
@ -706,14 +811,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
};
let macro_resolutions = mem::take(&mut self.multi_segment_macro_resolutions);
for (mut path, path_span, kind, parent_scope, initial_res) in macro_resolutions {
for (mut path, path_span, kind, parent_scope, initial_res, ns) in macro_resolutions {
// FIXME: Path resolution will ICE if segment IDs present.
for seg in &mut path {
seg.id = None;
}
match self.resolve_path(
&path,
Some(MacroNS),
Some(ns),
&parent_scope,
Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
None,
@ -721,6 +826,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
check_consistency(self, &path, path_span, kind, initial_res, res)
}
// This may be a trait for glob delegation expansions.
PathResult::Module(ModuleOrUniformRoot::Module(module)) => check_consistency(
self,
&path,
path_span,
kind,
initial_res,
module.res().unwrap(),
),
path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
let mut suggestion = None;
let (span, label, module) =

View File

@ -1678,6 +1678,7 @@ symbols! {
shadow_call_stack,
shl,
shl_assign,
shorter_tail_lifetimes,
should_panic,
shr,
shr_assign,

View File

@ -341,37 +341,29 @@ pub(crate) mod rustc {
// We consider three kinds of enums, each demanding a different
// treatment of their layout computation:
// 1. enums that are uninhabited
// 2. enums for which all but one variant is uninhabited
// 3. enums with multiple inhabited variants
// 1. enums that are uninhabited ZSTs
// 2. enums that delegate their layout to a variant
// 3. enums with multiple variants
match layout.variants() {
_ if layout.abi.is_uninhabited() => {
// Uninhabited enums are usually (always?) zero-sized. In
// the (unlikely?) event that an uninhabited enum is
// non-zero-sized, this assert will trigger an ICE, and this
// code should be modified such that a `layout.size` amount
// of uninhabited bytes is returned instead.
//
// Uninhabited enums are currently implemented such that
// their layout is described with `Variants::Single`, even
// though they don't necessarily have a 'single' variant to
// defer to. That said, we don't bother specifically
// matching on `Variants::Single` in this arm because the
// behavioral principles here remain true even if, for
// whatever reason, the compiler describes an uninhabited
// enum with `Variants::Multiple`.
assert_eq!(layout.size, Size::ZERO);
Variants::Single { .. }
if layout.abi.is_uninhabited() && layout.size == Size::ZERO =>
{
// The layout representation of uninhabited, ZST enums is
// defined to be like that of the `!` type, as opposed of a
// typical enum. Consequently, they cannot be descended into
// as if they typical enums. We therefore special-case this
// scenario and simply return an uninhabited `Tree`.
Ok(Self::uninhabited())
}
Variants::Single { index } => {
// `Variants::Single` on non-uninhabited enums denotes that
// `Variants::Single` on enums with variants denotes that
// the enum delegates its layout to the variant at `index`.
layout_of_variant(*index)
}
Variants::Multiple { tag_field, .. } => {
// `Variants::Multiple` denotes an enum with multiple
// inhabited variants. The layout of such an enum is the
// disjunction of the layouts of its tagged variants.
// variants. The layout of such an enum is the disjunction
// of the layouts of its tagged variants.
// For enums (but not coroutines), the tag field is
// currently always the first field of the layout.

View File

@ -183,7 +183,7 @@
//!
//! let spinlock_clone = Arc::clone(&spinlock);
//!
//! let thread = thread::spawn(move|| {
//! let thread = thread::spawn(move || {
//! spinlock_clone.store(0, Ordering::Release);
//! });
//!

View File

@ -20,7 +20,7 @@ use crate::sync::{Condvar, Mutex};
/// let c = Arc::clone(&barrier);
/// // The same messages will be printed together.
/// // You will NOT see any interleaving.
/// handles.push(thread::spawn(move|| {
/// handles.push(thread::spawn(move || {
/// println!("before wait");
/// c.wait();
/// println!("after wait");
@ -115,7 +115,7 @@ impl Barrier {
/// let c = Arc::clone(&barrier);
/// // The same messages will be printed together.
/// // You will NOT see any interleaving.
/// handles.push(thread::spawn(move|| {
/// handles.push(thread::spawn(move || {
/// println!("before wait");
/// c.wait();
/// println!("after wait");

View File

@ -88,7 +88,7 @@ impl WaitTimeoutResult {
/// let pair2 = Arc::clone(&pair);
///
/// // Inside of our lock, spawn a new thread, and then wait for it to start.
/// thread::spawn(move|| {
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
@ -166,7 +166,7 @@ impl Condvar {
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move|| {
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
@ -221,7 +221,7 @@ impl Condvar {
/// let pair = Arc::new((Mutex::new(true), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move|| {
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut pending = lock.lock().unwrap();
/// *pending = false;
@ -280,7 +280,7 @@ impl Condvar {
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move|| {
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
@ -352,7 +352,7 @@ impl Condvar {
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move|| {
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
@ -420,7 +420,7 @@ impl Condvar {
/// let pair = Arc::new((Mutex::new(true), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move|| {
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut pending = lock.lock().unwrap();
/// *pending = false;
@ -484,7 +484,7 @@ impl Condvar {
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move|| {
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
@ -524,7 +524,7 @@ impl Condvar {
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = Arc::clone(&pair);
///
/// thread::spawn(move|| {
/// thread::spawn(move || {
/// let (lock, cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;

View File

@ -51,7 +51,7 @@
//!
//! // Create a simple streaming channel
//! let (tx, rx) = channel();
//! thread::spawn(move|| {
//! thread::spawn(move || {
//! tx.send(10).unwrap();
//! });
//! assert_eq!(rx.recv().unwrap(), 10);
@ -69,7 +69,7 @@
//! let (tx, rx) = channel();
//! for i in 0..10 {
//! let tx = tx.clone();
//! thread::spawn(move|| {
//! thread::spawn(move || {
//! tx.send(i).unwrap();
//! });
//! }
@ -99,7 +99,7 @@
//! use std::sync::mpsc::sync_channel;
//!
//! let (tx, rx) = sync_channel::<i32>(0);
//! thread::spawn(move|| {
//! thread::spawn(move || {
//! // This will wait for the parent thread to start receiving
//! tx.send(53).unwrap();
//! });
@ -510,7 +510,7 @@ pub enum TrySendError<T> {
/// let (sender, receiver) = channel();
///
/// // Spawn off an expensive computation
/// thread::spawn(move|| {
/// thread::spawn(move || {
/// # fn expensive_computation() {}
/// sender.send(expensive_computation()).unwrap();
/// });
@ -561,7 +561,7 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
/// // this returns immediately
/// sender.send(1).unwrap();
///
/// thread::spawn(move|| {
/// thread::spawn(move || {
/// // this will block until the previous message has been received
/// sender.send(2).unwrap();
/// });

View File

@ -62,7 +62,7 @@ use crate::fmt;
/// FOO.set(2);
///
/// // each thread starts out with the initial value of 1
/// let t = thread::spawn(move|| {
/// let t = thread::spawn(move || {
/// assert_eq!(FOO.get(), 1);
/// FOO.set(3);
/// });

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,8 @@ Apple Mac Catalyst targets.
## Target maintainers
- [@badboy](https://github.com/badboy)
- [@BlackHoleFox](https://github.com/BlackHoleFox)
- [@madsmtm](https://github.com/madsmtm)
## Requirements

View File

@ -0,0 +1 @@
pub trait Trait {}

View File

@ -0,0 +1,31 @@
//@ check-fail
//@ edition:2018
//@ failure-status: 101
//@ aux-build:pub_trait.rs
//@ compile-flags: --test --test-args --test-threads=1
//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
#![doc(test(attr(deny(non_local_definitions))))]
#![doc(test(attr(allow(dead_code))))]
/// This will produce a warning:
/// ```rust,no_run
/// # extern crate pub_trait;
/// # use pub_trait::Trait;
///
/// struct Local;
/// impl Trait for &Local {}
/// ```
///
/// But this shoudln't produce a warning:
/// ```rust,no_run
/// # extern crate pub_trait;
/// # use pub_trait::Trait;
///
/// struct Local;
/// impl Trait for &Local {}
///
/// # fn main() {}
/// ```
pub fn doctest() {}

View File

@ -0,0 +1,37 @@
running 2 tests
test $DIR/non-local-defs-impl.rs - doctest (line 13) - compile ... FAILED
test $DIR/non-local-defs-impl.rs - doctest (line 22) - compile ... ok
failures:
---- $DIR/non-local-defs-impl.rs - doctest (line 13) stdout ----
error: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/non-local-defs-impl.rs:18:1
|
LL | impl Trait for &Local {}
| ^^^^^-----^^^^^------
| | |
| | `&'_ Local` is not local
| | help: remove `&` to make the `impl` local
| `Trait` is not local
|
= note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type
= note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl`
= help: make this doc-test a standalone test with its own `fn main() { ... }`
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
note: the lint level is defined here
--> $DIR/non-local-defs-impl.rs:11:9
|
LL | #![deny(non_local_definitions)]
| ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
Couldn't compile the test.
failures:
$DIR/non-local-defs-impl.rs - doctest (line 13)
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME

View File

@ -20,15 +20,16 @@ LL | fn needs_async_fn(_: impl async Fn()) {}
| ^^^^^^^^^^ required by this bound in `needs_async_fn`
error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
--> $DIR/wrong-fn-kind.rs:9:29
--> $DIR/wrong-fn-kind.rs:9:20
|
LL | fn needs_async_fn(_: impl async Fn()) {}
| --------------- change this to accept `FnMut` instead of `Fn`
...
LL | needs_async_fn(async || {
| _____--------------_--------_^
| | | |
| | | in this closure
| -------------- ^-------
| | |
| _____|______________in this closure
| | |
| | expects `Fn` instead of `FnMut`
LL | |
LL | | x += 1;

View File

@ -18,6 +18,7 @@ async gen fn async_gen_fn() {
fn main() {
let _ = async { break; }; //~ ERROR `break` inside `async` block
let _ = async || { break; }; //~ ERROR `break` inside `async` closure
let _ = gen { break; }; //~ ERROR `break` inside `gen` block

View File

@ -38,16 +38,16 @@ LL | let _ = async { break; };
| enclosing `async` block
error[E0267]: `break` inside `async` closure
--> $DIR/break-inside-coroutine-issue-124495.rs:21:24
--> $DIR/break-inside-coroutine-issue-124495.rs:22:24
|
LL | let _ = async || { break; };
| --^^^^^---
| -----------^^^^^---
| | |
| | cannot `break` inside `async` closure
| enclosing `async` closure
error[E0267]: `break` inside `gen` block
--> $DIR/break-inside-coroutine-issue-124495.rs:23:19
--> $DIR/break-inside-coroutine-issue-124495.rs:24:19
|
LL | let _ = gen { break; };
| ------^^^^^---
@ -56,7 +56,7 @@ LL | let _ = gen { break; };
| enclosing `gen` block
error[E0267]: `break` inside `async gen` block
--> $DIR/break-inside-coroutine-issue-124495.rs:25:25
--> $DIR/break-inside-coroutine-issue-124495.rs:26:25
|
LL | let _ = async gen { break; };
| ------------^^^^^---

View File

@ -0,0 +1,32 @@
//@ check-pass
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {
fn foo(&self) {}
fn bar(&self) {}
}
impl Trait for u8 {}
struct S(u8);
mod to_import {
pub fn check(arg: &u8) -> &u8 { arg }
}
impl Trait for S {
reuse Trait::* {
use to_import::check;
let _arr = Some(self.0).map(|x| [x * 2; 3]);
check(&self.0)
}
}
fn main() {
let s = S(0);
s.foo();
s.bar();
}

View File

@ -0,0 +1,11 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {}
struct S;
impl S {
reuse Trait::*; //~ ERROR empty glob delegation is not supported
}
fn main() {}

View File

@ -0,0 +1,8 @@
error: empty glob delegation is not supported
--> $DIR/empty-glob.rs:8:5
|
LL | reuse Trait::*;
| ^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -0,0 +1,12 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {}
struct S;
impl Trait for u8 {
reuse unresolved::*; //~ ERROR failed to resolve: use of undeclared crate or module `unresolved`
reuse S::*; //~ ERROR expected trait, found struct `S`
}
fn main() {}

View File

@ -0,0 +1,15 @@
error: expected trait, found struct `S`
--> $DIR/glob-bad-path.rs:9:11
|
LL | reuse S::*;
| ^ not a trait
error[E0433]: failed to resolve: use of undeclared crate or module `unresolved`
--> $DIR/glob-bad-path.rs:8:11
|
LL | reuse unresolved::*;
| ^^^^^^^^^^ use of undeclared crate or module `unresolved`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0433`.

View File

@ -0,0 +1,33 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait1 {
fn method(&self) -> u8;
}
trait Trait2 {
fn method(&self) -> u8;
}
trait Trait {
fn method(&self) -> u8;
}
impl Trait1 for u8 {
fn method(&self) -> u8 { 0 }
}
impl Trait1 for u16 {
fn method(&self) -> u8 { 1 }
}
impl Trait2 for u8 {
fn method(&self) -> u8 { 2 }
}
impl Trait for u8 {
reuse Trait1::*;
reuse Trait2::*; //~ ERROR duplicate definitions with name `method`
}
impl Trait for u16 {
reuse Trait1::*;
reuse Trait1::*; //~ ERROR duplicate definitions with name `method`
}
fn main() {}

View File

@ -0,0 +1,25 @@
error[E0201]: duplicate definitions with name `method`:
--> $DIR/glob-glob-conflict.rs:26:5
|
LL | fn method(&self) -> u8;
| ----------------------- item in trait
...
LL | reuse Trait1::*;
| ---------------- previous definition here
LL | reuse Trait2::*;
| ^^^^^^^^^^^^^^^^ duplicate definition
error[E0201]: duplicate definitions with name `method`:
--> $DIR/glob-glob-conflict.rs:30:5
|
LL | fn method(&self) -> u8;
| ----------------------- item in trait
...
LL | reuse Trait1::*;
| ---------------- previous definition here
LL | reuse Trait1::*;
| ^^^^^^^^^^^^^^^^ duplicate definition
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0201`.

View File

@ -0,0 +1,36 @@
//@ check-pass
#![feature(fn_delegation)]
#![allow(incomplete_features)]
mod inner {
pub trait TraitFoo {
fn foo(&self) -> u8;
}
pub trait TraitBar {
fn bar(&self) -> u8;
}
impl TraitFoo for u8 {
fn foo(&self) -> u8 { 0 }
}
impl TraitBar for u8 {
fn bar(&self) -> u8 { 1 }
}
}
trait Trait {
fn foo(&self) -> u8;
fn bar(&self) -> u8;
}
impl Trait for u8 {
reuse inner::TraitFoo::*;
reuse inner::TraitBar::*;
}
fn main() {
let u = 0u8;
u.foo();
u.bar();
}

View File

@ -0,0 +1,38 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {
fn method(&self);
const CONST: u8;
type Type;
#[allow(non_camel_case_types)]
type method;
}
impl Trait for u8 {
fn method(&self) {}
const CONST: u8 = 0;
type Type = u8;
type method = u8;
}
struct Good(u8);
impl Trait for Good {
reuse Trait::* { &self.0 }
// Explicit definitions for non-delegatable items.
const CONST: u8 = 0;
type Type = u8;
type method = u8;
}
struct Bad(u8);
impl Trait for Bad { //~ ERROR not all trait items implemented, missing: `CONST`, `Type`, `method`
reuse Trait::* { &self.0 }
//~^ ERROR item `CONST` is an associated method, which doesn't match its trait `Trait`
//~| ERROR item `Type` is an associated method, which doesn't match its trait `Trait`
//~| ERROR duplicate definitions with name `method`
//~| ERROR expected function, found associated constant `Trait::CONST`
//~| ERROR expected function, found associated type `Trait::Type`
}
fn main() {}

View File

@ -0,0 +1,62 @@
error[E0324]: item `CONST` is an associated method, which doesn't match its trait `Trait`
--> $DIR/glob-non-fn.rs:30:5
|
LL | const CONST: u8;
| ---------------- item in trait
...
LL | reuse Trait::* { &self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait
error[E0324]: item `Type` is an associated method, which doesn't match its trait `Trait`
--> $DIR/glob-non-fn.rs:30:5
|
LL | type Type;
| ---------- item in trait
...
LL | reuse Trait::* { &self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait
error[E0201]: duplicate definitions with name `method`:
--> $DIR/glob-non-fn.rs:30:5
|
LL | fn method(&self);
| ----------------- item in trait
...
LL | reuse Trait::* { &self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| duplicate definition
| previous definition here
error[E0423]: expected function, found associated constant `Trait::CONST`
--> $DIR/glob-non-fn.rs:30:11
|
LL | reuse Trait::* { &self.0 }
| ^^^^^ not a function
error[E0423]: expected function, found associated type `Trait::Type`
--> $DIR/glob-non-fn.rs:30:11
|
LL | reuse Trait::* { &self.0 }
| ^^^^^
|
= note: can't use a type alias as a constructor
error[E0046]: not all trait items implemented, missing: `CONST`, `Type`, `method`
--> $DIR/glob-non-fn.rs:29:1
|
LL | const CONST: u8;
| --------------- `CONST` from trait
LL | type Type;
| --------- `Type` from trait
LL | #[allow(non_camel_case_types)]
LL | type method;
| ----------- `method` from trait
...
LL | impl Trait for Bad {
| ^^^^^^^^^^^^^^^^^^ missing `CONST`, `Type`, `method` in implementation
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0046, E0201, E0324, E0423.
For more information about an error, try `rustc --explain E0046`.

View File

@ -0,0 +1,20 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {
fn method() {}
}
reuse Trait::*; //~ ERROR glob delegation is only supported in impls
trait OtherTrait {
reuse Trait::*; //~ ERROR glob delegation is only supported in impls
}
extern {
reuse Trait::*; //~ ERROR delegation is not supported in `extern` blocks
}
fn main() {
reuse Trait::*; //~ ERROR glob delegation is only supported in impls
}

View File

@ -0,0 +1,26 @@
error: delegation is not supported in `extern` blocks
--> $DIR/glob-non-impl.rs:15:5
|
LL | reuse Trait::*;
| ^^^^^^^^^^^^^^^
error: glob delegation is only supported in impls
--> $DIR/glob-non-impl.rs:8:1
|
LL | reuse Trait::*;
| ^^^^^^^^^^^^^^^
error: glob delegation is only supported in impls
--> $DIR/glob-non-impl.rs:11:5
|
LL | reuse Trait::*;
| ^^^^^^^^^^^^^^^
error: glob delegation is only supported in impls
--> $DIR/glob-non-impl.rs:19:5
|
LL | reuse Trait::*;
| ^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors

View File

@ -0,0 +1,37 @@
//@ check-pass
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {
fn foo(&self) -> u8;
fn bar(&self) -> u8;
}
impl Trait for u8 {
fn foo(&self) -> u8 { 0 }
fn bar(&self) -> u8 { 1 }
}
struct S(u8);
struct Z(u8);
impl Trait for S {
reuse Trait::* { &self.0 }
fn bar(&self) -> u8 { 2 }
}
impl Trait for Z {
reuse Trait::* { &self.0 }
reuse Trait::bar { &self.0 }
}
fn main() {
let s = S(2);
s.foo();
s.bar();
let z = Z(2);
z.foo();
z.bar();
}

View File

@ -0,0 +1,35 @@
//@ check-pass
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {
fn foo(&self) -> u8;
fn bar(&self) -> u8;
}
impl Trait for u8 {
fn foo(&self) -> u8 { 0 }
fn bar(&self) -> u8 { 1 }
}
struct S(u8);
struct Z(u8);
impl Trait for S {
reuse Trait::* { &self.0 }
}
impl Trait for Z {
reuse <u8 as Trait>::* { &self.0 }
}
fn main() {
let s = S(2);
s.foo();
s.bar();
let z = Z(3);
z.foo();
z.bar();
}

View File

@ -0,0 +1,26 @@
//@ check-pass
#![feature(fn_delegation)]
#![allow(incomplete_features)]
trait Trait {
fn foo(&self) -> u8 { 0 }
fn bar(&self) -> u8 { 1 }
}
impl Trait for u8 {}
struct S(u8);
// Macro expansion works inside delegation items.
macro_rules! u8 { () => { u8 } }
macro_rules! self_0 { ($self:ident) => { &$self.0 } }
impl Trait for S {
reuse <u8!() as Trait>::* { self_0!(self) }
}
fn main() {
let s = S(2);
s.foo();
s.bar();
}

View File

@ -0,0 +1,8 @@
//@ edition:2021
#[macro_export]
macro_rules! edition_2021_block {
($($c:tt)*) => {
{ $($c)* }
}
}

View File

@ -0,0 +1,9 @@
//@ edition:2024
//@ compile-flags: -Zunstable-options
#[macro_export]
macro_rules! edition_2024_block {
($($c:tt)*) => {
{ $($c)* }
}
}

View File

@ -0,0 +1,16 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/tail-expr-drop-order-negative.rs:11:15
|
LL | x.replace(std::cell::RefCell::new(123).borrow()).is_some()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary value which is freed while still in use
LL |
LL | }
| - borrow might be used here, when `x` is dropped and runs the destructor for type `Option<Ref<'_, i32>>`
|
= note: consider using a `let` binding to create a longer lived value
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0716`.

View File

@ -0,0 +1,17 @@
//@ revisions: edition2021 edition2024
//@ [edition2024] compile-flags: -Zunstable-options
//@ [edition2024] edition: 2024
//@ [edition2021] check-pass
#![feature(shorter_tail_lifetimes)]
fn why_would_you_do_this() -> bool {
let mut x = None;
// Make a temporary `RefCell` and put a `Ref` that borrows it in `x`.
x.replace(std::cell::RefCell::new(123).borrow()).is_some()
//[edition2024]~^ ERROR: temporary value dropped while borrowed
}
fn main() {
why_would_you_do_this();
}

View File

@ -0,0 +1,108 @@
//@ aux-build:edition-2021-macros.rs
//@ aux-build:edition-2024-macros.rs
//@ compile-flags: -Z validate-mir -Zunstable-options
//@ edition: 2024
//@ run-pass
#![feature(shorter_tail_lifetimes)]
#![allow(unused_imports)]
#![allow(dead_code)]
#![allow(unused_variables)]
#[macro_use]
extern crate edition_2021_macros;
#[macro_use]
extern crate edition_2024_macros;
use std::cell::RefCell;
use std::convert::TryInto;
#[derive(Default)]
struct DropOrderCollector(RefCell<Vec<u32>>);
struct LoudDrop<'a>(&'a DropOrderCollector, u32);
impl Drop for LoudDrop<'_> {
fn drop(&mut self) {
println!("{}", self.1);
self.0.0.borrow_mut().push(self.1);
}
}
impl DropOrderCollector {
fn option_loud_drop(&self, n: u32) -> Option<LoudDrop> {
Some(LoudDrop(self, n))
}
fn loud_drop(&self, n: u32) -> LoudDrop {
LoudDrop(self, n)
}
fn assert_sorted(&self, expected: usize) {
let result = self.0.borrow();
assert_eq!(result.len(), expected);
for i in 1..result.len() {
assert!(
result[i - 1] < result[i],
"inversion at {} ({} followed by {})",
i - 1,
result[i - 1],
result[i]
);
}
}
}
fn edition_2021_around_2021() {
let c = DropOrderCollector::default();
let _ = edition_2021_block! {
let a = c.loud_drop(1);
edition_2021_block! {
let b = c.loud_drop(0);
c.loud_drop(2).1
}
};
c.assert_sorted(3);
}
fn edition_2021_around_2024() {
let c = DropOrderCollector::default();
let _ = edition_2021_block! {
let a = c.loud_drop(2);
edition_2024_block! {
let b = c.loud_drop(1);
c.loud_drop(0).1
}
};
c.assert_sorted(3);
}
fn edition_2024_around_2021() {
let c = DropOrderCollector::default();
let _ = edition_2024_block! {
let a = c.loud_drop(2);
edition_2021_block! {
let b = c.loud_drop(0);
c.loud_drop(1).1
}
};
c.assert_sorted(3);
}
fn edition_2024_around_2024() {
let c = DropOrderCollector::default();
let _ = edition_2024_block! {
let a = c.loud_drop(2);
edition_2024_block! {
let b = c.loud_drop(1);
c.loud_drop(0).1
}
};
c.assert_sorted(3);
}
fn main() {
edition_2021_around_2021();
edition_2021_around_2024();
edition_2024_around_2021();
edition_2024_around_2024();
}

View File

@ -0,0 +1,8 @@
fn f() -> usize {
let c = std::cell::RefCell::new("..");
c.borrow().len() //~ ERROR: `c` does not live long enough
}
fn main() {
let _ = f();
}

View File

@ -0,0 +1,26 @@
error[E0597]: `c` does not live long enough
--> $DIR/feature-gate-shorter_tail_lifetimes.rs:3:5
|
LL | let c = std::cell::RefCell::new("..");
| - binding `c` declared here
LL | c.borrow().len()
| ^---------
| |
| borrowed value does not live long enough
| a temporary with access to the borrow is created here ...
LL | }
| -
| |
| `c` dropped here while still borrowed
| ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, &str>`
|
= note: the temporary is part of an expression at the end of a block;
consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
|
LL | let x = c.borrow().len(); x
| +++++++ +++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0597`.

View File

@ -0,0 +1,26 @@
error[E0597]: `cell` does not live long enough
--> $DIR/refcell-in-tail-expr.rs:12:27
|
LL | let cell = std::cell::RefCell::new(0u8);
| ---- binding `cell` declared here
LL |
LL | if let Ok(mut byte) = cell.try_borrow_mut() {
| ^^^^-----------------
| |
| borrowed value does not live long enough
| a temporary with access to the borrow is created here ...
...
LL | }
| -
| |
| `cell` dropped here while still borrowed
| ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Result<RefMut<'_, u8>, BorrowMutError>`
|
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
|
LL | };
| +
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0597`.

View File

@ -0,0 +1,16 @@
//@ revisions: edition2021 edition2024
//@ [edition2021] edition: 2021
//@ [edition2024] edition: 2024
//@ [edition2024] compile-flags: -Zunstable-options
//@ [edition2024] check-pass
#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))]
fn main() {
let cell = std::cell::RefCell::new(0u8);
if let Ok(mut byte) = cell.try_borrow_mut() {
//[edition2021]~^ ERROR: `cell` does not live long enough
*byte = 1;
}
}

View File

@ -0,0 +1,26 @@
error[E0597]: `c` does not live long enough
--> $DIR/shorter-tail-expr-lifetime.rs:10:5
|
LL | let c = std::cell::RefCell::new("..");
| - binding `c` declared here
LL | c.borrow().len()
| ^---------
| |
| borrowed value does not live long enough
| a temporary with access to the borrow is created here ...
LL | }
| -
| |
| `c` dropped here while still borrowed
| ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, &str>`
|
= note: the temporary is part of an expression at the end of a block;
consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
|
LL | let x = c.borrow().len(); x
| +++++++ +++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0597`.

View File

@ -0,0 +1,15 @@
//@ revisions: edition2021 edition2024
//@ [edition2024] compile-flags: -Zunstable-options
//@ [edition2024] edition: 2024
//@ [edition2024] run-pass
#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))]
fn f() -> usize {
let c = std::cell::RefCell::new("..");
c.borrow().len() //[edition2021]~ ERROR: `c` does not live long enough
}
fn main() {
let _ = f();
}

View File

@ -0,0 +1,9 @@
//@ edition: 2024
//@ compile-flags: -Zunstable-options
#![feature(shorter_tail_lifetimes)]
fn main() {
let _ = { String::new().as_str() }.len();
//~^ ERROR temporary value dropped while borrowed
}

View File

@ -0,0 +1,15 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/tail-expr-in-nested-expr.rs:7:15
|
LL | let _ = { String::new().as_str() }.len();
| ^^^^^^^^^^^^^---------
| | |
| | temporary value is freed at the end of this statement
| creates a temporary value which is freed while still in use
| borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0716`.

View File

@ -0,0 +1,29 @@
//@ revisions: edition2021 edition2024
//@ ignore-wasm no panic or subprocess support
//@ [edition2024] compile-flags: -Zunstable-options
//@ [edition2024] edition: 2024
//@ run-pass
#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))]
use std::sync::Mutex;
struct PanicOnDrop;
impl Drop for PanicOnDrop {
fn drop(&mut self) {
panic!()
}
}
fn f(m: &Mutex<i32>) -> i32 {
let _x = PanicOnDrop;
*m.lock().unwrap()
}
fn main() {
let m = Mutex::new(0);
let _ = std::panic::catch_unwind(|| f(&m));
#[cfg(edition2024)]
assert!(m.lock().is_ok());
#[cfg(edition2021)]
assert!(m.lock().is_err());
}

View File

@ -17,14 +17,14 @@ fn foo(x: &u32) -> &u32 {
fn baz(x: &u32) -> &&u32 {
let x = 22;
&&x
//~^ ERROR cannot return value referencing local variable
//~^ ERROR cannot return value referencing local variable `x`
//~| ERROR cannot return reference to temporary value
}
fn foobazbar<'a>(x: u32, y: &'a u32) -> &'a u32 {
let x = 22;
&x
//~^ ERROR cannot return reference to local variable
//~^ ERROR cannot return reference to local variable `x`
}
fn foobar<'a>(x: &'a u32) -> &'a u32 {

View File

@ -1,4 +1,5 @@
// Checks existence of a note for "a caller chooses ty for ty param" upon return ty mismatch.
// Checks existence or absence of a note for "a caller chooses ty for ty param" upon return ty
// mismatch.
fn f<T>() -> (T,) {
(0,) //~ ERROR mismatched types
@ -14,6 +15,14 @@ fn h() -> u8 {
0u8
}
// This case was reported in <https://github.com/rust-lang/rust/issues/126547> where it doesn't
// make sense to make the "note caller chooses ty for ty param" note if the found type contains
// the ty param...
fn k<T>(_t: &T) -> T {
_t
//~^ ERROR mismatched types
}
fn main() {
f::<()>();
g::<(), ()>;

View File

@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/return-ty-mismatch-note.rs:4:6
--> $DIR/return-ty-mismatch-note.rs:5:6
|
LL | fn f<T>() -> (T,) {
| - expected this type parameter
@ -10,7 +10,7 @@ LL | (0,)
found type `{integer}`
error[E0308]: mismatched types
--> $DIR/return-ty-mismatch-note.rs:8:6
--> $DIR/return-ty-mismatch-note.rs:9:6
|
LL | fn g<U, V>() -> (U, V) {
| - expected this type parameter
@ -21,7 +21,7 @@ LL | (0, "foo")
found type `{integer}`
error[E0308]: mismatched types
--> $DIR/return-ty-mismatch-note.rs:8:9
--> $DIR/return-ty-mismatch-note.rs:9:9
|
LL | fn g<U, V>() -> (U, V) {
| - expected this type parameter
@ -31,6 +31,19 @@ LL | (0, "foo")
= note: expected type parameter `V`
found reference `&'static str`
error: aborting due to 3 previous errors
error[E0308]: mismatched types
--> $DIR/return-ty-mismatch-note.rs:22:5
|
LL | fn k<T>(_t: &T) -> T {
| - - expected `T` because of return type
| |
| expected this type parameter
LL | _t
| ^^ expected type parameter `T`, found `&T`
|
= note: expected type parameter `_`
found reference `&_`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -10,7 +10,6 @@ LL | t.clone()
|
= note: expected type parameter `_`
found reference `&_`
= note: the caller chooses a type for `T` which can be different from `&T`
note: `T` does not implement `Clone`, so `&T` was cloned instead
--> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
|

View File

@ -19,8 +19,14 @@ enum SingleUninhabited {
Y(Uninhabited),
}
enum MultipleUninhabited {
X(u8, Uninhabited),
Y(Uninhabited, u16),
}
fn main() {
assert_transmutable::<Uninhabited>();
assert_transmutable::<SingleInhabited>();
assert_transmutable::<SingleUninhabited>();
assert_transmutable::<MultipleUninhabited>();
}

View File

@ -30,7 +30,7 @@ fn void() {
}
// Non-ZST uninhabited types are, nonetheless, uninhabited.
fn yawning_void() {
fn yawning_void_struct() {
enum Void {}
struct YawningVoid(Void, u128);
@ -49,6 +49,28 @@ fn yawning_void() {
assert::is_maybe_transmutable::<(), Void>(); //~ ERROR: cannot be safely transmuted
}
// Non-ZST uninhabited types are, nonetheless, uninhabited.
fn yawning_void_enum() {
enum Void {}
enum YawningVoid {
A(Void, u128),
}
const _: () = {
assert!(std::mem::size_of::<YawningVoid>() == std::mem::size_of::<u128>());
// Just to be sure the above constant actually evaluated:
assert!(false); //~ ERROR: evaluation of constant value failed
};
// This transmutation is vacuously acceptable; since one cannot construct a
// `Void`, unsoundness cannot directly arise from transmuting a void into
// anything else.
assert::is_maybe_transmutable::<YawningVoid, u128>();
assert::is_maybe_transmutable::<(), Void>(); //~ ERROR: cannot be safely transmuted
}
// References to uninhabited types are, logically, uninhabited, but for layout
// purposes are not ZSTs, and aren't treated as uninhabited when they appear in
// enum variants.

View File

@ -7,10 +7,18 @@ LL | assert!(false);
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0080]: evaluation of constant value failed
--> $DIR/uninhabited.rs:65:9
--> $DIR/uninhabited.rs:63:9
|
LL | assert!(false);
| ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/uninhabited.rs:65:9
| ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/uninhabited.rs:63:9
|
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0080]: evaluation of constant value failed
--> $DIR/uninhabited.rs:87:9
|
LL | assert!(false);
| ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/uninhabited.rs:87:9
|
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
@ -36,11 +44,33 @@ LL | | }
LL | | }>
| |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `()` cannot be safely transmuted into `yawning_void::Void`
error[E0277]: `()` cannot be safely transmuted into `yawning_void_struct::Void`
--> $DIR/uninhabited.rs:49:41
|
LL | assert::is_maybe_transmutable::<(), Void>();
| ^^^^ `yawning_void::Void` is uninhabited
| ^^^^ `yawning_void_struct::Void` is uninhabited
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/uninhabited.rs:10:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this function
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, {
| ______________^
LL | | Assume {
LL | | alignment: true,
LL | | lifetimes: true,
... |
LL | | }
LL | | }>
| |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `()` cannot be safely transmuted into `yawning_void_enum::Void`
--> $DIR/uninhabited.rs:71:41
|
LL | assert::is_maybe_transmutable::<(), Void>();
| ^^^^ `yawning_void_enum::Void` is uninhabited
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/uninhabited.rs:10:14
@ -59,7 +89,7 @@ LL | | }>
| |__________^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `DistantVoid`
--> $DIR/uninhabited.rs:70:43
--> $DIR/uninhabited.rs:92:43
|
LL | assert::is_maybe_transmutable::<u128, DistantVoid>();
| ^^^^^^^^^^^ at least one value of `u128` isn't a bit-valid value of `DistantVoid`
@ -80,7 +110,7 @@ LL | | }
LL | | }>
| |__________^ required by this bound in `is_maybe_transmutable`
error: aborting due to 5 previous errors
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0080, E0277.
For more information about an error, try `rustc --explain E0080`.