Inherit lifetimes for async fn instead of duplicating them.
The current desugaring of `async fn foo<'a>(&usize) -> &u8` is equivalent to
```rust
fn foo<'a, '0>(&'0 usize) -> foo<'static, 'static>::Opaque<'a, '0, '_>;
type foo<'_a, '_0>::Opaque<'a, '0, '1> = impl Future<Output = &'1 u8>;
```
following the RPIT model.
Duplicating all the inherited lifetime parameters and setting the inherited version to `'static` makes lowering more complex and causes issues like #61949. This PR removes the duplication of inherited lifetimes to directly use
```rust
fn foo<'a, '0>(&'0 usize) -> foo<'a, '0>::Opaque<'_>;
type foo<'a, '0>::Opaque<'1> = impl Future<Output = &'1 u8>;
```
following the TAIT model.
Fixes https://github.com/rust-lang/rust/issues/61949
- [Macro attributes may follow `#[derive]` and will see the original (pre-`cfg`) input.][87220]
- [Accept curly-brace macros in expressions, like `m!{ .. }.method()` and `m!{ .. }?`.][88690]
- [Allow panicking in constant evaluation.][89508]
+- [Ignore derived `Clone` and `Debug` implementations during dead code analysis.][85200]
Compiler
--------
Compatibility notes
-------------------
+- [Ignore derived `Clone` and `Debug` implementations during dead code analysis.][85200]
+ This will break some builds that set `#![deny(dead_code)]`.
+
Internal changes
----------------
These changes provide no direct user facing benefits, but represent significant
- [Added an experimental backend for codegen with `libgccjit`.][87260]
+[85200]: https://github.com/rust-lang/rust/pull/85200/
[86191]: https://github.com/rust-lang/rust/pull/86191/
[87220]: https://github.com/rust-lang/rust/pull/87220/
[87260]: https://github.com/rust-lang/rust/pull/87260/
err.emit();
}
Entry::Vacant(v) => {
- v.insert(idx);
+ if r == reg {
+ v.insert(idx);
+ }
}
}
};
}
pub fn trailing_comma(&mut self) {
+ self.scan_break(BreakToken { pre_break: Some(','), ..BreakToken::default() });
+ }
+
+ pub fn trailing_comma_or_space(&mut self) {
self.scan_break(BreakToken {
blank_space: 1,
pre_break: Some(','),
if !field.is_last || has_rest {
self.word_space(",");
} else {
- self.trailing_comma();
+ self.trailing_comma_or_space();
}
}
if has_rest {
use crate::pp::Breaks::Inconsistent;
-use crate::pprust::state::{AnnNode, PrintState, State};
+use crate::pprust::state::delimited::IterDelimited;
+use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
use rustc_ast as ast;
use rustc_ast::GenericBound;
self.end(); // end outer head-block
}
ast::ItemKind::Use(ref tree) => {
- self.head(visibility_qualified(&item.vis, "use"));
+ self.print_visibility(&item.vis);
+ self.word_nbsp("use");
self.print_use_tree(tree);
self.word(";");
- self.end(); // end inner head-block
- self.end(); // end outer head-block
}
ast::ItemKind::Static(ref ty, mutbl, ref body) => {
let def = ast::Defaultness::Final;
ast::UseTreeKind::Simple(rename, ..) => {
self.print_path(&tree.prefix, false, 0);
if let Some(rename) = rename {
- self.space();
- self.word_space("as");
+ self.nbsp();
+ self.word_nbsp("as");
self.print_ident(rename);
}
}
self.word("*");
}
ast::UseTreeKind::Nested(ref items) => {
- if tree.prefix.segments.is_empty() {
- self.word("{");
- } else {
+ if !tree.prefix.segments.is_empty() {
self.print_path(&tree.prefix, false, 0);
- self.word("::{");
+ self.word("::");
+ }
+ if items.is_empty() {
+ self.word("{}");
+ } else if items.len() == 1 {
+ self.print_use_tree(&items[0].0);
+ } else {
+ self.cbox(INDENT_UNIT);
+ self.word("{");
+ self.zerobreak();
+ self.ibox(0);
+ for use_tree in items.iter().delimited() {
+ self.print_use_tree(&use_tree.0);
+ if !use_tree.is_last {
+ self.word(",");
+ if let ast::UseTreeKind::Nested(_) = use_tree.0.kind {
+ self.hardbreak();
+ } else {
+ self.space();
+ }
+ }
+ }
+ self.end();
+ self.trailing_comma();
+ self.offset(-INDENT_UNIT);
+ self.word("}");
+ self.end();
}
- self.commasep(Inconsistent, &items, |this, &(ref tree, _)| {
- this.print_use_tree(tree)
- });
- self.word("}");
}
}
}
verb: &str,
optional_adverb_for_moved: &str,
moved_path: Option<String>,
- ) -> DiagnosticBuilder<'cx> {
+ ) -> DiagnosticBuilder<'tcx> {
let moved_path = moved_path.map(|mp| format!(": `{}`", mp)).unwrap_or_default();
struct_span_err!(
found,
TypeError::RegionsPlaceholderMismatch,
);
- err.buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_error(err);
}
UniverseInfoInner::TypeOp(ref type_op_info) => {
type_op_info.report_error(mbcx, placeholder, error_element, cause);
// FIXME: This error message isn't great, but it doesn't show
// up in the existing UI tests. Consider investigating this
// some more.
- mbcx.infcx
- .tcx
- .sess
- .struct_span_err(cause.span, "higher-ranked subtype error")
- .buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_error(
+ mbcx.infcx.tcx.sess.struct_span_err(cause.span, "higher-ranked subtype error"),
+ );
}
}
}
{
adjusted
} else {
- self.fallback_error(tcx, cause.span).buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_error(self.fallback_error(tcx, cause.span));
return;
};
let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
if let Some(nice_error) = nice_error {
- nice_error.buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_error(nice_error);
} else {
- self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_error(self.fallback_error(tcx, span));
}
}
}
format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
} else {
- if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
+ if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {
if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
debug!(
"report_use_of_moved_or_uninitialized place: error suppressed \
}
}
- if let Some((_, mut old_err)) =
- self.move_error_reported.insert(move_out_indices, (used_place, err))
- {
- // Cancel the old error so it doesn't ICE.
- old_err.cancel();
- }
+ self.buffer_move_error(move_out_indices, (used_place, err));
}
}
Some(borrow_span),
None,
);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
pub(crate) fn report_use_while_mutably_borrowed(
if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
let err =
self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
return;
}
),
};
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
fn report_local_value_does_not_live_long_enough(
None,
);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
fn report_thread_local_value_does_not_live_long_enough(
loan.kind.describe_mutability(),
);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
return;
}
self.explain_deref_coercion(loan, &mut err);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) {
}
}
err.span_label(span, msg);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
};
self.add_move_hints(error, &mut err, err_span);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
fn report_cannot_move_from_static(
}
}
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
/// User cannot make signature of a trait mutable without changing the
diag.sort_span = mir_span.shrink_to_hi();
// Buffer the diagnostic
- diag.buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_error(diag);
}
}
let type_test_span = type_test.locations.span(&self.body);
if let Some(lower_bound_region) = lower_bound_region {
- self.infcx
- .construct_generic_bound_failure(
- type_test_span,
- None,
- type_test.generic_kind,
- lower_bound_region,
- )
- .buffer(&mut self.errors_buffer);
+ self.buffer_error(self.infcx.construct_generic_bound_failure(
+ type_test_span,
+ None,
+ type_test.generic_kind,
+ lower_bound_region,
+ ));
} else {
// FIXME. We should handle this case better. It
// indicates that we have e.g., some region variable
// to report it; we could probably handle it by
// iterating over the universal regions and reporting
// an error that multiple bounds are required.
- self.infcx
- .tcx
- .sess
- .struct_span_err(
- type_test_span,
- &format!("`{}` does not live long enough", type_test.generic_kind),
- )
- .buffer(&mut self.errors_buffer);
+ self.buffer_error(self.infcx.tcx.sess.struct_span_err(
+ type_test_span,
+ &format!("`{}` does not live long enough", type_test.generic_kind),
+ ));
}
}
RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => {
let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
- unexpected_hidden_region_diagnostic(
+ self.buffer_error(unexpected_hidden_region_diagnostic(
self.infcx.tcx,
span,
named_ty,
named_region,
- )
- .buffer(&mut self.errors_buffer);
+ ));
}
RegionErrorKind::BoundUniversalRegionError {
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f);
if let Some(diag) = nice.try_report_from_nll() {
- diag.buffer(&mut self.errors_buffer);
+ self.buffer_error(diag);
return;
}
}
}
}
- diag.buffer(&mut self.errors_buffer);
+ self.buffer_error(diag);
}
/// Report a specialized error when `FnMut` closures return a reference to a captured variable.
}
}
+ let mut errors = error::BorrowckErrors::new();
+
// Gather the upvars of a closure, if any.
let tables = tcx.typeck_opt_const_arg(def);
if let Some(ErrorReported) = tables.tainted_by_errors {
infcx.set_tainted_by_errors();
+ errors.set_tainted_by_errors();
}
let upvars: Vec<_> = tables
.closure_min_captures_flattened(def.did.to_def_id())
let location_table_owned = LocationTable::new(body);
let location_table = &location_table_owned;
- let mut errors_buffer = Vec::new();
let (move_data, move_errors): (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>) =
match MoveData::gather_moves(&body, tcx, param_env) {
Ok(move_data) => (move_data, Vec::new()),
®ioncx,
&opt_closure_req,
&opaque_type_values,
- &mut errors_buffer,
+ &mut errors,
);
// The various `flow_*` structures can be large. We drop `flow_inits` here
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
reservation_warnings: Default::default(),
- move_error_reported: BTreeMap::new(),
uninitialized_error_reported: Default::default(),
- errors_buffer,
regioncx: regioncx.clone(),
used_mut: Default::default(),
used_mut_upvars: SmallVec::new(),
region_names: RefCell::default(),
next_region_name: RefCell::new(1),
polonius_output: None,
+ errors,
};
promoted_mbcx.report_move_errors(move_errors);
- errors_buffer = promoted_mbcx.errors_buffer;
+ errors = promoted_mbcx.errors;
};
}
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
reservation_warnings: Default::default(),
- move_error_reported: BTreeMap::new(),
uninitialized_error_reported: Default::default(),
- errors_buffer,
regioncx: Rc::clone(®ioncx),
used_mut: Default::default(),
used_mut_upvars: SmallVec::new(),
region_names: RefCell::default(),
next_region_name: RefCell::new(1),
polonius_output,
+ errors,
};
// Compute and report region errors, if any.
diag.message = initial_diag.styled_message().clone();
diag.span = initial_diag.span.clone();
- diag.buffer(&mut mbcx.errors_buffer);
+ mbcx.buffer_error(diag);
},
);
initial_diag.cancel();
mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
- let used_mut = mbcx.used_mut;
+ let used_mut = std::mem::take(&mut mbcx.used_mut);
for local in mbcx.body.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) {
let local_decl = &mbcx.body.local_decls[local];
let lint_root = match &mbcx.body.source_scopes[local_decl.source_info.scope].local_data {
})
}
- // Buffer any move errors that we collected and de-duplicated.
- for (_, (_, diag)) in mbcx.move_error_reported {
- diag.buffer(&mut mbcx.errors_buffer);
- }
-
- if !mbcx.errors_buffer.is_empty() {
- mbcx.errors_buffer.sort_by_key(|diag| diag.sort_span);
-
- for diag in mbcx.errors_buffer.drain(..) {
- mbcx.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag);
- }
- }
+ let tainted_by_errors = mbcx.emit_errors();
let result = BorrowCheckResult {
concrete_opaque_types: opaque_type_values,
closure_requirements: opt_closure_req,
used_mut_upvars: mbcx.used_mut_upvars,
+ tainted_by_errors,
};
let body_with_facts = if return_body_with_facts {
/// for the activation of the borrow.
reservation_warnings:
FxHashMap<BorrowIndex, (Place<'tcx>, Span, Location, BorrowKind, BorrowData<'tcx>)>,
- /// This field keeps track of move errors that are to be reported for given move indices.
- ///
- /// There are situations where many errors can be reported for a single move out (see #53807)
- /// and we want only the best of those errors.
- ///
- /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
- /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
- /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
- /// all move errors have been reported, any diagnostics in this map are added to the buffer
- /// to be emitted.
- ///
- /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
- /// when errors in the map are being re-added to the error buffer so that errors with the
- /// same primary span come out in a consistent order.
- move_error_reported: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'cx>)>,
/// This field keeps track of errors reported in the checking of uninitialized variables,
/// so that we don't report seemingly duplicate errors.
uninitialized_error_reported: FxHashSet<PlaceRef<'tcx>>,
- /// Errors to be reported buffer
- errors_buffer: Vec<Diagnostic>,
/// This field keeps track of all the local variables that are declared mut and are mutated.
/// Used for the warning issued by an unused mutable local variable.
used_mut: FxHashSet<Local>,
/// Results of Polonius analysis.
polonius_output: Option<Rc<PoloniusOutput>>,
+
+ errors: error::BorrowckErrors<'tcx>,
}
// Check that:
if conflict_error || mutability_error {
debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
-
self.access_place_error_reported.insert((place_span.0, place_span.1));
}
}
error_reported = true;
match kind {
ReadKind::Copy => {
- this.report_use_while_mutably_borrowed(location, place_span, borrow)
- .buffer(&mut this.errors_buffer);
+ let err = this
+ .report_use_while_mutably_borrowed(location, place_span, borrow);
+ this.buffer_error(err);
}
ReadKind::Borrow(bk) => {
- this.report_conflicting_borrow(location, place_span, bk, borrow)
- .buffer(&mut this.errors_buffer);
+ let err =
+ this.report_conflicting_borrow(location, place_span, bk, borrow);
+ this.buffer_error(err);
}
}
Control::Break
error_reported = true;
match kind {
WriteKind::MutableBorrow(bk) => {
- this.report_conflicting_borrow(location, place_span, bk, borrow)
- .buffer(&mut this.errors_buffer);
+ let err =
+ this.report_conflicting_borrow(location, place_span, bk, borrow);
+ this.buffer_error(err);
}
WriteKind::StorageDeadOrDrop => this
.report_borrowed_value_does_not_live_long_enough(
yield_span,
);
- err.buffer(&mut self.errors_buffer);
+ self.buffer_error(err);
}
}
| WriteKind::MutableBorrow(BorrowKind::Shared)
| WriteKind::MutableBorrow(BorrowKind::Shallow),
) => {
- if let (Err(_), true) = (
- self.is_mutable(place.as_ref(), is_local_mutation_allowed),
- self.errors_buffer.is_empty(),
- ) {
+ if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
+ && !self.has_buffered_errors()
+ {
// rust-lang/rust#46908: In pure NLL mode this code path should be
// unreachable, but we use `delay_span_bug` because we can hit this when
// dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug`
}
}
+mod error {
+ use super::*;
+
+ pub struct BorrowckErrors<'tcx> {
+ /// This field keeps track of move errors that are to be reported for given move indices.
+ ///
+ /// There are situations where many errors can be reported for a single move out (see #53807)
+ /// and we want only the best of those errors.
+ ///
+ /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
+ /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
+ /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
+ /// all move errors have been reported, any diagnostics in this map are added to the buffer
+ /// to be emitted.
+ ///
+ /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
+ /// when errors in the map are being re-added to the error buffer so that errors with the
+ /// same primary span come out in a consistent order.
+ buffered_move_errors:
+ BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
+ /// Errors to be reported buffer
+ buffered: Vec<Diagnostic>,
+ /// Set to Some if we emit an error during borrowck
+ tainted_by_errors: Option<ErrorReported>,
+ }
+
+ impl BorrowckErrors<'_> {
+ pub fn new() -> Self {
+ BorrowckErrors {
+ buffered_move_errors: BTreeMap::new(),
+ buffered: Default::default(),
+ tainted_by_errors: None,
+ }
+ }
+
+ pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
+ self.tainted_by_errors = Some(ErrorReported {});
+ t.buffer(&mut self.buffered);
+ }
+
+ pub fn set_tainted_by_errors(&mut self) {
+ self.tainted_by_errors = Some(ErrorReported {});
+ }
+ }
+
+ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
+ pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
+ self.errors.buffer_error(t);
+ }
+
+ pub fn buffer_move_error(
+ &mut self,
+ move_out_indices: Vec<MoveOutIndex>,
+ place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>),
+ ) -> bool {
+ if let Some((_, mut diag)) =
+ self.errors.buffered_move_errors.insert(move_out_indices, place_and_err)
+ {
+ // Cancel the old diagnostic so we don't ICE
+ diag.cancel();
+ false
+ } else {
+ true
+ }
+ }
+
+ pub fn emit_errors(&mut self) -> Option<ErrorReported> {
+ // Buffer any move errors that we collected and de-duplicated.
+ for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
+ // We have already set tainted for this error, so just buffer it.
+ diag.buffer(&mut self.errors.buffered);
+ }
+
+ if !self.errors.buffered.is_empty() {
+ self.errors.buffered.sort_by_key(|diag| diag.sort_span);
+
+ for diag in self.errors.buffered.drain(..) {
+ self.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag);
+ }
+ }
+
+ self.errors.tainted_by_errors
+ }
+
+ pub fn has_buffered_errors(&self) -> bool {
+ self.errors.buffered.is_empty()
+ }
+
+ pub fn has_move_error(
+ &self,
+ move_out_indices: &[MoveOutIndex],
+ ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> {
+ self.errors.buffered_move_errors.get(move_out_indices)
+ }
+ }
+}
+
/// The degree of overlap between 2 places for borrow-checking.
enum Overlap {
/// The places might partially overlap - in this case, we give
//! The entry point of the NLL borrow checker.
use rustc_data_structures::vec_map::VecMap;
-use rustc_errors::Diagnostic;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere};
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
- errors_buffer: &mut Vec<Diagnostic>,
+ errors: &mut crate::error::BorrowckErrors<'tcx>,
) {
let tcx = infcx.tcx;
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
err.note(&format!("Inferred opaque type values:\n{:#?}", opaque_type_values));
}
- err.buffer(errors_buffer);
+ errors.buffer_error(err);
}
fn for_each_region_constraint(
mut krate: ast::Crate,
resolver: &mut dyn ResolverExpand,
sess: &Session,
- alt_std_name: Option<Symbol>,
) -> ast::Crate {
let edition = sess.parse_sess.edition;
span,
ident,
vec![cx.attribute(cx.meta_word(span, sym::macro_use))],
- ast::ItemKind::ExternCrate(alt_std_name),
+ ast::ItemKind::ExternCrate(None),
),
);
}
// The target doesn't care; the subtarget reads our attribute.
apply_tune_cpu_attr(cx, llfn);
- let mut function_features = codegen_fn_attrs
- .target_features
+ let function_features =
+ codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::<Vec<&str>>();
+
+ if let Some(f) = llvm_util::check_tied_features(
+ cx.tcx.sess,
+ &function_features.iter().map(|f| (*f, true)).collect(),
+ ) {
+ let span = cx
+ .tcx
+ .get_attrs(instance.def_id())
+ .iter()
+ .find(|a| a.has_name(rustc_span::sym::target_feature))
+ .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
+ let msg = format!(
+ "the target features {} must all be either enabled or disabled together",
+ f.join(", ")
+ );
+ let mut err = cx.tcx.sess.struct_span_err(span, &msg);
+ err.help("add the missing features in a `target_feature` attribute");
+ err.emit();
+ return;
+ }
+
+ let mut function_features = function_features
.iter()
- .flat_map(|f| {
- let feature = f.as_str();
- llvm_util::to_llvm_feature(cx.tcx.sess, feature)
+ .flat_map(|feat| {
+ llvm_util::to_llvm_feature(cx.tcx.sess, feat)
.into_iter()
.map(|f| format!("+{}", f))
.collect::<Vec<String>>()
use crate::{llvm, llvm_util};
use libc::c_int;
use libloading::Library;
-use rustc_codegen_ssa::target_features::supported_target_features;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_codegen_ssa::target_features::{supported_target_features, tied_target_features};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_fs_util::path_to_c_string;
use rustc_middle::bug;
use rustc_session::config::PrintRequest;
("aarch64", "frintts") => vec!["fptoint"],
("aarch64", "fcma") => vec!["complxnum"],
("aarch64", "pmuv3") => vec!["perfmon"],
+ ("aarch64", "paca") => vec!["pauth"],
+ ("aarch64", "pacg") => vec!["pauth"],
(_, s) => vec![s],
}
}
+// Given a map from target_features to whether they are enabled or disabled,
+// ensure only valid combinations are allowed.
+pub fn check_tied_features(
+ sess: &Session,
+ features: &FxHashMap<&str, bool>,
+) -> Option<&'static [&'static str]> {
+ for tied in tied_target_features(sess) {
+ // Tied features must be set to the same value, or not set at all
+ let mut tied_iter = tied.iter();
+ let enabled = features.get(tied_iter.next().unwrap());
+
+ if tied_iter.any(|f| enabled != features.get(f)) {
+ return Some(tied);
+ }
+ }
+ None
+}
+
pub fn target_features(sess: &Session) -> Vec<Symbol> {
let target_machine = create_informational_target_machine(sess);
supported_target_features(sess)
Some(_) | None => {}
};
+ fn strip(s: &str) -> &str {
+ s.strip_prefix(&['+', '-']).unwrap_or(s)
+ }
+
let filter = |s: &str| {
if s.is_empty() {
return vec![];
}
- let feature = if s.starts_with('+') || s.starts_with('-') {
- &s[1..]
- } else {
+ let feature = strip(s);
+ if feature == s {
return vec![s.to_string()];
- };
+ }
+
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
// are not passed down to LLVM.
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
features.extend(sess.target.features.split(',').flat_map(&filter));
// -Ctarget-features
- features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter));
-
+ let feats: Vec<&str> = sess.opts.cg.target_feature.split(',').collect();
+ // LLVM enables based on the last occurence of a feature
+ if let Some(f) =
+ check_tied_features(sess, &feats.iter().map(|f| (strip(f), !f.starts_with("-"))).collect())
+ {
+ sess.err(&format!(
+ "Target features {} must all be enabled or disabled together",
+ f.join(", ")
+ ));
+ }
+ features.extend(feats.iter().flat_map(|&f| filter(f)));
features
}
("ssbs", Some(sym::aarch64_target_feature)),
// FEAT_SB
("sb", Some(sym::aarch64_target_feature)),
- // FEAT_PAUTH
- ("pauth", Some(sym::aarch64_target_feature)),
+ // FEAT_PAUTH (address authentication)
+ ("paca", Some(sym::aarch64_target_feature)),
+ // FEAT_PAUTH (generic authentication)
+ ("pacg", Some(sym::aarch64_target_feature)),
// FEAT_DPB
("dpb", Some(sym::aarch64_target_feature)),
// FEAT_DPB2
("v8.7a", Some(sym::aarch64_target_feature)),
];
+const AARCH64_TIED_FEATURES: &[&[&str]] = &[&["paca", "pacg"]];
+
const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("adx", Some(sym::adx_target_feature)),
("aes", None),
}
}
+pub fn tied_target_features(sess: &Session) -> &'static [&'static [&'static str]] {
+ match &*sess.target.arch {
+ "aarch64" => AARCH64_TIED_FEATURES,
+ _ => &[],
+ }
+}
+
pub(crate) fn provide(providers: &mut Providers) {
providers.supported_target_features = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
ScalarMaybeUninit, StackPopCleanup,
};
-use rustc_errors::ErrorReported;
use rustc_hir::def::DefKind;
use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled;
let cid = key.value;
let def = cid.instance.def.with_opt_param();
-
- if let Some(def) = def.as_local() {
- if tcx.has_typeck_results(def.did) {
- if let Some(error_reported) = tcx.typeck_opt_const_arg(def).tainted_by_errors {
- return Err(ErrorHandled::Reported(error_reported));
- }
- }
- if !tcx.is_mir_available(def.did) {
- tcx.sess.delay_span_bug(
- tcx.def_span(def.did),
- &format!("no MIR body is available for {:?}", def.did),
- );
- return Err(ErrorHandled::Reported(ErrorReported {}));
- }
- if let Some(error_reported) = tcx.mir_const_qualif_opt_const_arg(def).error_occured {
- return Err(ErrorHandled::Reported(error_reported));
- }
- }
-
let is_static = tcx.is_static(def.did);
let mut ecx = InterpCx::new(
+use rustc_errors::ErrorReported;
+use rustc_hir::def::DefKind;
use rustc_middle::mir;
use rustc_middle::ty::{self, Ty};
use std::borrow::Borrow;
ty::InstanceDef::Item(def) => {
if ecx.tcx.is_ctfe_mir_available(def.did) {
Ok(ecx.tcx.mir_for_ctfe_opt_const_arg(def))
+ } else if ecx.tcx.def_kind(def.did) == DefKind::AssocConst {
+ ecx.tcx.sess.delay_span_bug(
+ rustc_span::DUMMY_SP,
+ "This is likely a const item that is missing from its impl",
+ );
+ throw_inval!(AlreadyReported(ErrorReported {}));
} else {
let path = ecx.tcx.def_path_str(def.did);
Err(ConstEvalErrKind::NeedsRfc(format!("calling extern function `{}`", path))
instance: ty::InstanceDef<'tcx>,
promoted: Option<mir::Promoted>,
) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
- // do not continue if typeck errors occurred (can only occur in local crate)
let def = instance.with_opt_param();
- if let Some(def) = def.as_local() {
- if self.tcx.has_typeck_results(def.did) {
- if let Some(error_reported) = self.tcx.typeck_opt_const_arg(def).tainted_by_errors {
- throw_inval!(AlreadyReported(error_reported))
- }
- }
- }
trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
- if let Some(promoted) = promoted {
- return Ok(&self.tcx.promoted_mir_opt_const_arg(def)[promoted]);
+ let body = if let Some(promoted) = promoted {
+ &self.tcx.promoted_mir_opt_const_arg(def)[promoted]
+ } else {
+ M::load_mir(self, instance)?
+ };
+ // do not continue if typeck errors occurred (can only occur in local crate)
+ if let Some(err) = body.tainted_by_errors {
+ throw_inval!(AlreadyReported(err));
}
- M::load_mir(self, instance)
+ Ok(body)
}
/// Call this on things you got out of the MIR (so it is as generic as the current
fn in_return_place(
&mut self,
ccx: &'mir ConstCx<'mir, 'tcx>,
- error_occured: Option<ErrorReported>,
+ tainted_by_errors: Option<ErrorReported>,
) -> ConstQualifs {
// Find the `Return` terminator if one exists.
//
.map(|(bb, _)| bb);
let return_block = match return_block {
- None => return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), error_occured),
+ None => {
+ return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), tainted_by_errors);
+ }
Some(bb) => bb,
};
needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc),
has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
custom_eq,
- error_occured,
+ tainted_by_errors,
}
}
}
pub fn in_any_value_of_ty<'tcx>(
cx: &ConstCx<'_, 'tcx>,
ty: Ty<'tcx>,
- error_occured: Option<ErrorReported>,
+ tainted_by_errors: Option<ErrorReported>,
) -> ConstQualifs {
ConstQualifs {
has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
- error_occured,
+ tainted_by_errors,
}
}
vec![],
body.span,
body.generator_kind(),
+ body.tainted_by_errors,
);
let promoter = Promoter {
hasher
}
- // A specialized write function for values with size <= 8.
#[inline]
- fn short_write<T>(&mut self, x: T) {
- let size = mem::size_of::<T>();
+ pub fn short_write<const LEN: usize>(&mut self, bytes: [u8; LEN]) {
let nbuf = self.nbuf;
- debug_assert!(size <= 8);
+ debug_assert!(LEN <= 8);
debug_assert!(nbuf < BUFFER_SIZE);
- debug_assert!(nbuf + size < BUFFER_WITH_SPILL_SIZE);
+ debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE);
- if nbuf + size < BUFFER_SIZE {
+ if nbuf + LEN < BUFFER_SIZE {
unsafe {
// The memcpy call is optimized away because the size is known.
let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
- ptr::copy_nonoverlapping(&x as *const _ as *const u8, dst, size);
+ ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN);
}
- self.nbuf = nbuf + size;
+ self.nbuf = nbuf + LEN;
return;
}
- unsafe { self.short_write_process_buffer(x) }
+ unsafe { self.short_write_process_buffer(bytes) }
}
// A specialized write function for values with size <= 8 that should only
// `self.nbuf` must cause `self.buf` to become fully initialized (and not
// overflow) if it wasn't already.
#[inline(never)]
- unsafe fn short_write_process_buffer<T>(&mut self, x: T) {
- let size = mem::size_of::<T>();
+ unsafe fn short_write_process_buffer<const LEN: usize>(&mut self, bytes: [u8; LEN]) {
let nbuf = self.nbuf;
- debug_assert!(size <= 8);
+ debug_assert!(LEN <= 8);
debug_assert!(nbuf < BUFFER_SIZE);
- debug_assert!(nbuf + size >= BUFFER_SIZE);
- debug_assert!(nbuf + size < BUFFER_WITH_SPILL_SIZE);
+ debug_assert!(nbuf + LEN >= BUFFER_SIZE);
+ debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE);
// Copy first part of input into end of buffer, possibly into spill
// element. The memcpy call is optimized away because the size is known.
let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
- ptr::copy_nonoverlapping(&x as *const _ as *const u8, dst, size);
+ ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN);
// Process buffer.
for i in 0..BUFFER_CAPACITY {
self.state.v0 ^= elem;
}
- // Copy remaining input into start of buffer by copying size - 1
- // elements from spill (at most size - 1 bytes could have overflowed
+ // Copy remaining input into start of buffer by copying LEN - 1
+ // elements from spill (at most LEN - 1 bytes could have overflowed
// into the spill). The memcpy call is optimized away because the size
- // is known. And the whole copy is optimized away for size == 1.
+ // is known. And the whole copy is optimized away for LEN == 1.
let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8;
- ptr::copy_nonoverlapping(src, self.buf.as_mut_ptr() as *mut u8, size - 1);
+ ptr::copy_nonoverlapping(src, self.buf.as_mut_ptr() as *mut u8, LEN - 1);
// This function should only be called when the write fills the buffer.
- // Therefore, when size == 1, the new `self.nbuf` must be zero. The size
- // is statically known, so the branch is optimized away.
- self.nbuf = if size == 1 { 0 } else { nbuf + size - BUFFER_SIZE };
+ // Therefore, when LEN == 1, the new `self.nbuf` must be zero.
+ // LEN is statically known, so the branch is optimized away.
+ self.nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE };
self.processed += BUFFER_SIZE;
}
impl Hasher for SipHasher128 {
#[inline]
fn write_u8(&mut self, i: u8) {
- self.short_write(i);
+ self.short_write(i.to_ne_bytes());
}
#[inline]
fn write_u16(&mut self, i: u16) {
- self.short_write(i);
+ self.short_write(i.to_ne_bytes());
}
#[inline]
fn write_u32(&mut self, i: u32) {
- self.short_write(i);
+ self.short_write(i.to_ne_bytes());
}
#[inline]
fn write_u64(&mut self, i: u64) {
- self.short_write(i);
+ self.short_write(i.to_ne_bytes());
}
#[inline]
fn write_usize(&mut self, i: usize) {
- self.short_write(i);
+ self.short_write(i.to_ne_bytes());
}
#[inline]
fn write_i8(&mut self, i: i8) {
- self.short_write(i as u8);
+ self.short_write((i as u8).to_ne_bytes());
}
#[inline]
fn write_i16(&mut self, i: i16) {
- self.short_write(i as u16);
+ self.short_write((i as u16).to_ne_bytes());
}
#[inline]
fn write_i32(&mut self, i: i32) {
- self.short_write(i as u32);
+ self.short_write((i as u32).to_ne_bytes());
}
#[inline]
fn write_i64(&mut self, i: i64) {
- self.short_write(i as u64);
+ self.short_write((i as u64).to_ne_bytes());
}
#[inline]
fn write_isize(&mut self, i: isize) {
- self.short_write(i as usize);
+ self.short_write((i as usize).to_ne_bytes());
}
#[inline]
#[inline]
fn write_u16(&mut self, i: u16) {
- self.state.write_u16(i.to_le());
+ self.state.short_write(i.to_le_bytes());
}
#[inline]
fn write_u32(&mut self, i: u32) {
- self.state.write_u32(i.to_le());
+ self.state.short_write(i.to_le_bytes());
}
#[inline]
fn write_u64(&mut self, i: u64) {
- self.state.write_u64(i.to_le());
+ self.state.short_write(i.to_le_bytes());
}
#[inline]
fn write_u128(&mut self, i: u128) {
- self.state.write_u128(i.to_le());
+ self.state.write(&i.to_le_bytes());
}
#[inline]
// Always treat usize as u64 so we get the same results on 32 and 64 bit
// platforms. This is important for symbol hashes when cross compiling,
// for example.
- self.state.write_u64((i as u64).to_le());
+ self.state.short_write((i as u64).to_le_bytes());
}
#[inline]
#[inline]
fn write_i16(&mut self, i: i16) {
- self.state.write_i16(i.to_le());
+ self.state.short_write((i as u16).to_le_bytes());
}
#[inline]
fn write_i32(&mut self, i: i32) {
- self.state.write_i32(i.to_le());
+ self.state.short_write((i as u32).to_le_bytes());
}
#[inline]
fn write_i64(&mut self, i: i64) {
- self.state.write_i64(i.to_le());
+ self.state.short_write((i as u64).to_le_bytes());
}
#[inline]
fn write_i128(&mut self, i: i128) {
- self.state.write_i128(i.to_le());
+ self.state.write(&(i as u128).to_le_bytes());
}
#[inline]
#[inline(never)]
fn hash_value(state: &mut SipHasher128, value: u64) {
state.write_u8(0xFF);
- state.write_u64(value.to_le());
+ state.short_write(value.to_le_bytes());
}
// `isize` values often seem to have a small (positive) numeric value in practice.
// 8 bytes. Since this prefix cannot occur when we hash a single byte, when we hash two
// `isize`s that fit within a different amount of bytes, they should always produce a different
// byte stream for the hasher.
- //
- // To ensure that this optimization hashes the exact same bytes on both little-endian and
- // big-endian architectures, we compare the value with 0xFF before we convert the number
- // into a unified representation (little-endian).
if value < 0xFF {
self.state.write_u8(value as u8);
} else {
E0185: include_str!("./error_codes/E0185.md"),
E0186: include_str!("./error_codes/E0186.md"),
E0191: include_str!("./error_codes/E0191.md"),
+E0192: include_str!("./error_codes/E0192.md"),
E0193: include_str!("./error_codes/E0193.md"),
E0195: include_str!("./error_codes/E0195.md"),
E0197: include_str!("./error_codes/E0197.md"),
// E0188, // can not cast an immutable reference to a mutable pointer
// E0189, // deprecated: can only cast a boxed pointer to a boxed object
// E0190, // deprecated: can only cast a &-pointer to an &-object
-// E0192, // negative impl only applicable to auto traits
// E0194, // merged into E0403
// E0196, // cannot determine a type for this closure
E0208,
+#### Note: this error code is no longer emitted by the compiler.
+
A negative impl was added on a trait implementation.
Erroneous code example:
-```compile_fail,E0192
+```compile_fail
trait Trait {
type Bar;
}
struct Foo;
-impl !Trait for Foo { } //~ ERROR E0192
+impl !Trait for Foo { } //~ ERROR
fn main() {}
```
///
/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
/// - Example: find all items with a `#[foo]` attribute on them.
-/// - How: Implement `ItemLikeVisitor` and call `tcx.hir().krate().visit_all_item_likes()`.
+/// - How: Implement `ItemLikeVisitor` and call `tcx.hir().visit_all_item_likes()`.
/// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
/// - Con: Don't get information about nesting
/// - Con: Don't have methods for specific bits of HIR, like "on
/// - Example: Examine each expression to look for its type and do some check or other.
/// - How: Implement `intravisit::Visitor` and override the `nested_visit_map()` method
/// to return `NestedVisitorMap::OnlyBodies` and use
-/// `tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within
-/// your `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget
-/// to invoke `intravisit::walk_expr()` to keep walking the subparts).
+/// `tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within your
+/// `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
+/// `intravisit::walk_expr()` to keep walking the subparts).
/// - Pro: Visitor methods for any kind of HIR node, not just item-like things.
/// - Pro: Integrates well into dependency tracking.
/// - Con: Don't get information about nesting between items
rustc_builtin_macros::register_builtin_macros(resolver);
krate = sess.time("crate_injection", || {
- let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s));
- rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess, alt_std_name)
+ rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess)
});
util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer());
/// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need
/// for `'static` bounds.
#[cfg(not(parallel_compiler))]
-pub fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
+fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
// SAFETY: join() is called immediately, so any closure captures are still
// alive.
match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() {
}
}
-pub fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
+fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
// For now we only allow this function to be called once as it'll dlopen a
// few things, which seems to work best if we only do that once. In
// general this assertion never trips due to the once guard in `get_codegen_backend`,
use crate::ty::{self, List, Ty, TyCtxt};
use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex};
+use rustc_errors::ErrorReported;
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc_hir::{self, GeneratorKind};
predecessor_cache: PredecessorCache,
is_cyclic: GraphIsCyclicCache,
+
+ pub tainted_by_errors: Option<ErrorReported>,
}
impl<'tcx> Body<'tcx> {
var_debug_info: Vec<VarDebugInfo<'tcx>>,
span: Span,
generator_kind: Option<GeneratorKind>,
+ tainted_by_errors: Option<ErrorReported>,
) -> Self {
// We need `arg_count` locals, and one for the return place.
assert!(
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
is_cyclic: GraphIsCyclicCache::new(),
+ tainted_by_errors,
};
body.is_polymorphic = body.has_param_types_or_consts();
body
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
is_cyclic: GraphIsCyclicCache::new(),
+ tainted_by_errors: None,
};
body.is_polymorphic = body.has_param_types_or_consts();
body
pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
pub used_mut_upvars: SmallVec<[Field; 8]>,
+ pub tainted_by_errors: Option<ErrorReported>,
}
/// The result of the `mir_const_qualif` query.
pub needs_drop: bool,
pub needs_non_const_drop: bool,
pub custom_eq: bool,
- pub error_occured: Option<ErrorReported>,
+ pub tainted_by_errors: Option<ErrorReported>,
}
/// After we borrow check a closure, we are left with various
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
use crate::middle::stability;
use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
-use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted};
+use crate::mir::{
+ Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
+};
use crate::thir::Thir;
use crate::traits;
use crate::ty::query::{self, TyCtxtAt};
}
}
+ pub fn mir_borrowck_opt_const_arg(
+ self,
+ def: ty::WithOptConstParam<LocalDefId>,
+ ) -> &'tcx BorrowCheckResult<'tcx> {
+ if let Some(param_did) = def.const_param_did {
+ self.mir_borrowck_const_arg((def.did, param_did))
+ } else {
+ self.mir_borrowck(def.did)
+ }
+ }
+
pub fn alloc_steal_thir(self, thir: Thir<'tcx>) -> &'tcx Steal<Thir<'tcx>> {
self.arena.alloc(Steal::new(thir))
}
crate::ty::UniverseIndex,
crate::ty::Variance,
::rustc_span::Span,
+ ::rustc_errors::ErrorReported,
}
///////////////////////////////////////////////////////////////////////////
let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id));
tcx.infer_ctxt().enter(|infcx| {
- let body = if let Some(ErrorReported) = typeck_results.tainted_by_errors {
- build::construct_error(&infcx, def, id, body_id, body_owner_kind)
+ let body = if let Some(error_reported) = typeck_results.tainted_by_errors {
+ build::construct_error(&infcx, def, id, body_id, body_owner_kind, error_reported)
} else if body_owner_kind.is_fn_or_closure() {
// fetch the fully liberated fn signature (that is, all bound
// types/lifetimes replaced)
hir_id: hir::HirId,
body_id: hir::BodyId,
body_owner_kind: hir::BodyOwnerKind,
+ err: ErrorReported,
) -> Body<'tcx> {
let tcx = infcx.tcx;
let span = tcx.hir().span(hir_id);
vec![],
span,
generator_kind,
+ Some(err),
);
body.generator.as_mut().map(|gen| gen.yield_ty = Some(ty));
body
self.var_debug_info,
self.fn_span,
self.generator_kind,
+ self.typeck_results.tainted_by_errors,
)
}
Default::default(),
body.span,
body.generator_kind(),
+ body.tainted_by_errors,
);
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
// Ensure that we compute the `mir_const_qualif` for constants at
// this point, before we steal the mir-const result.
// Also this means promotion can rely on all const checks having been done.
- let _ = tcx.mir_const_qualif_opt_const_arg(def);
+ let const_qualifs = tcx.mir_const_qualif_opt_const_arg(def);
let mut body = tcx.mir_const(def).steal();
+ if let Some(error_reported) = const_qualifs.tainted_by_errors {
+ body.tainted_by_errors = Some(error_reported);
+ }
let mut required_consts = Vec::new();
let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts);
return tcx.mir_drops_elaborated_and_const_checked(def);
}
- // (Mir-)Borrowck uses `mir_promoted`, so we have to force it to
- // execute before we can steal.
- if let Some(param_did) = def.const_param_did {
- tcx.ensure().mir_borrowck_const_arg((def.did, param_did));
- } else {
- tcx.ensure().mir_borrowck(def.did);
- }
+ let mir_borrowck = tcx.mir_borrowck_opt_const_arg(def);
let is_fn_like = tcx.hir().get_by_def_id(def.did).fn_kind().is_some();
if is_fn_like {
let (body, _) = tcx.mir_promoted(def);
let mut body = body.steal();
+ if let Some(error_reported) = mir_borrowck.tainted_by_errors {
+ body.tainted_by_errors = Some(error_reported);
+ }
// IMPORTANT
pm::run_passes(tcx, &mut body, &[&remove_false_edges::RemoveFalseEdges]);
return tcx.arena.alloc(IndexVec::new());
}
- if let Some(param_did) = def.const_param_did {
- tcx.ensure().mir_borrowck_const_arg((def.did, param_did));
- } else {
- tcx.ensure().mir_borrowck(def.did);
- }
- let (_, promoted) = tcx.mir_promoted(def);
- let mut promoted = promoted.steal();
+ let tainted_by_errors = tcx.mir_borrowck_opt_const_arg(def).tainted_by_errors;
+ let mut promoted = tcx.mir_promoted(def).1.steal();
for body in &mut promoted {
+ if let Some(error_reported) = tainted_by_errors {
+ body.tainted_by_errors = Some(error_reported);
+ }
run_post_borrowck_cleanup_passes(tcx, body);
}
vec![],
span,
None,
+ // FIXME(compiler-errors): is this correct?
+ None,
)
}
} else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs)
} else if !ate_colon && (self.check(&TokenKind::Comma) || self.check(&TokenKind::Gt)) {
- // We're probably inside of a `Path<'a>` that needs a turbofish, so suppress the
- // "must be followed by a colon" error, and the "expected one of" error.
- self.diagnostic().delay_span_bug(lo, "this label wasn't parsed correctly");
+ // We're probably inside of a `Path<'a>` that needs a turbofish
+ let msg = "expected `while`, `for`, `loop` or `{` after a label";
+ self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
consume_colon = false;
Ok(self.mk_expr_err(lo))
} else {
// edit:
// only do this if the const and usage of the non-constant value are on the same line
// the further the two are apart, the higher the chance of the suggestion being wrong
- // also make sure that the pos for the suggestion is not 0 (ICE #90878)
- let sp =
- self.session.source_map().span_extend_to_prev_str(ident.span, current, true);
-
- let pos_for_suggestion = sp.lo().0.saturating_sub(current.len() as u32);
+ let sp = self
+ .session
+ .source_map()
+ .span_extend_to_prev_str(ident.span, current, true, false);
- if sp.lo().0 == 0
- || pos_for_suggestion == 0
- || self.session.source_map().is_multiline(sp)
- {
- err.span_label(ident.span, &format!("this would need to be a `{}`", sugg));
- } else {
- let sp = sp.with_lo(BytePos(pos_for_suggestion));
- err.span_suggestion(
- sp,
- &format!("consider using `{}` instead of `{}`", sugg, current),
- format!("{} {}", sugg, ident),
- Applicability::MaybeIncorrect,
- );
- err.span_label(span, "non-constant value");
+ match sp {
+ Some(sp) if !self.session.source_map().is_multiline(sp) => {
+ let sp = sp.with_lo(BytePos(sp.lo().0 - (current.len() as u32)));
+ err.span_suggestion(
+ sp,
+ &format!("consider using `{}` instead of `{}`", sugg, current),
+ format!("{} {}", sugg, ident),
+ Applicability::MaybeIncorrect,
+ );
+ err.span_label(span, "non-constant value");
+ }
+ _ => {
+ err.span_label(ident.span, &format!("this would need to be a `{}`", sugg));
+ }
}
+
err
}
ResolutionError::BindingShadowsSomethingUnacceptable {
externs: Externs(BTreeMap::new()),
extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
crate_name: None,
- alt_std_name: None,
libs: Vec::new(),
unstable_features: UnstableFeatures::Disallow,
debug_assertions: true,
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
extern_dep_specs,
crate_name,
- alt_std_name: None,
libs,
debug_assertions,
actually_rustdoc: false,
externs: Externs [UNTRACKED],
extern_dep_specs: ExternDepSpecs [UNTRACKED],
crate_name: Option<String> [TRACKED],
- /// An optional name to use as the crate for std during std injection,
- /// written `extern crate name as std`. Defaults to `std`. Used by
- /// out-of-tree drivers.
- alt_std_name: Option<String> [TRACKED],
/// Indicates how the compiler should treat unstable features.
unstable_features: UnstableFeatures [TRACKED],
}
/// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by
- /// whitespace. Returns the same span if no character could be found or if an error occurred
- /// while retrieving the code snippet.
- pub fn span_extend_to_prev_str(&self, sp: Span, pat: &str, accept_newlines: bool) -> Span {
+ /// whitespace. Returns None if the pattern could not be found or if an error occurred while
+ /// retrieving the code snippet.
+ pub fn span_extend_to_prev_str(
+ &self,
+ sp: Span,
+ pat: &str,
+ accept_newlines: bool,
+ include_whitespace: bool,
+ ) -> Option<Span> {
// assure that the pattern is delimited, to avoid the following
// fn my_fn()
// ^^^^ returned span without the check
// ---------- correct span
+ let prev_source = self.span_to_prev_source(sp).ok()?;
for ws in &[" ", "\t", "\n"] {
let pat = pat.to_owned() + ws;
- if let Ok(prev_source) = self.span_to_prev_source(sp) {
- let prev_source = prev_source.rsplit(&pat).next().unwrap_or("").trim_start();
- if prev_source.is_empty() && sp.lo().0 != 0 {
- return sp.with_lo(BytePos(sp.lo().0 - 1));
- } else if accept_newlines || !prev_source.contains('\n') {
- return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
+ if let Some(pat_pos) = prev_source.rfind(&pat) {
+ let just_after_pat_pos = pat_pos + pat.len() - 1;
+ let just_after_pat_plus_ws = if include_whitespace {
+ just_after_pat_pos
+ + prev_source[just_after_pat_pos..]
+ .find(|c: char| !c.is_whitespace())
+ .unwrap_or(0)
+ } else {
+ just_after_pat_pos
+ };
+ let len = prev_source.len() - just_after_pat_plus_ws;
+ let prev_source = &prev_source[just_after_pat_plus_ws..];
+ if accept_newlines || !prev_source.trim_start().contains('\n') {
+ return Some(sp.with_lo(BytePos(sp.lo().0 - len as u32)));
}
}
}
- sp
+ None
}
/// Returns the source snippet as `String` after the given `Span`.
}
pub fn generate_fn_name_span(&self, span: Span) -> Option<Span> {
- let prev_span = self.span_extend_to_prev_str(span, "fn", true);
+ let prev_span = self.span_extend_to_prev_str(span, "fn", true, true).unwrap_or(span);
if let Ok(snippet) = self.span_to_snippet(prev_span) {
debug!(
"generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}",
pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> {
// Try to extend the span to the previous "fn" keyword to retrieve the function
// signature.
- let sugg_span = self.span_extend_to_prev_str(span, "fn", false);
- if sugg_span != span {
+ if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) {
if let Ok(snippet) = self.span_to_snippet(sugg_span) {
// Consume the function name.
let mut offset = snippet
[] => {}
[trait_info] => {
let msg = format!(
- "the trait `{}` defines an item `{}`, but is explicitely unimplemented",
+ "the trait `{}` defines an item `{}`, but is explicitly unimplemented",
self.tcx.def_path_str(trait_info.def_id),
item_name
);
}
trait_infos => {
let mut msg = format!(
- "the following traits define an item `{}`, but are explicitely unimplemented:",
+ "the following traits define an item `{}`, but are explicitly unimplemented:",
item_name
);
for trait_info in trait_infos {
/// Returns the current working directory as a [`PathBuf`].
///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `getcwd` function on Unix
+/// and the `GetCurrentDirectoryW` function on Windows.
+///
/// # Errors
///
/// Returns an [`Err`] if the current working directory value is invalid.
/// Changes the current working directory to the specified path.
///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `chdir` function on Unix
+/// and the `SetCurrentDirectoryW` function on Windows.
+///
/// Returns an [`Err`] if the operation fails.
///
/// # Examples
/// The filesystem does not support making so many hardlinks to the same file.
#[unstable(feature = "io_error_more", issue = "86442")]
TooManyLinks,
- /// Filename too long.
+ /// A filename was invalid.
///
- /// The limit might be from the underlying filesystem or API, or an administratively imposed
- /// resource limit.
+ /// This error can also cause if it exceeded the filename length limit.
#[unstable(feature = "io_error_more", issue = "86442")]
- FilenameTooLong,
+ InvalidFilename,
/// Program argument list too long.
///
/// When trying to run an external program, a system or process limit on the size of the
DirectoryNotEmpty => "directory not empty",
ExecutableFileBusy => "executable file busy",
FileTooLarge => "file too large",
- FilenameTooLong => "filename too long",
FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)",
FilesystemQuotaExceeded => "filesystem quota exceeded",
HostUnreachable => "host unreachable",
Interrupted => "operation interrupted",
InvalidData => "invalid data",
+ InvalidFilename => "invalid filename",
InvalidInput => "invalid input parameter",
IsADirectory => "is a directory",
NetworkDown => "network down",
Deadlock,
CrossesDevices,
TooManyLinks,
- FilenameTooLong,
+ InvalidFilename,
ArgumentListTooLong,
Interrupted,
Other,
#[doc(no_inline)] // Note (#82861): required for correct documentation
pub use core::arch::*;
+ #[stable(feature = "simd_aarch64", since = "1.60.0")]
+ pub use std_detect::is_aarch64_feature_detected;
#[stable(feature = "simd_x86", since = "1.27.0")]
pub use std_detect::is_x86_feature_detected;
#[unstable(feature = "stdsimd", issue = "48556")]
pub use std_detect::{
- is_aarch64_feature_detected, is_arm_feature_detected, is_mips64_feature_detected,
- is_mips_feature_detected, is_powerpc64_feature_detected, is_powerpc_feature_detected,
- is_riscv_feature_detected,
+ is_arm_feature_detected, is_mips64_feature_detected, is_mips_feature_detected,
+ is_powerpc64_feature_detected, is_powerpc_feature_detected, is_riscv_feature_detected,
};
}
fn as_fd(&self) -> BorrowedFd<'_>;
}
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsFd> AsFd for &T {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ T::as_fd(self)
+ }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsFd> AsFd for &mut T {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ T::as_fd(self)
+ }
+}
+
#[unstable(feature = "io_safety", issue = "87074")]
impl AsFd for BorrowedFd<'_> {
#[inline]
///
/// fn main() -> std::io::Result<()> {
/// let f = std::fs::File::open("/file")?;
-/// fs::fchown(f, Some(0), Some(0))?;
+/// fs::fchown(&f, Some(0), Some(0))?;
/// Ok(())
/// }
/// ```
fn as_handle(&self) -> BorrowedHandle<'_>;
}
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsHandle> AsHandle for &T {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ T::as_handle(self)
+ }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsHandle> AsHandle for &mut T {
+ #[inline]
+ fn as_handle(&self) -> BorrowedHandle<'_> {
+ T::as_handle(self)
+ }
+}
+
impl AsHandle for BorrowedHandle<'_> {
#[inline]
fn as_handle(&self) -> BorrowedHandle<'_> {
fn as_socket(&self) -> BorrowedSocket<'_>;
}
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsSocket> AsSocket for &T {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ T::as_socket(self)
+ }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsSocket> AsSocket for &mut T {
+ #[inline]
+ fn as_socket(&self) -> BorrowedSocket<'_> {
+ T::as_socket(self)
+ }
+}
+
impl AsSocket for BorrowedSocket<'_> {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
impl Hash for Path {
fn hash<H: Hasher>(&self, h: &mut H) {
let bytes = self.as_u8_slice();
- let prefix_len = match parse_prefix(&self.inner) {
+ let (prefix_len, verbatim) = match parse_prefix(&self.inner) {
Some(prefix) => {
prefix.hash(h);
- prefix.len()
+ (prefix.len(), prefix.is_verbatim())
}
- None => 0,
+ None => (0, false),
};
let bytes = &bytes[prefix_len..];
let mut bytes_hashed = 0;
for i in 0..bytes.len() {
- if is_sep_byte(bytes[i]) {
+ let is_sep = if verbatim { is_verbatim_sep(bytes[i]) } else { is_sep_byte(bytes[i]) };
+ if is_sep {
if i > component_start {
let to_hash = &bytes[component_start..i];
h.write(to_hash);
}
// skip over separator and optionally a following CurDir item
- // since components() would normalize these away
- component_start = i + match bytes[i..] {
- [_, b'.', b'/', ..] | [_, b'.'] => 2,
- _ => 1,
- };
+ // since components() would normalize these away.
+ component_start = i + 1;
+
+ let tail = &bytes[component_start..];
+
+ if !verbatim {
+ component_start += match tail {
+ [b'.'] => 1,
+ [b'.', sep @ _, ..] if is_sep_byte(*sep) => 1,
+ _ => 0,
+ };
+ }
}
}
relative_from: Some("")
);
+ tc!("foo/.", "foo",
+ eq: true,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("")
+ );
+
+ tc!("foo/./bar", "foo/bar",
+ eq: true,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("")
+ );
+
tc!("foo/bar", "foo",
eq: false,
starts_with: true,
ends_with: true,
relative_from: Some("")
);
+
+ tc!(r"C:\foo\.\bar.txt", r"C:\foo\bar.txt",
+ eq: true,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("")
+ );
+
+ tc!(r"C:\foo\.", r"C:\foo",
+ eq: true,
+ starts_with: true,
+ ends_with: true,
+ relative_from: Some("")
+ );
+
+ tc!(r"\\?\C:\foo\.\bar.txt", r"\\?\C:\foo\bar.txt",
+ eq: false,
+ starts_with: false,
+ ends_with: false,
+ relative_from: None
+ );
}
}
libc::ENOSPC => StorageFull,
libc::ENOSYS => Unsupported,
libc::EMLINK => TooManyLinks,
- libc::ENAMETOOLONG => FilenameTooLong,
+ libc::ENAMETOOLONG => InvalidFilename,
libc::ENETDOWN => NetworkDown,
libc::ENETUNREACH => NetworkUnreachable,
libc::ENOTCONN => NotConnected,
c::ERROR_FILE_NOT_FOUND => return NotFound,
c::ERROR_PATH_NOT_FOUND => return NotFound,
c::ERROR_NO_DATA => return BrokenPipe,
+ c::ERROR_INVALID_NAME => return InvalidFilename,
c::ERROR_INVALID_PARAMETER => return InvalidInput,
c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory,
c::ERROR_SEM_TIMEOUT
c::ERROR_POSSIBLE_DEADLOCK => return Deadlock,
c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
- c::ERROR_FILENAME_EXCED_RANGE => return FilenameTooLong,
+ c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename,
_ => {}
}
#![cfg_attr(
any(
all(target_arch = "arm", any(target_os = "linux", target_os = "android")),
- all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")),
+ all(bootstrap, target_arch = "aarch64", any(target_os = "linux", target_os = "android")),
all(target_arch = "powerpc", target_os = "linux"),
all(target_arch = "powerpc64", target_os = "linux"),
- any(target_arch = "x86", target_arch = "x86_64"),
),
feature(stdsimd)
)]
println!("flagm: {}", is_aarch64_feature_detected!("flagm"));
println!("ssbs: {}", is_aarch64_feature_detected!("ssbs"));
println!("sb: {}", is_aarch64_feature_detected!("sb"));
- println!("pauth: {}", is_aarch64_feature_detected!("pauth"));
+ println!("paca: {}", is_aarch64_feature_detected!("paca"));
+ println!("pacg: {}", is_aarch64_feature_detected!("pacg"));
println!("dpb: {}", is_aarch64_feature_detected!("dpb"));
println!("dpb2: {}", is_aarch64_feature_detected!("dpb2"));
println!("sve2: {}", is_aarch64_feature_detected!("sve2"));
-Subproject commit eaee02ffdf5d820729ccdf2f95fa08b08c7d24d2
+Subproject commit 863d31b8e1314e15d124384e5eaa9ab21e12bd79
--- /dev/null
+// pp-exact
+// edition:2021
+
+#![allow(unused_imports)]
+
+use ::std::fmt::{self, Debug, Display, Write as _};
+
+use core::option::Option::*;
+
+use core::{
+ cmp::{Eq, Ord, PartialEq, PartialOrd},
+ convert::{AsMut, AsRef, From, Into},
+ iter::{
+ DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator,
+ IntoIterator, Iterator,
+ },
+ marker::{
+ Copy as Copy, Send as Send, Sized as Sized, Sync as Sync, Unpin as U,
+ },
+ ops::{*, Drop, Fn, FnMut, FnOnce},
+};
+
+fn main() {}
--- /dev/null
+// ignore-tidy-linelength
+
+// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items" 1
+// @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id"
+// @is - "$.index[*][?(@.name=='dyn')].inner.items[0]" $sync_int_gen
+
+// @is - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}'
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.kind" \"resolved_path\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" []
+// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.name" \"Fn\"
+// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[*]" 3
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[0].trait_bound.trait.inner.name" \"Send\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[1].trait_bound.trait.inner.name" \"Sync\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}'
+pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>;
--- /dev/null
+// ignore-tidy-linelength
+
+// @is fn_lifetime.json "$.index[*][?(@.name=='GenericFn')].kind" \"typedef\"
+
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*]" 1
+// @is - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].name" \"\'a\"
+// @has - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime"
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime.outlives[*]" 0
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.where_predicates[*]" 0
+// @is - "$.index[*][?(@.name=='GenericFn')].inner.type.kind" \"function_pointer\"
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.generic_params[*]" 0
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.inputs[*]" 1
+// @is - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.inputs[*][1].inner.lifetime" \"\'a\"
+// @is - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.output.inner.lifetime" \"\'a\"
+
+pub type GenericFn<'a> = fn(&'a i32) -> &'a i32;
+
+// @is fn_lifetime.json "$.index[*][?(@.name=='ForAll')].kind" \"typedef\"
+// @count - "$.index[*][?(@.name=='ForAll')].inner.generics.params[*]" 0
+// @count - "$.index[*][?(@.name=='ForAll')].inner.generics.where_predicates[*]" 0
+// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*]" 1
+// @is - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].name" \"\'a\"
+// @has - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].kind.lifetime"
+// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].kind.lifetime.outlives[*]" 0
+// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.inputs[*]" 1
+// @is - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.inputs[*][1].inner.lifetime" \"\'a\"
+// @is - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.output.inner.lifetime" \"\'a\"
+pub type ForAll = for<'a> fn(&'a i32) -> &'a i32;
--- /dev/null
+// ignore-tidy-linelength
+
+// @set result = generic_default.json "$.index[*][?(@.name=='Result')].id"
+pub enum Result<T, E> {
+ Ok(T),
+ Err(E),
+}
+
+// @set my_error = - "$.index[*][?(@.name=='MyError')].id"
+pub struct MyError {}
+
+// @is - "$.index[*][?(@.name=='MyResult')].kind" \"typedef\"
+// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.where_predicates[*]" 0
+// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[*]" 2
+// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].name" \"T\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].name" \"E\"
+// @has - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type"
+// @has - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type"
+// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type.bounds[*]" 0
+// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.bounds[*]" 0
+// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type.default" null
+// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.kind" \"resolved_path\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.inner.id" $my_error
+// @is - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.inner.name" \"MyError\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.kind" \"resolved_path\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.id" $result
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.name" \"Result\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.bindings" []
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"generic\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[1].type.kind" \"generic\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[0].type.inner" \"T\"
+// @is - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[1].type.inner" \"E\"
+pub type MyResult<T, E = MyError> = Result<T, E>;
--> $DIR/parse-error.rs:39:37
|
LL | let mut foo = 0;
- | ---------- help: consider using `const` instead of `let`: `const foo`
+ | ----------- help: consider using `const` instead of `let`: `const foo`
...
LL | asm!("{}", options(), const foo);
| ^^^ non-constant value
--> $DIR/parse-error.rs:48:44
|
LL | let mut foo = 0;
- | ---------- help: consider using `const` instead of `let`: `const foo`
+ | ----------- help: consider using `const` instead of `let`: `const foo`
...
LL | asm!("{}", clobber_abi("C"), const foo);
| ^^^ non-constant value
--> $DIR/parse-error.rs:55:31
|
LL | let mut foo = 0;
- | ---------- help: consider using `const` instead of `let`: `const foo`
+ | ----------- help: consider using `const` instead of `let`: `const foo`
...
LL | asm!("{a}", a = const foo, a = const bar);
| ^^^ non-constant value
--> $DIR/parse-error.rs:55:46
|
LL | let mut bar = 0;
- | ---------- help: consider using `const` instead of `let`: `const bar`
+ | ----------- help: consider using `const` instead of `let`: `const bar`
...
LL | asm!("{a}", a = const foo, a = const bar);
| ^^^ non-constant value
--> $DIR/parse-error.rs:62:45
|
LL | let mut bar = 0;
- | ---------- help: consider using `const` instead of `let`: `const bar`
+ | ----------- help: consider using `const` instead of `let`: `const bar`
...
LL | asm!("{a}", in("x0") foo, a = const bar);
| ^^^ non-constant value
--> $DIR/parse-error.rs:65:45
|
LL | let mut bar = 0;
- | ---------- help: consider using `const` instead of `let`: `const bar`
+ | ----------- help: consider using `const` instead of `let`: `const bar`
...
LL | asm!("{a}", in("x0") foo, a = const bar);
| ^^^ non-constant value
--> $DIR/parse-error.rs:68:41
|
LL | let mut bar = 0;
- | ---------- help: consider using `const` instead of `let`: `const bar`
+ | ----------- help: consider using `const` instead of `let`: `const bar`
...
LL | asm!("{1}", in("x0") foo, const bar);
| ^^^ non-constant value
--- /dev/null
+// compile-flags: --target armv7-unknown-linux-gnueabihf
+// needs-llvm-components: arm
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+#[lang = "sized"]
+trait Sized {}
+
+fn main() {
+ unsafe {
+ asm!("", out("d0") _, out("d1") _);
+ asm!("", out("d0") _, out("s1") _);
+ //~^ ERROR register `s1` conflicts with register `d0`
+ }
+}
--- /dev/null
+error: register `s1` conflicts with register `d0`
+ --> $DIR/reg-conflict.rs:17:31
+ |
+LL | asm!("", out("d0") _, out("s1") _);
+ | ----------- ^^^^^^^^^^^ register `s1`
+ | |
+ | register `d0`
+
+error: aborting due to previous error
+
--> $DIR/parse-error.rs:39:37
|
LL | let mut foo = 0;
- | ---------- help: consider using `const` instead of `let`: `const foo`
+ | ----------- help: consider using `const` instead of `let`: `const foo`
...
LL | asm!("{}", options(), const foo);
| ^^^ non-constant value
--> $DIR/parse-error.rs:50:44
|
LL | let mut foo = 0;
- | ---------- help: consider using `const` instead of `let`: `const foo`
+ | ----------- help: consider using `const` instead of `let`: `const foo`
...
LL | asm!("{}", clobber_abi("C"), const foo);
| ^^^ non-constant value
--> $DIR/parse-error.rs:57:31
|
LL | let mut foo = 0;
- | ---------- help: consider using `const` instead of `let`: `const foo`
+ | ----------- help: consider using `const` instead of `let`: `const foo`
...
LL | asm!("{a}", a = const foo, a = const bar);
| ^^^ non-constant value
--> $DIR/parse-error.rs:57:46
|
LL | let mut bar = 0;
- | ---------- help: consider using `const` instead of `let`: `const bar`
+ | ----------- help: consider using `const` instead of `let`: `const bar`
...
LL | asm!("{a}", a = const foo, a = const bar);
| ^^^ non-constant value
--> $DIR/parse-error.rs:64:46
|
LL | let mut bar = 0;
- | ---------- help: consider using `const` instead of `let`: `const bar`
+ | ----------- help: consider using `const` instead of `let`: `const bar`
...
LL | asm!("{a}", in("eax") foo, a = const bar);
| ^^^ non-constant value
--> $DIR/parse-error.rs:67:46
|
LL | let mut bar = 0;
- | ---------- help: consider using `const` instead of `let`: `const bar`
+ | ----------- help: consider using `const` instead of `let`: `const bar`
...
LL | asm!("{a}", in("eax") foo, a = const bar);
| ^^^ non-constant value
--> $DIR/parse-error.rs:70:42
|
LL | let mut bar = 0;
- | ---------- help: consider using `const` instead of `let`: `const bar`
+ | ----------- help: consider using `const` instead of `let`: `const bar`
...
LL | asm!("{1}", in("eax") foo, const bar);
| ^^^ non-constant value
--- /dev/null
+// check-pass
+
+pub trait Associate {
+ type Associated;
+}
+
+pub struct Wrap<'a> {
+ pub field: &'a i32,
+}
+
+pub trait Create<T> {
+ fn create() -> Self;
+}
+
+pub fn oh_no<'a, T>()
+where
+ Wrap<'a>: Associate,
+ <Wrap<'a> as Associate>::Associated: Create<T>,
+{
+ <Wrap<'a> as Associate>::Associated::create();
+}
+
+
+pub fn main() {}
--- /dev/null
+struct X<const N: usize = {
+ let s: &'static str; s.len()
+ //~^ ERROR borrow of possibly-uninitialized variable
+}>;
+
+fn main() {}
--- /dev/null
+error[E0381]: borrow of possibly-uninitialized variable: `s`
+ --> $DIR/const-generic-default-wont-borrowck.rs:2:26
+ |
+LL | let s: &'static str; s.len()
+ | ^^^^^^^ use of possibly-uninitialized `*s`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
//~^ ERROR mutable references
//~| ERROR calls in constant functions
//~| ERROR calls in constant functions
- //~| ERROR E0080
//~| ERROR `for` is not allowed in a `const fn`
sum += i;
}
LL | |
LL | |
LL | |
-... |
+LL | |
LL | | sum += i;
LL | | }
| |_____^
LL | for i in 0..x {
| ^^^^
-error[E0080]: evaluation of constant value failed
- --> $DIR/const-fn-error.rs:5:14
- |
-LL | for i in 0..x {
- | ^^^^
- | |
- | calling non-const function `<std::ops::Range<usize> as IntoIterator>::into_iter`
- | inside `f` at $DIR/const-fn-error.rs:5:14
-...
-LL | let a : [i32; f(X)];
- | ---- inside `main::{constant#0}` at $DIR/const-fn-error.rs:18:19
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0015, E0080, E0658.
+Some errors have detailed explanations: E0015, E0658.
For more information about an error, try `rustc --explain E0015`.
LL | const S: &'static mut str = &mut " hello ";
| ^^^^^^^^^^^^^^ cannot borrow as mutable
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/issue-76510.rs:5:1
- |
-LL | const S: &'static mut str = &mut " hello ";
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered mutable reference in a `const`
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- ╾─alloc3──╼ 07 00 00 00 │ ╾──╼....
- }
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0080, E0596, E0658, E0764.
-For more information about an error, try `rustc --explain E0080`.
+Some errors have detailed explanations: E0596, E0658, E0764.
+For more information about an error, try `rustc --explain E0596`.
LL | const S: &'static mut str = &mut " hello ";
| ^^^^^^^^^^^^^^ cannot borrow as mutable
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/issue-76510.rs:5:1
- |
-LL | const S: &'static mut str = &mut " hello ";
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered mutable reference in a `const`
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 16, align: 8) {
- ╾───────alloc3────────╼ 07 00 00 00 00 00 00 00 │ ╾──────╼........
- }
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0080, E0596, E0658, E0764.
-For more information about an error, try `rustc --explain E0080`.
+Some errors have detailed explanations: E0596, E0658, E0764.
+For more information about an error, try `rustc --explain E0596`.
//~^ ERROR: mutable references are not allowed in the final value of constants
//~| ERROR: mutation through a reference is not allowed in constants
//~| ERROR: cannot borrow data in a `&` reference as mutable
-//~| ERROR: it is undefined behavior to use this value
const fn trigger() -> [(); unsafe {
let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3));
-const FOO: *const u32 = { //~ ERROR encountered dangling pointer in final constant
+const FOO: *const u32 = {
let x;
&x //~ ERROR borrow of possibly-uninitialized variable: `x`
};
LL | &x
| ^^ use of possibly-uninitialized `x`
-error: encountered dangling pointer in final constant
- --> $DIR/issue-78655.rs:1:1
- |
-LL | / const FOO: *const u32 = {
-LL | | let x;
-LL | | &x
-LL | | };
- | |__^
-
error: could not evaluate constant pattern
--> $DIR/issue-78655.rs:7:9
|
LL | let FOO = FOO;
| ^^^
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0381`.
--- /dev/null
+// Regression test for issue #91560.
+
+// run-rustfix
+
+#![allow(unused,non_upper_case_globals)]
+
+fn foo() {
+ const length: usize = 2;
+ //~^ HELP: consider using `const`
+ let arr = [0; length];
+ //~^ ERROR: attempt to use a non-constant value in a constant [E0435]
+}
+
+fn bar() {
+ const length: usize = 2;
+ //~^ HELP: consider using `const`
+ let arr = [0; length];
+ //~^ ERROR: attempt to use a non-constant value in a constant [E0435]
+}
+
+fn main() {}
--- /dev/null
+// Regression test for issue #91560.
+
+// run-rustfix
+
+#![allow(unused,non_upper_case_globals)]
+
+fn foo() {
+ let mut length: usize = 2;
+ //~^ HELP: consider using `const`
+ let arr = [0; length];
+ //~^ ERROR: attempt to use a non-constant value in a constant [E0435]
+}
+
+fn bar() {
+ let length: usize = 2;
+ //~^ HELP: consider using `const`
+ let arr = [0; length];
+ //~^ ERROR: attempt to use a non-constant value in a constant [E0435]
+}
+
+fn main() {}
--- /dev/null
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/issue-91560.rs:10:19
+ |
+LL | let mut length: usize = 2;
+ | -------------- help: consider using `const` instead of `let`: `const length`
+LL |
+LL | let arr = [0; length];
+ | ^^^^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/issue-91560.rs:17:19
+ |
+LL | let length: usize = 2;
+ | ------------ help: consider using `const` instead of `let`: `const length`
+LL |
+LL | let arr = [0; length];
+ | ^^^^^^ non-constant value
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0435`.
--- /dev/null
+// check-fail
+
+// This should pass, but it requires `Sized` to be coinductive.
+
+#![feature(generic_associated_types)]
+
+trait Allocator {
+ type Allocated<T>;
+}
+
+enum LinkedList<A: Allocator> {
+ Head,
+ Next(A::Allocated<Self>)
+ //~^ overflow
+}
+
+fn main() {}
--- /dev/null
+error[E0275]: overflow evaluating the requirement `LinkedList<A>: Sized`
+ --> $DIR/issue-80626.rs:13:10
+ |
+LL | Next(A::Allocated<Self>)
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: no field of an enum variant may have a dynamically sized type
+ = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+ |
+LL | Next(&A::Allocated<Self>)
+ | +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | Next(Box<A::Allocated<Self>>)
+ | ++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
--- /dev/null
+// check-fail
+
+// This should pass, but seems to run into a TAIT issue.
+
+#![feature(generic_associated_types)]
+#![feature(type_alias_impl_trait)]
+
+pub trait Stream {
+ type Item;
+}
+
+impl Stream for () {
+ type Item = i32;
+}
+
+trait Yay<AdditionalValue> {
+ type InnerStream<'s>: Stream<Item = i32> + 's;
+ fn foo<'s>() -> Self::InnerStream<'s>;
+}
+
+impl<'a> Yay<&'a ()> for () {
+ type InnerStream<'s> = impl Stream<Item = i32> + 's;
+ //~^ the type
+ fn foo<'s>() -> Self::InnerStream<'s> { todo!() }
+}
+
+fn main() {}
--- /dev/null
+error[E0477]: the type `impl Stream<Item = i32>` does not fulfill the required lifetime
+ --> $DIR/issue-86218.rs:22:28
+ |
+LL | type InnerStream<'s> = impl Stream<Item = i32> + 's;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: type must outlive the lifetime `'s` as defined here as required by this binding
+ --> $DIR/issue-86218.rs:22:22
+ |
+LL | type InnerStream<'s> = impl Stream<Item = i32> + 's;
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0477`.
--- /dev/null
+// check-fail
+
+// This should pass, but we need an extension of implied bounds (probably).
+
+#![feature(generic_associated_types)]
+
+pub trait AsRef2 {
+ type Output<'a> where Self: 'a;
+
+ fn as_ref2<'a>(&'a self) -> Self::Output<'a>;
+}
+
+impl<T> AsRef2 for Vec<T> {
+ type Output<'a> where Self: 'a = &'a [T];
+
+ fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
+ &self[..]
+ }
+}
+
+#[derive(Debug)]
+struct Foo<T>(T);
+#[derive(Debug)]
+struct FooRef<'a, U>(&'a [U]);
+
+impl<'b, T, U> AsRef2 for Foo<T> //~ the type parameter
+where
+ // * `for<'b, 'c> T: AsRef2<Output<'b> = &'c [U]>>` does not work
+ //
+ // * `U` is unconstrained but should be allowed in this context because `Output` is
+ // an associated type
+ T: AsRef2<Output<'b> = &'b [U]>,
+ U: 'b
+{
+ type Output<'a> where Self: 'a = FooRef<'a, U>;
+
+ fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
+ FooRef(self.0.as_ref2())
+ }
+}
+
+fn main() {
+ let foo = Foo(vec![1, 2, 3]);
+ dbg!(foo.as_ref2());
+}
--- /dev/null
+error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
+ --> $DIR/issue-87735.rs:26:13
+ |
+LL | impl<'b, T, U> AsRef2 for Foo<T>
+ | ^ unconstrained type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
--- /dev/null
+// check-fail
+
+// This should pass, but unnormalized input args aren't treated as implied.
+
+#![feature(generic_associated_types)]
+
+trait MyTrait {
+ type Assoc<'a, 'b> where 'b: 'a;
+ fn do_sth(arg: Self::Assoc<'_, '_>);
+}
+
+struct Foo;
+
+impl MyTrait for Foo {
+ type Assoc<'a, 'b> where 'b: 'a = u32;
+
+ fn do_sth(_: u32) {} //~ lifetime bound
+ // fn do_sth(_: Self::Assoc<'static, 'static>) {}
+ // fn do_sth(_: Self::Assoc<'_, '_>) {}
+}
+
+fn main() {}
--- /dev/null
+error[E0478]: lifetime bound not satisfied
+ --> $DIR/issue-87748.rs:17:5
+ |
+LL | fn do_sth(_: u32) {}
+ | ^^^^^^^^^^^^^^^^^
+ |
+note: lifetime parameter instantiated with the anonymous lifetime #2 defined here
+ --> $DIR/issue-87748.rs:17:5
+ |
+LL | fn do_sth(_: u32) {}
+ | ^^^^^^^^^^^^^^^^^
+note: but lifetime parameter must outlive the anonymous lifetime #1 defined here
+ --> $DIR/issue-87748.rs:17:5
+ |
+LL | fn do_sth(_: u32) {}
+ | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0478`.
--- /dev/null
+// check-fail
+
+// This should pass.
+
+#![feature(generic_associated_types)]
+
+use std::fmt::Debug;
+
+trait Foo {
+ type Ass where Self::Ass: Debug;
+}
+
+#[derive(Debug)]
+struct Bar;
+
+impl Foo for Bar {
+ type Ass = Bar;
+ //~^ overflow
+}
+
+fn main() {}
--- /dev/null
+error[E0275]: overflow evaluating the requirement `<Bar as Foo>::Ass == _`
+ --> $DIR/issue-87755.rs:17:16
+ |
+LL | type Ass = Bar;
+ | ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
--- /dev/null
+// check-fail
+
+// This should pass, but using a type alias vs a reference directly
+// changes late-bound -> early-bound.
+
+#![feature(generic_associated_types)]
+
+trait Scanner {
+ type Input<'a>;
+ type Token<'a>;
+
+ fn scan<'a>(&mut self, i : Self::Input<'a>) -> Self::Token<'a>;
+}
+
+struct IdScanner();
+
+impl Scanner for IdScanner {
+ type Input<'a> = &'a str;
+ type Token<'a> = &'a str;
+
+ fn scan<'a>(&mut self, s : &'a str) -> &'a str { //~ lifetime parameters
+ s
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0195]: lifetime parameters or bounds on method `scan` do not match the trait declaration
+ --> $DIR/issue-87803.rs:21:12
+ |
+LL | fn scan<'a>(&mut self, i : Self::Input<'a>) -> Self::Token<'a>;
+ | ---- lifetimes in impl do not match this method in trait
+...
+LL | fn scan<'a>(&mut self, s : &'a str) -> &'a str {
+ | ^^^^ lifetimes do not match method in trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0195`.
--- /dev/null
+// check-fail
+
+// This should pass, but has a missed normalization due to HRTB.
+
+#![feature(generic_associated_types)]
+
+trait Iterable {
+ type Iterator<'a> where Self: 'a;
+ fn iter(&self) -> Self::Iterator<'_>;
+}
+
+struct SomeImplementation();
+
+impl Iterable for SomeImplementation {
+ type Iterator<'a> = std::iter::Empty<usize>;
+ fn iter(&self) -> Self::Iterator<'_> {
+ std::iter::empty()
+ }
+}
+
+fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) {
+ f(&mut i.iter());
+}
+
+fn main() {
+ do_something(SomeImplementation(), |_| ());
+ do_something(SomeImplementation(), test);
+ //~^ type mismatch
+}
+
+fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {}
--- /dev/null
+error[E0631]: type mismatch in function arguments
+ --> $DIR/issue-88382.rs:27:40
+ |
+LL | do_something(SomeImplementation(), test);
+ | ------------ ^^^^ expected signature of `for<'a> fn(&mut <SomeImplementation as Iterable>::Iterator<'a>) -> _`
+ | |
+ | required by a bound introduced by this call
+...
+LL | fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {}
+ | ------------------------------------------------- found signature of `for<'r> fn(&'r mut std::iter::Empty<usize>) -> _`
+ |
+note: required by a bound in `do_something`
+ --> $DIR/issue-88382.rs:21:56
+ |
+LL | fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `do_something`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0631`.
--- /dev/null
+// check-fail
+
+// This should pass, but has a missed normalization due to HRTB.
+
+#![feature(generic_associated_types)]
+
+pub trait Marker {}
+
+pub trait Trait {
+ type Assoc<'a>;
+}
+
+fn test<T>(value: T)
+where
+ T: Trait,
+ for<'a> T::Assoc<'a>: Marker,
+{
+}
+
+impl Marker for () {}
+
+struct Foo;
+
+impl Trait for Foo {
+ type Assoc<'a> = ();
+}
+
+fn main() {
+ test(Foo);
+ //~^ the trait bound
+}
--- /dev/null
+error[E0277]: the trait bound `for<'a> <_ as Trait>::Assoc<'a>: Marker` is not satisfied
+ --> $DIR/issue-88460.rs:29:5
+ |
+LL | test(Foo);
+ | ^^^^ the trait `for<'a> Marker` is not implemented for `<_ as Trait>::Assoc<'a>`
+ |
+note: required by a bound in `test`
+ --> $DIR/issue-88460.rs:16:27
+ |
+LL | fn test<T>(value: T)
+ | ---- required by a bound in this
+...
+LL | for<'a> T::Assoc<'a>: Marker,
+ | ^^^^^^ required by this bound in `test`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-fail
+
+// This should pass, but requires more logic.
+
+#![feature(generic_associated_types)]
+
+trait A {
+ type I<'a>;
+}
+
+pub struct TestA<F>
+{
+ f: F,
+}
+
+impl<F> A for TestA<F> {
+ type I<'a> = &'a F;
+}
+
+struct TestB<Q, F>
+{
+ q: Q,
+ f: F,
+}
+
+impl<'q, Q, I, F> A for TestB<Q, F> //~ the type parameter
+where
+ Q: A<I<'q> = &'q I>,
+ F: Fn(I),
+{
+ type I<'a> = ();
+}
+
+fn main() {}
--- /dev/null
+error[E0207]: the type parameter `I` is not constrained by the impl trait, self type, or predicates
+ --> $DIR/issue-88526.rs:26:13
+ |
+LL | impl<'q, Q, I, F> A for TestB<Q, F>
+ | ^ unconstrained type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
--- /dev/null
+// check-fail
+// edition:2021
+
+// This should pass, but seems to run into a TAIT bug.
+
+#![feature(type_alias_impl_trait)]
+#![feature(generic_associated_types)]
+
+use std::future::Future;
+
+trait Stream {
+ type Item;
+}
+
+struct Empty<T>(T);
+impl<T> Stream for Empty<T> {
+ type Item = ();
+}
+fn empty<T>() -> Empty<T> {
+ todo!()
+}
+
+trait X {
+ type LineStream<'a, Repr>: Stream<Item = Repr> where Self: 'a;
+
+ type LineStreamFut<'a,Repr>: Future<Output = Self::LineStream<'a, Repr>> where Self: 'a;
+
+ fn line_stream<'a,Repr>(&'a self) -> Self::LineStreamFut<'a,Repr>;
+}
+
+struct Y;
+
+impl X for Y {
+ type LineStream<'a, Repr> = impl Stream<Item = Repr>; //~ could not find
+
+ type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>> ;
+
+ fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> { //~ type mismatch
+ async {empty()}
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == impl Stream<Item = Repr>`
+ --> $DIR/issue-89008.rs:38:43
+ |
+LL | type LineStream<'a, Repr> = impl Stream<Item = Repr>;
+ | ------------------------ the expected opaque type
+...
+LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found struct `Empty`
+ |
+ = note: expected opaque type `impl Stream<Item = Repr>`
+ found struct `Empty<_>`
+
+error: could not find defining uses
+ --> $DIR/issue-89008.rs:34:33
+ |
+LL | type LineStream<'a, Repr> = impl Stream<Item = Repr>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
--- /dev/null
+// check-pass
+
+#![feature(generic_associated_types)]
+
+trait Foo<T> {
+ type Type<'a>
+ where
+ T: 'a;
+}
+
+impl<T> Foo<T> for () {
+ type Type<'a>
+ where
+ T: 'a,
+ = ();
+}
+
+fn foo<T>() {
+ let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+}
+
+pub fn main() {}
// run-pass
+// ignore-wasm32-bare FIXME(#93923) llvm miscompilation
use std::collections::HashMap;
use std::path::Path;
fn main() {
f<'a,>
//~^ ERROR expected
+ //~| ERROR expected
+}
+
+fn bar(a: usize, b: usize) -> usize {
+ a + b
+}
+
+fn foo() {
+ let x = 1;
+ bar('y, x);
+ //~^ ERROR expected
}
+error: expected `while`, `for`, `loop` or `{` after a label
+ --> $DIR/issue-93282.rs:2:9
+ |
+LL | f<'a,>
+ | ^ expected `while`, `for`, `loop` or `{` after a label
+
error: expected one of `.`, `:`, `;`, `?`, `for`, `loop`, `while`, `{`, `}`, or an operator, found `,`
--> $DIR/issue-93282.rs:2:9
|
LL | f::<'a,>
| ++
-error: aborting due to previous error
+error: expected `while`, `for`, `loop` or `{` after a label
+ --> $DIR/issue-93282.rs:13:11
+ |
+LL | bar('y, x);
+ | ^ expected `while`, `for`, `loop` or `{` after a label
+
+error: aborting due to 3 previous errors
let _ = f<'_, i8>();
//~^ ERROR expected one of
//~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+ //~| ERROR expected
f<'_>();
//~^ comparison operators cannot be chained
//~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+ //~| ERROR expected
let _ = f<u8>;
//~^ ERROR comparison operators cannot be chained
LL | let _ = f::<u8, i8>();
| ++
+error: expected `while`, `for`, `loop` or `{` after a label
+ --> $DIR/require-parens-for-chained-comparison.rs:22:17
+ |
+LL | let _ = f<'_, i8>();
+ | ^ expected `while`, `for`, `loop` or `{` after a label
+
error: expected one of `.`, `:`, `;`, `?`, `else`, `for`, `loop`, `while`, `{`, or an operator, found `,`
--> $DIR/require-parens-for-chained-comparison.rs:22:17
|
LL | let _ = f::<'_, i8>();
| ++
+error: expected `while`, `for`, `loop` or `{` after a label
+ --> $DIR/require-parens-for-chained-comparison.rs:27:9
+ |
+LL | f<'_>();
+ | ^ expected `while`, `for`, `loop` or `{` after a label
+
error: comparison operators cannot be chained
- --> $DIR/require-parens-for-chained-comparison.rs:26:6
+ --> $DIR/require-parens-for-chained-comparison.rs:27:6
|
LL | f<'_>();
| ^ ^
| ++
error: comparison operators cannot be chained
- --> $DIR/require-parens-for-chained-comparison.rs:30:14
+ --> $DIR/require-parens-for-chained-comparison.rs:32:14
|
LL | let _ = f<u8>;
| ^ ^
= help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
= help: or use `(...)` if you meant to specify fn arguments
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
--- /dev/null
+error: Target features paca, pacg must all be enabled or disabled together
+
+error: aborting due to previous error
+
--- /dev/null
+// only-aarch64
+// revisions: one two three four
+//[one] compile-flags: -C target-feature=+paca
+//[two] compile-flags: -C target-feature=-pacg,+pacg
+//[three] compile-flags: -C target-feature=+paca,+pacg,-paca
+//[four] check-pass
+//[four] compile-flags: -C target-feature=-paca,+pacg -C target-feature=+paca
+
+fn main() {}
--- /dev/null
+error: Target features paca, pacg must all be enabled or disabled together
+
+error: aborting due to previous error
+
--- /dev/null
+error: Target features paca, pacg must all be enabled or disabled together
+
+error: aborting due to previous error
+
--- /dev/null
+// only-aarch64
+// build-fail
+
+#![feature(aarch64_target_feature, target_feature_11)]
+
+fn main() {
+ #[target_feature(enable = "pacg")]
+ //~^ ERROR must all be either enabled or disabled together
+ unsafe fn inner() {}
+
+ unsafe {
+ foo();
+ bar();
+ baz();
+ inner();
+ }
+}
+
+#[target_feature(enable = "paca")]
+//~^ ERROR must all be either enabled or disabled together
+unsafe fn foo() {}
+
+
+#[target_feature(enable = "paca,pacg")]
+unsafe fn bar() {}
+
+#[target_feature(enable = "paca")]
+#[target_feature(enable = "pacg")]
+unsafe fn baz() {}
--- /dev/null
+error: the target features paca, pacg must all be either enabled or disabled together
+ --> $DIR/tied-features.rs:7:5
+ |
+LL | #[target_feature(enable = "pacg")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add the missing features in a `target_feature` attribute
+
+error: the target features paca, pacg must all be either enabled or disabled together
+ --> $DIR/tied-features.rs:19:1
+ |
+LL | #[target_feature(enable = "paca")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add the missing features in a `target_feature` attribute
+
+error: aborting due to 2 previous errors
+
Qux.clone();
//~^ ERROR no method named `clone` found for struct `Qux`
//~| NOTE method not found in `Qux`
- //~| NOTE `Clone` defines an item `clone`, but is explicitely unimplemented
+ //~| NOTE `Clone` defines an item `clone`, but is explicitly unimplemented
0_u32.bar();
//~^ ERROR no method named `bar` found for type `u32`
//~| NOTE method not found in `u32`
- //~| NOTE `Bar` defines an item `bar`, but is explicitely unimplemented
+ //~| NOTE `Bar` defines an item `bar`, but is explicitly unimplemented
Qux.foo();
//~^ ERROR no method named `foo` found for struct `Qux`
//~| NOTE method not found in `Qux`
- //~| NOTE the following traits define an item `foo`, but are explicitely unimplemented
+ //~| NOTE the following traits define an item `foo`, but are explicitly unimplemented
0_u32.foo();
//~^ ERROR no method named `foo` found for type `u32`
//~| NOTE method not found in `u32`
- //~| NOTE `FooBar` defines an item `foo`, but is explicitely unimplemented
+ //~| NOTE `FooBar` defines an item `foo`, but is explicitly unimplemented
}
| ^^^^^ method not found in `Qux`
|
= help: items from traits can only be used if the trait is implemented and in scope
- = note: the trait `Clone` defines an item `clone`, but is explicitely unimplemented
+ = note: the trait `Clone` defines an item `clone`, but is explicitly unimplemented
error[E0599]: no method named `bar` found for type `u32` in the current scope
--> $DIR/explicitly-unimplemented-error-message.rs:39:11
| ^^^ method not found in `u32`
|
= help: items from traits can only be used if the trait is implemented and in scope
- = note: the trait `Bar` defines an item `bar`, but is explicitely unimplemented
+ = note: the trait `Bar` defines an item `bar`, but is explicitly unimplemented
error[E0599]: no method named `foo` found for struct `Qux` in the current scope
--> $DIR/explicitly-unimplemented-error-message.rs:44:9
| ^^^ method not found in `Qux`
|
= help: items from traits can only be used if the trait is implemented and in scope
- = note: the following traits define an item `foo`, but are explicitely unimplemented:
+ = note: the following traits define an item `foo`, but are explicitly unimplemented:
Foo
FooBar
|
LL | trait Foo {
| ^^^^^^^^^
- = note: the trait `FooBar` defines an item `foo`, but is explicitely unimplemented
+ = note: the trait `FooBar` defines an item `foo`, but is explicitly unimplemented
error: aborting due to 4 previous errors
let val = cache.get_value(&command.args[0])?;
let results = select(&val, &command.args[1]).unwrap();
- results.len() == expected
+ let eq = results.len() == expected;
+ if !command.negated && !eq {
+ return Err(CkError::FailedCheck(
+ format!(
+ "`{}` matched to `{:?}` with length {}, but expected length {}",
+ &command.args[1],
+ results,
+ results.len(),
+ expected
+ ),
+ command,
+ ));
+ } else {
+ eq
+ }
}
CommandKind::Is => {
// @has <path> <jsonpath> <value> = check *exactly one* item matched by path, and it equals value
panic!("No variable: `{}`. Current state: `{:?}`", &s[1..], cache.variables)
}))
} else {
- Cow::Owned(serde_json::from_str(s).unwrap())
+ Cow::Owned(serde_json::from_str(s).expect(&format!("Cannot convert `{}` to json", s)))
}
}
fn walk(&mut self, dir: &Path, report: &mut Report) {
for entry in t!(dir.read_dir()).map(|e| t!(e)) {
let path = entry.path();
- let kind = t!(entry.file_type());
- if kind.is_dir() {
+ // Goes through symlinks
+ let metadata = t!(fs::metadata(&path));
+ if metadata.is_dir() {
self.walk(&path, report);
} else {
self.check(&path, report);
-Subproject commit a284d4f551ee12f7761128998efccdabebc4922f
+Subproject commit 0db40903769f38669936c5ebb0b882b18c27f449
//! Checks that all error codes have at least one test to prevent having error
//! codes that are silently not thrown by the compiler anymore.
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
use std::ffi::OsStr;
use std::fs::read_to_string;
use std::path::Path;
let mut found_explanations = 0;
let mut found_tests = 0;
let mut error_codes: HashMap<String, ErrorCodeStatus> = HashMap::new();
+ let mut explanations: HashSet<String> = HashSet::new();
// We want error codes which match the following cases:
//
// * foo(a, E0111, a)
for path in paths {
super::walk(path, &mut |path| super::filter_dirs(path), &mut |entry, contents| {
let file_name = entry.file_name();
+ let entry_path = entry.path();
+
if file_name == "error_codes.rs" {
extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors);
found_explanations += 1;
- } else if entry.path().extension() == Some(OsStr::new("stderr")) {
+ } else if entry_path.extension() == Some(OsStr::new("stderr")) {
extract_error_codes_from_tests(contents, &mut error_codes);
found_tests += 1;
- } else if entry.path().extension() == Some(OsStr::new("rs")) {
+ } else if entry_path.extension() == Some(OsStr::new("rs")) {
let path = entry.path().to_string_lossy();
if PATHS_TO_IGNORE_FOR_EXTRACTION.iter().all(|c| !path.contains(c)) {
extract_error_codes_from_source(contents, &mut error_codes, ®ex);
}
+ } else if entry_path
+ .parent()
+ .and_then(|p| p.file_name())
+ .map(|p| p == "error_codes")
+ .unwrap_or(false)
+ && entry_path.extension() == Some(OsStr::new("md"))
+ {
+ explanations.insert(file_name.to_str().unwrap().replace(".md", ""));
}
});
}
eprintln!("No error code was found in compilation errors!");
*bad = true;
}
+ if explanations.is_empty() {
+ eprintln!("No error code explanation was found!");
+ *bad = true;
+ }
if errors.is_empty() {
println!("Found {} error codes", error_codes.len());
}
}
}
+ if errors.is_empty() {
+ for explanation in explanations {
+ if !error_codes.contains_key(&explanation) {
+ errors.push(format!(
+ "{} error code explanation should be listed in `error_codes.rs`",
+ explanation
+ ));
+ }
+ }
+ }
errors.sort();
for err in &errors {
eprintln!("{}", err);
}
- println!("Found {} error codes with no tests", errors.len());
+ println!("Found {} error(s) in error codes", errors.len());
if !errors.is_empty() {
*bad = true;
}