Auto merge of #154985 - JonathanBrouwer:rollup-a467ECK, r=JonathanBrouwer

Rollup of 15 pull requests

Successful merges:

 - rust-lang/rust#153995 (Use convergent attribute to funcs for GPU targets)
 - rust-lang/rust#154184 (stabilize s390x vector registers)
 - rust-lang/rust#151898 (constify DoubleEndedIterator)
 - rust-lang/rust#154235 (remove unnecessary variables and delimiter check)
 - rust-lang/rust#154473 (move borrow checker tests)
 - rust-lang/rust#154745 (Replace span_look_ahead with span_followed_by)
 - rust-lang/rust#154778 (make field representing types invariant over the base type)
 - rust-lang/rust#154867 (Fix private fields diagnostics and improve error messages)
 - rust-lang/rust#154879 (Don't store `pattern_ty` in `TestableCase`)
 - rust-lang/rust#154910 (Suppress `unreachable_code` lint in `derive(PartialEq, Clone)`)
 - rust-lang/rust#154923 (Fix ICE in next-solver dyn-compatibility check)
 - rust-lang/rust#154934 (Add getters for `rustc_pattern_analysis::constructor::Slice` fields)
 - rust-lang/rust#154938 (match exhaustiveness: Show the guard exhaustivity note only when it's the guards alone that cause non-exhaustiveness)
 - rust-lang/rust#154961 (Use derived impl for `GappedRange` subdiagnostic)
 - rust-lang/rust#154980 (rustc-dev-guide subtree update)
This commit is contained in:
bors
2026-04-08 13:30:13 +00:00
112 changed files with 1129 additions and 985 deletions
@@ -129,23 +129,23 @@ fn get_substructure_equality_expr(
EnumMatching(.., fields) | Struct(.., fields) => {
let combine = move |acc, field| {
let rhs = get_field_equality_expr(cx, field);
if let Some(lhs) = acc {
match acc {
// Combine the previous comparison with the current field
// using logical AND.
return Some(cx.expr_binary(field.span, BinOpKind::And, lhs, rhs));
Some(lhs) => Some(cx.expr_binary(field.span, BinOpKind::And, lhs, rhs)),
// Start the chain with the first field's comparison.
None => Some(rhs),
}
// Start the chain with the first field's comparison.
Some(rhs)
};
// First compare scalar fields, then compound fields, combining all
// with logical AND.
return fields
fields
.iter()
.filter(|field| !field.maybe_scalar)
.fold(fields.iter().filter(|field| field.maybe_scalar).fold(None, combine), combine)
// If there are no fields, treat as always equal.
.unwrap_or_else(|| cx.expr_bool(span, true));
.unwrap_or_else(|| cx.expr_bool(span, true))
}
EnumDiscr(disc, match_expr) => {
let lhs = get_field_equality_expr(cx, disc);
@@ -154,7 +154,7 @@ fn get_substructure_equality_expr(
};
// Compare the discriminant first (cheaper), then the rest of the
// fields.
return cx.expr_binary(disc.span, BinOpKind::And, lhs, match_expr.clone());
cx.expr_binary(disc.span, BinOpKind::And, lhs, match_expr.clone())
}
StaticEnum(..) => cx.dcx().span_bug(
span,
@@ -136,6 +136,17 @@ fn create_wrapper_function(
None
};
if tcx.sess.target.is_like_gpu {
// Conservatively apply convergent to all functions in case they may call
// a convergent function. Rely on LLVM to optimize away the unnecessary
// convergent attributes.
attributes::apply_to_llfn(
llfn,
llvm::AttributePlace::Function,
&[llvm::AttributeKind::Convergent.create_attr(cx.llcx)],
);
}
let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) };
let mut bx = SBuilder::build(&cx, llbb);
+8 -1
View File
@@ -14,7 +14,7 @@
use std::borrow::Borrow;
use itertools::Itertools;
use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods;
use rustc_codegen_ssa::traits::{MiscCodegenMethods, TypeMembershipCodegenMethods};
use rustc_data_structures::fx::FxIndexSet;
use rustc_middle::ty::{Instance, Ty};
use rustc_sanitizers::{cfi, kcfi};
@@ -70,6 +70,13 @@ pub(crate) fn declare_raw_fn<'ll, 'tcx>(
let mut attrs = SmallVec::<[_; 4]>::new();
if cx.sess().target.is_like_gpu {
// Conservatively apply convergent to all functions in case they may call
// a convergent function. Rely on LLVM to optimize away the unnecessary
// convergent attributes.
attrs.push(llvm::AttributeKind::Convergent.create_attr(cx.llcx));
}
if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) {
attrs.push(llvm::AttributeKind::NoRedZone.create_attr(cx.llcx));
}
@@ -293,6 +293,7 @@ pub(crate) enum AttributeKind {
CapturesNone = 46,
SanitizeRealtimeNonblocking = 47,
SanitizeRealtimeBlocking = 48,
Convergent = 49,
}
/// LLVMIntPredicate
+20 -17
View File
@@ -2439,25 +2439,28 @@ fn report_private_fields(
})
.partition(|field| field.2);
err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field");
if !remaining_private_fields.is_empty() {
let names = if remaining_private_fields.len() > 6 {
String::new()
} else {
format!(
"{} ",
listify(&remaining_private_fields, |(name, _, _)| format!("`{name}`"))
.expect("expected at least one private field to report")
)
};
err.note(format!(
"{}private field{s} {names}that {were} not provided",
if used_fields.is_empty() { "" } else { "...and other " },
s = pluralize!(remaining_private_fields.len()),
were = pluralize!("was", remaining_private_fields.len()),
));
}
if let ty::Adt(def, _) = adt_ty.kind() {
if (def.did().is_local() || !used_fields.is_empty())
&& !remaining_private_fields.is_empty()
{
let names = if remaining_private_fields.len() > 6 {
String::new()
} else {
format!(
"{} ",
listify(&remaining_private_fields, |(name, _, _)| format!("`{name}`"))
.expect("expected at least one private field to report")
)
};
err.note(format!(
"{}private field{s} {names}that {were} not provided",
if used_fields.is_empty() { "" } else { "...and other " },
s = pluralize!(remaining_private_fields.len()),
were = pluralize!("was", remaining_private_fields.len()),
));
}
let def_id = def.did();
let mut items = self
.tcx
@@ -119,6 +119,12 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
_ => {}
}
// Don't emit the lint if we are in an impl marked as `#[automatically_derive]`.
// This is relevant for deriving `Clone` and `PartialEq` on types containing `!`.
if self.tcx.is_automatically_derived(self.tcx.parent(id.owner.def_id.into())) {
return;
}
// Don't warn twice.
self.diverges.set(Diverges::WarnedAlways);
@@ -365,6 +365,7 @@ enum class LLVMRustAttributeKind {
CapturesNone = 46,
SanitizeRealtimeNonblocking = 47,
SanitizeRealtimeBlocking = 48,
Convergent = 49,
};
static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
@@ -461,6 +462,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
return Attribute::SanitizeRealtime;
case LLVMRustAttributeKind::SanitizeRealtimeBlocking:
return Attribute::SanitizeRealtimeBlocking;
case LLVMRustAttributeKind::Convergent:
return Attribute::Convergent;
}
report_fatal_error("bad LLVMRustAttributeKind");
}
@@ -152,6 +152,7 @@ pub(super) fn for_pattern(
}
PatKind::Range(ref range) => {
assert_eq!(pattern.ty, range.ty);
if range.is_full_range(cx.tcx) == Some(true) {
None
} else {
@@ -380,7 +381,6 @@ pub(super) fn for_pattern(
place,
testable_case,
subpairs,
pattern_ty: pattern.ty,
pattern_span: pattern.span,
})
} else {
@@ -1277,7 +1277,7 @@ enum PatConstKind {
/// tested, and a test to perform on that place.
///
/// Each node also has a list of subpairs (possibly empty) that must also match,
/// and a reference to the THIR pattern it represents.
/// and some additional information from the THIR pattern it represents.
#[derive(Debug, Clone)]
pub(crate) struct MatchPairTree<'tcx> {
/// This place...
@@ -1301,9 +1301,7 @@ pub(crate) struct MatchPairTree<'tcx> {
/// that tests its field for the value `3`.
subpairs: Vec<Self>,
/// Type field of the pattern this node was created from.
pattern_ty: Ty<'tcx>,
/// Span field of the pattern this node was created from.
/// Span field of the THIR pattern this node was created from.
pattern_span: Span,
}
@@ -44,10 +44,7 @@ pub(super) fn pick_test_for_match_pair(
TestKind::ScalarEq { value }
}
TestableCase::Range(ref range) => {
assert_eq!(range.ty, match_pair.pattern_ty);
TestKind::Range(Arc::clone(range))
}
TestableCase::Range(ref range) => TestKind::Range(Arc::clone(range)),
TestableCase::Slice { len, op } => TestKind::SliceLen { len, op },
@@ -532,6 +532,18 @@ fn check_match(
| hir::MatchSource::AwaitDesugar
| hir::MatchSource::FormatArgs => None,
};
// Check if the match would be exhaustive if all guards were removed.
// If so, we leave a note that guards don't count towards exhaustivity.
let would_be_exhaustive_without_guards = {
let any_arm_has_guard = tarms.iter().any(|arm| arm.has_guard);
any_arm_has_guard && {
let guardless_arms: Vec<_> =
tarms.iter().map(|arm| MatchArm { has_guard: false, ..*arm }).collect();
rustc_pattern_analysis::rustc::analyze_match(&cx, &guardless_arms, scrut.ty)
.is_ok_and(|report| report.non_exhaustiveness_witnesses.is_empty())
}
};
self.error = Err(report_non_exhaustive_match(
&cx,
self.thir,
@@ -540,6 +552,7 @@ fn check_match(
witnesses,
arms,
braces_span,
would_be_exhaustive_without_guards,
));
}
}
@@ -1100,8 +1113,7 @@ fn report_arm_reachability<'p, 'tcx>(
let arm_span = cx.tcx.hir_span(hir_id);
let whole_arm_span = if is_match_arm {
// If the arm is followed by a comma, extend the span to include it.
let with_whitespace = sm.span_extend_while_whitespace(arm_span);
if let Some(comma) = sm.span_look_ahead(with_whitespace, ",", Some(1)) {
if let Some(comma) = sm.span_followed_by(arm_span, ",") {
Some(arm_span.to(comma))
} else {
Some(arm_span)
@@ -1154,6 +1166,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
witnesses: Vec<WitnessPat<'p, 'tcx>>,
arms: &[ArmId],
braces_span: Option<Span>,
would_be_exhaustive_without_guards: bool,
) -> ErrorGuaranteed {
let is_empty_match = arms.is_empty();
let non_empty_enum = match scrut_ty.kind() {
@@ -1364,8 +1377,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
},
);
let all_arms_have_guards = arms.iter().all(|arm_id| thir[*arm_id].guard.is_some());
if !is_empty_match && all_arms_have_guards {
if would_be_exhaustive_without_guards {
err.subdiagnostic(NonExhaustiveMatchAllArmsGuarded);
}
if let Some((span, sugg)) = suggestion {
+4 -7
View File
@@ -72,12 +72,11 @@ fn lex_token_tree_open_delim(
let close_spacing = if let Some(close_delim) = self.token.kind.close_delim() {
if close_delim == open_delim {
// Correct delimiter.
let (open_delimiter, open_delimiter_span) =
self.diag_info.open_delimiters.pop().unwrap();
self.diag_info.open_delimiters.pop().unwrap();
let close_delimiter_span = self.token.span;
if tts.is_empty() && close_delim == Delimiter::Brace {
let empty_block_span = open_delimiter_span.to(close_delimiter_span);
let empty_block_span = pre_span.to(close_delimiter_span);
if !sm.is_multiline(empty_block_span) {
// Only track if the block is in the form of `{}`, otherwise it is
// likely that it was written on purpose.
@@ -86,11 +85,9 @@ fn lex_token_tree_open_delim(
}
// only add braces
if let (Delimiter::Brace, Delimiter::Brace) = (open_delimiter, open_delim) {
if Delimiter::Brace == open_delim {
// Add all the matching spans, we will sort by span later
self.diag_info
.matching_block_spans
.push((open_delimiter_span, close_delimiter_span));
self.diag_info.matching_block_spans.push((pre_span, close_delimiter_span));
}
// Move past the closing delimiter.
@@ -495,6 +495,15 @@ fn is_covered_by(self, other: Self) -> bool {
other.kind.covers_length(self.arity())
}
// Getters. They are used by rust-analyzer.
pub fn array_len(self) -> Option<usize> {
self.array_len
}
pub fn kind(self) -> SliceKind {
self.kind
}
/// This computes constructor splitting for variable-length slices, as explained at the top of
/// the file.
///
+5 -14
View File
@@ -1,4 +1,3 @@
use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::Span;
@@ -99,25 +98,17 @@ pub struct ExclusiveRangeMissingGap {
pub gap_with: Vec<GappedRange>,
}
#[derive(Subdiagnostic)]
#[label(
"this could appear to continue range `{$first_range}`, but `{$gap}` isn't matched by either of them"
)]
pub struct GappedRange {
#[primary_span]
pub span: Span,
pub gap: String, // a printed pattern
pub first_range: String, // a printed pattern
}
impl Subdiagnostic for GappedRange {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let GappedRange { span, gap, first_range } = self;
// FIXME(mejrs) Use `#[subdiagnostic(eager)]` instead
let message = format!(
"this could appear to continue range `{first_range}`, but `{gap}` isn't matched by \
either of them"
);
diag.span_label(span, message);
}
}
#[derive(Diagnostic)]
#[diag("some variants are not matched explicitly")]
#[help("ensure that all variants are matched explicitly by adding the suggested match arms")]
+3 -5
View File
@@ -1467,11 +1467,9 @@ fn validate_res_from_ribs(
// `const name: Ty = expr;`. This is a heuristic, it will
// break down in the presence of macros.
let sm = self.tcx.sess.source_map();
let type_span = match sm.span_look_ahead(
original_rib_ident_def.span,
":",
None,
) {
let type_span = match sm
.span_followed_by(original_rib_ident_def.span, ":")
{
None => {
Some(original_rib_ident_def.span.shrink_to_hi())
}
+18 -4
View File
@@ -1989,10 +1989,25 @@ fn followed_by_brace(&self, span: Span) -> (bool, Option<Span>) {
// where a brace being opened means a block is being started. Look
// ahead for the next text to see if `span` is followed by a `{`.
let sm = self.r.tcx.sess.source_map();
if let Some(followed_brace_span) = sm.span_look_ahead(span, "{", Some(50)) {
if let Some(open_brace_span) = sm.span_followed_by(span, "{") {
// In case this could be a struct literal that needs to be surrounded
// by parentheses, find the appropriate span.
let close_brace_span = sm.span_look_ahead(followed_brace_span, "}", Some(50));
let close_brace_span =
sm.span_to_next_source(open_brace_span).ok().and_then(|next_source| {
// Find the matching `}` accounting for nested braces.
let mut depth: u32 = 1;
let offset = next_source.char_indices().find_map(|(i, c)| {
match c {
'{' => depth += 1,
'}' if depth == 1 => return Some(i),
'}' => depth -= 1,
_ => {}
}
None
})?;
let start = open_brace_span.hi() + rustc_span::BytePos(offset as u32);
Some(open_brace_span.with_lo(start).with_hi(start + rustc_span::BytePos(1)))
});
let closing_brace = close_brace_span.map(|sp| span.to(sp));
(true, closing_brace)
} else {
@@ -4110,8 +4125,7 @@ fn add_missing_lifetime_specifiers_label<'a>(
let sugg: String = std::iter::repeat_n(existing_name.as_str(), lt.count)
.intersperse(", ")
.collect();
let is_empty_brackets =
source_map.span_look_ahead(lt.span, ">", Some(50)).is_some();
let is_empty_brackets = source_map.span_followed_by(lt.span, ">").is_some();
let sugg = if is_empty_brackets { sugg } else { format!("{sugg}, ") };
(lt.span.shrink_to_hi(), sugg)
}
+7 -15
View File
@@ -964,21 +964,13 @@ pub fn next_point(&self, sp: Span) -> Span {
Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt, None)
}
/// Check whether span is followed by some specified expected string in limit scope
pub fn span_look_ahead(&self, span: Span, expect: &str, limit: Option<usize>) -> Option<Span> {
let mut sp = span;
for _ in 0..limit.unwrap_or(100_usize) {
sp = self.next_point(sp);
if let Ok(ref snippet) = self.span_to_snippet(sp) {
if snippet == expect {
return Some(sp);
}
if snippet.chars().any(|c| !c.is_whitespace()) {
break;
}
}
}
None
/// Check whether span is followed by some specified target string, ignoring whitespace.
/// *Only suitable for diagnostics.*
pub fn span_followed_by(&self, span: Span, target: &str) -> Option<Span> {
let span = self.span_extend_while_whitespace(span);
self.span_to_next_source(span).ok()?.strip_prefix(target).map(|_| {
Span::new(span.hi(), span.hi() + BytePos(target.len() as u32), span.ctxt(), None)
})
}
/// Finds the width of the character, either before or after the end of provided span,
@@ -752,6 +752,25 @@ fn test_next_point() {
assert!(sm.span_to_snippet(span).is_err());
}
#[test]
fn test_span_followed_by_stops_at_end_of_file() {
let sm = SourceMap::new(FilePathMapping::empty());
sm.new_source_file(filename(&sm, "example.rs"), "x".to_string());
let span = Span::with_root_ctxt(BytePos(0), BytePos(1));
assert_eq!(sm.span_followed_by(span, "y"), None);
}
#[test]
fn test_span_followed_by_skips_whitespace() {
let sm = SourceMap::new(FilePathMapping::empty());
sm.new_source_file(filename(&sm, "example.rs"), "x \n yz".to_string());
let span = Span::with_root_ctxt(BytePos(0), BytePos(1));
let span = sm.span_followed_by(span, "yz").unwrap();
assert_eq!(sm.span_to_snippet(span), Ok("yz".to_string()));
}
#[cfg(target_os = "linux")]
#[test]
fn read_binary_file_handles_lying_stat() {
+1 -1
View File
@@ -623,7 +623,7 @@ pub fn supported_types(
Self::Hexagon(r) => r.supported_types(arch),
Self::LoongArch(r) => r.supported_types(arch),
Self::Mips(r) => r.supported_types(arch),
Self::S390x(r) => r.supported_types(arch, allow_experimental_reg),
Self::S390x(r) => r.supported_types(arch),
Self::Sparc(r) => r.supported_types(arch),
Self::SpirV(r) => r.supported_types(arch),
Self::Wasm(r) => r.supported_types(arch),
+4 -12
View File
@@ -38,22 +38,14 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
pub fn supported_types(
self,
_arch: InlineAsmArch,
allow_experimental_reg: bool,
) -> &'static [(InlineAsmType, Option<Symbol>)] {
match self {
Self::reg | Self::reg_addr => types! { _: I8, I16, I32, I64; },
Self::freg => types! { _: F16, F32, F64; },
Self::vreg => {
if allow_experimental_reg {
// non-clobber-only vector register support is unstable.
types! {
vector: I32, F16, F32, I64, F64, I128, F128,
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2);
}
} else {
&[]
}
}
Self::vreg => types! {
vector: I32, F16, F32, I64, F64, I128, F128,
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2);
},
Self::areg => &[],
}
}
@@ -459,7 +459,7 @@ pub fn report_selection_error(
(cand.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind())
{
// Wrap method receivers and `&`-references in parens
let suggestion = if self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)).is_some() {
let suggestion = if self.tcx.sess.source_map().span_followed_by(span, ".").is_some() {
vec![
(span.shrink_to_lo(), format!("(")),
(span.shrink_to_hi(), format!(" as {})", cand.self_ty())),
@@ -603,6 +603,9 @@ fn receiver_for_self_ty<'tcx>(
/// contained by the trait object, because the object that needs to be coerced is behind
/// a pointer.
///
/// If lowering already produced an error in the receiver type, we conservatively treat it as
/// undispatchable instead of asking the solver.
///
/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result in
/// a new check that `Trait` is dyn-compatible, creating a cycle.
/// Instead, we emulate a placeholder by introducing a new type parameter `U` such that
@@ -630,6 +633,10 @@ fn receiver_is_dispatchable<'tcx>(
) -> bool {
debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
if receiver_ty.references_error() {
return false;
}
let (Some(unsize_did), Some(dispatch_from_dyn_did)) =
(tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait())
else {
+4 -1
View File
@@ -8,7 +8,10 @@
#[expect(missing_debug_implementations)]
#[fundamental]
pub struct FieldRepresentingType<T: ?Sized, const VARIANT: u32, const FIELD: u32> {
_phantom: PhantomData<T>,
// We want this type to be invariant over `T`, because otherwise `field_of!(Struct<'short>,
// field)` is a subtype of `field_of!(Struct<'long>, field)`. This subtype relationship does not
// have an immediately obvious meaning and we want to prevent people from relying on it.
_phantom: PhantomData<fn(T) -> T>,
}
// SAFETY: `FieldRepresentingType` doesn't contain any `T`
+10 -5
View File
@@ -1,3 +1,4 @@
use crate::marker::Destruct;
use crate::num::NonZero;
use crate::ops::{ControlFlow, Try};
@@ -38,7 +39,8 @@
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "DoubleEndedIterator"]
pub trait DoubleEndedIterator: Iterator {
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
pub const trait DoubleEndedIterator: [const] Iterator {
/// Removes and returns an element from the end of the iterator.
///
/// Returns `None` when there are no more elements.
@@ -135,6 +137,7 @@ pub trait DoubleEndedIterator: Iterator {
/// [`Err(k)`]: Err
#[inline]
#[unstable(feature = "iter_advance_by", issue = "77404")]
#[rustc_non_const_trait_method]
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
for i in 0..n {
if self.next_back().is_none() {
@@ -188,6 +191,7 @@ fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
/// ```
#[inline]
#[stable(feature = "iter_nth_back", since = "1.37.0")]
#[rustc_non_const_trait_method]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
if self.advance_back_by(n).is_err() {
return None;
@@ -230,8 +234,8 @@ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
F: [const] FnMut(B, Self::Item) -> R + [const] Destruct,
R: [const] Try<Output = B>,
{
let mut accum = init;
while let Some(x) = self.next_back() {
@@ -300,8 +304,8 @@ fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
#[stable(feature = "iter_rfold", since = "1.27.0")]
fn rfold<B, F>(mut self, init: B, mut f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
Self: Sized + [const] Destruct,
F: [const] FnMut(B, Self::Item) -> B + [const] Destruct,
{
let mut accum = init;
while let Some(x) = self.next_back() {
@@ -363,6 +367,7 @@ fn rfold<B, F>(mut self, init: B, mut f: F) -> B
/// ```
#[inline]
#[stable(feature = "iter_rfind", since = "1.27.0")]
#[rustc_non_const_trait_method]
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
where
Self: Sized,
@@ -12,6 +12,7 @@ jobs:
uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main
with:
github-app-id: ${{ vars.APP_CLIENT_ID }}
pr-author: "workflows-rustc-dev-guide[bot]"
zulip-stream-id: 196385
zulip-bot-email: "rustc-dev-guide-gha-notif-bot@rust-lang.zulipchat.com"
pr-base-branch: main
+1 -1
View File
@@ -1 +1 @@
562dee4820c458d823175268e41601d4c060588a
30d0309fa821f7a0984a9629e0d227ca3c0d2eda
+5 -3
View File
@@ -72,6 +72,7 @@
- [WASI](notification-groups/wasi.md)
- [WebAssembly](notification-groups/wasm.md)
- [Windows](notification-groups/windows.md)
- [GPU target](notification-groups/gpu-target.md)
- [Licenses](./licenses.md)
- [Editions](guides/editions.md)
@@ -100,9 +101,9 @@
- [Parallel compilation](./parallel-rustc.md)
- [Rustdoc internals](./rustdoc-internals.md)
- [Search](./rustdoc-internals/search.md)
- [The `rustdoc-html` test suite](./rustdoc-internals/rustdoc-html-test-suite.md)
- [The `rustdoc-gui` test suite](./rustdoc-internals/rustdoc-gui-test-suite.md)
- [The `rustdoc-json` test suite](./rustdoc-internals/rustdoc-json-test-suite.md)
- [The `rustdoc-html` test suite](./rustdoc-internals/rustdoc-html-test-suite.md)
- [The `rustdoc-gui` test suite](./rustdoc-internals/rustdoc-gui-test-suite.md)
- [The `rustdoc-json` test suite](./rustdoc-internals/rustdoc-json-test-suite.md)
- [GPU offload internals](./offload/internals.md)
- [Installation](./offload/installation.md)
- [Usage](./offload/usage.md)
@@ -189,6 +190,7 @@
- [Significant changes and quirks](./solve/significant-changes.md)
- [Sharing the trait solver with rust-analyzer](./solve/sharing-crates-with-rust-analyzer.md)
- [`Unsize` and `CoerceUnsized` traits](./traits/unsize.md)
- [Having separate `Trait` and `Projection` bounds](./traits/separate-projection-bounds.md)
- [Variance](./variance.md)
- [Coherence checking](./coherence.md)
- [HIR Type checking](./hir-typeck/summary.md)
@@ -1,15 +1,15 @@
# Code Index
rustc has a lot of important data structures. This is an attempt to give some
guidance on where to learn more about some of the key data structures of the
compiler.
rustc has a lot of important data structures.
This is an attempt to give some guidance on where to learn more
about some of the key data structures of the compiler.
Item | Kind | Short description | Chapter | Declaration
----------------|----------|-----------------------------|--------------------|-------------------
`BodyId` | struct | One of four types of HIR node identifiers | [Identifiers in the HIR] | [compiler/rustc_hir/src/hir.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.BodyId.html)
`Compiler` | struct | Represents a compiler session and can be used to drive a compilation. | [The Rustc Driver and Interface] | [compiler/rustc_interface/src/interface.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Compiler.html)
`ast::Crate` | struct | A syntax-level representation of a parsed crate | [The parser] | [compiler/rustc_ast/src/ast.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/struct.Crate.html)
`rustc_hir::Crate` | struct | A more abstract, compiler-friendly form of a crate's AST | [The Hir] | [compiler/rustc_hir/src/hir.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Crate.html)
`hir::Crate` | struct | A more abstract, compiler-friendly form of a crate's AST | [The Hir] | [compiler/rustc_middle/src/hir/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/struct.Crate.html)
`DefId` | struct | One of four types of HIR node identifiers | [Identifiers in the HIR] | [compiler/rustc_hir/src/def_id.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html)
`Diag` | struct | A struct for a compiler diagnostic, such as an error or lint | [Emitting Diagnostics] | [compiler/rustc_errors/src/diagnostic.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html)
`DocContext` | struct | A state container used by rustdoc when crawling through a crate to gather its documentation | [Rustdoc] | [src/librustdoc/core.rs](https://github.com/rust-lang/rust/blob/HEAD/src/librustdoc/core.rs)
@@ -1,17 +1,22 @@
# Glossary
Term | Meaning
------------------------------------------------------|--------
Term | Meaning
-----------------------------------------------|--------
<span id="1zst">1-ZST</span> | A *one-aligned [zero-sized type](#zst)*. A type of size zero with an [alignment][size-align] of one.
<span id="arena">arena, arena allocation</span> | An _arena_ is a large memory buffer from which other memory allocations are made. This style of allocation is called _arena allocation_. See [this chapter](../memory.md) for more info.
<span id="ast">AST</span> | The _abstract syntax tree_ produced by the `rustc_ast` crate; reflects user syntax very closely.
<span id="apit">APIT</span> | An argument-position `impl Trait`. Also known as an anonymous type parameter. ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#anonymous-type-parameters)).
<span id="binder">binder</span> | A _binder_ is a place where a variable or type is declared; for example, the `<T>` is a binder for the generic type parameter `T` in `fn foo<T>(..)`, and \|`a`\|` ...` is a binder for the parameter `a`. See [the background chapter for more](./background.md#free-vs-bound).
<span id="body-id">`BodyId`</span> | An identifier that refers to a specific body (definition of a function or constant) in the crate. See [the HIR chapter for more](../hir.md#identifiers-in-the-hir).
<span id="bound-var">bound variable</span> | A _bound variable_ is one that is declared within an expression/term. For example, the variable `a` is bound within the closure expression \|`a`\|` a * 2`. See [the background chapter for more](./background.md#free-vs-bound)
<span id="afidt">AFIDT</span> | Short for _async function in `dyn Trait`_. See also [AFIT](#afit).
<span id="afit">AFIT</span> | Short for _async function in trait_. They desugar to [RPITITs](#rpitit).
<span id="ast">AST</span> | The _abstract syntax tree_ (an [IR](#ir)) produced by the parser; reflects the surface / user syntax very closely.
<span id="apit">APIT</span> | Short for _argument-position `impl Trait`_. Also known as universial `impl Trait` (as opposed to existential) or anonymous type parameter. ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#anonymous-type-parameters)).
<span id="atpit">ATPIT</span> | Short for _associated-type-position `impl Trait`_. Also known as [ITIAT](#itiat).
<span id="binder">binder</span> | A _binder_ is a place where a variable or type is declared; for example, the `<T>` is a binder for the type parameter `T` in `fn foo<T>(..)`, `for<'a>` is a binder for the lifetime parameter `'a` and `\|a\| …` is a binder for the parameter `a`. See [the background chapter for more](./background.md#free-vs-bound).
<span id="body">body</span> | The definition of a function or constant that contains "executable code".
<span id="body-id">`BodyId`</span> | An identifier that refers to a specific [body](#body) in the crate. See [the HIR chapter for more](../hir.md#identifiers-in-the-hir).
<span id="bound-var">bound variable</span> | A _bound variable_ is one that is declared within an expression or term (in the general sense). For example, the variable `a` is bound within the closure expression `\|a\| a * 2` and lifetime variable `'a` is bound within the type expression `for<'a> fn(&'a str) -> bool`. See [the background chapter for more](./background.md#free-vs-bound)
<span id="codegen">codegen</span> | Short for _code generation_. The code to translate MIR into LLVM IR.
<span id="codegen-unit">codegen unit</span> | When we produce LLVM IR, we group the Rust code into a number of codegen units (sometimes abbreviated as CGUs). Each of these units is processed by LLVM independently from one another, enabling parallelism. They are also the unit of incremental re-use. ([see more](../backend/codegen.md))
<span id="completeness">completeness</span> | A technical term in type theory, it means that every type-safe program also type-checks. Having both soundness and completeness is very hard, and usually soundness is more important. (see "soundness").
<span id="cfg">control-flow graph</span> | A representation of the control-flow of a program; see [the background chapter for more](./background.md#cfg)
<span id="cfg">control-flow graph, CFG</span> | A representation of the control-flow of a program; see [the background chapter for more](./background.md#cfg)
<span id="ctfe">CTFE</span> | Short for _compile-time function evaluation_, this is the ability of the compiler to evaluate `const fn`s at compile time. This is part of the compiler's constant evaluation system. ([see more](../const-eval.md))
<span id="cx">`cx`</span> | We tend to use _cx_ as an abbreviation for _context_. See also `tcx`, `infcx`, etc.
<span id="ctxt">`ctxt`</span> | We also use _ctxt_ as an abbreviation for _context_, e.g. [`TyCtxt`](#TyCtxt). See also [cx](#cx) or [tcx](#tcx).
@@ -23,14 +28,18 @@ Term | Meaning
<span id="double-ptr">double pointer</span> | A pointer with additional metadata. See [fat pointer](#fat-ptr) for more.
<span id="drop-glue">drop glue</span> | (Internal) compiler-generated instructions that handle calling the destructors (`Drop`) for data types.
<span id="dst">DST</span> | Short for *dynamically-sized type*, this is a type for which the compiler cannot statically know the size in memory (e.g. `str` or `[u8]`). Such types don't implement `Sized` and cannot be allocated on the stack. They can only occur as the last field in a struct. They can only be used behind a pointer (e.g. `&str` or `&[u8]`).
<span id="ebl">early-bound lifetime</span> | A lifetime region that is substituted at its definition site. Bound in an item's `Generics` and substituted/instantiated using a `GenericArgs`. Contrast with **late-bound lifetime**. ([see more](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/region_kind/enum.RegionKind.html#bound-regions))
<span id="ebl">early-bound lifetime</span> | A lifetime / region that is substituted at its definition site. Bound in an item's `Generics` and substituted/instantiated using a `GenericArgs`. Contrast with **late-bound lifetime**. ([see more](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/region_kind/enum.RegionKind.html#bound-regions))
<span id="effect">effects</span> | Right now only means const traits and `~const` bounds. ([see more](../effects.md))
<span id="empty-type">empty type</span> | See [uninhabited type](#ut).
<span id="fat-ptr">fat pointer</span> | A two word value carrying the address of some value, along with some further information necessary to put the value to use. Rust includes two kinds of _fat pointers_: references to slices, and trait objects. A reference to a slice carries the starting address of the slice and its length. A trait object carries a value's address and a pointer to the trait's implementation appropriate to that value. "Fat pointers" are also known as "wide pointers", and "double pointers".
<span id="free-var">free variable</span> | A _free variable_ is one that is not bound within an expression or term; see [the background chapter for more](./background.md#free-vs-bound)
<span id="free-var">free variable</span> | A _free variable_ is one that is not bound within an expression or term (in the general sense); see [the background chapter for more](./background.md#free-vs-bound)
<span id="gac">GAC</span> | A _generic associated constant_, an associated constant with (own) generic parameters or a where-clause. Part of feature [`generic_const_items`] (GCI).
<span id="gat">GAT</span> | A _generic associated type_, an associated type that has (own) generic parameters or a where-clause. Introduced in [RFC 1598].
<span id="generics">generics</span> | The list of generic parameters defined on an item. There are three kinds of generic parameters: Type, lifetime and const parameters.
<span id="hir">HIR</span> | The _high-level [IR](#ir)_, created by lowering and desugaring the AST. ([see more](../hir.md))
<span id="hir">HIR</span> | The _high-level [IR](#ir)_, created by lowering / desugaring the AST. ([see more](../hir.md))
<span id="hir-id">`HirId`</span> | Identifies a particular node in the HIR by combining a def-id with an "intra-definition offset". See [the HIR chapter for more](../hir.md#identifiers-in-the-hir).
<span id="iac">IAC</span> | A (more often than not type-level) _inherent associated constant_, an associated constant in an inherent impl `impl Type { … }`. Often mentioned in the context of feature [`min_generic_const_items`] (mGCA, MGCA). An IGAC is an inherent [GAC](#gac).
<span id="iat">IAT</span> | An _inherent associated type_, an associated type defined in an inherent impl `impl Type { … }`. An IGAT is an inherent [GAT](#gat), a generic IAT.
<span id="ice">ICE</span> | Short for _internal compiler error_, this is when the compiler crashes.
<span id="ich">ICH</span> | Short for _incremental compilation hash_, these are used as fingerprints for things such as HIR and crate metadata, to check if changes have been made. This is useful in incremental compilation to see if part of a crate has changed and should be recompiled.
<span id="infcx">`infcx`</span> | The type inference context (`InferCtxt`). (see `rustc_middle::infer`)
@@ -41,12 +50,17 @@ Term | Meaning
<span id="ir">IR</span> | Short for _intermediate representation_, a general term in compilers. During compilation, the code is transformed from raw source (ASCII text) to various IRs. In Rust, these are primarily HIR, MIR, and LLVM IR. Each IR is well-suited for some set of computations. For example, MIR is well-suited for the borrow checker, and LLVM IR is well-suited for codegen because LLVM accepts it.
<span id="irlo">IRLO, irlo</span> | Sometimes used as an abbreviation for [internals.rust-lang.org](https://internals.rust-lang.org).
<span id="item">item</span> | A kind of "definition" in the language, such as a static, const, use statement, module, struct, etc. Concretely, this corresponds to the `Item` type.
<span id="item-sig">item signature</span> | The type signature / annotation / ascription of an item (e.g., struct, function). Often mentioned in the context of type inference since they are a place where we don't perform inference contrary to types in [bodies](#body).
<span id="itiat">ITIAT</span> | Short for _`impl Trait` in associated type_. Also known as [ATPIT](#atpit).
<span id="lang-item">lang item</span> | Items that represent concepts intrinsic to the language itself, such as special built-in traits like `Sync` and `Send`; or traits representing operations such as `Add`; or functions that are called by the compiler. ([see more](https://doc.rust-lang.org/1.9.0/book/lang-items.html))
<span id="lbl">late-bound lifetime</span> | A lifetime region that is substituted at its call site. Bound in a HRTB and substituted by specific functions in the compiler, such as `liberate_late_bound_regions`. Contrast with **early-bound lifetime**. ([see more](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/region_kind/enum.RegionKind.html#bound-regions))
<span id="lbl">late-bound lifetime</span> | A lifetime / region that is substituted at its call site. Bound in a HRTB and substituted by specific functions in the compiler, such as `liberate_late_bound_regions`. Contrast with **early-bound lifetime**. ([see more](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/region_kind/enum.RegionKind.html#bound-regions))
<span id="local-crate">local crate</span> | The crate currently being compiled. This is in contrast to "upstream crates" which refer to dependencies of the local crate.
<span id="lowering">lowering</span> | The act of converting a higher-level [IR](#ir) to a lower-level one. E.g., AST lowering (from [AST](#ast) to [HIR](#hir)) or HIR ty lowering (from HIR to [middle ty IR](#middle-ty-ir)).
<span id="lta">LTA</span> | A _lazy type alias_, a type alias that gets "properly" represented as an alias in the [middle ty IR](#middle-ty-ir); contrary to (eager) type aliases whose reference sites get expanded to the underlying aliased type (the RHS of the type alias after instantiation) during HIR ty lowering, its reference sites get [lowered](#lowering) to an [`AliasTy`].
<span id="lto">LTO</span> | Short for *link-time optimizations*, this is a set of optimizations offered by LLVM that occur just before the final binary is linked. These include optimizations like removing functions that are never used in the final program, for example. _ThinLTO_ is a variant of LTO that aims to be a bit more scalable and efficient, but possibly sacrifices some optimizations. You may also read issues in the Rust repo about "FatLTO", which is the loving nickname given to non-Thin LTO. LLVM documentation: [here][lto] and [here][thinlto].
<span id="llvm">[LLVM]</span> | (actually not an acronym :P) an open-source compiler backend. It accepts LLVM IR and outputs native binaries. Various languages (e.g. Rust) can then implement a compiler front-end that outputs LLVM IR and use LLVM to compile to all the platforms LLVM supports.
<span id="memoization">memoization</span> | The process of storing the results of (pure) computations (such as pure function calls) to avoid having to repeat them in the future. This is typically a trade-off between execution speed and memory usage.
<span id="middle-ty-ir">middle ty IR</span> | The collection of types defined in module [`rustc_middle::ty`] used by the type checker and the trait solver. They essentially form an [IR](#ir).
<span id="mir">MIR</span> | The _mid-level [IR](#ir)_ that is created after type-checking for use by borrowck and codegen. ([see more](../mir/index.md))
<span id="miri">Miri</span> | A tool to detect Undefined Behavior in (unsafe) Rust code. ([see more](https://github.com/rust-lang/miri))
<span id="mono">monomorphization</span> | The process of taking generic implementations of types and functions and instantiating them with concrete types. For example, in the code we might have `Vec<T>`, but in the final executable, we will have a copy of the `Vec` code for every concrete type used in the program (e.g. a copy for `Vec<usize>`, a copy for `Vec<MyStruct>`, etc).
@@ -66,39 +80,49 @@ Term | Meaning
<span id="recovery">recovery</span> | Recovery refers to handling invalid syntax during parsing (e.g. a missing comma) and continuing to parse the AST. This avoid showing spurious errors to the user (e.g. showing 'missing field' errors when the struct definition contains errors).
<span id="region">region</span> | Another term for "lifetime" often used in the literature and in the borrow checker.
<span id="rib">rib</span> | A data structure in the name resolver that keeps track of a single scope for names. ([see more](../name-resolution.md))
<span id="rpit">RPIT</span> | A return-position `impl Trait`. ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#abstract-return-types)).
<span id="rpitit">RPITIT</span> | A return-position `impl Trait` in trait. Unlike RPIT, this is desugared to a generic associated type (GAT). Introduced in [RFC 3425](https://rust-lang.github.io/rfcs/3425-return-position-impl-trait-in-traits.html). ([see more](../return-position-impl-trait-in-trait.md))
<span id="rustbuild">rustbuild</span> | A deprecated term for the part of bootstrap that is written in Rust
<span id="rpit">RPIT</span> | Short for _return-position `impl Trait`_. An existential `impl Trait` (as opposed to universial) like [TAITs](#tait) and [ATPIT](#atpit). ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#abstract-return-types)).
<span id="rpitit">RPITIT</span> | Short for _return-position `impl Trait` in trait_. Unlike [RPIT](#rpit), this is desugared to a generic associated type ([GAT](#gat)). Introduced in [RFC 3425]. ([see more](../return-position-impl-trait-in-trait.md))
<span id="rustbuild">rustbuild 👎</span> | A **deprecated** term for the part of bootstrap that is written in Rust
<span id="scrutinee">scrutinee</span> | A scrutinee is the expression that is matched on in `match` expressions and similar pattern matching constructs. For example, in `match x { A => 1, B => 2 }`, the expression `x` is the scrutinee.
<span id="sess">`sess`</span> | The compiler _session_, which stores global data used throughout compilation
<span id="side-tables">side tables</span> | Because the [AST](#ast) and HIR are immutable once created, we often carry extra information about them in the form of hashtables, indexed by the id of a particular node.
<span id="sigil">sigil</span> | Like a keyword but composed entirely of non-alphanumeric tokens. For example, `&` is a sigil for references.
<span id="soundness">soundness</span> | A technical term in type theory. Roughly, if a type system is sound, then a program that type-checks is type-safe. That is, one can never (in safe rust) force a value into a variable of the wrong type. (see "completeness").
<span id="span">span</span> | A location in the user's source code, used for error reporting primarily. These are like a file-name/line-number/column tuple on steroids: they carry a start/end point, and also track macro expansions and compiler desugaring. All while being packed into a few bytes (really, it's an index into a table). See the [`Span`] datatype for more.
<span id="subst">subst</span> | The act of _substituting_ the generic parameters inside of a type, constant expression, etc. with concrete generic arguments by supplying [substs](#substs). Nowadays referred to as _instantiating_ in the compiler.
<span id="substs">substs</span> | The _substitutions_ for a given generic item (e.g. the `i32`, `u32` in `HashMap<i32, u32>`). Nowadays referred to as the list of _generic arguments_ in the compiler (but note that strictly speaking these two concepts differ, see the literature).
<span id="subst">subst 👎</span> | The act of _substituting_ the generic parameters inside of a type, constant expression, etc. with concrete generic arguments by supplying [substs](#substs). Nowadays referred to as _instantiating_ in the compiler.
<span id="substs">substs 👎</span> | The _substitutions_ for a given generic item (e.g. the `i32`, `u32` in `HashMap<i32, u32>`). Nowadays referred to as the list of _generic arguments_ in the compiler (but note that strictly speaking these two concepts differ, see the literature).
<span id="sysroot">sysroot</span> | The directory for build artifacts that are loaded by the compiler at runtime. ([see more](../building/bootstrapping/what-bootstrapping-does.html#what-is-a-sysroot))
<span id="tag">tag</span> | The "tag" of an enum/generator encodes the [discriminant](#discriminant) of the active variant/state. Tags can either be "direct" (simply storing the discriminant in a field) or use a ["niche"](#niche).
<span id="tait">TAIT</span> | A type-alias `impl Trait`. Introduced in [RFC 2515](https://rust-lang.github.io/rfcs/2515-type_alias_impl_trait.html).
<span id="tait">TAIT</span> | Short for _type-alias `impl Trait`_. Introduced in [RFC 2515].
<span id="tcx">`tcx`</span> | Standard variable name for the "typing context" (`TyCtxt`), main data structure of the compiler. ([see more](../ty.md))
<span id="lifetime-tcx">`'tcx`</span> | The lifetime of the allocation arenas used by `TyCtxt`. Most data interned during a compilation session will use this lifetime with the exception of HIR data which uses the `'hir` lifetime. ([see more](../ty.md))
<span id="token">token</span> | The smallest unit of parsing. Tokens are produced after lexing ([see more](../the-parser.md)).
<span id="tls">[TLS]</span> | *Thread-local storage*. Variables may be defined so that each thread has its own copy (rather than all threads sharing the variable). This has some interactions with LLVM. Not all platforms support TLS.
<span id="tls">[TLS]</span> | _Thread-local storage_. Variables may be defined so that each thread has its own copy (rather than all threads sharing the variable). This has some interactions with LLVM. Not all platforms support TLS.
<span id="trait-ref">trait reference, trait ref </span> | The name of a trait along with a suitable list of generic arguments. ([see more](../traits/goals-and-clauses.md#trait-ref))
<span id="trans">trans</span> | Short for _translation_, the code to translate MIR into LLVM IR. Renamed to [codegen](#codegen).
<span id="trans">trans 👎</span> | Short for _translation_, the code to translate MIR into LLVM IR. **Renamed to** [codegen](#codegen).
<span id="ty">`Ty`</span> | The internal representation of a type. ([see more](../ty.md))
<span id="tyctxt">`TyCtxt`</span> | The data structure often referred to as [`tcx`](#tcx) in code which provides access to session data and the query system.
<span id="ufcs">UFCS</span> | Short for _universal function call syntax_, this is an unambiguous syntax for calling a method. **Term no longer in use!** Prefer _fully-qualified path/syntax_. ([see more](../hir-typeck/summary.md), [see the reference](https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls))
<span id="ufcs">UFCS 👎</span> | Short for _universal function call syntax_, this is an unambiguous syntax for calling a method. **Term no longer in use!** Prefer _fully-qualified path / syntax_. ([see more](../hir-typeck/summary.md), [see the reference](https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls))
<span id="ut">uninhabited type</span> | A type which has _no_ values. This is not the same as a ZST, which has exactly 1 value. An example of an uninhabited type is `enum Foo {}`, which has no variants, and so, can never be created. The compiler can treat code that deals with uninhabited types as dead code, since there is no such value to be manipulated. `!` (the never type) is an uninhabited type. Uninhabited types are also called _empty types_.
<span id="upvar">upvar</span> | A variable captured by a closure from outside the closure.
<span id="variance">variance</span> | Determines how changes to a generic parameter affect subtyping; for example, if `T` is a subtype of `U`, then `Vec<T>` is a subtype `Vec<U>` because `Vec` is _covariant_ in its generic parameter. See [the background chapter](./background.md#variance) for a more general explanation. See the [variance chapter](../variance.md) for an explanation of how type checking handles variance.
<span id="variant-idx">variant index</span> | In an enum, identifies a variant by assigning them indices starting at 0. This is purely internal and not to be confused with the ["discriminant"](#discriminant) which can be overwritten by the user (e.g. `enum Bool { True = 42, False = 0 }`).
<span id="wf">well-formedness</span> | Semantically: An expression that evaluates to meaningful result. In type systems: A type related construct which follows rules of the type system.
<span id="wf">well-formedness, wfness, wf</span> | Semantically: An expression that evaluates to meaningful result. In type systems: A type related construct which follows rules of the type system.
<span id="wide-ptr">wide pointer</span> | A pointer with additional metadata. See [fat pointer](#fat-ptr) for more.
<span id="zst">ZST</span> | *Zero-sized type*. A type whose values have size 0 bytes. Since `2^0 = 1`, such types can have exactly one value. For example, `()` (unit) is a ZST. `struct Foo;` is also a ZST. The compiler can do some nice optimizations around ZSTs.
See also <https://doc.rust-lang.org/reference/glossary.html#glossary>.
[LLVM]: https://llvm.org/
[lto]: https://llvm.org/docs/LinkTimeOptimization.html
[`Span`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
[thinlto]: https://clang.llvm.org/docs/ThinLTO.html
[RFC 1598]: https://rust-lang.github.io/rfcs/1598-generic_associated_types.html
[RFC 2515]: https://rust-lang.github.io/rfcs/2515-type_alias_impl_trait.html
[RFC 3425]: https://rust-lang.github.io/rfcs/3425-return-position-impl-trait-in-traits.html
[TLS]: https://llvm.org/docs/LangRef.html#thread-local-storage-models
[`AliasTy`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.AliasTy.html
[`Span`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
[`generic_const_items`]: https://github.com/rust-lang/rust/issues/113521
[`min_generic_const_items`]: https://github.com/rust-lang/rust/issues/132980
[`rustc_middle::ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/index.html
[lto]: https://llvm.org/docs/LinkTimeOptimization.html
[size-align]: https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment
[thinlto]: https://clang.llvm.org/docs/ThinLTO.html
@@ -1,8 +1,9 @@
# Interpreter
The interpreter is a virtual machine for executing MIR without compiling to
machine code. It is usually invoked via `tcx.const_eval_*` functions. The
interpreter is shared between the compiler (for compile-time function
machine code.
It is usually invoked via `tcx.const_eval_*` functions.
The interpreter is shared between the compiler (for compile-time function
evaluation, CTFE) and the tool [Miri](https://github.com/rust-lang/miri/), which
uses the same virtual machine to detect Undefined Behavior in (unsafe) Rust
code.
@@ -26,7 +27,8 @@ The compiler needs to figure out the length of the array before being able to
create items that use the type (locals, constants, function arguments, ...).
To obtain the (in this case empty) parameter environment, one can call
`let param_env = tcx.param_env(length_def_id);`. The `GlobalId` needed is
`let param_env = tcx.param_env(length_def_id);`.
The `GlobalId` needed is
```rust,ignore
let gid = GlobalId {
@@ -36,7 +38,8 @@ let gid = GlobalId {
```
Invoking `tcx.const_eval(param_env.and(gid))` will now trigger the creation of
the MIR of the array length expression. The MIR will look something like this:
the MIR of the array length expression.
The MIR will look something like this:
```mir
Foo::{{constant}}#0: usize = {
@@ -59,37 +62,45 @@ Before the evaluation, a virtual memory location (in this case essentially a
`vec![u8; 4]` or `vec![u8; 8]`) is created for storing the evaluation result.
At the start of the evaluation, `_0` and `_1` are
`Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef))`. This is quite
`Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef))`.
This is quite
a mouthful: [`Operand`] can represent either data stored somewhere in the
[interpreter memory](#memory) (`Operand::Indirect`), or (as an optimization)
immediate data stored in-line. And [`Immediate`] can either be a single
immediate data stored in-line.
And [`Immediate`] can either be a single
(potentially uninitialized) [scalar value][`Scalar`] (integer or thin pointer),
or a pair of two of them. In our case, the single scalar value is *not* (yet)
initialized.
or a pair of two of them.
In our case, the single scalar value is *not* (yet) initialized.
When the initialization of `_1` is invoked, the value of the `FOO` constant is
required, and triggers another call to `tcx.const_eval_*`, which will not be shown
here. If the evaluation of FOO is successful, `42` will be subtracted from its
here.
If the evaluation of FOO is successful, `42` will be subtracted from its
value `4096` and the result stored in `_1` as
`Operand::Immediate(Immediate::ScalarPair(Scalar::Raw { data: 4054, .. },
Scalar::Raw { data: 0, .. })`. The first part of the pair is the computed value,
the second part is a bool that's true if an overflow happened. A `Scalar::Raw`
Scalar::Raw { data: 0, .. })`.
The first part of the pair is the computed value,
the second part is a bool that's true if an overflow happened.
A `Scalar::Raw`
also stores the size (in bytes) of this scalar value; we are eliding that here.
The next statement asserts that said boolean is `0`. In case the assertion
The next statement asserts that said boolean is `0`.
In case the assertion
fails, its error message is used for reporting a compile-time error.
Since it does not fail, `Operand::Immediate(Immediate::Scalar(Scalar::Raw {
data: 4054, .. }))` is stored in the virtual memory it was allocated before the
evaluation. `_0` always refers to that location directly.
evaluation.
`_0` always refers to that location directly.
After the evaluation is done, the return value is converted from [`Operand`] to
[`ConstValue`] by [`op_to_const`]: the former representation is geared towards
what is needed *during* const evaluation, while [`ConstValue`] is shaped by the
needs of the remaining parts of the compiler that consume the results of const
evaluation. As part of this conversion, for types with scalar values, even if
evaluation.
As part of this conversion, for types with scalar values, even if
the resulting [`Operand`] is `Indirect`, it will return an immediate
`ConstValue::Scalar(computed_value)` (instead of the usual `ConstValue::ByRef`).
`ConstValue::Scalar(computed_value)` (instead of the usual `ConstValue::Indirect`).
This makes using the result much more efficient and also more convenient, as no
further queries need to be executed in order to get at something as simple as a
`usize`.
@@ -107,12 +118,13 @@ the interpreter, but just use the cached result.
The interpreter's outside-facing datastructures can be found in
[rustc_middle/src/mir/interpret](https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_middle/src/mir/interpret).
This is mainly the error enum and the [`ConstValue`] and [`Scalar`] types. A
`ConstValue` can be either `Scalar` (a single `Scalar`, i.e., integer or thin
This is mainly the error enum and the [`ConstValue`] and [`Scalar`] types.
A `ConstValue` can be either `Scalar` (a single `Scalar`, i.e., integer or thin
pointer), `Slice` (to represent byte slices and strings, as needed for pattern
matching) or `ByRef`, which is used for anything else and refers to a virtual
allocation. These allocations can be accessed via the methods on
`tcx.interpret_interner`. A `Scalar` is either some `Raw` integer or a pointer;
matching) or `Indirect`, which is used for anything else and refers to a virtual
allocation.
These allocations can be accessed via the methods on `tcx.interpret_interner`.
A `Scalar` is either some `Raw` integer or a pointer;
see [the next section](#memory) for more on that.
If you are expecting a numeric result, you can use `eval_usize` (panics on
@@ -122,29 +134,38 @@ in an `Option<u64>` yielding the `Scalar` if possible.
## Memory
To support any kind of pointers, the interpreter needs to have a "virtual memory" that the
pointers can point to. This is implemented in the [`Memory`] type. In the
simplest model, every global variable, stack variable and every dynamic
allocation corresponds to an [`Allocation`] in that memory. (Actually using an
pointers can point to.
This is implemented in the [`Memory`] type.
In the simplest model, every global variable, stack variable and every dynamic
allocation corresponds to an [`Allocation`] in that memory.
(Actually using an
allocation for every MIR stack variable would be very inefficient; that's why we
have `Operand::Immediate` for stack variables that are both small and never have
their address taken. But that is purely an optimization.)
their address taken.
But that is purely an optimization.)
Such an `Allocation` is basically just a sequence of `u8` storing the value of
each byte in this allocation. (Plus some extra data, see below.) Every
`Allocation` has a globally unique `AllocId` assigned in `Memory`. With that, a
each byte in this allocation.
(Plus some extra data, see below.) Every
`Allocation` has a globally unique `AllocId` assigned in `Memory`.
With that, a
[`Pointer`] consists of a pair of an `AllocId` (indicating the allocation) and
an offset into the allocation (indicating which byte of the allocation the
pointer points to). It may seem odd that a `Pointer` is not just an integer
pointer points to).
It may seem odd that a `Pointer` is not just an integer
address, but remember that during const evaluation, we cannot know at which
actual integer address the allocation will end up -- so we use `AllocId` as
symbolic base addresses, which means we need a separate offset. (As an aside,
symbolic base addresses, which means we need a separate offset.
(As an aside,
it turns out that pointers at run-time are
[more than just integers, too](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#pointer-provenance).)
These allocations exist so that references and raw pointers have something to
point to. There is no global linear heap in which things are allocated, but each
point to.
There is no global linear heap in which things are allocated, but each
allocation (be it for a local variable, a static or a (future) heap allocation)
gets its own little memory with exactly the required size. So if you have a
gets its own little memory with exactly the required size.
So if you have a
pointer to an allocation for a local variable `a`, there is no possible (no
matter how unsafe) operation that you can do that would ever change said pointer
to a pointer to a different local variable `b`.
@@ -152,31 +173,35 @@ Pointer arithmetic on `a` will only ever change its offset; the `AllocId` stays
This, however, causes a problem when we want to store a `Pointer` into an
`Allocation`: we cannot turn it into a sequence of `u8` of the right length!
`AllocId` and offset together are twice as big as a pointer "seems" to be. This
is what the `relocation` field of `Allocation` is for: the byte offset of the
`AllocId` and offset together are twice as big as a pointer "seems" to be.
This is what the `relocation` field of `Allocation` is for: the byte offset of the
`Pointer` gets stored as a bunch of `u8`, while its `AllocId` gets stored
out-of-band. The two are reassembled when the `Pointer` is read from memory.
out-of-band.
The two are reassembled when the `Pointer` is read from memory.
The other bit of extra data an `Allocation` needs is `undef_mask` for keeping
track of which of its bytes are initialized.
### Global memory and exotic allocations
`Memory` exists only during evaluation; it gets destroyed when the
final value of the constant is computed. In case that constant contains any
final value of the constant is computed.
In case that constant contains any
pointers, those get "interned" and moved to a global "const eval memory" that is
part of `TyCtxt`. These allocations stay around for the remaining computation
part of `TyCtxt`.
These allocations stay around for the remaining computation
and get serialized into the final output (so that dependent crates can use
them).
Moreover, to also support function pointers, the global memory in `TyCtxt` can
also contain "virtual allocations": instead of an `Allocation`, these contain an
`Instance`. That allows a `Pointer` to point to either normal data or a
`Instance`.
That allows a `Pointer` to point to either normal data or a
function, which is needed to be able to evaluate casts from function pointers to
raw pointers.
Finally, the [`GlobalAlloc`] type used in the global memory also contains a
variant `Static` that points to a particular `const` or `static` item. This is
needed to support circular statics, where we need to have a `Pointer` to a
variant `Static` that points to a particular `const` or `static` item.
This is needed to support circular statics, where we need to have a `Pointer` to a
`static` for which we cannot yet have an `Allocation` as we do not know the
bytes of its value.
@@ -188,17 +213,19 @@ bytes of its value.
### Pointer values vs Pointer types
One common cause of confusion in the interpreter is that being a pointer *value* and having
a pointer *type* are entirely independent properties. By "pointer value", we
a pointer *type* are entirely independent properties.
By "pointer value", we
refer to a `Scalar::Ptr` containing a `Pointer` and thus pointing somewhere into
the interpreter's virtual memory. This is in contrast to `Scalar::Raw`, which is just some
concrete integer.
the interpreter's virtual memory.
This is in contrast to `Scalar::Raw`, which is just some concrete integer.
However, a variable of pointer or reference *type*, such as `*const T` or `&T`,
does not have to have a pointer *value*: it could be obtained by casting or
transmuting an integer to a pointer.
transmuting an integer to a pointer.
And similarly, when casting or transmuting a reference to some
actual allocation to an integer, we end up with a pointer *value*
(`Scalar::Ptr`) at integer *type* (`usize`). This is a problem because we
(`Scalar::Ptr`) at integer *type* (`usize`).
This is a problem because we
cannot meaningfully perform integer operations such as division on pointer
values.
@@ -207,30 +234,33 @@ values.
Although the main entry point to constant evaluation is the `tcx.const_eval_*`
functions, there are additional functions in
[rustc_const_eval/src/const_eval](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_const_eval/index.html)
that allow accessing the fields of a `ConstValue` (`ByRef` or otherwise). You should
that allow accessing the fields of a `ConstValue` (`Indirect` or otherwise).
You should
never have to access an `Allocation` directly except for translating it to the
compilation target (at the moment just LLVM).
The interpreter starts by creating a virtual stack frame for the current constant that is
being evaluated. There's essentially no difference between a constant and a
being evaluated.
There's essentially no difference between a constant and a
function with no arguments, except that constants do not allow local (named)
variables at the time of writing this guide.
A stack frame is defined by the `Frame` type in
[rustc_const_eval/src/interpret/eval_context.rs](https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_const_eval/src/interpret/eval_context.rs)
and contains all the local
variables memory (`None` at the start of evaluation). Each frame refers to the
evaluation of either the root constant or subsequent calls to `const fn`. The
evaluation of another constant simply calls `tcx.const_eval_*`, which produce an
and contains all the local variables memory (`None` at the start of evaluation).
Each frame refers to the
evaluation of either the root constant or subsequent calls to `const fn`.
The evaluation of another constant simply calls `tcx.const_eval_*`, which produce an
entirely new and independent stack frame.
The frames are just a `Vec<Frame>`, there's no way to actually refer to a
`Frame`'s memory even if horrible shenanigans are done via unsafe code. The only
memory that can be referred to are `Allocation`s.
`Frame`'s memory even if horrible shenanigans are done via unsafe code.
The only memory that can be referred to are `Allocation`s.
The interpreter now calls the `step` method (in
[rustc_const_eval/src/interpret/step.rs](https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_const_eval/src/interpret/step.rs)
) until it either returns an error or has no further statements to execute. Each
statement will now initialize or modify the locals or the virtual memory
referred to by a local. This might require evaluating other constants or
) until it either returns an error or has no further statements to execute.
Each statement will now initialize or modify the locals or the virtual memory
referred to by a local.
This might require evaluating other constants or
statics, which just recursively invokes `tcx.const_eval_*`.
+2 -1
View File
@@ -953,7 +953,7 @@ You can match on the following names and values, using `name = "value"`:
Only `"MainFunctionType"` is supported.
- `from_desugaring`: Match against a particular variant of the `DesugaringKind` enum.
The desugaring is identified by its variant name, for example
`"QuestionMark"` for `?` desugaring or `"TryBlock"` for `try` blocks.
`"QuestionMark"` for `?` desugaring, or `"TryBlock"` for `try` blocks.
- `Self` and any generic arguments of the trait, like `Self = "alloc::string::String"`
or `Rhs="i32"`.
@@ -964,6 +964,7 @@ The compiler can provide several values to match on, for example:
- references to said slices and arrays.
- `"fn"`, `"unsafe fn"` or `"#[target_feature] fn"` when self is a function.
- `"{integer}"` and `"{float}"` if the type is a number but we haven't inferred it yet.
- `"{struct}"`, `"{enum}"` and `"{union}"` to match self as an ADT
- combinations of the above, like `"[{integral}; _]"`.
For example, the `Iterator` trait can be filtered in the following way:
@@ -20,7 +20,7 @@ which boils down to a static with type [`&rustc_lint_defs::Lint`]
as the macro is somewhat unwieldy to add new fields to,
like all macros).
we lint against direct declarations without the use of the macro.
We lint against direct declarations without the use of the macro.
Lint declarations don't carry any "state" - they are merely global identifiers
and descriptions of lints.
@@ -130,9 +130,9 @@ f(&String::new());
f(&String::new());
```
The lifetime parameter on `foo` being early bound requires all callers of `f` to provide a borrow with the same lifetime.
In this example, we call `foo`'s function item type twice, each time with a borrow of a temporary.
These two borrows could not possibly have lifetimes that overlap as the temporaries are only alive during the function call, not after.
The lifetime parameter on `foo` being early bound requires all callers of `f` to provide a borrow with the same lifetime, as this is not possible the borrow checker errors.
These two borrows could not possibly have lifetimes that overlap as the temporaries are only alive during the function call, not after, so we get a compilation error.
If the lifetime parameter on `foo` was late bound, this would be able to compile as each caller could provide a different lifetime argument for its borrow.
See the following example, which demonstrates this using the `bar` function defined above:
+34 -23
View File
@@ -1,13 +1,15 @@
# The HIR
The HIR "High-Level Intermediate Representation" is the primary IR used
in most of rustc. It is a compiler-friendly representation of the abstract
in most of rustc.
It is a compiler-friendly representation of the abstract
syntax tree (AST) that is generated after parsing, macro expansion, and name
resolution (see [Lowering](./hir/lowering.md) for how the HIR is created).
Many parts of HIR resemble Rust surface syntax quite closely, with
the exception that some of Rust's expression forms have been desugared away.
For example, `for` loops are converted into a `loop` and do not appear in
the HIR. This makes HIR more amenable to analysis than a normal AST.
the HIR.
This makes HIR more amenable to analysis than a normal AST.
This chapter covers the main concepts of the HIR.
@@ -30,17 +32,18 @@ cargo rustc -- -Z unpretty=hir
The top-level data-structure in the HIR is the [`Crate`], which stores
the contents of the crate currently being compiled (we only ever
construct HIR for the current crate). Whereas in the AST the crate
construct HIR for the current crate).
Whereas in the AST the crate
data structure basically just contains the root module, the HIR
`Crate` structure contains a number of maps and other things that
serve to organize the content of the crate for easier access.
[`Crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Crate.html
[`Crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/struct.Crate.html
For example, the contents of individual items (e.g. modules,
functions, traits, impls, etc) in the HIR are not immediately
accessible in the parents. So, for example, if there is a module item
`foo` containing a function `bar()`:
accessible in the parents.
So, for example, if there is a module item `foo` containing a function `bar()`:
```rust
mod foo {
@@ -49,8 +52,8 @@ mod foo {
```
then in the HIR the representation of module `foo` (the [`Mod`]
struct) would only have the **`ItemId`** `I` of `bar()`. To get the
details of the function `bar()`, we would lookup `I` in the
struct) would only have the **`ItemId`** `I` of `bar()`.
To get the details of the function `bar()`, we would lookup `I` in the
`items` map.
[`Mod`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Mod.html
@@ -62,9 +65,11 @@ There are similar maps for things like trait items and impl items,
as well as "bodies" (explained below).
The other reason to set up the representation this way is for better
integration with incremental compilation. This way, if you gain access
integration with incremental compilation.
This way, if you gain access
to an [`&rustc_hir::Item`] (e.g. for the mod `foo`), you do not immediately
gain access to the contents of the function `bar()`. Instead, you only
gain access to the contents of the function `bar()`.
Instead, you only
gain access to the **id** for `bar()`, and you must invoke some
function to lookup the contents of `bar()` given its id; this gives
the compiler a chance to observe that you accessed the data for
@@ -79,23 +84,27 @@ the compiler a chance to observe that you accessed the data for
The HIR uses a bunch of different identifiers that coexist and serve different purposes.
- A [`DefId`], as the name suggests, identifies a particular definition, or top-level
item, in a given crate. It is composed of two parts: a [`CrateNum`] which identifies
item, in a given crate.
It is composed of two parts: a [`CrateNum`] which identifies
the crate the definition comes from, and a [`DefIndex`] which identifies the definition
within the crate. Unlike [`HirId`]s, there isn't a [`DefId`] for every expression, which
within the crate.
Unlike [`HirId`]s, there isn't a [`DefId`] for every expression, which
makes them more stable across compilations.
- A [`LocalDefId`] is basically a [`DefId`] that is known to come from the current crate.
This allows us to drop the [`CrateNum`] part, and use the type system to ensure that
only local definitions are passed to functions that expect a local definition.
- A [`HirId`] uniquely identifies a node in the HIR of the current crate. It is composed
of two parts: an `owner` and a `local_id` that is unique within the `owner`. This
combination makes for more stable values which are helpful for incremental compilation.
- A [`HirId`] uniquely identifies a node in the HIR of the current crate.
It is composed of two parts:
an `owner` and a `local_id` that is unique within the `owner`.
This combination makes for more stable values which are helpful for incremental compilation.
Unlike [`DefId`]s, a [`HirId`] can refer to [fine-grained entities][Node] like expressions,
but stays local to the current crate.
- A [`BodyId`] identifies a HIR [`Body`] in the current crate. It is currently only
a wrapper around a [`HirId`]. For more info about HIR bodies, please refer to the
- A [`BodyId`] identifies a HIR [`Body`] in the current crate.
It is currently only a wrapper around a [`HirId`].
For more info about HIR bodies, please refer to the
[HIR chapter][hir-bodies].
These identifiers can be converted into one another through the `TyCtxt`.
@@ -112,8 +121,8 @@ These identifiers can be converted into one another through the `TyCtxt`.
## HIR Operations
Most of the time when you are working with the HIR, you will do so via
`TyCtxt`. It contains a number of methods, defined in the `hir::map` module and
Most of the time when you are working with the HIR, you will do so via `TyCtxt`.
It contains a number of methods, defined in the `hir::map` module and
mostly prefixed with `hir_`, to convert between IDs of various kinds and to
lookup data associated with a HIR node.
@@ -126,8 +135,10 @@ You need a `LocalDefId`, rather than a `DefId`, since only local items have HIR
[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.local_def_id_to_hir_id
Similarly, you can use [`tcx.hir_node(n)`][hir_node] to lookup the node for a
[`HirId`]. This returns a `Option<Node<'hir>>`, where [`Node`] is an enum
defined in the map. By matching on this, you can find out what sort of
[`HirId`].
This returns a `Option<Node<'hir>>`, where [`Node`] is an enum
defined in the map.
By matching on this, you can find out what sort of
node the `HirId` referred to and also get a pointer to the data
itself. Often, you know what sort of node `n` is e.g. if you know
that `n` must be some HIR expression, you can do
@@ -148,8 +159,8 @@ calls like [`tcx.parent_hir_node(n)`][parent_hir_node].
## HIR Bodies
A [`rustc_hir::Body`] represents some kind of executable code, such as the body
of a function/closure or the definition of a constant. Bodies are
associated with an **owner**, which is typically some kind of item
of a function/closure or the definition of a constant.
Bodies are associated with an **owner**, which is typically some kind of item
(e.g. an `fn()` or `const`), but could also be a closure expression
(e.g. `|x, y| x + y`). You can use the `TyCtxt` to find the body
associated with a given def-id ([`hir_maybe_body_owned_by`]) or to find
+28 -1
View File
@@ -15,8 +15,26 @@ of such structures include but are not limited to
* Existential `impl Trait`
* Converted to a virtual `existential type` declaration
The implementation of AST lowering is in the [`rustc_ast_lowering`] crate.
The entry point is [`lower_to_hir`], which retrieves the post-expansion AST
and resolver data from [`TyCtxt`] and builds the [`hir::Crate`] for the whole crate.
Lowering is organized around HIR owners. [`lower_to_hir`] first indexes the
crate and then [`ItemLowerer::lower_node`] lowers each crate, item, associated
item, and foreign item.
Most of the lowering logic lives on [`LoweringContext`]. The implementation is
split across multiple files in the [`rustc_ast_lowering`] crate such as `item.rs`,
`expr.rs`, `pat.rs`, `path.rs`, and others, but they all share the same [`LoweringContext`]
state and IDlowering machinery.
Each owner is lowered in its own [`with_hir_id_owner`] scope. This is why the
`HirId` invariants below matter: `lower_node_id` maps AST `NodeId`s into the
current owner, while `next_id` creates fresh HIR-only nodes introduced during
desugaring.
Lowering needs to uphold several invariants in order to not trigger the
sanity checks in `compiler/rustc_passes/src/hir_id_validator.rs`:
sanity checks in [`compiler/rustc_passes/src/hir_id_validator.rs`][hir_id_validator]:
1. A `HirId` must be used if created. So if you use the `lower_node_id`,
you *must* use the resulting `NodeId` or `HirId` (either is fine, since
@@ -33,6 +51,15 @@ sanity checks in `compiler/rustc_passes/src/hir_id_validator.rs`:
which produces both a new `NodeId` as well as automatically lowering it
for you so you also get the `HirId`.
[`rustc_ast_lowering`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/index.html
[`lower_to_hir`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/fn.lower_to_hir.html
[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html
[`hir::Crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Crate.html
[`ItemLowerer::lower_node`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/item/struct.ItemLowerer.html
[`LoweringContext`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/struct.LoweringContext.html
[`with_hir_id_owner`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/struct.LoweringContext.html#method.with_hir_id_owner
[hir_id_validator]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_passes/src/hir_id_validator.rs
If you are creating new `DefId`s, since each `DefId` needs to have a
corresponding `NodeId`, it is advisable to add these `NodeId`s to the
`AST` so you don't have to generate new ones during lowering. This has
@@ -28,6 +28,7 @@ Here's the list of the notification groups:
- [WebAssembly](./wasm.md)
- [Windows](./windows.md)
- [Rust for Linux](./rust-for-linux.md)
- [GPU target](./gpu-target.md)
## What issues are a good fit for notification groups?
@@ -0,0 +1,18 @@
# GPU target notification group
**Github Label:** None <br>
**Ping command:** `@rustbot ping gpu-target`
This notification group deals with linker related issues and their integration
within the compiler.
The group also has an associated Zulip stream ([`#t-compiler/linker`])
where people can go to ask questions and discuss GPU-related topics and issues.
if you're interested in participating, feel free to sign up for this group! To
do so, open a PR against the [rust-lang/team] repository and add your GitHub
user to [this file][gpu-target-team].
[`#t-compiler/linker`]: https://rust-lang.zulipchat.com/#narrow/channel/585172-t-compiler.2Flinker
[rust-lang/team]: https://github.com/rust-lang/team
[gpu-target-team]: https://github.com/rust-lang/team/blob/main/teams/gpu-target.toml
@@ -7,7 +7,7 @@ otherwise be printed to stderr.
To get diagnostics from the compiler,
configure [`rustc_interface::Config`] to output diagnostic to a buffer,
and run [`rustc_hir_typeck::typeck`] for each item.
and run [`TyCtxtEnsureOk::typeck`] for each item.
```rust
{{#include ../../examples/rustc-interface-getting-diagnostics.rs}}
@@ -15,5 +15,4 @@ and run [`rustc_hir_typeck::typeck`] for each item.
[`rustc_interface`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/index.html
[`rustc_interface::Config`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Config.html
[`TyCtxt.analysis`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/passes/fn.analysis.html
[`rustc_hir_typeck::typeck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn.typeck.html
[`TyCtxtEnsureOk::typeck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.TyCtxtEnsureOk.html#method.typeck
@@ -48,7 +48,7 @@ The "entry point" to this module is
The first step in [`clean::utils::krate`][ck1] is to invoke
[`visit_ast::RustdocVisitor`] to process the module tree into an intermediate [`visit_ast::Module`].
This is the step that actually crawls the
[`rustc_hir::Crate`], normalizing various aspects of name resolution, such as:
[`rustc_middle::hir::Crate`], normalizing various aspects of name resolution, such as:
* handling `#[doc(inline)]` and `#[doc(no_inline)]`
* handling import globs and cycles, so there are no duplicates or infinite
@@ -79,7 +79,7 @@ which describe the publicly-documentable items in the target crate.
[`core.rs`]: https://github.com/rust-lang/rust/blob/HEAD/src/librustdoc/core.rs
[`Item`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/clean/types/struct.Item.html
[`run_global_ctxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/core/fn.run_global_ctxt.html
[`rustc_hir::Crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Crate.html
[`rustc_middle::hir::Crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/struct.Crate.html
[`rustdoc::core::DocContext`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/core/struct.DocContext.html
[`rustdoc::core::run_global_ctxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/core/fn.run_global_ctxt.html
[`visit_ast::Module`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/visit_ast/struct.Module.html
@@ -108,19 +108,20 @@ Here is the list of passes as of <!-- date-check --> March 2023:
- `calculate-doc-coverage` calculates information used for the `--show-coverage`
flag.
- `check-doc-test-visibility` runs `doctest` visibilityrelated `lint`s. This pass
runs before `strip-private`, which is why it needs to be separate from `run-lints`.
- `check-doc-test-visibility` runs `doctest` visibilityrelated `lint`s.
This pass runs before `strip-private`,
which is why it needs to be separate from `run-lints`.
- `collect-intra-doc-links` resolves [intra-doc links](https://doc.rust-lang.org/nightly/rustdoc/write-documentation/linking-to-items-by-name.html).
- `collect-trait-impls` collects `trait` `impl`s for each item in the crate. For
example, if we define a `struct` that implements a `trait`, this pass will note
that the `struct` implements that `trait`.
- `collect-trait-impls` collects `trait` `impl`s for each item in the crate.
For example, if we define a `struct` that implements a `trait`,
this pass will note that the `struct` implements that `trait`.
- `propagate-doc-cfg` propagates `#[doc(cfg(...))]` to child items.
- `run-lints` runs some of `rustdoc`'s `lint`s, defined in `passes/lint`. This is
the last pass to run.
- `run-lints` runs some of `rustdoc`'s `lint`s, defined in `passes/lint`.
This is the last pass to run.
- `bare_urls` detects links that are not linkified, e.g., in Markdown such as
`Go to https://example.com/.` It suggests wrapping the link with angle brackets:
@@ -233,7 +234,8 @@ is complicated from two other constraints that `rustdoc` runs under:
configurations, such as `libstd` having a single package of docs that
cover all supported operating systems.
This means `rustdoc` has to be able to generate docs from `HIR`.
* Docs can inline across crates. Since crate metadata doesn't contain `HIR`,
* Docs can inline across crates.
Since crate metadata doesn't contain `HIR`,
it must be possible to generate inlined docs from the `rustc_middle` data.
The "clean" [`AST`][ast] acts as a common output format for both input formats.
+61 -42
View File
@@ -2,12 +2,13 @@
**In general, we expect every PR that fixes a bug in rustc to come accompanied
by a regression test of some kind.** This test should fail in `main` but pass
after the PR. These tests are really useful for preventing us from repeating the
after the PR.
These tests are really useful for preventing us from repeating the
mistakes of the past.
The first thing to decide is which kind of test to add. This will depend on the
nature of the change and what you want to exercise. Here are some rough
guidelines:
The first thing to decide is which kind of test to add.
This will depend on the nature of the change and what you want to exercise.
Here are some rough guidelines:
- The majority of compiler tests are done with [compiletest].
- The majority of compiletest tests are [UI](ui.md) tests in the [`tests/ui`]
@@ -17,18 +18,24 @@ guidelines:
- The majority of standard library tests are written as doctests, which
illustrate and exercise typical API behavior.
- Additional [unit tests](intro.md#package-tests) should go in
`library/${crate}/tests` (where `${crate}` is usually `core`, `alloc`, or
`std`).
`library/${crate}/tests` (where `${crate}` is usually `std`).
- Tests for the `alloc` or `core` crates must go in separate crates: `alloctests` or `coretests` respectively.
- NOTE: That when adding unit tests for unstable features the `#![feature(...)]`
declaration must be added to `library/${crate}tests/tests/lib.rs` and not to
`library/${crate}tests/lib.rs`.
- If the code is part of an isolated system, and you are not testing compiler
output, consider using a [unit or integration test](intro.md#package-tests).
- Need to run rustdoc? Prefer a `rustdoc` or `rustdoc-ui` test. Occasionally
you'll need `rustdoc-js` as well.
- Need to run rustdoc?
Prefer a `rustdoc` or `rustdoc-ui` test.
Occasionally you'll need `rustdoc-js` as well.
- Other compiletest test suites are generally used for special purposes:
- Need to run gdb or lldb? Use the `debuginfo` test suite.
- Need to inspect LLVM IR or MIR IR? Use the `codegen` or `mir-opt` test
suites.
- Need to inspect the resulting binary in some way? Or if all the other test
suites are too limited for your purposes? Then use `run-make`.
- Need to run gdb or lldb?
Use the `debuginfo` test suite.
- Need to inspect LLVM IR or MIR IR?
Use the `codegen` or `mir-opt` test suites.
- Need to inspect the resulting binary in some way?
Or if all the other test suites are too limited for your purposes?
Then use `run-make`.
- Use `run-make-cargo` if you need to exercise in-tree `cargo` in conjunction
with in-tree `rustc`.
- Check out the [compiletest] chapter for more specialized test suites.
@@ -44,14 +51,16 @@ modified several years later, how can we make it easier for them?).
## UI test walkthrough
The following is a basic guide for creating a [UI test](ui.md), which is one of
the most common compiler tests. For this tutorial, we'll be adding a test for an
async error message.
the most common compiler tests.
For this tutorial, we'll be adding a test for an async error message.
### Step 1: Add a test file
The first step is to create a Rust source file somewhere in the [`tests/ui`]
tree. When creating a test, do your best to find a good location and name (see
[Test organization](ui.md#test-organization) for more). Since naming is the
tree.
When creating a test, do your best to find a good location and name (see
[Test organization](ui.md#test-organization) for more).
Since naming is the
hardest part of development, everything should be downhill from here!
Let's place our async test at `tests/ui/async-await/await-without-async.rs`:
@@ -74,19 +83,23 @@ A few things to notice about our test:
- The top should start with a short comment that [explains what the test is
for](#explanatory_comment).
- The `//@ edition:2018` comment is called a [directive](directives.md) which
provides instructions to compiletest on how to build the test. Here we need to
provides instructions to compiletest on how to build the test.
Here we need to
set the edition for `async` to work (the default is edition 2015).
- Following that is the source of the test. Try to keep it succinct and to the
point. This may require some effort if you are trying to minimize an example
- Following that is the source of the test.
Try to keep it succinct and to the point.
This may require some effort if you are trying to minimize an example
from a bug report.
- We end this test with an empty `fn main` function. This is because the default
- We end this test with an empty `fn main` function.
This is because the default
for UI tests is a `bin` crate-type, and we don't want the "main not found"
error in our test. Alternatively, you could add `#![crate_type="lib"]`.
error in our test.
Alternatively, you could add `#![crate_type="lib"]`.
### Step 2: Generate the expected output
The next step is to create the expected output snapshots from the compiler. This
can be done with the `--bless` option:
The next step is to create the expected output snapshots from the compiler.
This can be done with the `--bless` option:
```sh
./x test tests/ui/async-await/await-without-async.rs --bless
@@ -96,8 +109,8 @@ This will build the compiler (if it hasn't already been built), compile the
test, and place the output of the compiler in a file called
`tests/ui/async-await/await-without-async.stderr`.
However, this step will fail! You should see an error message, something like
this:
However, this step will fail!
You should see an error message, something like this:
> error: /rust/tests/ui/async-await/await-without-async.rs:7: unexpected
> error: '7:10: 7:16: `await` is only allowed inside `async` functions and
@@ -109,7 +122,8 @@ annotations in the source file.
### Step 3: Add error annotations
Every error needs to be annotated with a comment in the source with the text of
the error. In this case, we can add the following comment to our test file:
the error.
In this case, we can add the following comment to our test file:
```rust,ignore
fn bar() {
@@ -133,9 +147,10 @@ It should now pass, yay!
### Step 4: Review the output
Somewhat hand-in-hand with the previous step, you should inspect the `.stderr`
file that was created to see if it looks like how you expect. If you are adding
a new diagnostic message, now would be a good time to also consider how readable
the message looks overall, particularly for people new to Rust.
file that was created to see if it looks like how you expect.
If you are adding a new diagnostic message,
now would be a good time to also consider how readable the message looks overall,
particularly for people new to Rust.
Our example `tests/ui/async-await/await-without-async.stderr` file should look
like this:
@@ -158,9 +173,9 @@ You may notice some things look a little different than the regular compiler
output.
- The `$DIR` removes the path information which will differ between systems.
- The `LL` values replace the line numbers. That helps avoid small changes in
the source from triggering large diffs. See the
[Normalization](ui.md#normalization) section for more.
- The `LL` values replace the line numbers.
That helps avoid small changes in the source from triggering large diffs.
See the [Normalization](ui.md#normalization) section for more.
Around this stage, you may need to iterate over the last few steps a few times
to tweak your test, re-bless the test, and re-review the output.
@@ -168,8 +183,10 @@ to tweak your test, re-bless the test, and re-review the output.
### Step 5: Check other tests
Sometimes when adding or changing a diagnostic message, this will affect other
tests in the test suite. The final step before posting a PR is to check if you
have affected anything else. Running the UI suite is usually a good start:
tests in the test suite.
The final step before posting a PR is to check if you
have affected anything else.
Running the UI suite is usually a good start:
```sh
./x test tests/ui
@@ -185,16 +202,18 @@ You may also need to re-bless the output with the `--bless` flag.
## Comment explaining what the test is about
The first comment of a test file should **summarize the point of the test**, and
highlight what is important about it. If there is an issue number associated
with the test, include the issue number.
highlight what is important about it.
If there is an issue number associated with the test, include the issue number.
This comment doesn't have to be super extensive. Just something like "Regression
test for #18060: match arms were matching in the wrong order." might already be
enough.
This comment doesn't have to be super extensive.
Just something like the following might be enough:
"Regression test for #18060: match arms were matching in the wrong order".
These comments are very useful to others later on when your test breaks, since
they often can highlight what the problem is. They are also useful if for some
they often can highlight what the problem is.
They are also useful if for some
reason the tests need to be refactored, since they let others know which parts
of the test were important. Often a test must be rewritten because it no longer
of the test were important.
Often a test must be rewritten because it no longer
tests what it was meant to test, and then it's useful to know what it *was*
meant to test exactly.
+7
View File
@@ -636,6 +636,13 @@ but not `tests/rustdoc-ui`) will specify
- `-A unused`
- `-W unused_attributes` (since these tend to be interesting for ui tests)
- `-A internal_features`
- `-A incomplete_features`
- `-A unused_parens`
- `-A unused_braces`
For more details, see [runtest].
[runtest]: https://github.com/rust-lang/rust/blob/HEAD/src/tools/compiletest/src/runtest.rs
If:
@@ -0,0 +1,47 @@
# Having separate `Trait` and `Projection` bounds
Given `T: Foo<AssocA = u32, AssocB = i32>` where-bound, we currently lower it to a `Trait(Foo<T>)` and separate `Projection(<T as Foo>::AssocA, u32)` and `Projection(<T as Foo>::AssocB, i32)` bounds.
Why do we not represent this as a single `Trait(Foo[T], [AssocA = u32, AssocB = u32]` bound instead?
The way we prove `Projection` bounds directly relies on proving the corresponding `Trait` bound: [old solver](https://github.com/rust-lang/rust/blob/461e9738a47e313e4457957fa95ff6a19a4b88d4/compiler/rustc_trait_selection/src/traits/project.rs#L898) [new solver](https://github.com/rust-lang/rust/blob/461e9738a47e313e4457957fa95ff6a19a4b88d4/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs#L37-L41).
It feels like it might make more sense to just have a single implementation which checks whether a trait is implemented and returns (a way to compute) its associated types.
This is unfortunately quite difficult, as we may use a different candidate for norm than for the corresponding trait bound.
See [alias-bound vs where-bound](https://rustc-dev-guide.rust-lang.org/solve/candidate-preference.html#we-always-consider-aliasbound-candidates) and [global where-bound vs impl](https://rustc-dev-guide.rust-lang.org/solve/candidate-preference.html#we-prefer-global-where-bounds-over-impls).
There are also some other subtle reasons for why we can't do so.
The most stupid is that for rigid aliases;
trying to normalize them does not consider any lifetime constraints from proving the trait bound.
This is necessary due to a lack of assumptions on binders - https://github.com/rust-lang/trait-system-refactor-initiative/issues/177 - and should be fixed longterm.
A separate issue is that, right now,
fetching the `type_of` associated types for `Trait` goals or in shadowed `Projection` candidates can cause query cycles for RPITIT.
See https://github.com/rust-lang/trait-system-refactor-initiative/issues/185.
There are also slight differences between candidates for some of the builtin impls, these do all seem generally undesirable and I consider them to be bugs which would be fixed if we had a unified approach here.
Finally, not having this split makes lowering where-clauses more annoying.
With the current system having duplicate where-clauses is not an issue and it can easily happen when elaborating super trait bounds.
We now need to make sure we merge all associated type constraints, e.g.:
```rust
trait Super {
type A;
type B;
}
trait Trait: Super<A = i32> {}
// how to elaborate Trait<B = u32>
```
Or even worse
```rust
trait Super<'a> {
type A;
type B;
}
trait Trait<'a>: Super<'a, A = i32> {}
// how to elaborate
// T: Trait<'a> + for<'b> Super<'b, B = u32>
```
@@ -24,12 +24,14 @@ Adt(&'tcx AdtDef, GenericArgs<'tcx>)
There are two parts:
- The [`AdtDef`][adtdef] references the struct/enum/union but without the values for its type
parameters. In our example, this is the `MyStruct` part *without* the argument `u32`.
parameters.
In our example, this is the `MyStruct` part *without* the argument `u32`.
(Note that in the HIR, structs, enums and unions are represented differently, but in `ty::Ty`,
they are all represented using `TyKind::Adt`.)
- The [`GenericArgs`] is a list of values that are to be substituted
for the generic parameters. In our example of `MyStruct<u32>`, we would end up with a list like
`[u32]`. Well dig more into generics and substitutions in a little bit.
for the generic parameters.
In our example of `MyStruct<u32>`, we would end up with a list like `[u32]`.
Well dig more into generics and substitutions in a little bit.
[adtdef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.AdtDef.html
[`GenericArgs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.GenericArgs.html
@@ -37,25 +39,29 @@ for the generic parameters. In our example of `MyStruct<u32>`, we would end up
### **`AdtDef` and `DefId`**
For every type defined in the source code, there is a unique `DefId` (see [this
chapter](../hir.md#identifiers-in-the-hir)). This includes ADTs and generics. In the `MyStruct<T>`
definition we gave above, there are two `DefId`s: one for `MyStruct` and one for `T`. Notice that
the code above does not generate a new `DefId` for `u32` because it is not defined in that code (it
is only referenced).
chapter](../hir.md#identifiers-in-the-hir)).
This includes ADTs and generics.
In the `MyStruct<T>` definition we gave above,
there are two `DefId`s: one for `MyStruct` and one for `T`.
Notice that the code above does not generate a new `DefId` for `u32`
because it is not defined in that code (it is only referenced).
`AdtDef` is more or less a wrapper around `DefId` with lots of useful helper methods. There is
essentially a one-to-one relationship between `AdtDef` and `DefId`. You can get the `AdtDef` for a
`DefId` with the [`tcx.adt_def(def_id)` query][adtdefq]. `AdtDef`s are all interned, as shown
by the `'tcx` lifetime.
`AdtDef` is more or less a wrapper around `DefId` with lots of useful helper methods.
There is essentially a one-to-one relationship between `AdtDef` and `DefId`.
You can get the `AdtDef` for a `DefId` with the [`tcx.adt_def(def_id)` query][adtdefq].
`AdtDef`s are all interned, as shown by the `'tcx` lifetime.
[adtdefq]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.adt_def
## Question: Why not substitute “inside” the `AdtDef`?
Recall that we represent a generic struct with `(AdtDef, args)`. So why bother with this scheme?
Recall that we represent a generic struct with `(AdtDef, args)`.
So why bother with this scheme?
Well, the alternate way we could have chosen to represent types would be to always create a new,
fully-substituted form of the `AdtDef` where all the types are already substituted. This seems like
less of a hassle. However, the `(AdtDef, args)` scheme has some advantages over this.
fully-substituted form of the `AdtDef` where all the types are already substituted.
This seems like less of a hassle.
However, the `(AdtDef, args)` scheme has some advantages over this.
First, `(AdtDef, args)` scheme has an efficiency win:
@@ -68,7 +74,8 @@ struct MyStruct<T> {
```
in an example like this, we can instantiate `MyStruct<A>` as `MyStruct<B>` (and so on) very cheaply,
by just replacing the one reference to `A` with `B`. But if we eagerly instantiated all the fields,
by just replacing the one reference to `A` with `B`.
But if we eagerly instantiated all the fields,
that could be a lot more work because we might have to go through all of the fields in the `AdtDef`
and update all of their types.
@@ -83,7 +90,9 @@ definition of that name, and not carried along “within” the type itself).
Given a generic type `MyType<A, B, …>`, we have to store the list of generic arguments for `MyType`.
In rustc this is done using [`GenericArgs`]. `GenericArgs` is a thin pointer to a slice of [`GenericArg`] representing a list of generic arguments for a generic item. For example, given a `struct HashMap<K, V>` with two type parameters, `K` and `V`, the `GenericArgs` used to represent the type `HashMap<i32, u32>` would be represented by `&'tcx [tcx.types.i32, tcx.types.u32]`.
In rustc this is done using [`GenericArgs`].
`GenericArgs` is a thin pointer to a slice of [`GenericArg`] representing a list of generic arguments for a generic item.
For example, given a `struct HashMap<K, V>` with two type parameters, `K` and `V`, the `GenericArgs` used to represent the type `HashMap<i32, u32>` would be represented by `&'tcx [tcx.types.i32, tcx.types.u32]`.
`GenericArg` is conceptually an `enum` with three variants, one for type arguments, one for const arguments and one for lifetime arguments.
In practice that is actually represented by [`GenericArgKind`] and [`GenericArg`] is a more space efficient version that has a method to
@@ -126,3 +135,36 @@ For the `MyStruct<U>` written in the `Foo` type alias, we would represent it in
- There would be an `AdtDef` (and corresponding `DefId`) for `MyStruct`.
- There would be a `GenericArgs` containing the list `[GenericArgKind::Type(Ty(u32))]`
- And finally a `TyKind::Adt` with the `AdtDef` and `GenericArgs` listed above.
## Nested generic args
```rust
struct MyStruct<T>(T);
impl<T> MyStruct<T> {
fn func<T2, T3>() {}
}
fn main() {
MyStruct::<u32>::func::<bool, char>();
}
```
The construct `MyStruct::<u32>::func::<bool, char>` is represented by a tuple: a DefId pointing at `func`, and then a
`GenericArgs` list that "walks" all containing generic parameters - in this case, the list would be `[u32, bool, char]`.
The [`ty::Generics`] type (returned by the [`generics_of`] query) contains the information of how a nested hierarchy
gets flattened down to a list, and lets you figure out which index in the `GenericArgs` list corresponds to which
generic.
The general theme of how it works is outermost to innermost (`T` before `T2` in the example), left to right
(`T2` before `T3`), but there are several complications:
- Traits have an implicit `Self` generic parameter which is the first (i.e. 0th) generic parameter. Note that `Self` doesn't mean a generic parameter in all situations, see [Res::SelfTyAlias](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def/enum.Res.html#variant.SelfTyAlias) and [Res::SelfCtor](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def/enum.Res.html#variant.SelfCtor).
- Only early-bound generic parameters are included, [late-bound generics] are not.
- ... and more...
Check out [`ty::Generics`] for exact specifics on how the flattening works.
[`ty::Generics`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Generics.html
[`generics_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.generics_of
[late-bound generics]: ../early-late-parameters.md
@@ -12,16 +12,11 @@ This tracks support for additional registers in architectures where inline assem
| Architecture | Register class | Registers | LLVM constraint code |
| ------------ | -------------- | --------- | -------------------- |
| s390x | `vreg` | `v[0-31]` | `v` |
> **Notes**:
> - s390x `vreg` is clobber-only in stable.
## Register class supported types
| Architecture | Register class | Target feature | Allowed types |
| ------------ | -------------- | -------------- | ------------- |
| s390x | `vreg` | `vector` | `i32`, `f32`, `i64`, `f64`, `i128`, `f128`, `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
| x86 | `xmm_reg` | `sse` | `i128` |
| x86 | `ymm_reg` | `avx` | `i128` |
| x86 | `zmm_reg` | `avx512f` | `i128` |
@@ -40,4 +35,3 @@ This tracks support for additional registers in architectures where inline assem
| Architecture | Register class | Modifier | Example output | LLVM modifier |
| ------------ | -------------- | -------- | -------------- | ------------- |
| s390x | `vreg` | None | `%v0` | None |
+10 -21
View File
@@ -8,7 +8,6 @@
//@ compile-flags: -Zmerge-functions=disabled
#![feature(no_core, repr_simd, f16, f128)]
#![cfg_attr(s390x_vector, feature(asm_experimental_reg))]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
@@ -19,27 +18,17 @@
type ptr = *const i32;
#[repr(simd)]
pub struct i8x16([i8; 16]);
#[repr(simd)]
pub struct i16x8([i16; 8]);
#[repr(simd)]
pub struct i32x4([i32; 4]);
#[repr(simd)]
pub struct i64x2([i64; 2]);
#[repr(simd)]
pub struct f16x8([f16; 8]);
#[repr(simd)]
pub struct f32x4([f32; 4]);
#[repr(simd)]
pub struct f64x2([f64; 2]);
pub struct Simd<T, const N: usize>([T; N]);
impl Copy for i8x16 {}
impl Copy for i16x8 {}
impl Copy for i32x4 {}
impl Copy for i64x2 {}
impl Copy for f16x8 {}
impl Copy for f32x4 {}
impl Copy for f64x2 {}
impl<T: Copy, const N: usize> Copy for Simd<T, N> {}
type i8x16 = Simd<i8, 16>;
type i16x8 = Simd<i16, 8>;
type i32x4 = Simd<i32, 4>;
type i64x2 = Simd<i64, 2>;
type f16x8 = Simd<f16, 8>;
type f32x4 = Simd<f32, 4>;
type f64x2 = Simd<f64, 2>;
extern "C" {
fn extern_func();
+28
View File
@@ -0,0 +1,28 @@
// Checks that when compiling for GPU targets, the convergent attribute
// is added to function declarations and definitions.
//@ add-minicore
//@ revisions: amdgpu nvptx
//@ [amdgpu] compile-flags: --crate-type=rlib --target=amdgcn-amd-amdhsa -Ctarget-cpu=gfx900
//@ [amdgpu] needs-llvm-components: amdgpu
//@ [nvptx] compile-flags: --crate-type=rlib --target=nvptx64-nvidia-cuda
//@ [nvptx] needs-llvm-components: nvptx
#![feature(no_core, lang_items, abi_gpu_kernel)]
#![no_core]
extern crate minicore;
use minicore::*;
extern "C" {
fn ext();
}
// CHECK: define {{.*}}_kernel void @fun(i32{{.*}}) unnamed_addr #[[ATTR:[0-9]+]] {
// CHECK: declare void @ext() unnamed_addr #[[ATTR]]
// CHECK: attributes #[[ATTR]] = {{.*}} convergent
#[no_mangle]
pub extern "gpu-kernel" fn fun(_: i32) {
unsafe {
ext();
}
}
+1 -23
View File
@@ -1,16 +1,13 @@
//@ add-minicore
//@ revisions: s390x s390x_vector s390x_vector_stable
//@ revisions: s390x s390x_vector
//@[s390x] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=-vector
//@[s390x] needs-llvm-components: systemz
//@[s390x_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
//@[s390x_vector] needs-llvm-components: systemz
//@[s390x_vector_stable] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
//@[s390x_vector_stable] needs-llvm-components: systemz
//@ ignore-backends: gcc
#![crate_type = "rlib"]
#![feature(no_core, repr_simd)]
#![cfg_attr(not(s390x_vector_stable), feature(asm_experimental_reg))]
#![no_core]
#![allow(non_camel_case_types)]
@@ -73,46 +70,27 @@ fn f() {
asm!("", out("v0") _); // always ok
asm!("", in("v0") v); // requires vector & asm_experimental_reg
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
//[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
//[s390x_vector_stable]~| ERROR type `i64x2` cannot be used with this register class in stable [E0658]
asm!("", out("v0") v); // requires vector & asm_experimental_reg
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
//[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
//[s390x_vector_stable]~| ERROR type `i64x2` cannot be used with this register class in stable [E0658]
asm!("", in("v0") x); // requires vector & asm_experimental_reg
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
//[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
//[s390x_vector_stable]~| ERROR type `i32` cannot be used with this register class in stable [E0658]
asm!("", out("v0") x); // requires vector & asm_experimental_reg
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
//[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
//[s390x_vector_stable]~| ERROR type `i32` cannot be used with this register class in stable [E0658]
asm!("", in("v0") b);
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
//[s390x_vector]~^^ ERROR type `u8` cannot be used with this register class
//[s390x_vector_stable]~^^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
//[s390x_vector_stable]~| ERROR type `u8` cannot be used with this register class
asm!("", out("v0") b);
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
//[s390x_vector]~^^ ERROR type `u8` cannot be used with this register class
//[s390x_vector_stable]~^^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
//[s390x_vector_stable]~| ERROR type `u8` cannot be used with this register class
asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
//[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
//[s390x_vector_stable]~| ERROR type `i64x2` cannot be used with this register class in stable [E0658]
asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
//[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
//[s390x_vector_stable]~| ERROR type `i32` cannot be used with this register class in stable [E0658]
asm!("/* {} */", in(vreg) b);
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
//[s390x_vector]~^^ ERROR type `u8` cannot be used with this register class
//[s390x_vector_stable]~^^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
//[s390x_vector_stable]~| ERROR type `u8` cannot be used with this register class
asm!("/* {} */", out(vreg) _); // requires vector & asm_experimental_reg
//[s390x]~^ ERROR register class `vreg` requires the `vector` target feature
//[s390x_vector_stable]~^^ ERROR register class `vreg` can only be used as a clobber in stable [E0658]
// Clobber-only registers
// areg
+54 -54
View File
@@ -1,149 +1,149 @@
error: invalid register `r11`: The frame pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:31:18
--> $DIR/bad-reg.rs:28:18
|
LL | asm!("", out("r11") _);
| ^^^^^^^^^^^^
error: invalid register `r15`: The stack pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:33:18
--> $DIR/bad-reg.rs:30:18
|
LL | asm!("", out("r15") _);
| ^^^^^^^^^^^^
error: invalid register `c0`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:35:18
--> $DIR/bad-reg.rs:32:18
|
LL | asm!("", out("c0") _);
| ^^^^^^^^^^^
error: invalid register `c1`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:37:18
--> $DIR/bad-reg.rs:34:18
|
LL | asm!("", out("c1") _);
| ^^^^^^^^^^^
error: invalid register `c2`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:39:18
--> $DIR/bad-reg.rs:36:18
|
LL | asm!("", out("c2") _);
| ^^^^^^^^^^^
error: invalid register `c3`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:41:18
--> $DIR/bad-reg.rs:38:18
|
LL | asm!("", out("c3") _);
| ^^^^^^^^^^^
error: invalid register `c4`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:43:18
--> $DIR/bad-reg.rs:40:18
|
LL | asm!("", out("c4") _);
| ^^^^^^^^^^^
error: invalid register `c5`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:45:18
--> $DIR/bad-reg.rs:42:18
|
LL | asm!("", out("c5") _);
| ^^^^^^^^^^^
error: invalid register `c6`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:47:18
--> $DIR/bad-reg.rs:44:18
|
LL | asm!("", out("c6") _);
| ^^^^^^^^^^^
error: invalid register `c7`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:49:18
--> $DIR/bad-reg.rs:46:18
|
LL | asm!("", out("c7") _);
| ^^^^^^^^^^^
error: invalid register `c8`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:51:18
--> $DIR/bad-reg.rs:48:18
|
LL | asm!("", out("c8") _);
| ^^^^^^^^^^^
error: invalid register `c9`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:53:18
--> $DIR/bad-reg.rs:50:18
|
LL | asm!("", out("c9") _);
| ^^^^^^^^^^^
error: invalid register `c10`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:55:18
--> $DIR/bad-reg.rs:52:18
|
LL | asm!("", out("c10") _);
| ^^^^^^^^^^^^
error: invalid register `c11`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:57:18
--> $DIR/bad-reg.rs:54:18
|
LL | asm!("", out("c11") _);
| ^^^^^^^^^^^^
error: invalid register `c12`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:59:18
--> $DIR/bad-reg.rs:56:18
|
LL | asm!("", out("c12") _);
| ^^^^^^^^^^^^
error: invalid register `c13`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:61:18
--> $DIR/bad-reg.rs:58:18
|
LL | asm!("", out("c13") _);
| ^^^^^^^^^^^^
error: invalid register `c14`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:63:18
--> $DIR/bad-reg.rs:60:18
|
LL | asm!("", out("c14") _);
| ^^^^^^^^^^^^
error: invalid register `c15`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:65:18
--> $DIR/bad-reg.rs:62:18
|
LL | asm!("", out("c15") _);
| ^^^^^^^^^^^^
error: invalid register `a0`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:67:18
--> $DIR/bad-reg.rs:64:18
|
LL | asm!("", out("a0") _);
| ^^^^^^^^^^^
error: invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:69:18
--> $DIR/bad-reg.rs:66:18
|
LL | asm!("", out("a1") _);
| ^^^^^^^^^^^
error: register class `areg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:120:18
--> $DIR/bad-reg.rs:98:18
|
LL | asm!("", in("a2") x);
| ^^^^^^^^^^
error: register class `areg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:123:18
--> $DIR/bad-reg.rs:101:18
|
LL | asm!("", out("a2") x);
| ^^^^^^^^^^^
error: register class `areg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:126:26
--> $DIR/bad-reg.rs:104:26
|
LL | asm!("/* {} */", in(areg) x);
| ^^^^^^^^^^
error: register class `areg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:129:26
--> $DIR/bad-reg.rs:107:26
|
LL | asm!("/* {} */", out(areg) _);
| ^^^^^^^^^^^
error: register `f0` conflicts with register `v0`
--> $DIR/bad-reg.rs:134:31
--> $DIR/bad-reg.rs:112:31
|
LL | asm!("", out("v0") _, out("f0") _);
| ----------- ^^^^^^^^^^^ register `f0`
@@ -151,7 +151,7 @@ LL | asm!("", out("v0") _, out("f0") _);
| register `v0`
error: register `f1` conflicts with register `v1`
--> $DIR/bad-reg.rs:136:31
--> $DIR/bad-reg.rs:114:31
|
LL | asm!("", out("v1") _, out("f1") _);
| ----------- ^^^^^^^^^^^ register `f1`
@@ -159,7 +159,7 @@ LL | asm!("", out("v1") _, out("f1") _);
| register `v1`
error: register `f2` conflicts with register `v2`
--> $DIR/bad-reg.rs:138:31
--> $DIR/bad-reg.rs:116:31
|
LL | asm!("", out("v2") _, out("f2") _);
| ----------- ^^^^^^^^^^^ register `f2`
@@ -167,7 +167,7 @@ LL | asm!("", out("v2") _, out("f2") _);
| register `v2`
error: register `f3` conflicts with register `v3`
--> $DIR/bad-reg.rs:140:31
--> $DIR/bad-reg.rs:118:31
|
LL | asm!("", out("v3") _, out("f3") _);
| ----------- ^^^^^^^^^^^ register `f3`
@@ -175,7 +175,7 @@ LL | asm!("", out("v3") _, out("f3") _);
| register `v3`
error: register `f4` conflicts with register `v4`
--> $DIR/bad-reg.rs:142:31
--> $DIR/bad-reg.rs:120:31
|
LL | asm!("", out("v4") _, out("f4") _);
| ----------- ^^^^^^^^^^^ register `f4`
@@ -183,7 +183,7 @@ LL | asm!("", out("v4") _, out("f4") _);
| register `v4`
error: register `f5` conflicts with register `v5`
--> $DIR/bad-reg.rs:144:31
--> $DIR/bad-reg.rs:122:31
|
LL | asm!("", out("v5") _, out("f5") _);
| ----------- ^^^^^^^^^^^ register `f5`
@@ -191,7 +191,7 @@ LL | asm!("", out("v5") _, out("f5") _);
| register `v5`
error: register `f6` conflicts with register `v6`
--> $DIR/bad-reg.rs:146:31
--> $DIR/bad-reg.rs:124:31
|
LL | asm!("", out("v6") _, out("f6") _);
| ----------- ^^^^^^^^^^^ register `f6`
@@ -199,7 +199,7 @@ LL | asm!("", out("v6") _, out("f6") _);
| register `v6`
error: register `f7` conflicts with register `v7`
--> $DIR/bad-reg.rs:148:31
--> $DIR/bad-reg.rs:126:31
|
LL | asm!("", out("v7") _, out("f7") _);
| ----------- ^^^^^^^^^^^ register `f7`
@@ -207,7 +207,7 @@ LL | asm!("", out("v7") _, out("f7") _);
| register `v7`
error: register `f8` conflicts with register `v8`
--> $DIR/bad-reg.rs:150:31
--> $DIR/bad-reg.rs:128:31
|
LL | asm!("", out("v8") _, out("f8") _);
| ----------- ^^^^^^^^^^^ register `f8`
@@ -215,7 +215,7 @@ LL | asm!("", out("v8") _, out("f8") _);
| register `v8`
error: register `f9` conflicts with register `v9`
--> $DIR/bad-reg.rs:152:31
--> $DIR/bad-reg.rs:130:31
|
LL | asm!("", out("v9") _, out("f9") _);
| ----------- ^^^^^^^^^^^ register `f9`
@@ -223,7 +223,7 @@ LL | asm!("", out("v9") _, out("f9") _);
| register `v9`
error: register `f10` conflicts with register `v10`
--> $DIR/bad-reg.rs:154:32
--> $DIR/bad-reg.rs:132:32
|
LL | asm!("", out("v10") _, out("f10") _);
| ------------ ^^^^^^^^^^^^ register `f10`
@@ -231,7 +231,7 @@ LL | asm!("", out("v10") _, out("f10") _);
| register `v10`
error: register `f11` conflicts with register `v11`
--> $DIR/bad-reg.rs:156:32
--> $DIR/bad-reg.rs:134:32
|
LL | asm!("", out("v11") _, out("f11") _);
| ------------ ^^^^^^^^^^^^ register `f11`
@@ -239,7 +239,7 @@ LL | asm!("", out("v11") _, out("f11") _);
| register `v11`
error: register `f12` conflicts with register `v12`
--> $DIR/bad-reg.rs:158:32
--> $DIR/bad-reg.rs:136:32
|
LL | asm!("", out("v12") _, out("f12") _);
| ------------ ^^^^^^^^^^^^ register `f12`
@@ -247,7 +247,7 @@ LL | asm!("", out("v12") _, out("f12") _);
| register `v12`
error: register `f13` conflicts with register `v13`
--> $DIR/bad-reg.rs:160:32
--> $DIR/bad-reg.rs:138:32
|
LL | asm!("", out("v13") _, out("f13") _);
| ------------ ^^^^^^^^^^^^ register `f13`
@@ -255,7 +255,7 @@ LL | asm!("", out("v13") _, out("f13") _);
| register `v13`
error: register `f14` conflicts with register `v14`
--> $DIR/bad-reg.rs:162:32
--> $DIR/bad-reg.rs:140:32
|
LL | asm!("", out("v14") _, out("f14") _);
| ------------ ^^^^^^^^^^^^ register `f14`
@@ -263,7 +263,7 @@ LL | asm!("", out("v14") _, out("f14") _);
| register `v14`
error: register `f15` conflicts with register `v15`
--> $DIR/bad-reg.rs:164:32
--> $DIR/bad-reg.rs:142:32
|
LL | asm!("", out("v15") _, out("f15") _);
| ------------ ^^^^^^^^^^^^ register `f15`
@@ -271,73 +271,73 @@ LL | asm!("", out("v15") _, out("f15") _);
| register `v15`
error: invalid register `f16`: unknown register
--> $DIR/bad-reg.rs:167:32
--> $DIR/bad-reg.rs:145:32
|
LL | asm!("", out("v16") _, out("f16") _);
| ^^^^^^^^^^^^
error: register class `vreg` requires the `vector` target feature
--> $DIR/bad-reg.rs:74:18
--> $DIR/bad-reg.rs:71:18
|
LL | asm!("", in("v0") v); // requires vector & asm_experimental_reg
| ^^^^^^^^^^
error: register class `vreg` requires the `vector` target feature
--> $DIR/bad-reg.rs:78:18
--> $DIR/bad-reg.rs:73:18
|
LL | asm!("", out("v0") v); // requires vector & asm_experimental_reg
| ^^^^^^^^^^^
error: register class `vreg` requires the `vector` target feature
--> $DIR/bad-reg.rs:82:18
--> $DIR/bad-reg.rs:75:18
|
LL | asm!("", in("v0") x); // requires vector & asm_experimental_reg
| ^^^^^^^^^^
error: register class `vreg` requires the `vector` target feature
--> $DIR/bad-reg.rs:86:18
--> $DIR/bad-reg.rs:77:18
|
LL | asm!("", out("v0") x); // requires vector & asm_experimental_reg
| ^^^^^^^^^^^
error: register class `vreg` requires the `vector` target feature
--> $DIR/bad-reg.rs:90:18
--> $DIR/bad-reg.rs:79:18
|
LL | asm!("", in("v0") b);
| ^^^^^^^^^^
error: register class `vreg` requires the `vector` target feature
--> $DIR/bad-reg.rs:95:18
--> $DIR/bad-reg.rs:82:18
|
LL | asm!("", out("v0") b);
| ^^^^^^^^^^^
error: register class `vreg` requires the `vector` target feature
--> $DIR/bad-reg.rs:100:26
--> $DIR/bad-reg.rs:85:26
|
LL | asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
| ^^^^^^^^^^
error: register class `vreg` requires the `vector` target feature
--> $DIR/bad-reg.rs:104:26
--> $DIR/bad-reg.rs:87:26
|
LL | asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
| ^^^^^^^^^^
error: register class `vreg` requires the `vector` target feature
--> $DIR/bad-reg.rs:108:26
--> $DIR/bad-reg.rs:89:26
|
LL | asm!("/* {} */", in(vreg) b);
| ^^^^^^^^^^
error: register class `vreg` requires the `vector` target feature
--> $DIR/bad-reg.rs:113:26
--> $DIR/bad-reg.rs:92:26
|
LL | asm!("/* {} */", out(vreg) _); // requires vector & asm_experimental_reg
| ^^^^^^^^^^^
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:120:27
--> $DIR/bad-reg.rs:98:27
|
LL | asm!("", in("a2") x);
| ^
@@ -345,7 +345,7 @@ LL | asm!("", in("a2") x);
= note: register class `areg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:123:28
--> $DIR/bad-reg.rs:101:28
|
LL | asm!("", out("a2") x);
| ^
@@ -353,7 +353,7 @@ LL | asm!("", out("a2") x);
= note: register class `areg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:126:35
--> $DIR/bad-reg.rs:104:35
|
LL | asm!("/* {} */", in(areg) x);
| ^
+47 -47
View File
@@ -1,149 +1,149 @@
error: invalid register `r11`: The frame pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:31:18
--> $DIR/bad-reg.rs:28:18
|
LL | asm!("", out("r11") _);
| ^^^^^^^^^^^^
error: invalid register `r15`: The stack pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:33:18
--> $DIR/bad-reg.rs:30:18
|
LL | asm!("", out("r15") _);
| ^^^^^^^^^^^^
error: invalid register `c0`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:35:18
--> $DIR/bad-reg.rs:32:18
|
LL | asm!("", out("c0") _);
| ^^^^^^^^^^^
error: invalid register `c1`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:37:18
--> $DIR/bad-reg.rs:34:18
|
LL | asm!("", out("c1") _);
| ^^^^^^^^^^^
error: invalid register `c2`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:39:18
--> $DIR/bad-reg.rs:36:18
|
LL | asm!("", out("c2") _);
| ^^^^^^^^^^^
error: invalid register `c3`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:41:18
--> $DIR/bad-reg.rs:38:18
|
LL | asm!("", out("c3") _);
| ^^^^^^^^^^^
error: invalid register `c4`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:43:18
--> $DIR/bad-reg.rs:40:18
|
LL | asm!("", out("c4") _);
| ^^^^^^^^^^^
error: invalid register `c5`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:45:18
--> $DIR/bad-reg.rs:42:18
|
LL | asm!("", out("c5") _);
| ^^^^^^^^^^^
error: invalid register `c6`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:47:18
--> $DIR/bad-reg.rs:44:18
|
LL | asm!("", out("c6") _);
| ^^^^^^^^^^^
error: invalid register `c7`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:49:18
--> $DIR/bad-reg.rs:46:18
|
LL | asm!("", out("c7") _);
| ^^^^^^^^^^^
error: invalid register `c8`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:51:18
--> $DIR/bad-reg.rs:48:18
|
LL | asm!("", out("c8") _);
| ^^^^^^^^^^^
error: invalid register `c9`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:53:18
--> $DIR/bad-reg.rs:50:18
|
LL | asm!("", out("c9") _);
| ^^^^^^^^^^^
error: invalid register `c10`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:55:18
--> $DIR/bad-reg.rs:52:18
|
LL | asm!("", out("c10") _);
| ^^^^^^^^^^^^
error: invalid register `c11`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:57:18
--> $DIR/bad-reg.rs:54:18
|
LL | asm!("", out("c11") _);
| ^^^^^^^^^^^^
error: invalid register `c12`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:59:18
--> $DIR/bad-reg.rs:56:18
|
LL | asm!("", out("c12") _);
| ^^^^^^^^^^^^
error: invalid register `c13`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:61:18
--> $DIR/bad-reg.rs:58:18
|
LL | asm!("", out("c13") _);
| ^^^^^^^^^^^^
error: invalid register `c14`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:63:18
--> $DIR/bad-reg.rs:60:18
|
LL | asm!("", out("c14") _);
| ^^^^^^^^^^^^
error: invalid register `c15`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:65:18
--> $DIR/bad-reg.rs:62:18
|
LL | asm!("", out("c15") _);
| ^^^^^^^^^^^^
error: invalid register `a0`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:67:18
--> $DIR/bad-reg.rs:64:18
|
LL | asm!("", out("a0") _);
| ^^^^^^^^^^^
error: invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:69:18
--> $DIR/bad-reg.rs:66:18
|
LL | asm!("", out("a1") _);
| ^^^^^^^^^^^
error: register class `areg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:120:18
--> $DIR/bad-reg.rs:98:18
|
LL | asm!("", in("a2") x);
| ^^^^^^^^^^
error: register class `areg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:123:18
--> $DIR/bad-reg.rs:101:18
|
LL | asm!("", out("a2") x);
| ^^^^^^^^^^^
error: register class `areg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:126:26
--> $DIR/bad-reg.rs:104:26
|
LL | asm!("/* {} */", in(areg) x);
| ^^^^^^^^^^
error: register class `areg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:129:26
--> $DIR/bad-reg.rs:107:26
|
LL | asm!("/* {} */", out(areg) _);
| ^^^^^^^^^^^
error: register `f0` conflicts with register `v0`
--> $DIR/bad-reg.rs:134:31
--> $DIR/bad-reg.rs:112:31
|
LL | asm!("", out("v0") _, out("f0") _);
| ----------- ^^^^^^^^^^^ register `f0`
@@ -151,7 +151,7 @@ LL | asm!("", out("v0") _, out("f0") _);
| register `v0`
error: register `f1` conflicts with register `v1`
--> $DIR/bad-reg.rs:136:31
--> $DIR/bad-reg.rs:114:31
|
LL | asm!("", out("v1") _, out("f1") _);
| ----------- ^^^^^^^^^^^ register `f1`
@@ -159,7 +159,7 @@ LL | asm!("", out("v1") _, out("f1") _);
| register `v1`
error: register `f2` conflicts with register `v2`
--> $DIR/bad-reg.rs:138:31
--> $DIR/bad-reg.rs:116:31
|
LL | asm!("", out("v2") _, out("f2") _);
| ----------- ^^^^^^^^^^^ register `f2`
@@ -167,7 +167,7 @@ LL | asm!("", out("v2") _, out("f2") _);
| register `v2`
error: register `f3` conflicts with register `v3`
--> $DIR/bad-reg.rs:140:31
--> $DIR/bad-reg.rs:118:31
|
LL | asm!("", out("v3") _, out("f3") _);
| ----------- ^^^^^^^^^^^ register `f3`
@@ -175,7 +175,7 @@ LL | asm!("", out("v3") _, out("f3") _);
| register `v3`
error: register `f4` conflicts with register `v4`
--> $DIR/bad-reg.rs:142:31
--> $DIR/bad-reg.rs:120:31
|
LL | asm!("", out("v4") _, out("f4") _);
| ----------- ^^^^^^^^^^^ register `f4`
@@ -183,7 +183,7 @@ LL | asm!("", out("v4") _, out("f4") _);
| register `v4`
error: register `f5` conflicts with register `v5`
--> $DIR/bad-reg.rs:144:31
--> $DIR/bad-reg.rs:122:31
|
LL | asm!("", out("v5") _, out("f5") _);
| ----------- ^^^^^^^^^^^ register `f5`
@@ -191,7 +191,7 @@ LL | asm!("", out("v5") _, out("f5") _);
| register `v5`
error: register `f6` conflicts with register `v6`
--> $DIR/bad-reg.rs:146:31
--> $DIR/bad-reg.rs:124:31
|
LL | asm!("", out("v6") _, out("f6") _);
| ----------- ^^^^^^^^^^^ register `f6`
@@ -199,7 +199,7 @@ LL | asm!("", out("v6") _, out("f6") _);
| register `v6`
error: register `f7` conflicts with register `v7`
--> $DIR/bad-reg.rs:148:31
--> $DIR/bad-reg.rs:126:31
|
LL | asm!("", out("v7") _, out("f7") _);
| ----------- ^^^^^^^^^^^ register `f7`
@@ -207,7 +207,7 @@ LL | asm!("", out("v7") _, out("f7") _);
| register `v7`
error: register `f8` conflicts with register `v8`
--> $DIR/bad-reg.rs:150:31
--> $DIR/bad-reg.rs:128:31
|
LL | asm!("", out("v8") _, out("f8") _);
| ----------- ^^^^^^^^^^^ register `f8`
@@ -215,7 +215,7 @@ LL | asm!("", out("v8") _, out("f8") _);
| register `v8`
error: register `f9` conflicts with register `v9`
--> $DIR/bad-reg.rs:152:31
--> $DIR/bad-reg.rs:130:31
|
LL | asm!("", out("v9") _, out("f9") _);
| ----------- ^^^^^^^^^^^ register `f9`
@@ -223,7 +223,7 @@ LL | asm!("", out("v9") _, out("f9") _);
| register `v9`
error: register `f10` conflicts with register `v10`
--> $DIR/bad-reg.rs:154:32
--> $DIR/bad-reg.rs:132:32
|
LL | asm!("", out("v10") _, out("f10") _);
| ------------ ^^^^^^^^^^^^ register `f10`
@@ -231,7 +231,7 @@ LL | asm!("", out("v10") _, out("f10") _);
| register `v10`
error: register `f11` conflicts with register `v11`
--> $DIR/bad-reg.rs:156:32
--> $DIR/bad-reg.rs:134:32
|
LL | asm!("", out("v11") _, out("f11") _);
| ------------ ^^^^^^^^^^^^ register `f11`
@@ -239,7 +239,7 @@ LL | asm!("", out("v11") _, out("f11") _);
| register `v11`
error: register `f12` conflicts with register `v12`
--> $DIR/bad-reg.rs:158:32
--> $DIR/bad-reg.rs:136:32
|
LL | asm!("", out("v12") _, out("f12") _);
| ------------ ^^^^^^^^^^^^ register `f12`
@@ -247,7 +247,7 @@ LL | asm!("", out("v12") _, out("f12") _);
| register `v12`
error: register `f13` conflicts with register `v13`
--> $DIR/bad-reg.rs:160:32
--> $DIR/bad-reg.rs:138:32
|
LL | asm!("", out("v13") _, out("f13") _);
| ------------ ^^^^^^^^^^^^ register `f13`
@@ -255,7 +255,7 @@ LL | asm!("", out("v13") _, out("f13") _);
| register `v13`
error: register `f14` conflicts with register `v14`
--> $DIR/bad-reg.rs:162:32
--> $DIR/bad-reg.rs:140:32
|
LL | asm!("", out("v14") _, out("f14") _);
| ------------ ^^^^^^^^^^^^ register `f14`
@@ -263,7 +263,7 @@ LL | asm!("", out("v14") _, out("f14") _);
| register `v14`
error: register `f15` conflicts with register `v15`
--> $DIR/bad-reg.rs:164:32
--> $DIR/bad-reg.rs:142:32
|
LL | asm!("", out("v15") _, out("f15") _);
| ------------ ^^^^^^^^^^^^ register `f15`
@@ -271,13 +271,13 @@ LL | asm!("", out("v15") _, out("f15") _);
| register `v15`
error: invalid register `f16`: unknown register
--> $DIR/bad-reg.rs:167:32
--> $DIR/bad-reg.rs:145:32
|
LL | asm!("", out("v16") _, out("f16") _);
| ^^^^^^^^^^^^
error: type `u8` cannot be used with this register class
--> $DIR/bad-reg.rs:90:27
--> $DIR/bad-reg.rs:79:27
|
LL | asm!("", in("v0") b);
| ^
@@ -285,7 +285,7 @@ LL | asm!("", in("v0") b);
= note: register class `vreg` supports these types: i32, f16, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2
error: type `u8` cannot be used with this register class
--> $DIR/bad-reg.rs:95:28
--> $DIR/bad-reg.rs:82:28
|
LL | asm!("", out("v0") b);
| ^
@@ -293,7 +293,7 @@ LL | asm!("", out("v0") b);
= note: register class `vreg` supports these types: i32, f16, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2
error: type `u8` cannot be used with this register class
--> $DIR/bad-reg.rs:108:35
--> $DIR/bad-reg.rs:89:35
|
LL | asm!("/* {} */", in(vreg) b);
| ^
@@ -301,7 +301,7 @@ LL | asm!("/* {} */", in(vreg) b);
= note: register class `vreg` supports these types: i32, f16, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:120:27
--> $DIR/bad-reg.rs:98:27
|
LL | asm!("", in("a2") x);
| ^
@@ -309,7 +309,7 @@ LL | asm!("", in("a2") x);
= note: register class `areg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:123:28
--> $DIR/bad-reg.rs:101:28
|
LL | asm!("", out("a2") x);
| ^
@@ -317,7 +317,7 @@ LL | asm!("", out("a2") x);
= note: register class `areg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:126:35
--> $DIR/bad-reg.rs:104:35
|
LL | asm!("/* {} */", in(areg) x);
| ^
@@ -1,489 +0,0 @@
error: invalid register `r11`: The frame pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:31:18
|
LL | asm!("", out("r11") _);
| ^^^^^^^^^^^^
error: invalid register `r15`: The stack pointer cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:33:18
|
LL | asm!("", out("r15") _);
| ^^^^^^^^^^^^
error: invalid register `c0`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:35:18
|
LL | asm!("", out("c0") _);
| ^^^^^^^^^^^
error: invalid register `c1`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:37:18
|
LL | asm!("", out("c1") _);
| ^^^^^^^^^^^
error: invalid register `c2`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:39:18
|
LL | asm!("", out("c2") _);
| ^^^^^^^^^^^
error: invalid register `c3`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:41:18
|
LL | asm!("", out("c3") _);
| ^^^^^^^^^^^
error: invalid register `c4`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:43:18
|
LL | asm!("", out("c4") _);
| ^^^^^^^^^^^
error: invalid register `c5`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:45:18
|
LL | asm!("", out("c5") _);
| ^^^^^^^^^^^
error: invalid register `c6`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:47:18
|
LL | asm!("", out("c6") _);
| ^^^^^^^^^^^
error: invalid register `c7`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:49:18
|
LL | asm!("", out("c7") _);
| ^^^^^^^^^^^
error: invalid register `c8`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:51:18
|
LL | asm!("", out("c8") _);
| ^^^^^^^^^^^
error: invalid register `c9`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:53:18
|
LL | asm!("", out("c9") _);
| ^^^^^^^^^^^
error: invalid register `c10`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:55:18
|
LL | asm!("", out("c10") _);
| ^^^^^^^^^^^^
error: invalid register `c11`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:57:18
|
LL | asm!("", out("c11") _);
| ^^^^^^^^^^^^
error: invalid register `c12`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:59:18
|
LL | asm!("", out("c12") _);
| ^^^^^^^^^^^^
error: invalid register `c13`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:61:18
|
LL | asm!("", out("c13") _);
| ^^^^^^^^^^^^
error: invalid register `c14`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:63:18
|
LL | asm!("", out("c14") _);
| ^^^^^^^^^^^^
error: invalid register `c15`: control registers are reserved by the kernel and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:65:18
|
LL | asm!("", out("c15") _);
| ^^^^^^^^^^^^
error: invalid register `a0`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:67:18
|
LL | asm!("", out("a0") _);
| ^^^^^^^^^^^
error: invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
--> $DIR/bad-reg.rs:69:18
|
LL | asm!("", out("a1") _);
| ^^^^^^^^^^^
error[E0658]: register class `vreg` can only be used as a clobber in stable
--> $DIR/bad-reg.rs:74:18
|
LL | asm!("", in("v0") v); // requires vector & asm_experimental_reg
| ^^^^^^^^^^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: register class `vreg` can only be used as a clobber in stable
--> $DIR/bad-reg.rs:78:18
|
LL | asm!("", out("v0") v); // requires vector & asm_experimental_reg
| ^^^^^^^^^^^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: register class `vreg` can only be used as a clobber in stable
--> $DIR/bad-reg.rs:82:18
|
LL | asm!("", in("v0") x); // requires vector & asm_experimental_reg
| ^^^^^^^^^^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: register class `vreg` can only be used as a clobber in stable
--> $DIR/bad-reg.rs:86:18
|
LL | asm!("", out("v0") x); // requires vector & asm_experimental_reg
| ^^^^^^^^^^^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: register class `vreg` can only be used as a clobber in stable
--> $DIR/bad-reg.rs:90:18
|
LL | asm!("", in("v0") b);
| ^^^^^^^^^^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: register class `vreg` can only be used as a clobber in stable
--> $DIR/bad-reg.rs:95:18
|
LL | asm!("", out("v0") b);
| ^^^^^^^^^^^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: register class `vreg` can only be used as a clobber in stable
--> $DIR/bad-reg.rs:100:26
|
LL | asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
| ^^^^^^^^^^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: register class `vreg` can only be used as a clobber in stable
--> $DIR/bad-reg.rs:104:26
|
LL | asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
| ^^^^^^^^^^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: register class `vreg` can only be used as a clobber in stable
--> $DIR/bad-reg.rs:108:26
|
LL | asm!("/* {} */", in(vreg) b);
| ^^^^^^^^^^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: register class `vreg` can only be used as a clobber in stable
--> $DIR/bad-reg.rs:113:26
|
LL | asm!("/* {} */", out(vreg) _); // requires vector & asm_experimental_reg
| ^^^^^^^^^^^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: register class `areg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:120:18
|
LL | asm!("", in("a2") x);
| ^^^^^^^^^^
error: register class `areg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:123:18
|
LL | asm!("", out("a2") x);
| ^^^^^^^^^^^
error: register class `areg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:126:26
|
LL | asm!("/* {} */", in(areg) x);
| ^^^^^^^^^^
error: register class `areg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:129:26
|
LL | asm!("/* {} */", out(areg) _);
| ^^^^^^^^^^^
error: register `f0` conflicts with register `v0`
--> $DIR/bad-reg.rs:134:31
|
LL | asm!("", out("v0") _, out("f0") _);
| ----------- ^^^^^^^^^^^ register `f0`
| |
| register `v0`
error: register `f1` conflicts with register `v1`
--> $DIR/bad-reg.rs:136:31
|
LL | asm!("", out("v1") _, out("f1") _);
| ----------- ^^^^^^^^^^^ register `f1`
| |
| register `v1`
error: register `f2` conflicts with register `v2`
--> $DIR/bad-reg.rs:138:31
|
LL | asm!("", out("v2") _, out("f2") _);
| ----------- ^^^^^^^^^^^ register `f2`
| |
| register `v2`
error: register `f3` conflicts with register `v3`
--> $DIR/bad-reg.rs:140:31
|
LL | asm!("", out("v3") _, out("f3") _);
| ----------- ^^^^^^^^^^^ register `f3`
| |
| register `v3`
error: register `f4` conflicts with register `v4`
--> $DIR/bad-reg.rs:142:31
|
LL | asm!("", out("v4") _, out("f4") _);
| ----------- ^^^^^^^^^^^ register `f4`
| |
| register `v4`
error: register `f5` conflicts with register `v5`
--> $DIR/bad-reg.rs:144:31
|
LL | asm!("", out("v5") _, out("f5") _);
| ----------- ^^^^^^^^^^^ register `f5`
| |
| register `v5`
error: register `f6` conflicts with register `v6`
--> $DIR/bad-reg.rs:146:31
|
LL | asm!("", out("v6") _, out("f6") _);
| ----------- ^^^^^^^^^^^ register `f6`
| |
| register `v6`
error: register `f7` conflicts with register `v7`
--> $DIR/bad-reg.rs:148:31
|
LL | asm!("", out("v7") _, out("f7") _);
| ----------- ^^^^^^^^^^^ register `f7`
| |
| register `v7`
error: register `f8` conflicts with register `v8`
--> $DIR/bad-reg.rs:150:31
|
LL | asm!("", out("v8") _, out("f8") _);
| ----------- ^^^^^^^^^^^ register `f8`
| |
| register `v8`
error: register `f9` conflicts with register `v9`
--> $DIR/bad-reg.rs:152:31
|
LL | asm!("", out("v9") _, out("f9") _);
| ----------- ^^^^^^^^^^^ register `f9`
| |
| register `v9`
error: register `f10` conflicts with register `v10`
--> $DIR/bad-reg.rs:154:32
|
LL | asm!("", out("v10") _, out("f10") _);
| ------------ ^^^^^^^^^^^^ register `f10`
| |
| register `v10`
error: register `f11` conflicts with register `v11`
--> $DIR/bad-reg.rs:156:32
|
LL | asm!("", out("v11") _, out("f11") _);
| ------------ ^^^^^^^^^^^^ register `f11`
| |
| register `v11`
error: register `f12` conflicts with register `v12`
--> $DIR/bad-reg.rs:158:32
|
LL | asm!("", out("v12") _, out("f12") _);
| ------------ ^^^^^^^^^^^^ register `f12`
| |
| register `v12`
error: register `f13` conflicts with register `v13`
--> $DIR/bad-reg.rs:160:32
|
LL | asm!("", out("v13") _, out("f13") _);
| ------------ ^^^^^^^^^^^^ register `f13`
| |
| register `v13`
error: register `f14` conflicts with register `v14`
--> $DIR/bad-reg.rs:162:32
|
LL | asm!("", out("v14") _, out("f14") _);
| ------------ ^^^^^^^^^^^^ register `f14`
| |
| register `v14`
error: register `f15` conflicts with register `v15`
--> $DIR/bad-reg.rs:164:32
|
LL | asm!("", out("v15") _, out("f15") _);
| ------------ ^^^^^^^^^^^^ register `f15`
| |
| register `v15`
error: invalid register `f16`: unknown register
--> $DIR/bad-reg.rs:167:32
|
LL | asm!("", out("v16") _, out("f16") _);
| ^^^^^^^^^^^^
error[E0658]: type `i64x2` cannot be used with this register class in stable
--> $DIR/bad-reg.rs:74:27
|
LL | asm!("", in("v0") v); // requires vector & asm_experimental_reg
| ^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: type `i64x2` cannot be used with this register class in stable
--> $DIR/bad-reg.rs:78:28
|
LL | asm!("", out("v0") v); // requires vector & asm_experimental_reg
| ^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: type `i32` cannot be used with this register class in stable
--> $DIR/bad-reg.rs:82:27
|
LL | asm!("", in("v0") x); // requires vector & asm_experimental_reg
| ^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: type `i32` cannot be used with this register class in stable
--> $DIR/bad-reg.rs:86:28
|
LL | asm!("", out("v0") x); // requires vector & asm_experimental_reg
| ^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: type `u8` cannot be used with this register class
--> $DIR/bad-reg.rs:90:27
|
LL | asm!("", in("v0") b);
| ^
|
= note: register class `vreg` supports these types:
error: type `u8` cannot be used with this register class
--> $DIR/bad-reg.rs:95:28
|
LL | asm!("", out("v0") b);
| ^
|
= note: register class `vreg` supports these types:
error[E0658]: type `i64x2` cannot be used with this register class in stable
--> $DIR/bad-reg.rs:100:35
|
LL | asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
| ^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: type `i32` cannot be used with this register class in stable
--> $DIR/bad-reg.rs:104:35
|
LL | asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
| ^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: type `u8` cannot be used with this register class
--> $DIR/bad-reg.rs:108:35
|
LL | asm!("/* {} */", in(vreg) b);
| ^
|
= note: register class `vreg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:120:27
|
LL | asm!("", in("a2") x);
| ^
|
= note: register class `areg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:123:28
|
LL | asm!("", out("a2") x);
| ^
|
= note: register class `areg` supports these types:
error: type `i32` cannot be used with this register class
--> $DIR/bad-reg.rs:126:35
|
LL | asm!("/* {} */", in(areg) x);
| ^
|
= note: register class `areg` supports these types:
error: aborting due to 63 previous errors
For more information about this error, try `rustc --explain E0658`.
@@ -1,4 +1,5 @@
// Issue 52126: With respect to variance, the assign-op's like += were
//! Test for https://github.com/rust-lang/rust/issues/52126
// With respect to variance, the assign-op's like += were
// accidentally lumped together with other binary op's. In both cases
// we were coercing the LHS of the op to the expected supertype.
//
@@ -1,5 +1,5 @@
error[E0597]: `line` does not live long enough
--> $DIR/issue-52126-assign-op-invariance.rs:34:28
--> $DIR/assign-op-invariance-lifetime.rs:35:28
|
LL | for line in vec!["123456789".to_string(), "12345678".to_string()] {
| ---- binding `line` declared here
@@ -1,5 +1,5 @@
//@ run-pass
// Regression test for #21400 which itself was extracted from
// Test for https://github.com/rust-lang/rust/issues/21400 extracted from
// stackoverflow.com/questions/28031155/is-my-borrow-checker-drunk/28031580
fn main() {
@@ -1,3 +1,4 @@
// Issue link https://github.com/rust-lang/rust/issues/45697
// Test that assignments to an `&mut` pointer which is found in a
// borrowed (but otherwise non-aliasable) location is illegal.
@@ -1,5 +1,5 @@
error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
--> $DIR/issue-45697.rs:20:9
--> $DIR/borrowed-mut-pointer-assign-overflow-off.rs:21:9
|
LL | let z = copy_borrowed_ptr(&mut y);
| ------ `y` is borrowed here
@@ -10,7 +10,7 @@ LL | *z.pointer += 1;
| --------------- borrow later used here
error[E0506]: cannot assign to `*y.pointer` because it is borrowed
--> $DIR/issue-45697.rs:20:9
--> $DIR/borrowed-mut-pointer-assign-overflow-off.rs:21:9
|
LL | let z = copy_borrowed_ptr(&mut y);
| ------ `*y.pointer` is borrowed here
@@ -1,3 +1,4 @@
// Issue link https://github.com/rust-lang/rust/issues/45697
// Test that assignments to an `&mut` pointer which is found in a
// borrowed (but otherwise non-aliasable) location is illegal.
@@ -1,5 +1,5 @@
error[E0503]: cannot use `*y.pointer` because it was mutably borrowed
--> $DIR/issue-45697-1.rs:20:9
--> $DIR/borrowed-mut-pointer-assign-overflow-on.rs:21:9
|
LL | let z = copy_borrowed_ptr(&mut y);
| ------ `y` is borrowed here
@@ -10,7 +10,7 @@ LL | *z.pointer += 1;
| --------------- borrow later used here
error[E0506]: cannot assign to `*y.pointer` because it is borrowed
--> $DIR/issue-45697-1.rs:20:9
--> $DIR/borrowed-mut-pointer-assign-overflow-on.rs:21:9
|
LL | let z = copy_borrowed_ptr(&mut y);
| ------ `*y.pointer` is borrowed here
@@ -1,6 +1,5 @@
//! Regression test for https://github.com/rust-lang/rust/issues/41498
//@ run-pass
// regression test for issue #41498.
struct S;
impl S {
fn mutate(&mut self) {}
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/40288
fn save_ref<'a>(refr: &'a i32, to: &mut [&'a i32]) {
for val in &mut *to {
*val = refr;
@@ -1,5 +1,5 @@
error[E0506]: cannot assign to `*refr` because it is borrowed
--> $DIR/issue-40288.rs:16:5
--> $DIR/cannot-assign-borrowed-ref-in-slice.rs:17:5
|
LL | save_ref(&*refr, &mut out);
| ------ `*refr` is borrowed here
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/41726
use std::collections::HashMap;
fn main() {
let things: HashMap<String, Vec<String>> = HashMap::new();
@@ -1,5 +1,5 @@
error[E0596]: cannot borrow data in an index of `HashMap<String, Vec<String>>` as mutable
--> $DIR/issue-41726.rs:5:9
--> $DIR/cannot-borrow-index-of-hashmap-in-for.rs:6:9
|
LL | things[src.as_str()].sort();
| ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/44405
use std::ops::Index;
struct Test;
@@ -1,5 +1,5 @@
error[E0596]: cannot borrow data in an index of `Container` as mutable
--> $DIR/issue-44405.rs:21:5
--> $DIR/cannot-borrow-index-output-mutably.rs:22:5
|
LL | container[&mut val].test();
| ^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/4335
#![feature(fn_traits)]
fn id<T>(t: T) -> T { t }
@@ -1,5 +1,5 @@
error[E0507]: cannot move out of `*v`, as `v` is a captured variable in an `FnMut` closure
--> $DIR/issue-4335.rs:6:20
--> $DIR/cannot-move-out-of-borrowed-ref-closure.rs:7:20
|
LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> {
| - ----- move occurs because `*v` has type `T`, which does not implement the `Copy` trait
@@ -12,7 +12,7 @@ LL | id(Box::new(|| *v))
|
= help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
help: if `T` implemented `Clone`, you could clone the value
--> $DIR/issue-4335.rs:5:10
--> $DIR/cannot-move-out-of-borrowed-ref-closure.rs:6:10
|
LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> {
| ^ consider constraining this type parameter with `Clone`
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/26619
pub struct History<'a> { pub _s: &'a str }
impl<'a> History<'a> {
@@ -1,5 +1,5 @@
error[E0515]: cannot return value referencing function parameter
--> $DIR/issue-26619.rs:5:76
--> $DIR/cannot-return-ref-to-fn-param-in-filter-map.rs:6:76
|
LL | for s in vec!["1|2".to_string()].into_iter().filter_map(|ref line| self.make_entry(line)) {
| -------- ^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
@@ -1,11 +1,11 @@
error[E0515]: cannot return reference to temporary value
--> $DIR/issue-27592.rs:16:14
--> $DIR/cannot-return-ref-to-temporary-format-args.rs:16:14
|
LL | write(|| format_args!("{}", String::from("Hello world")));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a reference to data owned by the current function
error[E0515]: cannot return value referencing temporary value
--> $DIR/issue-27592.rs:16:14
--> $DIR/cannot-return-ref-to-temporary-format-args.rs:16:14
|
LL | write(|| format_args!("{}", String::from("Hello world")));
| ^^^^^^^^^^^^^^^^^^^---------------------------^
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/18566
use std::ops::Deref;
struct MyPtr<'a>(&'a mut usize);
@@ -1,5 +1,5 @@
error[E0499]: cannot borrow `*s` as mutable more than once at a time
--> $DIR/issue-18566.rs:23:19
--> $DIR/deref-and-mut-borrow-conflict.rs:24:19
|
LL | MyPtr(s).poke(s);
| - ---- ^ second mutable borrow occurs here
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/28971
enum Foo {
Bar(u8)
}
@@ -1,5 +1,5 @@
error[E0599]: no variant, associated function, or constant named `Baz` found for enum `Foo` in the current scope
--> $DIR/issue-28971.rs:7:18
--> $DIR/fnmut-borrow-error-in-closure-match.rs:8:18
|
LL | enum Foo {
| -------- variant, associated function, or constant `Baz` not found for this enum
@@ -14,7 +14,7 @@ LL + Foo::Bar(..) => (),
|
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
--> $DIR/issue-28971.rs:15:5
--> $DIR/fnmut-borrow-error-in-closure-match.rs:16:5
|
LL | f();
| ^ cannot borrow as mutable
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/42106
fn do_something<T>(collection: &mut Vec<T>) {
let _a = &collection;
collection.swap(1, 2); //~ ERROR also borrowed as immutable
@@ -1,5 +1,5 @@
error[E0502]: cannot borrow `*collection` as mutable because it is also borrowed as immutable
--> $DIR/issue-42106.rs:3:5
--> $DIR/immutable-borrow-prevents-mut-method.rs:4:5
|
LL | let _a = &collection;
| ----------- immutable borrow occurs here
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/18783
use std::cell::RefCell;
fn main() {
@@ -1,5 +1,5 @@
error[E0499]: cannot borrow `y` as mutable more than once at a time
--> $DIR/issue-18783.rs:7:21
--> $DIR/mut-borrow-conflict-in-closures-vec.rs:8:21
|
LL | c.push(Box::new(|| y = 0));
| -- - first borrow occurs due to use of `y` in closure
@@ -14,7 +14,7 @@ LL | }
| - first borrow might be used here, when `c` is dropped and runs the destructor for type `RefCell<Vec<Box<dyn FnMut()>>>`
error[E0499]: cannot borrow `y` as mutable more than once at a time
--> $DIR/issue-18783.rs:16:29
--> $DIR/mut-borrow-conflict-in-closures-vec.rs:17:29
|
LL | Push::push(&c, Box::new(|| y = 0));
| -- - first borrow occurs due to use of `y` in closure
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/25579
//@ check-pass
enum Sexpression {
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/28839
//@ run-pass
pub struct Foo;
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/29053
//@ run-pass
fn main() {
let x: &'static str = "x";
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/47703
//@ check-pass
struct MyStruct<'a> {
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/47703
//@ check-pass
struct AtomicRefMut<'a> {
@@ -1,3 +1,4 @@
//! Regression test for https://github.com/rust-lang/rust/issues/47703
//@ check-pass
struct WithDrop;
@@ -1,5 +1,5 @@
error[E0382]: use of moved value: `s`
--> $DIR/issue-29723.rs:10:13
--> $DIR/use-moved-value-in-match-guard-drop.rs:10:13
|
LL | let s = String::new();
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait
@@ -16,7 +16,7 @@ LL | 0 if { drop(s.clone()); false } => String::from("oops"),
| ++++++++
error[E0382]: use of moved value: `s`
--> $DIR/issue-29723.rs:18:14
--> $DIR/use-moved-value-in-match-guard-drop.rs:18:14
|
LL | let s = String::new();
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait
@@ -0,0 +1,23 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/151311>
//@ edition: 2024
//@ compile-flags: -Znext-solver=globally
#![feature(unsafe_binders)]
use std::ops::Deref;
trait Foo: Deref<Target = unsafe<'a> &'a dyn Bar> {
fn method(self: &unsafe<'ops> &'a Bar) {}
//~^ ERROR expected a type, found a trait
//~| ERROR use of undeclared lifetime name `'a`
}
trait Bar {}
fn test(x: &dyn Foo) {
//~^ ERROR the trait `Foo` is not dyn compatible
x.method();
//~^ ERROR no method named `method` found for reference `&dyn Foo`
}
fn main() {}
@@ -0,0 +1,62 @@
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:36
|
LL | fn method(self: &unsafe<'ops> &'a Bar) {}
| ^^ undeclared lifetime
|
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the type lifetime-generic with a new `'a` lifetime
|
LL | fn method(self: &unsafe<'a, 'ops> &'a Bar) {}
| +++
help: consider introducing lifetime `'a` here
|
LL | fn method<'a>(self: &unsafe<'ops> &'a Bar) {}
| ++++
help: consider introducing lifetime `'a` here
|
LL | trait Foo<'a>: Deref<Target = unsafe<'a> &'a dyn Bar> {
| ++++
error[E0782]: expected a type, found a trait
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:39
|
LL | fn method(self: &unsafe<'ops> &'a Bar) {}
| ^^^
|
help: you can add the `dyn` keyword if you want a trait object
|
LL | fn method(self: &unsafe<'ops> &'a dyn Bar) {}
| +++
error[E0038]: the trait `Foo` is not dyn compatible
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:17:13
|
LL | fn method(self: &unsafe<'ops> &'a Bar) {}
| --------------------- help: consider changing method `method`'s `self` parameter to be `&self`: `&Self`
...
LL | fn test(x: &dyn Foo) {
| ^^^^^^^ `Foo` is not dyn compatible
|
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:10:21
|
LL | trait Foo: Deref<Target = unsafe<'a> &'a dyn Bar> {
| --- this trait is not dyn compatible...
LL | fn method(self: &unsafe<'ops> &'a Bar) {}
| ^^^^^^^^^^^^^^^^^^^^^ ...because method `method`'s `self` parameter cannot be dispatched on
error[E0599]: no method named `method` found for reference `&dyn Foo` in the current scope
--> $DIR/unsafe-binders-bare-trait-object-next-solver.rs:19:7
|
LL | fn method(self: &unsafe<'ops> &'a Bar) {}
| --------------------- the method might not be found because of this arbitrary self type
...
LL | x.method();
| ^^^^^^ method not found in `&dyn Foo`
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0038, E0261, E0599, E0782.
For more information about an error, try `rustc --explain E0038`.
@@ -0,0 +1,18 @@
#[derive(PartialEq)]
struct T { pub x: i32 }
#[derive(PartialEq)]
struct U { }
fn main() {
// Parser will report an error here
if T { x: 10 } == T {} {}
//~^ ERROR struct literals are not allowed here
//~| ERROR expected value, found struct `T`
// Regression test for the `followed_by_brace` helper:
// comments inside the braces should not suppress the parenthesized struct literal suggestion.
if U { /* keep comment here */ } == U {}
//~^ ERROR E0423
//~| ERROR expected expression, found `==`
}
@@ -0,0 +1,42 @@
error: struct literals are not allowed here
--> $DIR/E0423-struct-literal-comment.rs:9:8
|
LL | if T { x: 10 } == T {} {}
| ^^^^^^^^^^^
|
help: surround the struct literal with parentheses
|
LL | if (T { x: 10 }) == T {} {}
| + +
error: expected expression, found `==`
--> $DIR/E0423-struct-literal-comment.rs:15:38
|
LL | if U { /* keep comment here */ } == U {}
| ^^ expected expression
error[E0423]: expected value, found struct `T`
--> $DIR/E0423-struct-literal-comment.rs:9:23
|
LL | if T { x: 10 } == T {} {}
| ^ not a value
|
help: surround the struct literal with parentheses
|
LL | if T { x: 10 } == (T {}) {}
| + +
error[E0423]: expected value, found struct `U`
--> $DIR/E0423-struct-literal-comment.rs:15:8
|
LL | if U { /* keep comment here */ } == U {}
| ^ not a value
|
help: surround the struct literal with parentheses
|
LL | if (U { /* keep comment here */ }) == U {}
| + +
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0423`.
@@ -1,6 +1,6 @@
//@ add-minicore
//@ compile-flags: --target s390x-unknown-linux-gnu
//@ needs-llvm-components: systemz
//@ compile-flags: --target x86_64-unknown-linux-gnu
//@ needs-llvm-components: x86
//@ ignore-backends: gcc
#![feature(no_core, lang_items, rustc_attrs)]
@@ -11,7 +11,6 @@
use minicore::*;
unsafe fn main() {
asm!("", in("v0") 0);
//~^ ERROR register class `vreg` can only be used as a clobber in stable
//~| ERROR type `i32` cannot be used with this register class
asm!("{:x}", in(xmm_reg) 0u128);
//~^ ERROR type `u128` cannot be used with this register class in stable
}
@@ -1,23 +1,13 @@
error[E0658]: register class `vreg` can only be used as a clobber in stable
--> $DIR/feature-gate-asm_experimental_reg.rs:14:14
error[E0658]: type `u128` cannot be used with this register class in stable
--> $DIR/feature-gate-asm_experimental_reg.rs:14:30
|
LL | asm!("", in("v0") 0);
| ^^^^^^^^^^
LL | asm!("{:x}", in(xmm_reg) 0u128);
| ^^^^^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: type `i32` cannot be used with this register class in stable
--> $DIR/feature-gate-asm_experimental_reg.rs:14:23
|
LL | asm!("", in("v0") 0);
| ^
|
= note: see issue #133416 <https://github.com/rust-lang/rust/issues/133416> for more information
= help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 2 previous errors
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0658`.
@@ -0,0 +1,34 @@
error: lifetime may not live long enough
--> $DIR/invariant.rs:15:5
|
LL | fn assert_invariant<'a, 'b>(x: field_of!(Struct<'a>, field), y: field_of!(Struct<'b>, field)) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | consume(x, y);
| ^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
= note: requirement occurs because of the type `field_of!(Struct<'_>, field)`, which makes the generic argument `Struct<'_>` invariant
= note: the struct `FieldRepresentingType<T, VARIANT, FIELD>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/invariant.rs:15:5
|
LL | fn assert_invariant<'a, 'b>(x: field_of!(Struct<'a>, field), y: field_of!(Struct<'b>, field)) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | consume(x, y);
| ^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
= note: requirement occurs because of the type `field_of!(Struct<'_>, field)`, which makes the generic argument `Struct<'_>` invariant
= note: the struct `FieldRepresentingType<T, VARIANT, FIELD>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'a` and `'b` must be the same: replace one with the other
error: aborting due to 2 previous errors
@@ -0,0 +1,34 @@
error: lifetime may not live long enough
--> $DIR/invariant.rs:15:5
|
LL | fn assert_invariant<'a, 'b>(x: field_of!(Struct<'a>, field), y: field_of!(Struct<'b>, field)) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | consume(x, y);
| ^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
= note: requirement occurs because of the type `field_of!(Struct<'_>, field)`, which makes the generic argument `Struct<'_>` invariant
= note: the struct `FieldRepresentingType<T, VARIANT, FIELD>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/invariant.rs:15:5
|
LL | fn assert_invariant<'a, 'b>(x: field_of!(Struct<'a>, field), y: field_of!(Struct<'b>, field)) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | consume(x, y);
| ^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
= note: requirement occurs because of the type `field_of!(Struct<'_>, field)`, which makes the generic argument `Struct<'_>` invariant
= note: the struct `FieldRepresentingType<T, VARIANT, FIELD>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'a` and `'b` must be the same: replace one with the other
error: aborting due to 2 previous errors
@@ -0,0 +1,20 @@
//@ revisions: old next
//@ [next] compile-flags: -Znext-solver
#![expect(incomplete_features)]
#![feature(field_projections)]
use std::field::field_of;
pub struct Struct<'a> {
field: &'a (),
}
fn consume<'a>(_: field_of!(Struct<'a>, field), _: field_of!(Struct<'a>, field)) {}
fn assert_invariant<'a, 'b>(x: field_of!(Struct<'a>, field), y: field_of!(Struct<'b>, field)) {
consume(x, y);
//~^ ERROR: lifetime may not live long enough
//~^^ ERROR: lifetime may not live long enough
}
fn main() {}
@@ -0,0 +1,20 @@
// Regression test for <https://github.com/rust-lang/rust/issues/154900>.
//
//@ check-pass
#![feature(never_type)]
#![crate_type = "lib"]
#![warn(unreachable_code)]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct S(!);
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct S2 {
f: !,
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum E {
E2(!),
E3 { f: ! },
}
@@ -569,6 +569,7 @@ note: `Result<!, !>` defined here
= note: not covered
= note: the matched value is of type `Result<!, !>`
= note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
= note: match arms with guards don't count towards exhaustivity
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL ~ Err(_) => {},
@@ -569,6 +569,7 @@ note: `Result<!, !>` defined here
= note: not covered
= note: the matched value is of type `Result<!, !>`
= note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required
= note: match arms with guards don't count towards exhaustivity
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL ~ Err(_) => {},
@@ -5,6 +5,7 @@ LL | match 0u8 {
| ^^^ pattern `128_u8..=u8::MAX` not covered
|
= note: the matched value is of type `u8`
= note: match arms with guards don't count towards exhaustivity
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL ~ 128 ..= 255 if true => {},
@@ -20,6 +20,7 @@ LL | match "world" {
|
= note: the matched value is of type `&str`
= note: `&str` cannot be matched exhaustively, so a wildcard `_` is necessary
= note: match arms with guards don't count towards exhaustivity
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL ~ "hello" => {},

Some files were not shown because too many files have changed in this diff Show More