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:
bors 2022-03-03 04:28:08 +00:00
commit 2f8d1a835b
43 changed files with 972 additions and 255 deletions

View File

@ -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(),

View File

@ -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)

View File

@ -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) => {

View File

@ -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.

View File

@ -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();
}

View File

@ -576,12 +576,12 @@ pub enum PassKind {
Module,
}
/// LLVMRustThinLTOData
// LLVMRustThinLTOData
extern "C" {
pub type ThinLTOData;
}
/// LLVMRustThinLTOBuffer
// LLVMRustThinLTOBuffer
extern "C" {
pub type ThinLTOBuffer;
}

View File

@ -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,
}
}

View File

@ -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)
})
}

View File

@ -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)
}

View File

@ -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);

View File

@ -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", &param.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! {

View File

@ -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,
}
}

View File

@ -56,6 +56,7 @@
#![feature(nonzero_ops)]
#![feature(unwrap_infallible)]
#![feature(decl_macro)]
#![feature(drain_filter)]
#![recursion_limit = "512"]
#![allow(rustc::potential_query_instability)]

View File

@ -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),
)

View File

@ -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[..] {
[&param_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[..] {
[&param_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.

View File

@ -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) {

View File

@ -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(

View File

@ -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;

View File

@ -11,3 +11,6 @@
// Implementations for `AsRawFd` etc. for network types.
mod net;
#[cfg(test)]
mod tests;

View File

@ -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()) }
}
}

View 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);
}

View File

@ -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()) }
}
}

View File

@ -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()) }
}
}

View File

@ -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

View File

@ -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

View File

@ -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"]

View File

@ -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() {}

View File

@ -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

View 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) {}
}

View 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() {}

View 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

View 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() {}

View 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() {}

View File

@ -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

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View 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() {}

View 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() {}

View 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`.