Auto merge of #104428 - matthiaskrgr:rollup-jo3078i, r=matthiaskrgr

Rollup of 13 pull requests

Successful merges:

 - #103842 (Adding Fuchsia compiler testing script, docs)
 - #104354 (Remove leading newlines from `NonZero*` doc examples)
 - #104372 (Update compiler-builtins)
 - #104380 (rustdoc: remove unused CSS `code { opacity: 1 }`)
 - #104381 (Remove dead NoneError diagnostic handling)
 - #104383 (Remove unused symbols and diagnostic items)
 - #104391 (Deriving cleanups)
 - #104403 (Specify language of code comment to generate document)
 - #104404 (Fix missing minification for static files)
 - #104413 ([llvm-wrapper] adapt for LLVM API change)
 - #104415 (rustdoc: fix corner case in search keyboard commands)
 - #104422 (Fix suggest associated call syntax)
 - #104426 (Add test for #102154)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors
2022-11-15 06:43:28 +00:00
38 changed files with 1444 additions and 349 deletions
+7 -9
View File
@@ -392,15 +392,7 @@ pub struct Generics {
impl Default for Generics {
/// Creates an instance of `Generics`.
fn default() -> Generics {
Generics {
params: Vec::new(),
where_clause: WhereClause {
has_where_token: false,
predicates: Vec::new(),
span: DUMMY_SP,
},
span: DUMMY_SP,
}
Generics { params: Vec::new(), where_clause: Default::default(), span: DUMMY_SP }
}
}
@@ -415,6 +407,12 @@ pub struct WhereClause {
pub span: Span,
}
impl Default for WhereClause {
fn default() -> WhereClause {
WhereClause { has_where_token: false, predicates: Vec::new(), span: DUMMY_SP }
}
}
/// A single predicate in a where-clause.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum WherePredicate {
@@ -1,4 +1,3 @@
use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::path_std;
@@ -19,7 +18,6 @@ pub fn expand_deriving_copy(
path: path_std!(marker::Copy),
skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: true,
methods: Vec::new(),
associated_types: Vec::new(),
@@ -75,7 +75,6 @@ pub fn expand_deriving_clone(
path: path_std!(clone::Clone),
skip_path_as_bound: false,
additional_bounds: bounds,
generics: Bounds::empty(),
supports_unions: true,
methods: vec![MethodDef {
name: sym::clone,
@@ -28,7 +28,6 @@ pub fn expand_deriving_eq(
path: path_std!(cmp::Eq),
skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: true,
methods: vec![MethodDef {
name: sym::assert_receiver_is_total_eq,
@@ -22,7 +22,6 @@ pub fn expand_deriving_ord(
path: path_std!(cmp::Ord),
skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
methods: vec![MethodDef {
name: sym::cmp,
@@ -86,7 +86,6 @@ fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOr
path: path_std!(cmp::PartialEq),
skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
methods,
associated_types: Vec::new(),
@@ -40,7 +40,6 @@ pub fn expand_deriving_partial_ord(
path: path_std!(cmp::PartialOrd),
skip_path_as_bound: false,
additional_bounds: vec![],
generics: Bounds::empty(),
supports_unions: false,
methods: vec![partial_cmp_def],
associated_types: Vec::new(),
@@ -23,7 +23,6 @@ pub fn expand_deriving_debug(
path: path_std!(fmt::Debug),
skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
methods: vec![MethodDef {
name: sym::fmt,
@@ -26,7 +26,6 @@ pub fn expand_deriving_rustc_decodable(
path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
methods: vec![MethodDef {
name: sym::decode,
@@ -27,7 +27,6 @@ pub fn expand_deriving_default(
path: Path::new(vec![kw::Default, sym::Default]),
skip_path_as_bound: has_a_default_variant(item),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
methods: vec![MethodDef {
name: kw::Default,
@@ -110,7 +110,6 @@ pub fn expand_deriving_rustc_encodable(
path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
methods: vec![MethodDef {
name: sym::encode,
@@ -195,9 +195,6 @@ pub struct TraitDef<'a> {
/// other than the current trait
pub additional_bounds: Vec<Ty>,
/// Any extra lifetimes and/or bounds, e.g., `D: serialize::Decoder`
pub generics: Bounds,
/// Can this trait be derived for unions?
pub supports_unions: bool,
@@ -583,19 +580,21 @@ fn create_derived_impl(
})
});
let Generics { mut params, mut where_clause, .. } =
self.generics.to_generics(cx, self.span, type_ident, generics);
let mut where_clause = ast::WhereClause::default();
where_clause.span = generics.where_clause.span;
let ctxt = self.span.ctxt();
let span = generics.span.with_ctxt(ctxt);
// Create the generic parameters
params.extend(generics.params.iter().map(|param| match &param.kind {
GenericParamKind::Lifetime { .. } => param.clone(),
GenericParamKind::Type { .. } => {
// I don't think this can be moved out of the loop, since
// a GenericBound requires an ast id
let bounds: Vec<_> =
let params: Vec<_> = generics
.params
.iter()
.map(|param| match &param.kind {
GenericParamKind::Lifetime { .. } => param.clone(),
GenericParamKind::Type { .. } => {
// I don't think this can be moved out of the loop, since
// a GenericBound requires an ast id
let bounds: Vec<_> =
// extra restrictions on the generics parameters to the
// type being derived upon
self.additional_bounds.iter().map(|p| {
@@ -608,21 +607,22 @@ fn create_derived_impl(
param.bounds.iter().cloned()
).collect();
cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None)
}
GenericParamKind::Const { ty, kw_span, .. } => {
let const_nodefault_kind = GenericParamKind::Const {
ty: ty.clone(),
kw_span: kw_span.with_ctxt(ctxt),
cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None)
}
GenericParamKind::Const { ty, kw_span, .. } => {
let const_nodefault_kind = GenericParamKind::Const {
ty: ty.clone(),
kw_span: kw_span.with_ctxt(ctxt),
// We can't have default values inside impl block
default: None,
};
let mut param_clone = param.clone();
param_clone.kind = const_nodefault_kind;
param_clone
}
}));
// We can't have default values inside impl block
default: None,
};
let mut param_clone = param.clone();
param_clone.kind = const_nodefault_kind;
param_clone
}
})
.collect();
// and similarly for where clauses
where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
@@ -1062,18 +1062,15 @@ fn expand_struct_method_body<'b>(
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, true);
mk_body(cx, selflike_fields)
} else {
// Neither packed nor copy. Need to use ref patterns.
// Packed and not copy. Need to use ref patterns.
let prefixes: Vec<_> =
(0..selflike_args.len()).map(|i| format!("__self_{}", i)).collect();
let addr_of = always_copy;
let selflike_fields =
trait_.create_struct_pattern_fields(cx, struct_def, &prefixes, addr_of);
let selflike_fields = trait_.create_struct_pattern_fields(cx, struct_def, &prefixes);
let mut body = mk_body(cx, selflike_fields);
let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]);
let by_ref = ByRef::from(is_packed && !always_copy);
let patterns =
trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, by_ref);
trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, ByRef::Yes);
// Do the let-destructuring.
let mut stmts: Vec<_> = iter::zip(selflike_args, patterns)
@@ -1254,9 +1251,7 @@ fn expand_enum_method_body<'b>(
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
// (see "Final wrinkle" note below for why.)
let addr_of = false; // because enums can't be repr(packed)
let fields =
trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes, addr_of);
let fields = trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes);
let sp = variant.span.with_ctxt(trait_.span.ctxt());
let variant_path = cx.path(sp, vec![type_ident, variant.ident]);
@@ -1519,15 +1514,13 @@ fn create_struct_pattern_fields(
cx: &mut ExtCtxt<'_>,
struct_def: &'a VariantData,
prefixes: &[String],
addr_of: bool,
) -> Vec<FieldInfo> {
self.create_fields(struct_def, |i, _struct_field, sp| {
prefixes
.iter()
.map(|prefix| {
let ident = self.mk_pattern_ident(prefix, i);
let expr = cx.expr_path(cx.path_ident(sp, ident));
if addr_of { cx.expr_addr_of(sp, expr) } else { expr }
cx.expr_path(cx.path_ident(sp, ident))
})
.collect()
})
@@ -25,7 +25,6 @@ pub fn expand_deriving_hash(
path,
skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
methods: vec![MethodDef {
name: sym::hash,
+171 -145
View File
@@ -20,11 +20,10 @@
};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::traits::util::supertraits;
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::print::with_crate_prefix;
use rustc_middle::ty::{
self, DefIdTree, GenericArg, GenericArgKind, ToPredicate, Ty, TyCtxt, TypeVisitable,
};
use rustc_middle::ty::{self, DefIdTree, GenericArgKind, ToPredicate, Ty, TyCtxt, TypeVisitable};
use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
@@ -263,15 +262,15 @@ pub fn report_method_error(
}) => {
let tcx = self.tcx;
let actual = self.resolve_vars_if_possible(rcvr_ty);
let ty_str = self.ty_to_string(actual);
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
let ty_str = self.ty_to_string(rcvr_ty);
let is_method = mode == Mode::MethodCall;
let item_kind = if is_method {
"method"
} else if actual.is_enum() {
} else if rcvr_ty.is_enum() {
"variant or associated item"
} else {
match (item_name.as_str().chars().next(), actual.is_fresh_ty()) {
match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) {
(Some(name), false) if name.is_lowercase() => "function or associated item",
(Some(_), false) => "associated item",
(Some(_), true) | (None, false) => "variant or associated item",
@@ -280,9 +279,9 @@ pub fn report_method_error(
};
if self.suggest_wrapping_range_with_parens(
tcx, actual, source, span, item_name, &ty_str,
tcx, rcvr_ty, source, span, item_name, &ty_str,
) || self.suggest_constraining_numerical_ty(
tcx, actual, source, span, item_kind, item_name, &ty_str,
tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str,
) {
return None;
}
@@ -290,9 +289,9 @@ pub fn report_method_error(
// Don't show generic arguments when the method can't be found in any implementation (#81576).
let mut ty_str_reported = ty_str.clone();
if let ty::Adt(_, generics) = actual.kind() {
if let ty::Adt(_, generics) = rcvr_ty.kind() {
if generics.len() > 0 {
let mut autoderef = self.autoderef(span, actual);
let mut autoderef = self.autoderef(span, rcvr_ty);
let candidate_found = autoderef.any(|(ty, _)| {
if let ty::Adt(adt_def, _) = ty.kind() {
self.tcx
@@ -321,16 +320,16 @@ pub fn report_method_error(
"no {} named `{}` found for {} `{}` in the current scope",
item_kind,
item_name,
actual.prefix_string(self.tcx),
rcvr_ty.prefix_string(self.tcx),
ty_str_reported,
);
if actual.references_error() {
if rcvr_ty.references_error() {
err.downgrade_to_delayed_bug();
}
if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
self.suggest_await_before_method(
&mut err, item_name, actual, cal, span,
&mut err, item_name, rcvr_ty, cal, span,
);
}
if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) {
@@ -341,7 +340,7 @@ pub fn report_method_error(
Applicability::MachineApplicable,
);
}
if let ty::RawPtr(_) = &actual.kind() {
if let ty::RawPtr(_) = &rcvr_ty.kind() {
err.note(
"try using `<*const T>::as_ref()` to get a reference to the \
type behind the pointer: https://doc.rust-lang.org/std/\
@@ -353,7 +352,7 @@ pub fn report_method_error(
);
}
let ty_span = match actual.kind() {
let ty_span = match rcvr_ty.kind() {
ty::Param(param_type) => Some(
param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()),
),
@@ -365,7 +364,7 @@ pub fn report_method_error(
span,
format!(
"{item_kind} `{item_name}` not found for this {}",
actual.prefix_string(self.tcx)
rcvr_ty.prefix_string(self.tcx)
),
);
}
@@ -398,122 +397,15 @@ pub fn report_method_error(
custom_span_label = true;
}
if static_candidates.len() == 1 {
let mut has_unsuggestable_args = false;
let ty_str = if let Some(CandidateSource::Impl(impl_did)) =
static_candidates.get(0)
{
// When the "method" is resolved through dereferencing, we really want the
// original type that has the associated function for accurate suggestions.
// (#61411)
let ty = tcx.at(span).type_of(*impl_did);
match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) {
(ty::Adt(def, _), ty::Adt(def_actual, substs)) if def == def_actual => {
// If there are any inferred arguments, (`{integer}`), we should replace
// them with underscores to allow the compiler to infer them
let infer_substs: Vec<GenericArg<'_>> = substs
.into_iter()
.map(|arg| {
if !arg.is_suggestable(tcx, true) {
has_unsuggestable_args = true;
match arg.unpack() {
GenericArgKind::Lifetime(_) => self
.next_region_var(RegionVariableOrigin::MiscVariable(
rustc_span::DUMMY_SP,
))
.into(),
GenericArgKind::Type(_) => self
.next_ty_var(TypeVariableOrigin {
span: rustc_span::DUMMY_SP,
kind: TypeVariableOriginKind::MiscVariable,
})
.into(),
GenericArgKind::Const(arg) => self
.next_const_var(
arg.ty(),
ConstVariableOrigin {
span: rustc_span::DUMMY_SP,
kind: ConstVariableOriginKind::MiscVariable,
},
)
.into(),
}
} else {
arg
}
})
.collect::<Vec<_>>();
tcx.value_path_str_with_substs(
def_actual.did(),
tcx.intern_substs(&infer_substs),
)
}
_ => self.ty_to_value_string(ty.peel_refs()),
}
} else {
self.ty_to_value_string(actual.peel_refs())
};
if let SelfSource::MethodCall(_) = source {
let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) &&
let Some(assoc) = self.associated_value(*impl_did, item_name) {
let sig = self.tcx.fn_sig(assoc.def_id);
if let Some(first) = sig.inputs().skip_binder().get(0) {
if first.peel_refs() == rcvr_ty.peel_refs() {
None
} else {
Some(if first.is_region_ptr() {
if first.is_mutable_ptr() { "&mut " } else { "&" }
} else {
""
})
}
} else {
None
}
} else {
None
};
let mut applicability = Applicability::MachineApplicable;
let args = if let Some((receiver, args)) = args {
// The first arg is the same kind as the receiver
let explicit_args = if first_arg.is_some() {
std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
} else {
// There is no `Self` kind to infer the arguments from
if has_unsuggestable_args {
applicability = Applicability::HasPlaceholders;
}
args.iter().collect()
};
format!(
"({}{})",
first_arg.unwrap_or(""),
explicit_args
.iter()
.map(|arg| tcx
.sess
.source_map()
.span_to_snippet(arg.span)
.unwrap_or_else(|_| {
applicability = Applicability::HasPlaceholders;
"_".to_owned()
}))
.collect::<Vec<_>>()
.join(", "),
)
} else {
applicability = Applicability::HasPlaceholders;
"(...)".to_owned()
};
err.span_suggestion(
sugg_span,
"use associated function syntax instead",
format!("{}::{}{}", ty_str, item_name, args),
applicability,
);
} else {
err.help(&format!("try with `{}::{}`", ty_str, item_name,));
}
self.suggest_associated_call_syntax(
&mut err,
&static_candidates,
rcvr_ty,
source,
item_name,
args,
sugg_span,
);
report_candidates(span, &mut err, &mut static_candidates, sugg_span);
} else if static_candidates.len() > 1 {
@@ -523,7 +415,7 @@ pub fn report_method_error(
let mut bound_spans = vec![];
let mut restrict_type_params = false;
let mut unsatisfied_bounds = false;
if item_name.name == sym::count && self.is_slice_ty(actual, span) {
if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
let msg = "consider using `len` instead";
if let SelfSource::MethodCall(_expr) = source {
err.span_suggestion_short(
@@ -537,7 +429,7 @@ pub fn report_method_error(
}
if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
let iterator_trait = self.tcx.def_path_str(iterator_trait);
err.note(&format!("`count` is defined on `{iterator_trait}`, which `{actual}` does not implement"));
err.note(&format!("`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"));
}
} else if !unsatisfied_predicates.is_empty() {
let mut type_params = FxHashMap::default();
@@ -876,7 +768,7 @@ trait bound{s}",
.map(|(_, path)| path)
.collect::<Vec<_>>()
.join("\n");
let actual_prefix = actual.prefix_string(self.tcx);
let actual_prefix = rcvr_ty.prefix_string(self.tcx);
info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
let (primary_message, label) =
if unimplemented_traits.len() == 1 && unimplemented_traits_only {
@@ -885,7 +777,7 @@ trait bound{s}",
.next()
.map(|(_, (trait_ref, obligation))| {
if trait_ref.self_ty().references_error()
|| actual.references_error()
|| rcvr_ty.references_error()
{
// Avoid crashing.
return (None, None);
@@ -921,7 +813,7 @@ trait bound{s}",
let label_span_not_found = |err: &mut Diagnostic| {
if unsatisfied_predicates.is_empty() {
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
let is_string_or_ref_str = match actual.kind() {
let is_string_or_ref_str = match rcvr_ty.kind() {
ty::Ref(_, ty, _) => {
ty.is_str()
|| matches!(
@@ -957,7 +849,7 @@ trait bound{s}",
// different from the received one
// So we avoid suggestion method with Box<Self>
// for instance
self.tcx.at(span).type_of(*def_id) != actual
self.tcx.at(span).type_of(*def_id) != rcvr_ty
&& self.tcx.at(span).type_of(*def_id) != rcvr_ty
}
(Mode::Path, false, _) => true,
@@ -1017,10 +909,12 @@ trait bound{s}",
// Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
// can't be called due to `typeof(expr): Clone` not holding.
if unsatisfied_predicates.is_empty() {
self.suggest_calling_method_on_field(&mut err, source, span, actual, item_name);
self.suggest_calling_method_on_field(
&mut err, source, span, rcvr_ty, item_name,
);
}
self.check_for_inner_self(&mut err, source, span, actual, item_name);
self.check_for_inner_self(&mut err, source, span, rcvr_ty, item_name);
bound_spans.sort();
bound_spans.dedup();
@@ -1028,7 +922,7 @@ trait bound{s}",
err.span_label(span, &msg);
}
if actual.is_numeric() && actual.is_fresh() || restrict_type_params {
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
} else {
self.suggest_traits_to_import(
&mut err,
@@ -1046,8 +940,8 @@ trait bound{s}",
// Don't emit a suggestion if we found an actual method
// that had unsatisfied trait bounds
if unsatisfied_predicates.is_empty() && actual.is_enum() {
let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
if let Some(suggestion) = lev_distance::find_best_match_for_name(
&adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
item_name.name,
@@ -1062,7 +956,7 @@ trait bound{s}",
}
}
if item_name.name == sym::as_str && actual.peel_refs().is_str() {
if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
let msg = "remove this method call";
let mut fallback_span = true;
if let SelfSource::MethodCall(expr) = source {
@@ -1178,6 +1072,138 @@ trait bound{s}",
None
}
/// Suggest calling `Ty::method` if `.method()` isn't found because the method
/// doesn't take a `self` receiver.
fn suggest_associated_call_syntax(
&self,
err: &mut Diagnostic,
static_candidates: &Vec<CandidateSource>,
rcvr_ty: Ty<'tcx>,
source: SelfSource<'tcx>,
item_name: Ident,
args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>])>,
sugg_span: Span,
) {
let mut has_unsuggestable_args = false;
let ty_str = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) {
// When the "method" is resolved through dereferencing, we really want the
// original type that has the associated function for accurate suggestions.
// (#61411)
let impl_ty = self.tcx.type_of(*impl_did);
let target_ty = self
.autoderef(sugg_span, rcvr_ty)
.find(|(rcvr_ty, _)| {
DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer }
.types_may_unify(*rcvr_ty, impl_ty)
})
.map_or(impl_ty, |(ty, _)| ty)
.peel_refs();
if let ty::Adt(def, substs) = target_ty.kind() {
// If there are any inferred arguments, (`{integer}`), we should replace
// them with underscores to allow the compiler to infer them
let infer_substs = self.tcx.mk_substs(substs.into_iter().map(|arg| {
if !arg.is_suggestable(self.tcx, true) {
has_unsuggestable_args = true;
match arg.unpack() {
GenericArgKind::Lifetime(_) => self
.next_region_var(RegionVariableOrigin::MiscVariable(
rustc_span::DUMMY_SP,
))
.into(),
GenericArgKind::Type(_) => self
.next_ty_var(TypeVariableOrigin {
span: rustc_span::DUMMY_SP,
kind: TypeVariableOriginKind::MiscVariable,
})
.into(),
GenericArgKind::Const(arg) => self
.next_const_var(
arg.ty(),
ConstVariableOrigin {
span: rustc_span::DUMMY_SP,
kind: ConstVariableOriginKind::MiscVariable,
},
)
.into(),
}
} else {
arg
}
}));
self.tcx.value_path_str_with_substs(def.did(), infer_substs)
} else {
self.ty_to_value_string(target_ty)
}
} else {
self.ty_to_value_string(rcvr_ty.peel_refs())
};
if let SelfSource::MethodCall(_) = source {
let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0)
&& let Some(assoc) = self.associated_value(*impl_did, item_name)
&& assoc.kind == ty::AssocKind::Fn
{
let sig = self.tcx.fn_sig(assoc.def_id);
if let Some(first) = sig.inputs().skip_binder().get(0) {
if first.peel_refs() == rcvr_ty.peel_refs() {
None
} else {
Some(if first.is_region_ptr() {
if first.is_mutable_ptr() { "&mut " } else { "&" }
} else {
""
})
}
} else {
None
}
} else {
None
};
let mut applicability = Applicability::MachineApplicable;
let args = if let Some((receiver, args)) = args {
// The first arg is the same kind as the receiver
let explicit_args = if first_arg.is_some() {
std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
} else {
// There is no `Self` kind to infer the arguments from
if has_unsuggestable_args {
applicability = Applicability::HasPlaceholders;
}
args.iter().collect()
};
format!(
"({}{})",
first_arg.unwrap_or(""),
explicit_args
.iter()
.map(|arg| self
.tcx
.sess
.source_map()
.span_to_snippet(arg.span)
.unwrap_or_else(|_| {
applicability = Applicability::HasPlaceholders;
"_".to_owned()
}))
.collect::<Vec<_>>()
.join(", "),
)
} else {
applicability = Applicability::HasPlaceholders;
"(...)".to_owned()
};
err.span_suggestion(
sugg_span,
"use associated function syntax instead",
format!("{}::{}{}", ty_str, item_name, args),
applicability,
);
} else {
err.help(&format!("try with `{}::{}`", ty_str, item_name,));
}
}
/// Suggest calling a field with a type that implements the `Fn*` traits instead of a method with
/// the same name as the field i.e. `(a.my_fn_ptr)(10)` instead of `a.my_fn_ptr(10)`.
fn suggest_calling_field_as_fn(
+2 -1
View File
@@ -11,7 +11,8 @@
/// scope.
///
/// ### Example
/// ```
///
/// ```rust
/// struct SomeStruct;
/// impl Drop for SomeStruct {
/// fn drop(&mut self) {
@@ -9,7 +9,7 @@
#include "llvm/IR/IntrinsicsARM.h"
#include "llvm/IR/Mangler.h"
#if LLVM_VERSION_GE(16, 0)
#include "llvm/IR/ModRef.h"
#include "llvm/Support/ModRef.h"
#endif
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFFImportFile.h"
+1 -52
View File
@@ -170,8 +170,6 @@
Count,
Cow,
Debug,
DebugStruct,
DebugTuple,
Decodable,
Decoder,
DecorateLint,
@@ -190,9 +188,6 @@
Error,
File,
FileType,
Fn,
FnMut,
FnOnce,
FormatSpec,
Formatter,
From,
@@ -211,7 +206,6 @@
Input,
Into,
IntoDiagnostic,
IntoFuture,
IntoIterator,
IoRead,
IoWrite,
@@ -256,7 +250,6 @@
Pointer,
Poll,
ProcMacro,
ProcMacroHack,
ProceduralMasqueradeDummyType,
Range,
RangeFrom,
@@ -332,7 +325,6 @@
abi_vectorcall,
abi_x86_interrupt,
abort,
aborts,
add,
add_assign,
add_with_overflow,
@@ -344,7 +336,6 @@
align,
align_offset,
alignment,
alignstack,
all,
alloc,
alloc_error_handler,
@@ -433,7 +424,6 @@
bool,
borrowck_graphviz_format,
borrowck_graphviz_postflow,
borrowck_graphviz_preflow,
box_free,
box_patterns,
box_syntax,
@@ -462,7 +452,6 @@
cfg_doctest,
cfg_eval,
cfg_hide,
cfg_macro,
cfg_panic,
cfg_sanitize,
cfg_target_abi,
@@ -470,7 +459,6 @@
cfg_target_feature,
cfg_target_has_atomic,
cfg_target_has_atomic_equal_alignment,
cfg_target_has_atomic_load_store,
cfg_target_thread_local,
cfg_target_vendor,
cfg_version,
@@ -495,19 +483,15 @@
cold,
collapse_debuginfo,
column,
column_macro,
compare_and_swap,
compare_exchange,
compare_exchange_weak,
compile_error,
compile_error_macro,
compiler,
compiler_builtins,
compiler_fence,
concat,
concat_bytes,
concat_idents,
concat_macro,
conservative_impl_trait,
console,
const_allocate,
@@ -528,7 +512,6 @@
const_fn_unsize,
const_for,
const_format_args,
const_generic_defaults,
const_generics,
const_generics_defaults,
const_if_match,
@@ -547,22 +530,19 @@
const_trait,
const_trait_bound_opt_out,
const_trait_impl,
const_transmute,
const_try,
constant,
constructor,
contents,
context,
convert,
copy,
copy_closures,
copy_nonoverlapping,
copysignf32,
copysignf64,
core,
core_intrinsics,
core_panic,
core_panic_2015_macro,
core_panic_2021_macro,
core_panic_macro,
cosf32,
cosf64,
@@ -598,7 +578,6 @@
debug_assertions,
debug_struct,
debug_struct_fields_finish,
debug_trait_builder,
debug_tuple,
debug_tuple_fields_finish,
debugger_visualizer,
@@ -630,7 +609,6 @@
discriminant_type,
discriminant_value,
dispatch_from_dyn,
display_trait,
div,
div_assign,
doc,
@@ -661,7 +639,6 @@
dyn_star,
dyn_trait,
e,
edition_macro_pats,
edition_panic,
eh_catch_typeinfo,
eh_personality,
@@ -674,7 +651,6 @@
encode,
end,
env,
env_macro,
eprint_macro,
eprintln_macro,
eq,
@@ -724,9 +700,7 @@
field,
field_init_shorthand,
file,
file_macro,
fill,
finish,
flags,
float,
float_to_int_unchecked,
@@ -735,8 +709,6 @@
fmaf32,
fmaf64,
fmt,
fmt_as_str,
fmt_internals,
fmul_fast,
fn_align,
fn_must_use,
@@ -751,7 +723,6 @@
format_args_macro,
format_args_nl,
format_macro,
fp,
freeze,
freg,
frem_fast,
@@ -814,7 +785,6 @@
ignore,
impl_header_lifetime_elision,
impl_lint_pass,
impl_macros,
impl_trait_in_bindings,
impl_trait_in_fn_trait_return,
implied_by,
@@ -826,7 +796,6 @@
include,
include_bytes,
include_bytes_macro,
include_macro,
include_str,
include_str_macro,
inclusive_range_syntax,
@@ -844,7 +813,6 @@
instruction_set,
integer_: "integer",
integral,
intel,
into_future,
into_iter,
intra_doc_pointers,
@@ -881,7 +849,6 @@
lifetimes,
likely,
line,
line_macro,
link,
link_args,
link_cfg,
@@ -926,7 +893,6 @@
masked,
match_beginning_vert,
match_default_bindings,
matches_macro,
maxnumf32,
maxnumf64,
may_dangle,
@@ -965,7 +931,6 @@
modifiers,
module,
module_path,
module_path_macro,
more_qualified_paths,
more_struct_aliases,
movbe_target_feature,
@@ -1035,7 +1000,6 @@
non_exhaustive,
non_exhaustive_omitted_patterns_lint,
non_modrs_mods,
none_error,
nontemporal_store,
noop_method_borrow,
noop_method_clone,
@@ -1060,7 +1024,6 @@
optin_builtin_traits,
option,
option_env,
option_env_macro,
options,
or,
or_patterns,
@@ -1103,7 +1066,6 @@
plugins,
pointee_trait,
pointer,
pointer_trait_fmt,
poll,
position,
post_dash_lto: "post-lto",
@@ -1130,7 +1092,6 @@
proc_dash_macro: "proc-macro",
proc_macro,
proc_macro_attribute,
proc_macro_def_site,
proc_macro_derive,
proc_macro_expr,
proc_macro_gen,
@@ -1231,9 +1192,6 @@
rust_cold_cc,
rust_eh_catch_typeinfo,
rust_eh_personality,
rust_eh_register_frames,
rust_eh_unregister_frames,
rust_oom,
rustc,
rustc_allocator,
rustc_allocator_zeroed,
@@ -1306,7 +1264,6 @@
rustc_serialize,
rustc_skip_array_during_method_dispatch,
rustc_specialization_trait,
rustc_stable,
rustc_std_internal_symbol,
rustc_strict_coherence,
rustc_symbol_name,
@@ -1434,7 +1391,6 @@
static_recursion,
staticlib,
std,
std_inject,
std_panic,
std_panic_2015_macro,
std_panic_macro,
@@ -1449,7 +1405,6 @@
str_trim_start,
strict_provenance,
stringify,
stringify_macro,
struct_field_attributes,
struct_inherit,
struct_variant,
@@ -1477,10 +1432,8 @@
target_has_atomic_load_store,
target_os,
target_pointer_width,
target_target_vendor,
target_thread_local,
target_vendor,
task,
tbm_target_feature,
termination,
termination_trait,
@@ -1492,7 +1445,6 @@
test_removed_feature,
test_runner,
test_unstable_lint,
then_with,
thread,
thread_local,
thread_local_macro,
@@ -1524,7 +1476,6 @@
try_trait_v2,
tt,
tuple,
tuple_from_req,
tuple_indexing,
tuple_trait,
two_phase,
@@ -1568,7 +1519,6 @@
unreachable_2015,
unreachable_2015_macro,
unreachable_2021,
unreachable_2021_macro,
unreachable_code,
unreachable_display,
unreachable_macro,
@@ -1587,7 +1537,6 @@
from crates.io via `Cargo.toml` instead?",
untagged_unions,
unused_imports,
unused_qualifications,
unwind,
unwind_attributes,
unwind_safe_trait,
@@ -650,41 +650,14 @@ fn report_selection_error(
))
);
if is_try_conversion {
let none_error = self
.tcx
.get_diagnostic_item(sym::none_error)
.map(|def_id| tcx.type_of(def_id));
let should_convert_option_to_result =
Some(trait_ref.skip_binder().substs.type_at(1)) == none_error;
let should_convert_result_to_option =
Some(trait_ref.self_ty().skip_binder()) == none_error;
if should_convert_option_to_result {
err.span_suggestion_verbose(
span.shrink_to_lo(),
"consider converting the `Option<T>` into a `Result<T, _>` \
using `Option::ok_or` or `Option::ok_or_else`",
".ok_or_else(|| /* error value */)",
Applicability::HasPlaceholders,
);
} else if should_convert_result_to_option {
err.span_suggestion_verbose(
span.shrink_to_lo(),
"consider converting the `Result<T, _>` into an `Option<T>` \
using `Result::ok`",
".ok()",
Applicability::MachineApplicable,
);
}
if let Some(ret_span) = self.return_type_span(&obligation) {
err.span_label(
ret_span,
&format!(
"expected `{}` because of this",
trait_ref.skip_binder().self_ty()
),
);
}
if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
err.span_label(
ret_span,
&format!(
"expected `{}` because of this",
trait_ref.skip_binder().self_ty()
),
);
}
if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
-1
View File
@@ -1054,7 +1054,6 @@ pub trait UpperHex {
pub trait Pointer {
/// Formats the value using the given formatter.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "pointer_trait_fmt"]
fn fmt(&self, f: &mut Formatter<'_>) -> Result;
}
-12
View File
@@ -338,7 +338,6 @@ macro_rules! debug_assert_ne {
/// ```
#[macro_export]
#[stable(feature = "matches_macro", since = "1.42.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "matches_macro")]
macro_rules! matches {
($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
match $expression {
@@ -820,7 +819,6 @@ pub(crate) mod builtin {
#[stable(feature = "compile_error_macro", since = "1.20.0")]
#[rustc_builtin_macro]
#[macro_export]
#[cfg_attr(not(test), rustc_diagnostic_item = "compile_error_macro")]
macro_rules! compile_error {
($msg:expr $(,)?) => {{ /* compiler built-in */ }};
}
@@ -944,7 +942,6 @@ macro_rules! format_args_nl {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
#[cfg_attr(not(test), rustc_diagnostic_item = "env_macro")]
macro_rules! env {
($name:expr $(,)?) => {{ /* compiler built-in */ }};
($name:expr, $error_msg:expr $(,)?) => {{ /* compiler built-in */ }};
@@ -973,7 +970,6 @@ macro_rules! env {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
#[cfg_attr(not(test), rustc_diagnostic_item = "option_env_macro")]
macro_rules! option_env {
($name:expr $(,)?) => {{ /* compiler built-in */ }};
}
@@ -1058,7 +1054,6 @@ macro_rules! concat_bytes {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
#[cfg_attr(not(test), rustc_diagnostic_item = "concat_macro")]
macro_rules! concat {
($($e:expr),* $(,)?) => {{ /* compiler built-in */ }};
}
@@ -1084,7 +1079,6 @@ macro_rules! concat {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
#[cfg_attr(not(test), rustc_diagnostic_item = "line_macro")]
macro_rules! line {
() => {
/* compiler built-in */
@@ -1124,7 +1118,6 @@ macro_rules! line {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
#[cfg_attr(not(test), rustc_diagnostic_item = "column_macro")]
macro_rules! column {
() => {
/* compiler built-in */
@@ -1150,7 +1143,6 @@ macro_rules! column {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
#[cfg_attr(not(test), rustc_diagnostic_item = "file_macro")]
macro_rules! file {
() => {
/* compiler built-in */
@@ -1175,7 +1167,6 @@ macro_rules! file {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
#[cfg_attr(not(test), rustc_diagnostic_item = "stringify_macro")]
macro_rules! stringify {
($($t:tt)*) => {
/* compiler built-in */
@@ -1282,7 +1273,6 @@ macro_rules! include_bytes {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
#[cfg_attr(not(test), rustc_diagnostic_item = "module_path_macro")]
macro_rules! module_path {
() => {
/* compiler built-in */
@@ -1316,7 +1306,6 @@ macro_rules! module_path {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
#[cfg_attr(not(test), rustc_diagnostic_item = "cfg_macro")]
macro_rules! cfg {
($($cfg:tt)*) => {
/* compiler built-in */
@@ -1367,7 +1356,6 @@ macro_rules! cfg {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
#[macro_export]
#[cfg_attr(not(test), rustc_diagnostic_item = "include_macro")]
macro_rules! include {
($file:expr $(,)?) => {{ /* compiler built-in */ }};
}
+6 -20
View File
@@ -321,7 +321,6 @@ impl $Ty {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
@@ -356,7 +355,6 @@ pub const fn checked_add(self, other: $Int) -> Option<$Ty> {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
@@ -391,8 +389,8 @@ pub const fn saturating_add(self, other: $Int) -> $Ty {
///
/// ```
/// #![feature(nonzero_ops)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
@@ -420,7 +418,6 @@ pub const fn saturating_add(self, other: $Int) -> $Ty {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
@@ -461,7 +458,6 @@ pub const fn checked_next_power_of_two(self) -> Option<$Ty> {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")]
@@ -486,7 +482,6 @@ pub const fn ilog2(self) -> u32 {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")]
@@ -526,7 +521,6 @@ impl $Ty {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
@@ -556,7 +550,6 @@ pub const fn abs(self) -> $Ty {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
@@ -591,7 +584,6 @@ pub const fn checked_abs(self) -> Option<$Ty> {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
@@ -626,7 +618,6 @@ pub const fn overflowing_abs(self) -> ($Ty, bool) {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
@@ -662,7 +653,6 @@ pub const fn saturating_abs(self) -> $Ty {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
@@ -905,7 +895,6 @@ impl $Ty {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
@@ -941,7 +930,6 @@ pub const fn checked_mul(self, other: $Ty) -> Option<$Ty> {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
@@ -986,8 +974,8 @@ pub const fn saturating_mul(self, other: $Ty) -> $Ty {
///
/// ```
/// #![feature(nonzero_ops)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
@@ -1014,7 +1002,6 @@ pub const fn saturating_mul(self, other: $Ty) -> $Ty {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")]
@@ -1058,7 +1045,6 @@ pub const fn checked_pow(self, other: u32) -> Option<$Ty> {
///
/// ```
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")]
@@ -1162,8 +1148,8 @@ impl $Ty {
///
/// ```
/// #![feature(nonzero_min_max)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), 1", stringify!($Int), ");")]
/// ```
#[unstable(feature = "nonzero_min_max", issue = "89065")]
@@ -1177,8 +1163,8 @@ impl $Ty {
///
/// ```
/// #![feature(nonzero_min_max)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")]
/// ```
#[unstable(feature = "nonzero_min_max", issue = "89065")]
@@ -1204,8 +1190,8 @@ impl $Ty {
///
/// ```
/// #![feature(nonzero_min_max)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), ", stringify!($Int), "::MIN);")]
/// ```
#[unstable(feature = "nonzero_min_max", issue = "89065")]
@@ -1223,8 +1209,8 @@ impl $Ty {
///
/// ```
/// #![feature(nonzero_min_max)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")]
/// ```
#[unstable(feature = "nonzero_min_max", issue = "89065")]
-6
View File
@@ -57,7 +57,6 @@
#[cfg(bootstrap)]
#[lang = "fn"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Fn"]
#[rustc_paren_sugar]
#[rustc_on_unimplemented(
on(
@@ -138,7 +137,6 @@ pub trait Fn<Args>: FnMut<Args> {
#[cfg(not(bootstrap))]
#[lang = "fn"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Fn"]
#[rustc_paren_sugar]
#[rustc_on_unimplemented(
on(
@@ -227,7 +225,6 @@ pub trait Fn<Args: Tuple>: FnMut<Args> {
#[cfg(bootstrap)]
#[lang = "fn_mut"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "FnMut"]
#[rustc_paren_sugar]
#[rustc_on_unimplemented(
on(
@@ -316,7 +313,6 @@ pub trait FnMut<Args>: FnOnce<Args> {
#[cfg(not(bootstrap))]
#[lang = "fn_mut"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "FnMut"]
#[rustc_paren_sugar]
#[rustc_on_unimplemented(
on(
@@ -397,7 +393,6 @@ pub trait FnMut<Args: Tuple>: FnOnce<Args> {
#[cfg(bootstrap)]
#[lang = "fn_once"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "FnOnce"]
#[rustc_paren_sugar]
#[rustc_on_unimplemented(
on(
@@ -483,7 +478,6 @@ pub trait FnOnce<Args> {
#[cfg(not(bootstrap))]
#[lang = "fn_once"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "FnOnce"]
#[rustc_paren_sugar]
#[rustc_on_unimplemented(
on(
-1
View File
@@ -80,7 +80,6 @@
#[doc(hidden)]
#[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")]
#[allow_internal_unstable(core_panic)]
#[rustc_diagnostic_item = "unreachable_2021_macro"]
#[rustc_macro_transparency = "semitransparent"]
pub macro unreachable_2021 {
() => (
+1 -1
View File
@@ -16,7 +16,7 @@ panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
libc = { version = "0.2.135", default-features = false, features = ['rustc-dep-of-std'] }
compiler_builtins = { version = "0.1.73" }
compiler_builtins = { version = "0.1.82" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep-of-std'] }
-2
View File
@@ -73,7 +73,6 @@ pub enum IpAddr {
/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex
/// ```
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(not(test), rustc_diagnostic_item = "Ipv4Addr")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Ipv4Addr {
octets: [u8; 4],
@@ -156,7 +155,6 @@ pub struct Ipv4Addr {
/// assert_eq!(localhost.is_loopback(), true);
/// ```
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(not(test), rustc_diagnostic_item = "Ipv6Addr")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Ipv6Addr {
octets: [u8; 16],
+1041
View File
@@ -0,0 +1,1041 @@
#!/usr/bin/env python3
"""
The Rust toolchain test runner for Fuchsia.
For instructions on running the compiler test suite, see
https://doc.rust-lang.org/stable/rustc/platform-support/fuchsia.html#aarch64-fuchsia-and-x86_64-fuchsia
"""
import argparse
from dataclasses import dataclass
import glob
import hashlib
import json
import os
import platform
import re
import shutil
import signal
import subprocess
import sys
from typing import ClassVar, List
@dataclass
class TestEnvironment:
rust_dir: str
sdk_dir: str
target_arch: str
package_server_pid: int = None
emu_addr: str = None
libstd_name: str = None
libtest_name: str = None
verbose: bool = False
@staticmethod
def tmp_dir():
tmp_dir = os.environ.get("TEST_TOOLCHAIN_TMP_DIR")
if tmp_dir is not None:
return os.path.abspath(tmp_dir)
return os.path.join(os.path.dirname(__file__), "tmp~")
@classmethod
def env_file_path(cls):
return os.path.join(cls.tmp_dir(), "test_env.json")
@classmethod
def from_args(cls, args):
return cls(
os.path.abspath(args.rust),
os.path.abspath(args.sdk),
args.target_arch,
verbose=args.verbose,
)
@classmethod
def read_from_file(cls):
with open(cls.env_file_path(), encoding="utf-8") as f:
test_env = json.loads(f.read())
return cls(
test_env["rust_dir"],
test_env["sdk_dir"],
test_env["target_arch"],
libstd_name=test_env["libstd_name"],
libtest_name=test_env["libtest_name"],
emu_addr=test_env["emu_addr"],
package_server_pid=test_env["package_server_pid"],
verbose=test_env["verbose"],
)
def image_name(self):
if self.target_arch == "x64":
return "qemu-x64"
if self.target_arch == "arm64":
return "qemu-arm64"
raise Exception(f"Unrecognized target architecture {self.target_arch}")
def write_to_file(self):
with open(self.env_file_path(), "w", encoding="utf-8") as f:
f.write(json.dumps(self.__dict__))
def ssh_dir(self):
return os.path.join(self.tmp_dir(), "ssh")
def ssh_keyfile_path(self):
return os.path.join(self.ssh_dir(), "fuchsia_ed25519")
def ssh_authfile_path(self):
return os.path.join(self.ssh_dir(), "fuchsia_authorized_keys")
def vdl_output_path(self):
return os.path.join(self.tmp_dir(), "vdl_output")
def package_server_log_path(self):
return os.path.join(self.tmp_dir(), "package_server_log")
def emulator_log_path(self):
return os.path.join(self.tmp_dir(), "emulator_log")
def packages_dir(self):
return os.path.join(self.tmp_dir(), "packages")
def output_dir(self):
return os.path.join(self.tmp_dir(), "output")
TEST_REPO_NAME: ClassVar[str] = "rust-testing"
def repo_dir(self):
return os.path.join(self.tmp_dir(), self.TEST_REPO_NAME)
def rustlib_dir(self):
if self.target_arch == "x64":
return "x86_64-fuchsia"
if self.target_arch == "arm64":
return "aarch64-fuchsia"
raise Exception(f"Unrecognized target architecture {self.target_arch}")
def libs_dir(self):
return os.path.join(
self.rust_dir,
"lib",
)
def rustlibs_dir(self):
return os.path.join(
self.libs_dir(),
"rustlib",
self.rustlib_dir(),
"lib",
)
def sdk_arch(self):
machine = platform.machine()
if machine == "x86_64":
return "x64"
if machine == "arm":
return "a64"
raise Exception(f"Unrecognized host architecture {machine}")
def tool_path(self, tool):
return os.path.join(self.sdk_dir, "tools", self.sdk_arch(), tool)
def host_arch_triple(self):
machine = platform.machine()
if machine == "x86_64":
return "x86_64-unknown-linux-gnu"
if machine == "arm":
return "aarch64-unknown-linux-gnu"
raise Exception(f"Unrecognized host architecture {machine}")
def zxdb_script_path(self):
return os.path.join(self.tmp_dir(), "zxdb_script")
def log_info(self, msg):
print(msg)
def log_debug(self, msg):
if self.verbose:
print(msg)
def subprocess_output(self):
if self.verbose:
return sys.stdout
return subprocess.DEVNULL
def ffx_daemon_log_path(self):
return os.path.join(self.tmp_dir(), "ffx_daemon_log")
def ffx_isolate_dir(self):
return os.path.join(self.tmp_dir(), "ffx_isolate")
def ffx_home_dir(self):
return os.path.join(self.ffx_isolate_dir(), "user-home")
def ffx_tmp_dir(self):
return os.path.join(self.ffx_isolate_dir(), "tmp")
def ffx_log_dir(self):
return os.path.join(self.ffx_isolate_dir(), "log")
def ffx_user_config_dir(self):
return os.path.join(self.ffx_xdg_config_home(), "Fuchsia", "ffx", "config")
def ffx_user_config_path(self):
return os.path.join(self.ffx_user_config_dir(), "config.json")
def ffx_xdg_config_home(self):
if platform.system() == "Darwin":
return os.path.join(self.ffx_home_dir(), "Library", "Preferences")
return os.path.join(self.ffx_home_dir(), ".local", "share")
def ffx_ascendd_path(self):
return os.path.join(self.ffx_tmp_dir(), "ascendd")
def start_ffx_isolation(self):
# Most of this is translated directly from ffx's isolate library
os.mkdir(self.ffx_isolate_dir())
os.mkdir(self.ffx_home_dir())
os.mkdir(self.ffx_tmp_dir())
os.mkdir(self.ffx_log_dir())
fuchsia_dir = os.path.join(self.ffx_home_dir(), ".fuchsia")
os.mkdir(fuchsia_dir)
fuchsia_debug_dir = os.path.join(fuchsia_dir, "debug")
os.mkdir(fuchsia_debug_dir)
metrics_dir = os.path.join(fuchsia_dir, "metrics")
os.mkdir(metrics_dir)
analytics_path = os.path.join(metrics_dir, "analytics-status")
with open(analytics_path, "w", encoding="utf-8") as analytics_file:
print("0", file=analytics_file)
ffx_path = os.path.join(metrics_dir, "ffx")
with open(ffx_path, "w", encoding="utf-8") as ffx_file:
print("1", file=ffx_file)
os.makedirs(self.ffx_user_config_dir())
with open(
self.ffx_user_config_path(), "w", encoding="utf-8"
) as config_json_file:
user_config_for_test = {
"log": {
"enabled": True,
"dir": self.ffx_log_dir(),
},
"overnet": {
"socket": self.ffx_ascendd_path(),
},
"ssh": {
"pub": self.ssh_authfile_path(),
"priv": self.ssh_keyfile_path(),
},
"test": {
"is_isolated": True,
"experimental_structured_output": True,
},
}
print(json.dumps(user_config_for_test), file=config_json_file)
ffx_env_path = os.path.join(self.ffx_user_config_dir(), ".ffx_env")
with open(ffx_env_path, "w", encoding="utf-8") as ffx_env_file:
ffx_env_config_for_test = {
"user": self.ffx_user_config_path(),
"build": None,
"global": None,
}
print(json.dumps(ffx_env_config_for_test), file=ffx_env_file)
# Start ffx daemon
# We want this to be a long-running process that persists after the script finishes
# pylint: disable=consider-using-with
with open(
self.ffx_daemon_log_path(), "w", encoding="utf-8"
) as ffx_daemon_log_file:
subprocess.Popen(
[
self.tool_path("ffx"),
"--config",
self.ffx_user_config_path(),
"daemon",
"start",
],
env=self.ffx_cmd_env(),
stdout=ffx_daemon_log_file,
stderr=ffx_daemon_log_file,
)
def ffx_cmd_env(self):
result = {
"HOME": self.ffx_home_dir(),
"XDG_CONFIG_HOME": self.ffx_xdg_config_home(),
"ASCENDD": self.ffx_ascendd_path(),
"FUCHSIA_SSH_KEY": self.ssh_keyfile_path(),
# We want to use our own specified temp directory
"TMP": self.tmp_dir(),
"TEMP": self.tmp_dir(),
"TMPDIR": self.tmp_dir(),
"TEMPDIR": self.tmp_dir(),
}
return result
def stop_ffx_isolation(self):
subprocess.check_call(
[
self.tool_path("ffx"),
"--config",
self.ffx_user_config_path(),
"daemon",
"stop",
],
env=self.ffx_cmd_env(),
stdout=self.subprocess_output(),
stderr=self.subprocess_output(),
)
def start(self):
"""Sets up the testing environment and prepares to run tests.
Args:
args: The command-line arguments to this command.
During setup, this function will:
- Locate necessary shared libraries
- Create a new temp directory (this is where all temporary files are stored)
- Start an emulator
- Start an update server
- Create a new package repo and register it with the emulator
- Write test environment settings to a temporary file
"""
# Initialize temp directory
if not os.path.exists(self.tmp_dir()):
os.mkdir(self.tmp_dir())
elif len(os.listdir(self.tmp_dir())) != 0:
raise Exception(f"Temp directory is not clean (in {self.tmp_dir()})")
os.mkdir(self.ssh_dir())
os.mkdir(self.output_dir())
# Find libstd and libtest
libstd_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libstd-*.so"))
libtest_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libtest-*.so"))
if not libstd_paths:
raise Exception(f"Failed to locate libstd (in {self.rustlibs_dir()})")
if not libtest_paths:
raise Exception(f"Failed to locate libtest (in {self.rustlibs_dir()})")
self.libstd_name = os.path.basename(libstd_paths[0])
self.libtest_name = os.path.basename(libtest_paths[0])
# Generate SSH keys for the emulator to use
self.log_info("Generating SSH keys...")
subprocess.check_call(
[
"ssh-keygen",
"-N",
"",
"-t",
"ed25519",
"-f",
self.ssh_keyfile_path(),
"-C",
"Generated by test_toolchain.py",
],
stdout=self.subprocess_output(),
stderr=self.subprocess_output(),
)
authfile_contents = subprocess.check_output(
[
"ssh-keygen",
"-y",
"-f",
self.ssh_keyfile_path(),
],
stderr=self.subprocess_output(),
)
with open(self.ssh_authfile_path(), "wb") as authfile:
authfile.write(authfile_contents)
# Start ffx isolation
self.log_info("Starting ffx isolation...")
self.start_ffx_isolation()
# Start emulator (this will generate the vdl output)
self.log_info("Starting emulator...")
subprocess.check_call(
[
self.tool_path("fvdl"),
"--sdk",
"start",
"--tuntap",
"--headless",
"--nointeractive",
"--ssh",
self.ssh_dir(),
"--vdl-output",
self.vdl_output_path(),
"--emulator-log",
self.emulator_log_path(),
"--image-name",
self.image_name(),
],
stdout=self.subprocess_output(),
stderr=self.subprocess_output(),
)
# Parse vdl output for relevant information
with open(self.vdl_output_path(), encoding="utf-8") as f:
vdl_content = f.read()
matches = re.search(
r'network_address:\s+"\[([0-9a-f]{1,4}:(:[0-9a-f]{1,4}){4}%qemu)\]"',
vdl_content,
)
self.emu_addr = matches.group(1)
# Create new package repo
self.log_info("Creating package repo...")
subprocess.check_call(
[
self.tool_path("pm"),
"newrepo",
"-repo",
self.repo_dir(),
],
stdout=self.subprocess_output(),
stderr=self.subprocess_output(),
)
# Start package server
self.log_info("Starting package server...")
with open(
self.package_server_log_path(), "w", encoding="utf-8"
) as package_server_log:
# We want this to be a long-running process that persists after the script finishes
# pylint: disable=consider-using-with
self.package_server_pid = subprocess.Popen(
[
self.tool_path("pm"),
"serve",
"-vt",
"-repo",
self.repo_dir(),
"-l",
":8084",
],
stdout=package_server_log,
stderr=package_server_log,
).pid
# Register package server with emulator
self.log_info("Registering package server...")
ssh_client = subprocess.check_output(
[
"ssh",
"-i",
self.ssh_keyfile_path(),
"-o",
"StrictHostKeyChecking=accept-new",
self.emu_addr,
"-f",
"echo $SSH_CLIENT",
],
text=True,
)
repo_addr = ssh_client.split()[0].replace("%", "%25")
repo_url = f"http://[{repo_addr}]:8084/config.json"
subprocess.check_call(
[
"ssh",
"-i",
self.ssh_keyfile_path(),
"-o",
"StrictHostKeyChecking=accept-new",
self.emu_addr,
"-f",
f"pkgctl repo add url -f 1 -n {self.TEST_REPO_NAME} {repo_url}",
],
stdout=self.subprocess_output(),
stderr=self.subprocess_output(),
)
# Write to file
self.write_to_file()
self.log_info("Success! Your environment is ready to run tests.")
# FIXME: shardify this
# `facet` statement required for TCP testing via
# protocol `fuchsia.posix.socket.Provider`. See
# https://fuchsia.dev/fuchsia-src/development/testing/components/test_runner_framework?hl=en#legacy_non-hermetic_tests
CML_TEMPLATE: ClassVar[
str
] = """
{{
program: {{
runner: "elf_test_runner",
binary: "bin/{exe_name}",
forward_stderr_to: "log",
forward_stdout_to: "log",
environ: [{env_vars}
]
}},
capabilities: [
{{ protocol: "fuchsia.test.Suite" }},
],
expose: [
{{
protocol: "fuchsia.test.Suite",
from: "self",
}},
],
use: [
{{ storage: "data", path: "/data" }},
{{ protocol: [ "fuchsia.process.Launcher" ] }},
{{ protocol: [ "fuchsia.posix.socket.Provider" ] }}
],
facets: {{
"fuchsia.test": {{ type: "system" }},
}},
}}
"""
MANIFEST_TEMPLATE = """
meta/package={package_dir}/meta/package
meta/{package_name}.cm={package_dir}/meta/{package_name}.cm
bin/{exe_name}={bin_path}
lib/{libstd_name}={rust_dir}/lib/rustlib/{rustlib_dir}/lib/{libstd_name}
lib/{libtest_name}={rust_dir}/lib/rustlib/{rustlib_dir}/lib/{libtest_name}
lib/ld.so.1={sdk_dir}/arch/{target_arch}/sysroot/lib/libc.so
lib/libzircon.so={sdk_dir}/arch/{target_arch}/sysroot/lib/libzircon.so
lib/libfdio.so={sdk_dir}/arch/{target_arch}/lib/libfdio.so
"""
TEST_ENV_VARS: ClassVar[List[str]] = [
"TEST_EXEC_ENV",
"RUST_MIN_STACK",
"RUST_BACKTRACE",
"RUST_NEWRT",
"RUST_LOG",
"RUST_TEST_THREADS",
]
def run(self, args):
"""Runs the requested test in the testing environment.
Args:
args: The command-line arguments to this command.
Returns:
The return code of the test (0 for success, else failure).
To run a test, this function will:
- Create, compile, archive, and publish a test package
- Run the test package on the emulator
- Forward the test's stdout and stderr as this script's stdout and stderr
"""
bin_path = os.path.abspath(args.bin_path)
# Build a unique, deterministic name for the test using the name of the
# binary and the last 6 hex digits of the hash of the full path
def path_checksum(path):
m = hashlib.sha256()
m.update(path.encode("utf-8"))
return m.hexdigest()[0:6]
base_name = os.path.basename(os.path.dirname(args.bin_path))
exe_name = base_name.lower().replace(".", "_")
package_name = f"{exe_name}_{path_checksum(bin_path)}"
package_dir = os.path.join(self.packages_dir(), package_name)
cml_path = os.path.join(package_dir, "meta", f"{package_name}.cml")
cm_path = os.path.join(package_dir, "meta", f"{package_name}.cm")
manifest_path = os.path.join(package_dir, f"{package_name}.manifest")
far_path = os.path.join(package_dir, f"{package_name}-0.far")
shared_libs = args.shared_libs[: args.n]
arguments = args.shared_libs[args.n :]
test_output_dir = os.path.join(self.output_dir(), package_name)
# Clean and create temporary output directory
if os.path.exists(test_output_dir):
shutil.rmtree(test_output_dir)
os.mkdir(test_output_dir)
# Open log file
log_path = os.path.join(test_output_dir, "log")
with open(log_path, "w", encoding="utf-8") as log_file:
def log(msg):
print(msg, file=log_file)
log_file.flush()
log(f"Bin path: {bin_path}")
log("Setting up package...")
# Set up package
subprocess.check_call(
[
self.tool_path("pm"),
"-o",
package_dir,
"-n",
package_name,
"init",
],
stdout=log_file,
stderr=log_file,
)
log("Writing CML...")
# Write and compile CML
with open(cml_path, "w", encoding="utf-8") as cml:
# Collect environment variables
env_vars = ""
for var_name in self.TEST_ENV_VARS:
var_value = os.getenv(var_name)
if var_value is not None:
env_vars += f'\n "{var_name}={var_value}",'
# Default to no backtrace for test suite
if os.getenv("RUST_BACKTRACE") == None:
env_vars += f'\n "RUST_BACKTRACE=0",'
cml.write(
self.CML_TEMPLATE.format(env_vars=env_vars, exe_name=exe_name)
)
log("Compiling CML...")
subprocess.check_call(
[
self.tool_path("cmc"),
"compile",
cml_path,
"--includepath",
".",
"--output",
cm_path,
],
stdout=log_file,
stderr=log_file,
)
log("Writing manifest...")
# Write, build, and archive manifest
with open(manifest_path, "w", encoding="utf-8") as manifest:
manifest.write(
self.MANIFEST_TEMPLATE.format(
bin_path=bin_path,
exe_name=exe_name,
package_dir=package_dir,
package_name=package_name,
rust_dir=self.rust_dir,
rustlib_dir=self.rustlib_dir(),
sdk_dir=self.sdk_dir,
libstd_name=self.libstd_name,
libtest_name=self.libtest_name,
target_arch=self.target_arch,
)
)
for shared_lib in shared_libs:
manifest.write(f"lib/{os.path.basename(shared_lib)}={shared_lib}\n")
log("Compiling and archiving manifest...")
subprocess.check_call(
[
self.tool_path("pm"),
"-o",
package_dir,
"-m",
manifest_path,
"build",
],
stdout=log_file,
stderr=log_file,
)
subprocess.check_call(
[
self.tool_path("pm"),
"-o",
package_dir,
"-m",
manifest_path,
"archive",
],
stdout=log_file,
stderr=log_file,
)
log("Publishing package to repo...")
# Publish package to repo
subprocess.check_call(
[
self.tool_path("pm"),
"publish",
"-a",
"-repo",
self.repo_dir(),
"-f",
far_path,
],
stdout=log_file,
stderr=log_file,
)
log("Running ffx test...")
# Run test on emulator
subprocess.run(
[
self.tool_path("ffx"),
"--config",
self.ffx_user_config_path(),
"test",
"run",
f"fuchsia-pkg://{self.TEST_REPO_NAME}/{package_name}#meta/{package_name}.cm",
"--min-severity-logs",
"TRACE",
"--output-directory",
test_output_dir,
"--",
]
+ arguments,
env=self.ffx_cmd_env(),
check=False,
stdout=log_file,
stderr=log_file,
)
log("Reporting test suite output...")
# Read test suite output
run_summary_path = os.path.join(test_output_dir, "run_summary.json")
if os.path.exists(run_summary_path):
with open(run_summary_path, encoding="utf-8") as f:
run_summary = json.loads(f.read())
suite = run_summary["data"]["suites"][0]
case = suite["cases"][0]
return_code = 0 if case["outcome"] == "PASSED" else 1
artifacts = case["artifacts"]
artifact_dir = case["artifact_dir"]
stdout_path = None
stderr_path = None
for path, artifact in artifacts.items():
artifact_path = os.path.join(test_output_dir, artifact_dir, path)
artifact_type = artifact["artifact_type"]
if artifact_type == "STDERR":
stderr_path = artifact_path
elif artifact_type == "STDOUT":
stdout_path = artifact_path
if stdout_path is not None and os.path.exists(stdout_path):
with open(stdout_path, encoding="utf-8") as f:
print(f.read(), file=sys.stdout, end="")
if stderr_path is not None and os.path.exists(stderr_path):
with open(stderr_path, encoding="utf-8") as f:
print(f.read(), file=sys.stderr, end="")
else:
log("Failed to open test run summary")
return_code = 254
log("Done!")
return return_code
def stop(self):
"""Shuts down and cleans up the testing environment.
Args:
args: The command-line arguments to this command.
Returns:
The return code of the test (0 for success, else failure).
During cleanup, this function will stop the emulator, package server, and
update server, then delete all temporary files. If an error is encountered
while stopping any running processes, the temporary files will not be deleted.
Passing --delete-tmp will force the process to delete the files anyway.
"""
self.log_debug("Reporting logs...")
# Print test log files
for test_dir in os.listdir(self.output_dir()):
log_path = os.path.join(self.output_dir(), test_dir, "log")
self.log_debug(f"\n---- Logs for test '{test_dir}' ----\n")
if os.path.exists(log_path):
with open(log_path, encoding="utf-8") as log:
self.log_debug(log.read())
else:
self.log_debug("No logs found")
# Print the emulator log
self.log_debug("\n---- Emulator logs ----\n")
if os.path.exists(self.emulator_log_path()):
with open(self.emulator_log_path(), encoding="utf-8") as log:
self.log_debug(log.read())
else:
self.log_debug("No emulator logs found")
# Print the package server log
self.log_debug("\n---- Package server log ----\n")
if os.path.exists(self.package_server_log_path()):
with open(self.package_server_log_path(), encoding="utf-8") as log:
self.log_debug(log.read())
else:
self.log_debug("No package server log found")
# Print the ffx daemon log
self.log_debug("\n---- ffx daemon log ----\n")
if os.path.exists(self.ffx_daemon_log_path()):
with open(self.ffx_daemon_log_path(), encoding="utf-8") as log:
self.log_debug(log.read())
else:
self.log_debug("No ffx daemon log found")
# Stop package server
self.log_info("Stopping package server...")
os.kill(self.package_server_pid, signal.SIGTERM)
# Shut down the emulator
self.log_info("Stopping emulator...")
subprocess.check_call(
[
self.tool_path("fvdl"),
"--sdk",
"kill",
"--launched-proto",
self.vdl_output_path(),
],
stdout=self.subprocess_output(),
stderr=self.subprocess_output(),
)
# Stop ffx isolation
self.log_info("Stopping ffx isolation...")
self.stop_ffx_isolation()
def delete_tmp(self):
# Remove temporary files
self.log_info("Deleting temporary files...")
shutil.rmtree(self.tmp_dir(), ignore_errors=True)
def debug(self, args):
command = [
self.tool_path("ffx"),
"--config",
self.ffx_user_config_path(),
"debug",
"connect",
"--",
"--build-id-dir",
os.path.join(self.sdk_dir, ".build-id"),
"--build-id-dir",
os.path.join(self.libs_dir(), ".build-id"),
]
# Add rust source if it's available
if args.rust_src is not None:
command += [
"--build-dir",
args.rust_src,
]
# Add fuchsia source if it's available
if args.fuchsia_src is not None:
command += [
"--build-dir",
os.path.join(args.fuchsia_src, "out", "default"),
]
# Load debug symbols for the test binary and automatically attach
if args.test is not None:
if args.rust_src is None:
raise Exception(
"A Rust source path is required with the `test` argument"
)
test_name = os.path.splitext(os.path.basename(args.test))[0]
build_dir = os.path.join(
args.rust_src,
"fuchsia-build",
self.host_arch_triple(),
)
test_dir = os.path.join(
build_dir,
"test",
os.path.dirname(args.test),
test_name,
)
with open(self.zxdb_script_path(), mode="w", encoding="utf-8") as f:
print(f"attach {test_name[:31]}", file=f)
command += [
"--symbol-path",
test_dir,
"-S",
self.zxdb_script_path(),
]
# Add any other zxdb arguments the user passed
if args.zxdb_args is not None:
command += args.zxdb_args
# Connect to the running emulator with zxdb
subprocess.run(command, env=self.ffx_cmd_env(), check=False)
def start(args):
test_env = TestEnvironment.from_args(args)
test_env.start()
return 0
def run(args):
test_env = TestEnvironment.read_from_file()
return test_env.run(args)
def stop(args):
test_env = TestEnvironment.read_from_file()
test_env.stop()
if not args.no_delete:
test_env.delete_tmp()
return 0
def delete_tmp(args):
del args
test_env = TestEnvironment.read_from_file()
test_env.delete_tmp()
return 0
def debug(args):
test_env = TestEnvironment.read_from_file()
test_env.debug(args)
return 0
def main():
parser = argparse.ArgumentParser()
def print_help(args):
del args
parser.print_help()
return 0
parser.set_defaults(func=print_help)
subparsers = parser.add_subparsers(help="valid sub-commands")
start_parser = subparsers.add_parser(
"start", help="initializes the testing environment"
)
start_parser.add_argument(
"--rust",
help="the directory of the installed Rust compiler for Fuchsia",
required=True,
)
start_parser.add_argument(
"--sdk",
help="the directory of the fuchsia SDK",
required=True,
)
start_parser.add_argument(
"--verbose",
help="prints more output from executed processes",
action="store_true",
)
start_parser.add_argument(
"--target-arch",
help="the architecture of the image to test",
required=True,
)
start_parser.set_defaults(func=start)
run_parser = subparsers.add_parser(
"run", help="run a test in the testing environment"
)
run_parser.add_argument(
"n", help="the number of shared libs passed along with the executable", type=int
)
run_parser.add_argument("bin_path", help="path to the binary to run")
run_parser.add_argument(
"shared_libs",
help="the shared libs passed along with the binary",
nargs=argparse.REMAINDER,
)
run_parser.set_defaults(func=run)
stop_parser = subparsers.add_parser(
"stop", help="shuts down and cleans up the testing environment"
)
stop_parser.add_argument(
"--no-delete",
default=False,
action="store_true",
help="don't delete temporary files after stopping",
)
stop_parser.set_defaults(func=stop)
delete_parser = subparsers.add_parser(
"delete-tmp",
help="deletes temporary files after the testing environment has been manually cleaned up",
)
delete_parser.set_defaults(func=delete_tmp)
debug_parser = subparsers.add_parser(
"debug",
help="connect to the active testing environment with zxdb",
)
debug_parser.add_argument(
"--rust-src",
default=None,
help="the path to the Rust source being tested",
)
debug_parser.add_argument(
"--fuchsia-src",
default=None,
help="the path to the Fuchsia source",
)
debug_parser.add_argument(
"--test",
default=None,
help="the path to the test to debug (e.g. ui/box/new.rs)",
)
debug_parser.add_argument(
"zxdb_args",
default=None,
nargs=argparse.REMAINDER,
help="any additional arguments to pass to zxdb",
)
debug_parser.set_defaults(func=debug)
args = parser.parse_args()
return args.func(args)
if __name__ == "__main__":
sys.exit(main())
+54 -2
View File
@@ -641,8 +641,60 @@ available on the [Fuchsia devsite].
### Running the compiler test suite
Running the Rust test suite on Fuchsia is [not currently supported], but work is
underway to enable it.
Pre-requisites for running the Rust test suite on Fuchsia are:
1. Checkout of Rust source.
1. Setup of `config-env.sh` and `config.toml` from "[Targeting Fuchsia with a compiler built from source](#targeting-fuchsia-with-a-compiler-built-from-source)".
1. Download of the Fuchsia SDK. Minimum supported SDK version is [9.20220726.1.1](https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core/linux-amd64/+/version:9.20220726.1.1)
Interfacing with the Fuchsia emulator is handled by our test runner script located
at `${RUST_SRC_PATH}/src/ci/docker/scripts/fuchsia-test-runner.py`.
We start by activating our Fuchsia test environment. From a terminal:
**Issue command from ${RUST_SRC_PATH}**
```sh
src/ci/docker/scripts/fuchsia-test-runner.py start
--rust .
--sdk ${SDK_PATH}
--target-arch {x64,arm64}
```
Next, for ease of commands, we copy `config-env.sh` and `config.toml` into our Rust source
code path, `${RUST_SRC_PATH}`.
From there, we utilize `x.py` to run our tests, using the test runner script to
run the tests on our emulator. To run the full `src/test/ui` test suite:
**Run from ${RUST_SRC_PATH}**
```sh
( \
source config-env.sh && \
./x.py \
--config config.toml \
--stage=2 \
test src/test/ui \
--target x86_64-fuchsia \
--run=always --jobs 1 \
--test-args --target-rustcflags -L \
--test-args --target-rustcflags ${SDK_PATH}/arch/{x64|arm64}/sysroot/lib \
--test-args --target-rustcflags -L \
--test-args --target-rustcflags ${SDK_PATH}/arch/{x64|arm64}/lib \
--test-args --target-rustcflags -Cpanic=abort \
--test-args --target-rustcflags -Zpanic_abort_tests \
--test-args --remote-test-client \
--test-args src/ci/docker/scripts/fuchsia-test-runner.py \
)
```
*Note: The test suite cannot be run in parallel at the moment, so `x.py`
must be run with `--jobs 1` to ensure only one test runs at a time.*
When finished, stop the test environment:
**Issue command from ${RUST_SRC_PATH}**
```sh
src/ci/docker/scripts/fuchsia-test-runner.py stop
```
## Debugging
@@ -1262,10 +1262,6 @@ h3.variant {
margin-left: 24px;
}
:target > code, :target > .code-header {
opacity: 1;
}
:target {
padding-right: 3px;
background-color: var(--target-background-color);
+1
View File
@@ -1491,6 +1491,7 @@ function initSearch(rawSearchIndex) {
const target = searchState.focusedByTab[searchState.currentTab] ||
document.querySelectorAll(".search-results.active a").item(0) ||
document.querySelectorAll("#titles > button").item(searchState.currentTab);
searchState.focusedByTab[searchState.currentTab] = null;
if (target) {
target.focus();
}
+6 -2
View File
@@ -19,9 +19,13 @@ fn new(filename: &str, bytes: &'static [u8]) -> StaticFile {
}
pub(crate) fn minified(&self) -> Vec<u8> {
if self.filename.ends_with(".css") {
let extension = match self.filename.extension() {
Some(e) => e,
None => return self.bytes.to_owned(),
};
if extension == "css" {
minifier::css::minify(str::from_utf8(self.bytes).unwrap()).unwrap().to_string().into()
} else if self.filename.ends_with(".js") {
} else if extension == "js" {
minifier::js::minify(str::from_utf8(self.bytes).unwrap()).to_string().into()
} else {
self.bytes.to_owned()
+28
View File
@@ -0,0 +1,28 @@
// Checks that the search tab results work correctly with function signature syntax
// First, try a search-by-name
goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
write: (".search-input", "Foo")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...
wait-for: "#titles"
// Now use the keyboard commands to switch to the third result.
press-key: "ArrowDown"
press-key: "ArrowDown"
press-key: "ArrowDown"
assert: ".search-results.active > a:focus:nth-of-type(3)"
// Now switch to the second tab, then back to the first one, then arrow back up.
press-key: "ArrowRight"
assert: ".search-results.active:nth-of-type(2) > a:focus:nth-of-type(1)"
press-key: "ArrowLeft"
assert: ".search-results.active:nth-of-type(1) > a:focus:nth-of-type(3)"
press-key: "ArrowUp"
assert: ".search-results.active > a:focus:nth-of-type(2)"
press-key: "ArrowUp"
assert: ".search-results.active > a:focus:nth-of-type(1)"
press-key: "ArrowUp"
assert: ".search-input:focus"
press-key: "ArrowDown"
assert: ".search-results.active > a:focus:nth-of-type(1)"
+13
View File
@@ -0,0 +1,13 @@
trait A<Y, N> {
type B;
}
type MaybeBox<T> = <T as A<T, Box<T>>>::B;
struct P {
t: MaybeBox<P>
}
impl<Y, N> A<Y, N> for P {
type B = N;
}
fn main() {
let t: MaybeBox<P>;
}
@@ -0,0 +1,4 @@
fn main() {
1_u32.MAX();
//~^ ERROR no method named `MAX` found for type `u32` in the current scope
}
@@ -0,0 +1,15 @@
error[E0599]: no method named `MAX` found for type `u32` in the current scope
--> $DIR/dont-suggest-ufcs-for-const.rs:2:11
|
LL | 1_u32.MAX();
| ------^^^--
| | |
| | this is an associated function, not a method
| help: use associated function syntax instead: `u32::MAX()`
|
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
= note: the candidate is defined in an impl for the type `u32`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.
@@ -0,0 +1,15 @@
// run-rustfix
#![allow(unused)]
struct Foo<T>(T);
impl<T> Foo<T> {
fn test() -> i32 { 1 }
}
fn main() {
let x = Box::new(Foo(1i32));
Foo::<i32>::test();
//~^ ERROR no method named `test` found for struct `Box<Foo<i32>>` in the current scope
}
@@ -0,0 +1,15 @@
// run-rustfix
#![allow(unused)]
struct Foo<T>(T);
impl<T> Foo<T> {
fn test() -> i32 { 1 }
}
fn main() {
let x = Box::new(Foo(1i32));
x.test();
//~^ ERROR no method named `test` found for struct `Box<Foo<i32>>` in the current scope
}
@@ -0,0 +1,19 @@
error[E0599]: no method named `test` found for struct `Box<Foo<i32>>` in the current scope
--> $DIR/suggest-assoc-fn-call-deref.rs:13:7
|
LL | x.test();
| --^^^^--
| | |
| | this is an associated function, not a method
| help: use associated function syntax instead: `Foo::<i32>::test()`
|
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
note: the candidate is defined in an impl for the type `Foo<T>`
--> $DIR/suggest-assoc-fn-call-deref.rs:8:5
|
LL | fn test() -> i32 { 1 }
| ^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.
+6 -6
View File
@@ -199,12 +199,12 @@ pub fn first_node_in_macro(cx: &LateContext<'_>, node: &impl HirNode) -> Option<
pub fn is_panic(cx: &LateContext<'_>, def_id: DefId) -> bool {
let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false };
matches!(
name.as_str(),
"core_panic_macro"
| "std_panic_macro"
| "core_panic_2015_macro"
| "std_panic_2015_macro"
| "core_panic_2021_macro"
name,
sym::core_panic_macro
| sym::std_panic_macro
| sym::core_panic_2015_macro
| sym::std_panic_2015_macro
| sym::core_panic_2021_macro
)
}