mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
///
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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 @@
|
||||
562dee4820c458d823175268e41601d4c060588a
|
||||
30d0309fa821f7a0984a9629e0d227ca3c0d2eda
|
||||
|
||||
@@ -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_*`.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ID‑lowering 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` visibility–related `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` visibility–related `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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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]`. We’ll 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]`.
|
||||
We’ll 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 |
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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);
|
||||
| ^
|
||||
|
||||
@@ -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`.
|
||||
+2
-1
@@ -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
-1
@@ -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
-1
@@ -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
@@ -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.
|
||||
|
||||
+2
-2
@@ -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
@@ -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.
|
||||
|
||||
+2
-2
@@ -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
@@ -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
-1
@@ -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
@@ -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
-1
@@ -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
@@ -1,3 +1,4 @@
|
||||
//! Regression test for https://github.com/rust-lang/rust/issues/44405
|
||||
use std::ops::Index;
|
||||
|
||||
struct Test;
|
||||
+1
-1
@@ -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
@@ -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 }
|
||||
+2
-2
@@ -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
@@ -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
-1
@@ -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
|
||||
+2
-2
@@ -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
-1
@@ -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
@@ -1,3 +1,4 @@
|
||||
//! Regression test for https://github.com/rust-lang/rust/issues/28971
|
||||
enum Foo {
|
||||
Bar(u8)
|
||||
}
|
||||
+2
-2
@@ -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
@@ -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
-1
@@ -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
@@ -1,3 +1,4 @@
|
||||
//! Regression test for https://github.com/rust-lang/rust/issues/18783
|
||||
use std::cell::RefCell;
|
||||
|
||||
fn main() {
|
||||
+2
-2
@@ -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
@@ -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
@@ -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
@@ -1,3 +1,4 @@
|
||||
//! Regression test for https://github.com/rust-lang/rust/issues/47703
|
||||
//@ check-pass
|
||||
|
||||
struct MyStruct<'a> {
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
//! Regression test for https://github.com/rust-lang/rust/issues/47703
|
||||
//@ check-pass
|
||||
|
||||
struct AtomicRefMut<'a> {
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
//! Regression test for https://github.com/rust-lang/rust/issues/47703
|
||||
//@ check-pass
|
||||
|
||||
struct WithDrop;
|
||||
+2
-2
@@ -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
Reference in New Issue
Block a user