Auto merge of #94541 - Dylan-DPC:rollup-564wbq3, r=Dylan-DPC
Rollup of 9 pull requests Successful merges: - #92061 (update char signess for openbsd) - #93072 (Compatible variants suggestion with desugaring) - #93354 (Add documentation about `BorrowedFd::to_owned`.) - #93663 (Rename `BorrowedFd::borrow_raw_fd` to `BorrowedFd::borrow_raw`.) - #94375 (Adt copy suggestions) - #94433 (Improve allowness of the unexpected_cfgs lint) - #94499 (Documentation was missed when demoting Windows XP to no_std only) - #94505 (Restore the local filter on mono item sorting) - #94529 (Unused doc comments blocks) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
2f8d1a835b
@ -1,8 +1,7 @@
|
||||
//! Parsing and validation of builtin attributes
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::node_id::CRATE_NODE_ID;
|
||||
use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem};
|
||||
use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem, NodeId};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
|
||||
@ -436,7 +435,12 @@ pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
|
||||
}
|
||||
|
||||
/// Tests if a cfg-pattern matches the cfg set
|
||||
pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool {
|
||||
pub fn cfg_matches(
|
||||
cfg: &ast::MetaItem,
|
||||
sess: &ParseSess,
|
||||
lint_node_id: NodeId,
|
||||
features: Option<&Features>,
|
||||
) -> bool {
|
||||
eval_condition(cfg, sess, features, &mut |cfg| {
|
||||
try_gate_cfg(cfg, sess, features);
|
||||
let error = |span, msg| {
|
||||
@ -470,7 +474,7 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
|
||||
sess.buffer_lint_with_diagnostic(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
CRATE_NODE_ID,
|
||||
lint_node_id,
|
||||
"unexpected `cfg` condition name",
|
||||
BuiltinLintDiagnostics::UnexpectedCfg(ident.span, name, None),
|
||||
);
|
||||
@ -482,7 +486,7 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
|
||||
sess.buffer_lint_with_diagnostic(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
CRATE_NODE_ID,
|
||||
lint_node_id,
|
||||
"unexpected `cfg` condition value",
|
||||
BuiltinLintDiagnostics::UnexpectedCfg(
|
||||
cfg.name_value_literal_span().unwrap(),
|
||||
|
@ -5,16 +5,21 @@
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::mir::{
|
||||
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
|
||||
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
||||
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
||||
};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
|
||||
use rustc_middle::ty::{
|
||||
self, suggest_constraining_type_param, suggest_constraining_type_params, PredicateKind, Ty,
|
||||
};
|
||||
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::TraitEngineExt as _;
|
||||
|
||||
use crate::borrow_set::TwoPhaseActivation;
|
||||
use crate::borrowck_errors;
|
||||
@ -423,7 +428,63 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
|
||||
None,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Try to find predicates on *generic params* that would allow copying `ty`
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let generics = tcx.generics_of(self.mir_def_id());
|
||||
if let Some(hir_generics) = tcx
|
||||
.typeck_root_def_id(self.mir_def_id().to_def_id())
|
||||
.as_local()
|
||||
.and_then(|def_id| tcx.hir().get_generics(def_id))
|
||||
{
|
||||
let predicates: Result<Vec<_>, _> = tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut fulfill_cx =
|
||||
<dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
|
||||
|
||||
let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
|
||||
let cause = ObligationCause::new(
|
||||
span,
|
||||
self.mir_hir_id(),
|
||||
rustc_infer::traits::ObligationCauseCode::MiscObligation,
|
||||
);
|
||||
fulfill_cx.register_bound(&infcx, self.param_env, ty, copy_did, cause);
|
||||
let errors = fulfill_cx.select_where_possible(&infcx);
|
||||
|
||||
// Only emit suggestion if all required predicates are on generic
|
||||
errors
|
||||
.into_iter()
|
||||
.map(|err| match err.obligation.predicate.kind().skip_binder() {
|
||||
PredicateKind::Trait(predicate) => {
|
||||
match predicate.self_ty().kind() {
|
||||
ty::Param(param_ty) => Ok((
|
||||
generics.type_param(param_ty, tcx),
|
||||
predicate
|
||||
.trait_ref
|
||||
.print_only_trait_path()
|
||||
.to_string(),
|
||||
)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
_ => Err(()),
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
if let Ok(predicates) = predicates {
|
||||
suggest_constraining_type_params(
|
||||
tcx,
|
||||
hir_generics,
|
||||
&mut err,
|
||||
predicates.iter().map(|(param, constraint)| {
|
||||
(param.name.as_str(), &**constraint, None)
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let span = if let Some(local) = place.as_local() {
|
||||
let decl = &self.body.local_decls[local];
|
||||
Some(decl.source_info.span)
|
||||
|
@ -19,7 +19,12 @@ pub fn expand_cfg(
|
||||
|
||||
match parse_cfg(cx, sp, tts) {
|
||||
Ok(cfg) => {
|
||||
let matches_cfg = attr::cfg_matches(&cfg, &cx.sess.parse_sess, cx.ecfg.features);
|
||||
let matches_cfg = attr::cfg_matches(
|
||||
&cfg,
|
||||
&cx.sess.parse_sess,
|
||||
cx.current_expansion.lint_node_id,
|
||||
cx.ecfg.features,
|
||||
);
|
||||
MacEager::expr(cx.expr_bool(sp, matches_cfg))
|
||||
}
|
||||
Err(mut err) => {
|
||||
|
@ -5,6 +5,7 @@
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_ast::{mut_visit, visit};
|
||||
use rustc_ast::{AstLike, Attribute};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
@ -26,15 +27,16 @@
|
||||
) -> Vec<Annotatable> {
|
||||
check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
|
||||
warn_on_duplicate_attribute(&ecx, &annotatable, sym::cfg_eval);
|
||||
vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)]
|
||||
vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable, ecx.current_expansion.lint_node_id)]
|
||||
}
|
||||
|
||||
crate fn cfg_eval(
|
||||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
annotatable: Annotatable,
|
||||
lint_node_id: NodeId,
|
||||
) -> Annotatable {
|
||||
CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true } }
|
||||
CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true, lint_node_id } }
|
||||
.configure_annotatable(annotatable)
|
||||
// Since the item itself has already been configured by the `InvocationCollector`,
|
||||
// we know that fold result vector will contain exactly one element.
|
||||
|
@ -64,7 +64,12 @@ fn expand(
|
||||
match &mut resolutions[..] {
|
||||
[] => {}
|
||||
[(_, first_item, _), others @ ..] => {
|
||||
*first_item = cfg_eval(sess, features, item.clone());
|
||||
*first_item = cfg_eval(
|
||||
sess,
|
||||
features,
|
||||
item.clone(),
|
||||
ecx.current_expansion.lint_node_id,
|
||||
);
|
||||
for (_, item, _) in others {
|
||||
*item = first_item.clone();
|
||||
}
|
||||
|
@ -576,12 +576,12 @@ pub enum PassKind {
|
||||
Module,
|
||||
}
|
||||
|
||||
/// LLVMRustThinLTOData
|
||||
// LLVMRustThinLTOData
|
||||
extern "C" {
|
||||
pub type ThinLTOData;
|
||||
}
|
||||
|
||||
/// LLVMRustThinLTOBuffer
|
||||
// LLVMRustThinLTOBuffer
|
||||
extern "C" {
|
||||
pub type ThinLTOBuffer;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use rustc_arena::TypedArena;
|
||||
use rustc_ast::CRATE_NODE_ID;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
@ -2434,7 +2435,7 @@ fn add_upstream_native_libraries(
|
||||
|
||||
fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
|
||||
match lib.cfg {
|
||||
Some(ref cfg) => rustc_attr::cfg_matches(cfg, &sess.parse_sess, None),
|
||||
Some(ref cfg) => rustc_attr::cfg_matches(cfg, &sess.parse_sess, CRATE_NODE_ID, None),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
|
||||
use rustc_ast::tokenstream::{DelimSpan, Spacing};
|
||||
use rustc_ast::tokenstream::{LazyTokenStream, TokenTree};
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_ast::{self as ast, AstLike, AttrStyle, Attribute, MetaItem};
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
@ -29,6 +30,7 @@ pub struct StripUnconfigured<'a> {
|
||||
/// This is only used for the input to derive macros,
|
||||
/// which needs eager expansion of `cfg` and `cfg_attr`
|
||||
pub config_tokens: bool,
|
||||
pub lint_node_id: NodeId,
|
||||
}
|
||||
|
||||
fn get_features(
|
||||
@ -196,8 +198,13 @@ fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feat
|
||||
}
|
||||
|
||||
// `cfg_attr`-process the crate's attributes and compute the crate's features.
|
||||
pub fn features(sess: &Session, mut krate: ast::Crate) -> (ast::Crate, Features) {
|
||||
let mut strip_unconfigured = StripUnconfigured { sess, features: None, config_tokens: false };
|
||||
pub fn features(
|
||||
sess: &Session,
|
||||
mut krate: ast::Crate,
|
||||
lint_node_id: NodeId,
|
||||
) -> (ast::Crate, Features) {
|
||||
let mut strip_unconfigured =
|
||||
StripUnconfigured { sess, features: None, config_tokens: false, lint_node_id };
|
||||
|
||||
let unconfigured_attrs = krate.attrs.clone();
|
||||
let diag = &sess.parse_sess.span_diagnostic;
|
||||
@ -353,7 +360,12 @@ fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> {
|
||||
);
|
||||
}
|
||||
|
||||
if !attr::cfg_matches(&cfg_predicate, &self.sess.parse_sess, self.features) {
|
||||
if !attr::cfg_matches(
|
||||
&cfg_predicate,
|
||||
&self.sess.parse_sess,
|
||||
self.lint_node_id,
|
||||
self.features,
|
||||
) {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
@ -445,7 +457,7 @@ fn in_cfg(&self, attrs: &[Attribute]) -> bool {
|
||||
}
|
||||
};
|
||||
parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
|
||||
attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features)
|
||||
attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.lint_node_id, self.features)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -551,11 +551,6 @@ fn collect_invocations(
|
||||
// attribute is expanded. Therefore, we don't need to configure the tokens
|
||||
// Derive macros *can* see the results of cfg-expansion - they are handled
|
||||
// specially in `fully_expand_fragment`
|
||||
cfg: StripUnconfigured {
|
||||
sess: &self.cx.sess,
|
||||
features: self.cx.ecfg.features,
|
||||
config_tokens: false,
|
||||
},
|
||||
cx: self.cx,
|
||||
invocations: Vec::new(),
|
||||
monotonic: self.monotonic,
|
||||
@ -1538,12 +1533,20 @@ fn pre_flat_map_node_collect_attr(cfg: &StripUnconfigured<'_>, attr: &ast::Attri
|
||||
|
||||
struct InvocationCollector<'a, 'b> {
|
||||
cx: &'a mut ExtCtxt<'b>,
|
||||
cfg: StripUnconfigured<'a>,
|
||||
invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>,
|
||||
monotonic: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||
fn cfg(&self) -> StripUnconfigured<'_> {
|
||||
StripUnconfigured {
|
||||
sess: &self.cx.sess,
|
||||
features: self.cx.ecfg.features,
|
||||
config_tokens: false,
|
||||
lint_node_id: self.cx.current_expansion.lint_node_id,
|
||||
}
|
||||
}
|
||||
|
||||
fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
|
||||
let expn_id = LocalExpnId::fresh_empty();
|
||||
let vis = kind.placeholder_visibility();
|
||||
@ -1683,7 +1686,7 @@ fn expand_cfg_true(
|
||||
attr: ast::Attribute,
|
||||
pos: usize,
|
||||
) -> bool {
|
||||
let res = self.cfg.cfg_true(&attr);
|
||||
let res = self.cfg().cfg_true(&attr);
|
||||
if res {
|
||||
// FIXME: `cfg(TRUE)` attributes do not currently remove themselves during expansion,
|
||||
// and some tools like rustdoc and clippy rely on that. Find a way to remove them
|
||||
@ -1696,7 +1699,7 @@ fn expand_cfg_true(
|
||||
|
||||
fn expand_cfg_attr(&self, node: &mut impl AstLike, attr: ast::Attribute, pos: usize) {
|
||||
node.visit_attrs(|attrs| {
|
||||
attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr, false));
|
||||
attrs.splice(pos..pos, self.cfg().expand_cfg_attr(attr, false));
|
||||
});
|
||||
}
|
||||
|
||||
@ -1718,7 +1721,7 @@ fn flat_map_node<Node: InvocationCollectorNode<OutputTy: Default>>(
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
Node::pre_flat_map_node_collect_attr(&self.cfg, &attr);
|
||||
Node::pre_flat_map_node_collect_attr(&self.cfg(), &attr);
|
||||
self.collect_attr((attr, pos, derives), node.to_annotatable(), Node::KIND)
|
||||
.make_ast::<Node>()
|
||||
}
|
||||
@ -1882,7 +1885,7 @@ fn visit_pat(&mut self, node: &mut P<ast::Pat>) {
|
||||
fn visit_expr(&mut self, node: &mut P<ast::Expr>) {
|
||||
// FIXME: Feature gating is performed inconsistently between `Expr` and `OptExpr`.
|
||||
if let Some(attr) = node.attrs.first() {
|
||||
self.cfg.maybe_emit_expr_attr_err(attr);
|
||||
self.cfg().maybe_emit_expr_attr_err(attr);
|
||||
}
|
||||
self.visit_node(node)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
use crate::proc_macro_decls;
|
||||
use crate::util;
|
||||
|
||||
use ast::CRATE_NODE_ID;
|
||||
use rustc_ast::mut_visit::MutVisitor;
|
||||
use rustc_ast::{self as ast, visit};
|
||||
use rustc_borrowck as mir_borrowck;
|
||||
@ -188,7 +189,7 @@ pub fn register_plugins<'a>(
|
||||
)
|
||||
});
|
||||
|
||||
let (krate, features) = rustc_expand::config::features(sess, krate);
|
||||
let (krate, features) = rustc_expand::config::features(sess, krate, CRATE_NODE_ID);
|
||||
// these need to be set "early" so that expansion sees `quote` if enabled.
|
||||
sess.init_features(features);
|
||||
|
||||
|
@ -1086,6 +1086,16 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
||||
fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) {
|
||||
warn_if_doc(cx, param.ident.span, "generic parameters", ¶m.attrs);
|
||||
}
|
||||
|
||||
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
|
||||
warn_if_doc(cx, block.span, "block", &block.attrs());
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
||||
if let ast::ItemKind::ForeignMod(_) = item.kind {
|
||||
warn_if_doc(cx, item.span, "extern block", &item.attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
|
@ -1,3 +1,4 @@
|
||||
use rustc_ast::CRATE_NODE_ID;
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::struct_span_err;
|
||||
@ -21,7 +22,7 @@
|
||||
|
||||
crate fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
|
||||
match lib.cfg {
|
||||
Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None),
|
||||
Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, CRATE_NODE_ID, None),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,7 @@
|
||||
#![feature(nonzero_ops)]
|
||||
#![feature(unwrap_infallible)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(drain_filter)]
|
||||
#![recursion_limit = "512"]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use rustc_hir::ItemId;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
|
||||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::source_map::Span;
|
||||
@ -380,7 +381,7 @@ fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey<'
|
||||
// instances into account. The others don't matter for
|
||||
// the codegen tests and can even make item order
|
||||
// unstable.
|
||||
InstanceDef::Item(def) => Some(def.did.index.as_usize()),
|
||||
InstanceDef::Item(def) => def.did.as_local().map(Idx::index),
|
||||
InstanceDef::VtableShim(..)
|
||||
| InstanceDef::ReifyShim(..)
|
||||
| InstanceDef::Intrinsic(..)
|
||||
@ -391,10 +392,8 @@ fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey<'
|
||||
| InstanceDef::CloneShim(..) => None,
|
||||
}
|
||||
}
|
||||
MonoItem::Static(def_id) => Some(def_id.index.as_usize()),
|
||||
MonoItem::GlobalAsm(item_id) => {
|
||||
Some(item_id.def_id.to_def_id().index.as_usize())
|
||||
}
|
||||
MonoItem::Static(def_id) => def_id.as_local().map(Idx::index),
|
||||
MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.index()),
|
||||
},
|
||||
item.symbol_name(tcx),
|
||||
)
|
||||
|
@ -7,6 +7,7 @@
|
||||
ProjectionTy, Term, Ty, TyCtxt, TypeAndMut,
|
||||
};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{Applicability, Diagnostic};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -157,9 +158,17 @@ pub fn suggest_arbitrary_trait_bound(
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum SuggestChangingConstraintsMessage<'a> {
|
||||
RestrictBoundFurther,
|
||||
RestrictType { ty: &'a str },
|
||||
RestrictTypeFurther { ty: &'a str },
|
||||
RemovingQSized,
|
||||
}
|
||||
|
||||
fn suggest_removing_unsized_bound(
|
||||
generics: &hir::Generics<'_>,
|
||||
err: &mut Diagnostic,
|
||||
suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>,
|
||||
param_name: &str,
|
||||
param: &hir::GenericParam<'_>,
|
||||
def_id: Option<DefId>,
|
||||
@ -221,13 +230,12 @@ fn suggest_removing_unsized_bound(
|
||||
// ^^^^^^^^^
|
||||
(_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
|
||||
suggestions.push((
|
||||
sp,
|
||||
"consider removing the `?Sized` bound to make the \
|
||||
type parameter `Sized`",
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
SuggestChangingConstraintsMessage::RemovingQSized,
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@ -249,13 +257,12 @@ fn suggest_removing_unsized_bound(
|
||||
// ^^^^^^^^^
|
||||
(_, pos) => param.bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
|
||||
suggestions.push((
|
||||
sp,
|
||||
"consider removing the `?Sized` bound to make the type parameter \
|
||||
`Sized`",
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
SuggestChangingConstraintsMessage::RemovingQSized,
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -271,184 +278,249 @@ pub fn suggest_constraining_type_param(
|
||||
constraint: &str,
|
||||
def_id: Option<DefId>,
|
||||
) -> bool {
|
||||
let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
|
||||
suggest_constraining_type_params(
|
||||
tcx,
|
||||
generics,
|
||||
err,
|
||||
[(param_name, constraint, def_id)].into_iter(),
|
||||
)
|
||||
}
|
||||
|
||||
let Some(param) = param else {
|
||||
return false;
|
||||
};
|
||||
/// Suggest restricting a type param with a new bound.
|
||||
pub fn suggest_constraining_type_params<'a>(
|
||||
tcx: TyCtxt<'_>,
|
||||
generics: &hir::Generics<'_>,
|
||||
err: &mut Diagnostic,
|
||||
param_names_and_constraints: impl Iterator<Item = (&'a str, &'a str, Option<DefId>)>,
|
||||
) -> bool {
|
||||
let mut grouped = FxHashMap::default();
|
||||
param_names_and_constraints.for_each(|(param_name, constraint, def_id)| {
|
||||
grouped.entry(param_name).or_insert(Vec::new()).push((constraint, def_id))
|
||||
});
|
||||
|
||||
const MSG_RESTRICT_BOUND_FURTHER: &str = "consider further restricting this bound";
|
||||
let msg_restrict_type = format!("consider restricting type parameter `{}`", param_name);
|
||||
let msg_restrict_type_further =
|
||||
format!("consider further restricting type parameter `{}`", param_name);
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let mut suggestions = Vec::new();
|
||||
|
||||
if def_id == tcx.lang_items().sized_trait() {
|
||||
// Type parameters are already `Sized` by default.
|
||||
err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint));
|
||||
suggest_removing_unsized_bound(generics, err, param_name, param, def_id);
|
||||
return true;
|
||||
}
|
||||
let mut suggest_restrict = |span| {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
MSG_RESTRICT_BOUND_FURTHER,
|
||||
format!(" + {}", constraint),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
};
|
||||
for (param_name, mut constraints) in grouped {
|
||||
let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
|
||||
let Some(param) = param else { return false };
|
||||
|
||||
if param_name.starts_with("impl ") {
|
||||
// If there's an `impl Trait` used in argument position, suggest
|
||||
// restricting it:
|
||||
//
|
||||
// fn foo(t: impl Foo) { ... }
|
||||
// --------
|
||||
// |
|
||||
// help: consider further restricting this bound with `+ Bar`
|
||||
//
|
||||
// Suggestion for tools in this case is:
|
||||
//
|
||||
// fn foo(t: impl Foo) { ... }
|
||||
// --------
|
||||
// |
|
||||
// replace with: `impl Foo + Bar`
|
||||
{
|
||||
let mut sized_constraints =
|
||||
constraints.drain_filter(|(_, def_id)| *def_id == tcx.lang_items().sized_trait());
|
||||
if let Some((constraint, def_id)) = sized_constraints.next() {
|
||||
applicability = Applicability::MaybeIncorrect;
|
||||
|
||||
suggest_restrict(param.span.shrink_to_hi());
|
||||
return true;
|
||||
}
|
||||
err.span_label(
|
||||
param.span,
|
||||
&format!("this type parameter needs to be `{}`", constraint),
|
||||
);
|
||||
suggest_removing_unsized_bound(
|
||||
generics,
|
||||
&mut suggestions,
|
||||
param_name,
|
||||
param,
|
||||
def_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if generics.where_clause.predicates.is_empty()
|
||||
// Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the
|
||||
// `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
|
||||
&& !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
|
||||
{
|
||||
if let Some(span) = param.bounds_span_for_suggestions() {
|
||||
// If user has provided some bounds, suggest restricting them:
|
||||
if constraints.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>().join(" + ");
|
||||
let mut suggest_restrict = |span| {
|
||||
suggestions.push((
|
||||
span,
|
||||
format!(" + {}", constraint),
|
||||
SuggestChangingConstraintsMessage::RestrictBoundFurther,
|
||||
))
|
||||
};
|
||||
|
||||
if param_name.starts_with("impl ") {
|
||||
// If there's an `impl Trait` used in argument position, suggest
|
||||
// restricting it:
|
||||
//
|
||||
// fn foo<T: Foo>(t: T) { ... }
|
||||
// ---
|
||||
// fn foo(t: impl Foo) { ... }
|
||||
// --------
|
||||
// |
|
||||
// help: consider further restricting this bound with `+ Bar`
|
||||
//
|
||||
// Suggestion for tools in this case is:
|
||||
//
|
||||
// fn foo<T: Foo>(t: T) { ... }
|
||||
// --
|
||||
// |
|
||||
// replace with: `T: Bar +`
|
||||
suggest_restrict(span);
|
||||
} else {
|
||||
// If user hasn't provided any bounds, suggest adding a new one:
|
||||
//
|
||||
// fn foo<T>(t: T) { ... }
|
||||
// - help: consider restricting this type parameter with `T: Foo`
|
||||
err.span_suggestion_verbose(
|
||||
param.span.shrink_to_hi(),
|
||||
&msg_restrict_type,
|
||||
format!(": {}", constraint),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
// fn foo(t: impl Foo) { ... }
|
||||
// --------
|
||||
// |
|
||||
// replace with: `impl Foo + Bar`
|
||||
|
||||
suggest_restrict(param.span.shrink_to_hi());
|
||||
continue;
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
// This part is a bit tricky, because using the `where` clause user can
|
||||
// provide zero, one or many bounds for the same type parameter, so we
|
||||
// have following cases to consider:
|
||||
//
|
||||
// 1) When the type parameter has been provided zero bounds
|
||||
//
|
||||
// Message:
|
||||
// fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
|
||||
// - help: consider restricting this type parameter with `where X: Bar`
|
||||
//
|
||||
// Suggestion:
|
||||
// fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
|
||||
// - insert: `, X: Bar`
|
||||
//
|
||||
//
|
||||
// 2) When the type parameter has been provided one bound
|
||||
//
|
||||
// Message:
|
||||
// fn foo<T>(t: T) where T: Foo { ... }
|
||||
// ^^^^^^
|
||||
// |
|
||||
// help: consider further restricting this bound with `+ Bar`
|
||||
//
|
||||
// Suggestion:
|
||||
// fn foo<T>(t: T) where T: Foo { ... }
|
||||
// ^^
|
||||
// |
|
||||
// replace with: `T: Bar +`
|
||||
//
|
||||
//
|
||||
// 3) When the type parameter has been provided many bounds
|
||||
//
|
||||
// Message:
|
||||
// fn foo<T>(t: T) where T: Foo, T: Bar {... }
|
||||
// - help: consider further restricting this type parameter with `where T: Zar`
|
||||
//
|
||||
// Suggestion:
|
||||
// fn foo<T>(t: T) where T: Foo, T: Bar {... }
|
||||
// - insert: `, T: Zar`
|
||||
//
|
||||
// Additionally, there may be no `where` clause whatsoever in the case that this was
|
||||
// reached because the generic parameter has a default:
|
||||
//
|
||||
// Message:
|
||||
// trait Foo<T=()> {... }
|
||||
// - help: consider further restricting this type parameter with `where T: Zar`
|
||||
//
|
||||
// Suggestion:
|
||||
// trait Foo<T=()> where T: Zar {... }
|
||||
// - insert: `where T: Zar`
|
||||
|
||||
if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
|
||||
&& generics.where_clause.predicates.len() == 0
|
||||
if generics.where_clause.predicates.is_empty()
|
||||
// Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the
|
||||
// `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
|
||||
&& !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
|
||||
{
|
||||
// Suggest a bound, but there is no existing `where` clause *and* the type param has a
|
||||
// default (`<T=Foo>`), so we suggest adding `where T: Bar`.
|
||||
err.span_suggestion_verbose(
|
||||
generics.where_clause.tail_span_for_suggestion(),
|
||||
&msg_restrict_type_further,
|
||||
format!(" where {}: {}", param_name, constraint),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
if let Some(span) = param.bounds_span_for_suggestions() {
|
||||
// If user has provided some bounds, suggest restricting them:
|
||||
//
|
||||
// fn foo<T: Foo>(t: T) { ... }
|
||||
// ---
|
||||
// |
|
||||
// help: consider further restricting this bound with `+ Bar`
|
||||
//
|
||||
// Suggestion for tools in this case is:
|
||||
//
|
||||
// fn foo<T: Foo>(t: T) { ... }
|
||||
// --
|
||||
// |
|
||||
// replace with: `T: Bar +`
|
||||
suggest_restrict(span);
|
||||
} else {
|
||||
// If user hasn't provided any bounds, suggest adding a new one:
|
||||
//
|
||||
// fn foo<T>(t: T) { ... }
|
||||
// - help: consider restricting this type parameter with `T: Foo`
|
||||
suggestions.push((
|
||||
param.span.shrink_to_hi(),
|
||||
format!(": {}", constraint),
|
||||
SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
|
||||
));
|
||||
}
|
||||
} else {
|
||||
let mut param_spans = Vec::new();
|
||||
// This part is a bit tricky, because using the `where` clause user can
|
||||
// provide zero, one or many bounds for the same type parameter, so we
|
||||
// have following cases to consider:
|
||||
//
|
||||
// 1) When the type parameter has been provided zero bounds
|
||||
//
|
||||
// Message:
|
||||
// fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
|
||||
// - help: consider restricting this type parameter with `where X: Bar`
|
||||
//
|
||||
// Suggestion:
|
||||
// fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
|
||||
// - insert: `, X: Bar`
|
||||
//
|
||||
//
|
||||
// 2) When the type parameter has been provided one bound
|
||||
//
|
||||
// Message:
|
||||
// fn foo<T>(t: T) where T: Foo { ... }
|
||||
// ^^^^^^
|
||||
// |
|
||||
// help: consider further restricting this bound with `+ Bar`
|
||||
//
|
||||
// Suggestion:
|
||||
// fn foo<T>(t: T) where T: Foo { ... }
|
||||
// ^^
|
||||
// |
|
||||
// replace with: `T: Bar +`
|
||||
//
|
||||
//
|
||||
// 3) When the type parameter has been provided many bounds
|
||||
//
|
||||
// Message:
|
||||
// fn foo<T>(t: T) where T: Foo, T: Bar {... }
|
||||
// - help: consider further restricting this type parameter with `where T: Zar`
|
||||
//
|
||||
// Suggestion:
|
||||
// fn foo<T>(t: T) where T: Foo, T: Bar {... }
|
||||
// - insert: `, T: Zar`
|
||||
//
|
||||
// Additionally, there may be no `where` clause whatsoever in the case that this was
|
||||
// reached because the generic parameter has a default:
|
||||
//
|
||||
// Message:
|
||||
// trait Foo<T=()> {... }
|
||||
// - help: consider further restricting this type parameter with `where T: Zar`
|
||||
//
|
||||
// Suggestion:
|
||||
// trait Foo<T=()> where T: Zar {... }
|
||||
// - insert: `where T: Zar`
|
||||
|
||||
for predicate in generics.where_clause.predicates {
|
||||
if let WherePredicate::BoundPredicate(WhereBoundPredicate {
|
||||
span,
|
||||
bounded_ty,
|
||||
..
|
||||
}) = predicate
|
||||
{
|
||||
if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
|
||||
if let Some(segment) = path.segments.first() {
|
||||
if segment.ident.to_string() == param_name {
|
||||
param_spans.push(span);
|
||||
if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
|
||||
&& generics.where_clause.predicates.len() == 0
|
||||
{
|
||||
// Suggest a bound, but there is no existing `where` clause *and* the type param has a
|
||||
// default (`<T=Foo>`), so we suggest adding `where T: Bar`.
|
||||
suggestions.push((
|
||||
generics.where_clause.tail_span_for_suggestion(),
|
||||
format!(" where {}: {}", param_name, constraint),
|
||||
SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
|
||||
));
|
||||
} else {
|
||||
let mut param_spans = Vec::new();
|
||||
|
||||
for predicate in generics.where_clause.predicates {
|
||||
if let WherePredicate::BoundPredicate(WhereBoundPredicate {
|
||||
span,
|
||||
bounded_ty,
|
||||
..
|
||||
}) = predicate
|
||||
{
|
||||
if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
|
||||
if let Some(segment) = path.segments.first() {
|
||||
if segment.ident.to_string() == param_name {
|
||||
param_spans.push(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match param_spans[..] {
|
||||
[¶m_span] => suggest_restrict(param_span.shrink_to_hi()),
|
||||
_ => {
|
||||
err.span_suggestion_verbose(
|
||||
generics.where_clause.tail_span_for_suggestion(),
|
||||
&msg_restrict_type_further,
|
||||
format!(", {}: {}", param_name, constraint),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
match param_spans[..] {
|
||||
[¶m_span] => suggest_restrict(param_span.shrink_to_hi()),
|
||||
_ => {
|
||||
suggestions.push((
|
||||
generics.where_clause.tail_span_for_suggestion(),
|
||||
constraints
|
||||
.iter()
|
||||
.map(|&(constraint, _)| format!(", {}: {}", param_name, constraint))
|
||||
.collect::<String>(),
|
||||
SuggestChangingConstraintsMessage::RestrictTypeFurther {
|
||||
ty: param_name,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
if suggestions.len() == 1 {
|
||||
let (span, suggestion, msg) = suggestions.pop().unwrap();
|
||||
|
||||
let s;
|
||||
let msg = match msg {
|
||||
SuggestChangingConstraintsMessage::RestrictBoundFurther => {
|
||||
"consider further restricting this bound"
|
||||
}
|
||||
SuggestChangingConstraintsMessage::RestrictType { ty } => {
|
||||
s = format!("consider restricting type parameter `{}`", ty);
|
||||
&s
|
||||
}
|
||||
SuggestChangingConstraintsMessage::RestrictTypeFurther { ty } => {
|
||||
s = format!("consider further restricting type parameter `{}`", ty);
|
||||
&s
|
||||
}
|
||||
SuggestChangingConstraintsMessage::RemovingQSized => {
|
||||
"consider removing the `?Sized` bound to make the type parameter `Sized`"
|
||||
}
|
||||
};
|
||||
|
||||
err.span_suggestion_verbose(span, msg, suggestion, applicability);
|
||||
} else {
|
||||
err.multipart_suggestion_verbose(
|
||||
"consider restricting type parameters",
|
||||
suggestions.into_iter().map(|(span, suggestion, _)| (span, suggestion)).collect(),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
|
||||
|
@ -276,11 +276,28 @@ fn suggest_compatible_variants(
|
||||
// we suggest adding a separate return expression instead.
|
||||
// (To avoid things like suggesting `Ok(while .. { .. })`.)
|
||||
if expr_ty.is_unit() {
|
||||
let mut id = expr.hir_id;
|
||||
let mut parent;
|
||||
|
||||
// Unroll desugaring, to make sure this works for `for` loops etc.
|
||||
loop {
|
||||
parent = self.tcx.hir().get_parent_node(id);
|
||||
if let Some(parent_span) = self.tcx.hir().opt_span(parent) {
|
||||
if parent_span.find_ancestor_inside(expr.span).is_some() {
|
||||
// The parent node is part of the same span, so is the result of the
|
||||
// same expansion/desugaring and not the 'real' parent node.
|
||||
id = parent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(hir::Node::Block(&hir::Block {
|
||||
span: block_span, expr: Some(e), ..
|
||||
})) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
|
||||
})) = self.tcx.hir().find(parent)
|
||||
{
|
||||
if e.hir_id == expr.hir_id {
|
||||
if e.hir_id == id {
|
||||
if let Some(span) = expr.span.find_ancestor_inside(block_span) {
|
||||
let return_suggestions =
|
||||
if self.tcx.is_diagnostic_item(sym::Result, expected_adt.did) {
|
||||
|
@ -117,7 +117,7 @@ mod c_char_definition {
|
||||
all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
|
||||
all(target_os = "l4re", target_arch = "x86_64"),
|
||||
all(
|
||||
target_os = "freebsd",
|
||||
any(target_os = "freebsd", target_os = "openbsd"),
|
||||
any(
|
||||
target_arch = "aarch64",
|
||||
target_arch = "arm",
|
||||
@ -130,7 +130,6 @@ mod c_char_definition {
|
||||
target_os = "netbsd",
|
||||
any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
|
||||
),
|
||||
all(target_os = "openbsd", target_arch = "aarch64"),
|
||||
all(
|
||||
target_os = "vxworks",
|
||||
any(
|
||||
|
@ -18,9 +18,10 @@
|
||||
//!
|
||||
//! Unless stated otherwise, all intrinsics for binary operations require SIMD vectors of equal types and lengths.
|
||||
|
||||
/// These intrinsics aren't linked directly from LLVM and are mostly undocumented, however they are
|
||||
/// mostly lowered to the matching LLVM instructions by the compiler in a fairly straightforward manner.
|
||||
/// The associated LLVM instruction or intrinsic is documented alongside each Rust intrinsic function.
|
||||
|
||||
// These intrinsics aren't linked directly from LLVM and are mostly undocumented, however they are
|
||||
// mostly lowered to the matching LLVM instructions by the compiler in a fairly straightforward manner.
|
||||
// The associated LLVM instruction or intrinsic is documented alongside each Rust intrinsic function.
|
||||
extern "platform-intrinsic" {
|
||||
/// add/fadd
|
||||
pub(crate) fn simd_add<T>(x: T, y: T) -> T;
|
||||
|
@ -11,3 +11,6 @@
|
||||
|
||||
// Implementations for `AsRawFd` etc. for network types.
|
||||
mod net;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
@ -21,6 +21,10 @@
|
||||
/// descriptor, so it can be used in FFI in places where a file descriptor is
|
||||
/// passed as an argument, it is not captured or consumed, and it never has the
|
||||
/// value `-1`.
|
||||
///
|
||||
/// This type's `.to_owned()` implementation returns another `BorrowedFd`
|
||||
/// rather than an `OwnedFd`. It just makes a trivial copy of the raw file
|
||||
/// descriptor, which is then borrowed under the same lifetime.
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
#[rustc_layout_scalar_valid_range_start(0)]
|
||||
@ -62,7 +66,7 @@ impl BorrowedFd<'_> {
|
||||
/// the returned `BorrowedFd`, and it must not have the value `-1`.
|
||||
#[inline]
|
||||
#[unstable(feature = "io_safety", issue = "87074")]
|
||||
pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self {
|
||||
pub unsafe fn borrow_raw(fd: RawFd) -> Self {
|
||||
assert_ne!(fd, u32::MAX as RawFd);
|
||||
// SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
|
||||
unsafe { Self { fd, _phantom: PhantomData } }
|
||||
@ -231,7 +235,7 @@ fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
// Safety: `OwnedFd` and `BorrowedFd` have the same validity
|
||||
// invariants, and the `BorrowdFd` is bounded by the lifetime
|
||||
// of `&self`.
|
||||
unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) }
|
||||
unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
34
library/std/src/os/fd/tests.rs
Normal file
34
library/std/src/os/fd/tests.rs
Normal file
@ -0,0 +1,34 @@
|
||||
#[cfg(any(unix, target_os = "wasi"))]
|
||||
#[test]
|
||||
fn test_raw_fd() {
|
||||
#[cfg(unix)]
|
||||
use crate::os::unix::io::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
|
||||
#[cfg(target_os = "wasi")]
|
||||
use crate::os::wasi::io::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
|
||||
|
||||
let raw_fd: RawFd = crate::io::stdin().as_raw_fd();
|
||||
|
||||
let stdin_as_file = unsafe { crate::fs::File::from_raw_fd(raw_fd) };
|
||||
assert_eq!(stdin_as_file.as_raw_fd(), raw_fd);
|
||||
assert_eq!(unsafe { BorrowedFd::borrow_raw(raw_fd).as_raw_fd() }, raw_fd);
|
||||
assert_eq!(stdin_as_file.into_raw_fd(), 0);
|
||||
}
|
||||
|
||||
#[cfg(any(unix, target_os = "wasi"))]
|
||||
#[test]
|
||||
fn test_fd() {
|
||||
#[cfg(unix)]
|
||||
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
#[cfg(target_os = "wasi")]
|
||||
use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
|
||||
let stdin = crate::io::stdin();
|
||||
let fd: BorrowedFd<'_> = stdin.as_fd();
|
||||
let raw_fd: RawFd = fd.as_raw_fd();
|
||||
let owned_fd: OwnedFd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
|
||||
|
||||
let stdin_as_file = crate::fs::File::from(owned_fd);
|
||||
|
||||
assert_eq!(stdin_as_file.as_fd().as_raw_fd(), raw_fd);
|
||||
assert_eq!(Into::<OwnedFd>::into(stdin_as_file).into_raw_fd(), raw_fd);
|
||||
}
|
@ -28,6 +28,10 @@
|
||||
/// And, it *may* have the value `NULL` (0), which can occur when consoles are
|
||||
/// detached from processes, or when `windows_subsystem` is used.
|
||||
///
|
||||
/// This type's `.to_owned()` implementation returns another `BorrowedHandle`
|
||||
/// rather than an `OwnedHandle`. It just makes a trivial copy of the raw
|
||||
/// handle, which is then borrowed under the same lifetime.
|
||||
///
|
||||
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
@ -131,7 +135,7 @@ impl BorrowedHandle<'_> {
|
||||
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
|
||||
#[inline]
|
||||
#[unstable(feature = "io_safety", issue = "87074")]
|
||||
pub unsafe fn borrow_raw_handle(handle: RawHandle) -> Self {
|
||||
pub unsafe fn borrow_raw(handle: RawHandle) -> Self {
|
||||
Self { handle, _phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
@ -345,7 +349,7 @@ fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
// Safety: `OwnedHandle` and `BorrowedHandle` have the same validity
|
||||
// invariants, and the `BorrowdHandle` is bounded by the lifetime
|
||||
// of `&self`.
|
||||
unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
|
||||
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,49 +377,49 @@ fn from(owned: OwnedHandle) -> Self {
|
||||
impl AsHandle for crate::io::Stdin {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
|
||||
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsHandle for crate::io::StdinLock<'a> {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
|
||||
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsHandle for crate::io::Stdout {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
|
||||
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsHandle for crate::io::StdoutLock<'a> {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
|
||||
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsHandle for crate::io::Stderr {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
|
||||
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsHandle for crate::io::StderrLock<'a> {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
|
||||
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsHandle for crate::process::ChildStdin {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
|
||||
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,7 +433,7 @@ fn from(child_stdin: crate::process::ChildStdin) -> OwnedHandle {
|
||||
impl AsHandle for crate::process::ChildStdout {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
|
||||
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,7 +447,7 @@ fn from(child_stdout: crate::process::ChildStdout) -> OwnedHandle {
|
||||
impl AsHandle for crate::process::ChildStderr {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
|
||||
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,7 +461,7 @@ fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle {
|
||||
impl<T> AsHandle for crate::thread::JoinHandle<T> {
|
||||
#[inline]
|
||||
fn as_handle(&self) -> BorrowedHandle<'_> {
|
||||
unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
|
||||
unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,10 @@
|
||||
/// so it can be used in FFI in places where a socket is passed as an argument,
|
||||
/// it is not captured or consumed, and it never has the value
|
||||
/// `INVALID_SOCKET`.
|
||||
///
|
||||
/// This type's `.to_owned()` implementation returns another `BorrowedSocket`
|
||||
/// rather than an `OwnedSocket`. It just makes a trivial copy of the raw
|
||||
/// socket, which is then borrowed under the same lifetime.
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
#[rustc_layout_scalar_valid_range_start(0)]
|
||||
@ -67,7 +71,7 @@ impl BorrowedSocket<'_> {
|
||||
/// `INVALID_SOCKET`.
|
||||
#[inline]
|
||||
#[unstable(feature = "io_safety", issue = "87074")]
|
||||
pub unsafe fn borrow_raw_socket(socket: RawSocket) -> Self {
|
||||
pub unsafe fn borrow_raw(socket: RawSocket) -> Self {
|
||||
debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket);
|
||||
Self { socket, _phantom: PhantomData }
|
||||
}
|
||||
@ -239,14 +243,14 @@ fn as_socket(&self) -> BorrowedSocket<'_> {
|
||||
// Safety: `OwnedSocket` and `BorrowedSocket` have the same validity
|
||||
// invariants, and the `BorrowdSocket` is bounded by the lifetime
|
||||
// of `&self`.
|
||||
unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) }
|
||||
unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsSocket for crate::net::TcpStream {
|
||||
#[inline]
|
||||
fn as_socket(&self) -> BorrowedSocket<'_> {
|
||||
unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) }
|
||||
unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,7 +271,7 @@ fn from(owned: OwnedSocket) -> Self {
|
||||
impl AsSocket for crate::net::TcpListener {
|
||||
#[inline]
|
||||
fn as_socket(&self) -> BorrowedSocket<'_> {
|
||||
unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) }
|
||||
unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,7 +292,7 @@ fn from(owned: OwnedSocket) -> Self {
|
||||
impl AsSocket for crate::net::UdpSocket {
|
||||
#[inline]
|
||||
fn as_socket(&self) -> BorrowedSocket<'_> {
|
||||
unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) }
|
||||
unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ pub fn panic_output() -> Option<impl io::Write> {
|
||||
impl AsFd for io::Stdin {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) }
|
||||
unsafe { BorrowedFd::borrow_raw(libc::STDIN_FILENO) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +104,7 @@ fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
impl<'a> AsFd for io::StdinLock<'a> {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) }
|
||||
unsafe { BorrowedFd::borrow_raw(libc::STDIN_FILENO) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
impl AsFd for io::Stdout {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) }
|
||||
unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
impl<'a> AsFd for io::StdoutLock<'a> {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) }
|
||||
unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,7 +128,7 @@ fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
impl AsFd for io::Stderr {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) }
|
||||
unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,6 +136,6 @@ fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
impl<'a> AsFd for io::StderrLock<'a> {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) }
|
||||
unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) }
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit b4a0e07552cf90ef8f1a5b775bf70e4db94b3d63
|
||||
Subproject commit bcbe010614f398ec86f3a9274d22e33e5f2ee60b
|
@ -139,7 +139,7 @@ target | std | notes
|
||||
`armv7r-none-eabi` | * | Bare ARMv7-R
|
||||
`armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat
|
||||
`asmjs-unknown-emscripten` | ✓ | asm.js via Emscripten
|
||||
`i586-pc-windows-msvc` | ✓ | 32-bit Windows w/o SSE
|
||||
`i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE
|
||||
`i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 4.4, glibc 2.23)
|
||||
`i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL
|
||||
`i686-linux-android` | ✓ | 32-bit x86 Android
|
||||
@ -236,7 +236,7 @@ target | std | host | notes
|
||||
`hexagon-unknown-linux-musl` | ? | |
|
||||
`i386-apple-ios` | ✓ | | 32-bit x86 iOS
|
||||
`i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
|
||||
`i686-pc-windows-msvc` | ✓ | | 32-bit Windows XP support
|
||||
`i686-pc-windows-msvc` | * | | 32-bit Windows XP support
|
||||
`i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
|
||||
`i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2
|
||||
[`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD
|
||||
@ -283,7 +283,7 @@ target | std | host | notes
|
||||
[`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly
|
||||
`x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64
|
||||
`x86_64-apple-tvos` | * | | x86 64-bit tvOS
|
||||
`x86_64-pc-windows-msvc` | ✓ | | 64-bit Windows XP support
|
||||
`x86_64-pc-windows-msvc` | * | | 64-bit Windows XP support
|
||||
`x86_64-sun-solaris` | ? | | Deprecated target for 64-bit Solaris 10/11, illumos
|
||||
`x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD
|
||||
`x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
|
||||
|
@ -3,7 +3,7 @@
|
||||
// of the enclosing functions don't get lost.
|
||||
//
|
||||
// Unfortunately, the order that debuginfo gets emitted into LLVM IR becomes a bit hard
|
||||
// to predict once async fns are involved.
|
||||
// to predict once async fns are involved, so DAG allows any order.
|
||||
//
|
||||
// Note that the test does not check async-fns when targeting MSVC because debuginfo for
|
||||
// those does not follow the enum-fallback encoding yet and thus is incomplete.
|
||||
@ -27,24 +27,24 @@
|
||||
// CHECK: ![[generic_async_block_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_block"
|
||||
|
||||
// function_containing_closure<u32>()
|
||||
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}<u32>", scope: ![[function_containing_closure_NAMESPACE]]
|
||||
// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0<u32>", scope: ![[function_containing_closure_NAMESPACE]]
|
||||
// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}<u32>", scope: ![[function_containing_closure_NAMESPACE]]
|
||||
// MSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0<u32>", scope: ![[function_containing_closure_NAMESPACE]]
|
||||
|
||||
// generic_async_function<Foo>()
|
||||
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: ![[generic_async_function_NAMESPACE]]
|
||||
// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: ![[generic_async_function_NAMESPACE]]
|
||||
|
||||
// generic_async_function<u32>()
|
||||
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}<u32>", scope: ![[generic_async_function_NAMESPACE]]
|
||||
// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}<u32>", scope: ![[generic_async_function_NAMESPACE]]
|
||||
|
||||
// generic_async_block<Foo>()
|
||||
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: ![[generic_async_block_NAMESPACE]]
|
||||
// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: ![[generic_async_block_NAMESPACE]]
|
||||
|
||||
// generic_async_block<u32>()
|
||||
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}<u32>", scope: ![[generic_async_block_NAMESPACE]]
|
||||
// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}<u32>", scope: ![[generic_async_block_NAMESPACE]]
|
||||
|
||||
// function_containing_closure<Foo>()
|
||||
// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: ![[function_containing_closure_NAMESPACE]]
|
||||
// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0<debuginfo_generic_closure_env_names::Foo>", scope: ![[function_containing_closure_NAMESPACE]]
|
||||
// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: ![[function_containing_closure_NAMESPACE]]
|
||||
// MSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0<debuginfo_generic_closure_env_names::Foo>", scope: ![[function_containing_closure_NAMESPACE]]
|
||||
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
@ -5,7 +5,8 @@
|
||||
async fn a() {}
|
||||
|
||||
async fn foo() -> Result<(), i32> {
|
||||
Ok(a().await) //~ ERROR mismatched types
|
||||
a().await;
|
||||
Ok(()) //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -6,10 +6,11 @@ LL | a().await
|
||||
|
|
||||
= note: expected enum `Result<(), i32>`
|
||||
found unit type `()`
|
||||
help: try wrapping the expression in `Ok`
|
||||
help: try adding an expression at the end of the block
|
||||
|
|
||||
LL ~ a().await;
|
||||
LL ~ Ok(())
|
||||
|
|
||||
LL | Ok(a().await)
|
||||
| +++ +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
14
src/test/ui/check-cfg/allow-macro-cfg.rs
Normal file
14
src/test/ui/check-cfg/allow-macro-cfg.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// This test check that local #[allow(unexpected_cfgs)] works
|
||||
//
|
||||
// check-pass
|
||||
// compile-flags:--check-cfg=names() -Z unstable-options
|
||||
|
||||
#[allow(unexpected_cfgs)]
|
||||
fn foo() {
|
||||
if cfg!(FALSE) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[allow(unexpected_cfgs)]
|
||||
if cfg!(FALSE) {}
|
||||
}
|
11
src/test/ui/check-cfg/allow-same-level.rs
Normal file
11
src/test/ui/check-cfg/allow-same-level.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// This test check that #[allow(unexpected_cfgs)] doesn't work if put on the same level
|
||||
//
|
||||
// check-pass
|
||||
// compile-flags:--check-cfg=names() -Z unstable-options
|
||||
|
||||
#[allow(unexpected_cfgs)]
|
||||
#[cfg(FALSE)]
|
||||
//~^ WARNING unexpected `cfg` condition name
|
||||
fn bar() {}
|
||||
|
||||
fn main() {}
|
10
src/test/ui/check-cfg/allow-same-level.stderr
Normal file
10
src/test/ui/check-cfg/allow-same-level.stderr
Normal file
@ -0,0 +1,10 @@
|
||||
warning: unexpected `cfg` condition name
|
||||
--> $DIR/allow-same-level.rs:7:7
|
||||
|
|
||||
LL | #[cfg(FALSE)]
|
||||
| ^^^^^
|
||||
|
|
||||
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
15
src/test/ui/check-cfg/allow-top-level.rs
Normal file
15
src/test/ui/check-cfg/allow-top-level.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// This test check that a top-level #![allow(unexpected_cfgs)] works
|
||||
//
|
||||
// check-pass
|
||||
// compile-flags:--check-cfg=names() -Z unstable-options
|
||||
|
||||
#![allow(unexpected_cfgs)]
|
||||
|
||||
#[cfg(FALSE)]
|
||||
fn bar() {}
|
||||
|
||||
fn foo() {
|
||||
if cfg!(FALSE) {}
|
||||
}
|
||||
|
||||
fn main() {}
|
12
src/test/ui/check-cfg/allow-upper-level.rs
Normal file
12
src/test/ui/check-cfg/allow-upper-level.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// This test check that #[allow(unexpected_cfgs)] work if put on an upper level
|
||||
//
|
||||
// check-pass
|
||||
// compile-flags:--check-cfg=names() -Z unstable-options
|
||||
|
||||
#[allow(unexpected_cfgs)]
|
||||
mod aa {
|
||||
#[cfg(FALSE)]
|
||||
fn bar() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -23,6 +23,21 @@ fn b() -> Result<(), ()> {
|
||||
//~| HELP try adding an expression
|
||||
}
|
||||
|
||||
fn c() -> Option<()> {
|
||||
for _ in [1, 2] {
|
||||
//~^ ERROR mismatched types
|
||||
f();
|
||||
}
|
||||
//~^ HELP try adding an expression
|
||||
}
|
||||
|
||||
fn d() -> Option<()> {
|
||||
c()?
|
||||
//~^ ERROR incompatible types
|
||||
//~| HELP try removing this `?`
|
||||
//~| HELP try adding an expression
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: Option<()> = while false {};
|
||||
//~^ ERROR mismatched types
|
||||
|
@ -37,7 +37,52 @@ LL + Ok(())
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/compatible-variants.rs:27:25
|
||||
--> $DIR/compatible-variants.rs:27:5
|
||||
|
|
||||
LL | fn c() -> Option<()> {
|
||||
| ---------- expected `Option<()>` because of return type
|
||||
LL | / for _ in [1, 2] {
|
||||
LL | |
|
||||
LL | | f();
|
||||
LL | | }
|
||||
| |_____^ expected enum `Option`, found `()`
|
||||
|
|
||||
= note: expected enum `Option<()>`
|
||||
found unit type `()`
|
||||
help: try adding an expression at the end of the block
|
||||
|
|
||||
LL ~ }
|
||||
LL + None
|
||||
|
|
||||
LL ~ }
|
||||
LL + Some(())
|
||||
|
|
||||
|
||||
error[E0308]: `?` operator has incompatible types
|
||||
--> $DIR/compatible-variants.rs:35:5
|
||||
|
|
||||
LL | c()?
|
||||
| ^^^^ expected enum `Option`, found `()`
|
||||
|
|
||||
= note: `?` operator cannot convert from `()` to `Option<()>`
|
||||
= note: expected enum `Option<()>`
|
||||
found unit type `()`
|
||||
help: try removing this `?`
|
||||
|
|
||||
LL - c()?
|
||||
LL + c()
|
||||
|
|
||||
help: try adding an expression at the end of the block
|
||||
|
|
||||
LL ~ c()?;
|
||||
LL + None
|
||||
|
|
||||
LL ~ c()?;
|
||||
LL + Some(())
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/compatible-variants.rs:42:25
|
||||
|
|
||||
LL | let _: Option<()> = while false {};
|
||||
| ---------- ^^^^^^^^^^^^^^ expected enum `Option`, found `()`
|
||||
@ -52,7 +97,7 @@ LL | let _: Option<()> = Some(while false {});
|
||||
| +++++ +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/compatible-variants.rs:31:9
|
||||
--> $DIR/compatible-variants.rs:46:9
|
||||
|
|
||||
LL | while false {}
|
||||
| ^^^^^^^^^^^^^^ expected enum `Option`, found `()`
|
||||
@ -69,7 +114,7 @@ LL + Some(())
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/compatible-variants.rs:35:31
|
||||
--> $DIR/compatible-variants.rs:50:31
|
||||
|
|
||||
LL | let _: Result<i32, i32> = 1;
|
||||
| ---------------- ^ expected enum `Result`, found integer
|
||||
@ -86,7 +131,7 @@ LL | let _: Result<i32, i32> = Err(1);
|
||||
| ++++ +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/compatible-variants.rs:38:26
|
||||
--> $DIR/compatible-variants.rs:53:26
|
||||
|
|
||||
LL | let _: Option<i32> = 1;
|
||||
| ----------- ^ expected enum `Option`, found integer
|
||||
@ -101,7 +146,7 @@ LL | let _: Option<i32> = Some(1);
|
||||
| +++++ +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/compatible-variants.rs:41:28
|
||||
--> $DIR/compatible-variants.rs:56:28
|
||||
|
|
||||
LL | let _: Hey<i32, i32> = 1;
|
||||
| ------------- ^ expected enum `Hey`, found integer
|
||||
@ -118,7 +163,7 @@ LL | let _: Hey<i32, i32> = Hey::B(1);
|
||||
| +++++++ +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/compatible-variants.rs:44:29
|
||||
--> $DIR/compatible-variants.rs:59:29
|
||||
|
|
||||
LL | let _: Hey<i32, bool> = false;
|
||||
| -------------- ^^^^^ expected enum `Hey`, found `bool`
|
||||
@ -133,7 +178,7 @@ LL | let _: Hey<i32, bool> = Hey::B(false);
|
||||
| +++++++ +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/compatible-variants.rs:48:19
|
||||
--> $DIR/compatible-variants.rs:63:19
|
||||
|
|
||||
LL | let _ = Foo { bar };
|
||||
| ^^^ expected enum `Option`, found `i32`
|
||||
@ -145,6 +190,6 @@ help: try wrapping the expression in `Some`
|
||||
LL | let _ = Foo { bar: Some(bar) };
|
||||
| ++++++++++ +
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -29,4 +29,18 @@ fn doc_comment_on_expr(num: u8) -> bool {
|
||||
fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {}
|
||||
//~^ ERROR: unused doc comment
|
||||
|
||||
fn doc_comment_on_block() {
|
||||
/// unused doc comment
|
||||
//~^ ERROR: unused doc comment
|
||||
{
|
||||
let x = 12;
|
||||
}
|
||||
}
|
||||
|
||||
/// unused doc comment
|
||||
//~^ ERROR: unused doc comment
|
||||
extern "C" {
|
||||
fn foo();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -49,6 +49,32 @@ LL | fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {}
|
||||
|
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/unused-doc-comments-edge-cases.rs:33:5
|
||||
|
|
||||
LL | /// unused doc comment
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | / {
|
||||
LL | | let x = 12;
|
||||
LL | | }
|
||||
| |_____- rustdoc does not generate documentation for expressions
|
||||
|
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/unused-doc-comments-edge-cases.rs:40:1
|
||||
|
|
||||
LL | /// unused doc comment
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | / extern "C" {
|
||||
LL | | fn foo();
|
||||
LL | | }
|
||||
| |_- rustdoc does not generate documentation for extern block
|
||||
|
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/unused-doc-comments-edge-cases.rs:14:9
|
||||
|
|
||||
@ -63,7 +89,7 @@ help: you might have meant to return this value
|
||||
LL | return true;
|
||||
| ++++++ +
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0658.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
|
@ -0,0 +1,6 @@
|
||||
// `Rc` is not ever `Copy`, we should not suggest adding `T: Copy` constraint
|
||||
fn duplicate_rc<T>(t: std::rc::Rc<T>) -> (std::rc::Rc<T>, std::rc::Rc<T>) {
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,13 @@
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/use_of_moved_value_clone_suggestions.rs:3:9
|
||||
|
|
||||
LL | fn duplicate_rc<T>(t: std::rc::Rc<T>) -> (std::rc::Rc<T>, std::rc::Rc<T>) {
|
||||
| - move occurs because `t` has type `Rc<T>`, which does not implement the `Copy` trait
|
||||
LL | (t, t)
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
72
src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed
Normal file
72
src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed
Normal file
@ -0,0 +1,72 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn duplicate_t<T: Copy>(t: T) -> (T, T) {
|
||||
//~^ HELP consider restricting type parameter `T`
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_opt<T: Copy>(t: Option<T>) -> (Option<T>, Option<T>) {
|
||||
//~^ HELP consider restricting type parameter `T`
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_tup1<T: Copy>(t: (T,)) -> ((T,), (T,)) {
|
||||
//~^ HELP consider restricting type parameter `T`
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_tup2<A: Copy, B: Copy>(t: (A, B)) -> ((A, B), (A, B)) {
|
||||
//~^ HELP consider restricting type parameters
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_custom<T: Trait + Copy>(t: S<T>) -> (S<T>, S<T>) {
|
||||
//~^ HELP consider restricting type parameter `T`
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
struct S<T>(T);
|
||||
trait Trait {}
|
||||
impl<T: Trait + Clone> Clone for S<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
impl<T: Trait + Copy> Copy for S<T> {}
|
||||
|
||||
trait A {}
|
||||
trait B {}
|
||||
|
||||
// Test where bounds are added with different bound placements
|
||||
fn duplicate_custom_1<T: Trait + Copy>(t: S<T>) -> (S<T>, S<T>) where {
|
||||
//~^ HELP consider restricting type parameter `T`
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>)
|
||||
where
|
||||
T: A + Trait + Copy,
|
||||
//~^ HELP consider further restricting this bound
|
||||
{
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>)
|
||||
where
|
||||
T: A,
|
||||
T: B, T: Trait, T: Copy
|
||||
//~^ HELP consider further restricting type parameter `T`
|
||||
{
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>)
|
||||
where
|
||||
T: B + Trait + Copy,
|
||||
//~^ HELP consider further restricting this bound
|
||||
{
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn main() {}
|
72
src/test/ui/moves/use_of_moved_value_copy_suggestions.rs
Normal file
72
src/test/ui/moves/use_of_moved_value_copy_suggestions.rs
Normal file
@ -0,0 +1,72 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn duplicate_t<T>(t: T) -> (T, T) {
|
||||
//~^ HELP consider restricting type parameter `T`
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_opt<T>(t: Option<T>) -> (Option<T>, Option<T>) {
|
||||
//~^ HELP consider restricting type parameter `T`
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_tup1<T>(t: (T,)) -> ((T,), (T,)) {
|
||||
//~^ HELP consider restricting type parameter `T`
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_tup2<A, B>(t: (A, B)) -> ((A, B), (A, B)) {
|
||||
//~^ HELP consider restricting type parameters
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_custom<T>(t: S<T>) -> (S<T>, S<T>) {
|
||||
//~^ HELP consider restricting type parameter `T`
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
struct S<T>(T);
|
||||
trait Trait {}
|
||||
impl<T: Trait + Clone> Clone for S<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
impl<T: Trait + Copy> Copy for S<T> {}
|
||||
|
||||
trait A {}
|
||||
trait B {}
|
||||
|
||||
// Test where bounds are added with different bound placements
|
||||
fn duplicate_custom_1<T>(t: S<T>) -> (S<T>, S<T>) where {
|
||||
//~^ HELP consider restricting type parameter `T`
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>)
|
||||
where
|
||||
T: A,
|
||||
//~^ HELP consider further restricting this bound
|
||||
{
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>)
|
||||
where
|
||||
T: A,
|
||||
T: B,
|
||||
//~^ HELP consider further restricting type parameter `T`
|
||||
{
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>)
|
||||
where
|
||||
T: B,
|
||||
//~^ HELP consider further restricting this bound
|
||||
{
|
||||
(t, t) //~ use of moved value: `t`
|
||||
}
|
||||
|
||||
fn main() {}
|
147
src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
Normal file
147
src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
Normal file
@ -0,0 +1,147 @@
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/use_of_moved_value_copy_suggestions.rs:6:9
|
||||
|
|
||||
LL | fn duplicate_t<T>(t: T) -> (T, T) {
|
||||
| - move occurs because `t` has type `T`, which does not implement the `Copy` trait
|
||||
LL |
|
||||
LL | (t, t)
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | fn duplicate_t<T: Copy>(t: T) -> (T, T) {
|
||||
| ++++++
|
||||
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/use_of_moved_value_copy_suggestions.rs:11:9
|
||||
|
|
||||
LL | fn duplicate_opt<T>(t: Option<T>) -> (Option<T>, Option<T>) {
|
||||
| - move occurs because `t` has type `Option<T>`, which does not implement the `Copy` trait
|
||||
LL |
|
||||
LL | (t, t)
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | fn duplicate_opt<T: Copy>(t: Option<T>) -> (Option<T>, Option<T>) {
|
||||
| ++++++
|
||||
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/use_of_moved_value_copy_suggestions.rs:16:9
|
||||
|
|
||||
LL | fn duplicate_tup1<T>(t: (T,)) -> ((T,), (T,)) {
|
||||
| - move occurs because `t` has type `(T,)`, which does not implement the `Copy` trait
|
||||
LL |
|
||||
LL | (t, t)
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | fn duplicate_tup1<T: Copy>(t: (T,)) -> ((T,), (T,)) {
|
||||
| ++++++
|
||||
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/use_of_moved_value_copy_suggestions.rs:21:9
|
||||
|
|
||||
LL | fn duplicate_tup2<A, B>(t: (A, B)) -> ((A, B), (A, B)) {
|
||||
| - move occurs because `t` has type `(A, B)`, which does not implement the `Copy` trait
|
||||
LL |
|
||||
LL | (t, t)
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
help: consider restricting type parameters
|
||||
|
|
||||
LL | fn duplicate_tup2<A: Copy, B: Copy>(t: (A, B)) -> ((A, B), (A, B)) {
|
||||
| ++++++ ++++++
|
||||
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/use_of_moved_value_copy_suggestions.rs:26:9
|
||||
|
|
||||
LL | fn duplicate_custom<T>(t: S<T>) -> (S<T>, S<T>) {
|
||||
| - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait
|
||||
LL |
|
||||
LL | (t, t)
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | fn duplicate_custom<T: Trait + Copy>(t: S<T>) -> (S<T>, S<T>) {
|
||||
| ++++++++++++++
|
||||
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/use_of_moved_value_copy_suggestions.rs:44:9
|
||||
|
|
||||
LL | fn duplicate_custom_1<T>(t: S<T>) -> (S<T>, S<T>) where {
|
||||
| - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait
|
||||
LL |
|
||||
LL | (t, t)
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | fn duplicate_custom_1<T: Trait + Copy>(t: S<T>) -> (S<T>, S<T>) where {
|
||||
| ++++++++++++++
|
||||
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/use_of_moved_value_copy_suggestions.rs:52:9
|
||||
|
|
||||
LL | fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>)
|
||||
| - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | (t, t)
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
LL | T: A + Trait + Copy,
|
||||
| ++++++++++++++
|
||||
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/use_of_moved_value_copy_suggestions.rs:61:9
|
||||
|
|
||||
LL | fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>)
|
||||
| - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | (t, t)
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
help: consider further restricting type parameter `T`
|
||||
|
|
||||
LL | T: B, T: Trait, T: Copy
|
||||
| ~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/use_of_moved_value_copy_suggestions.rs:69:9
|
||||
|
|
||||
LL | fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>)
|
||||
| - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | (t, t)
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
LL | T: B + Trait + Copy,
|
||||
| ++++++++++++++
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
Loading…
Reference in New Issue
Block a user