diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index 2d378013dd053..3b37a393846b2 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -41,3 +41,112 @@ parser_switch_mut_let_order = parser_missing_let_before_mut = missing keyword parser_use_let_not_auto = write `let` instead of `auto` to introduce a new variable parser_use_let_not_var = write `let` instead of `var` to introduce a new variable + +parser_invalid_comparison_operator = invalid comparison operator `{$invalid}` + .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}` + .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering` + +parser_invalid_logical_operator = `{$incorrect}` is not a logical operator + .note = unlike in e.g., python and PHP, `&&` and `||` are used for logical operators + .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction + .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction + +parser_tilde_is_not_unary_operator = `~` cannot be used as a unary operator + .suggestion = use `!` to perform bitwise not + +parser_unexpected_token_after_not = unexpected {$negated_desc} after identifier + .suggestion = use `!` to perform logical negation + +parser_malformed_loop_label = malformed loop label + .suggestion = use the correct loop label format + +parser_lifetime_in_borrow_expression = borrow expressions cannot be annotated with lifetimes + .suggestion = remove the lifetime annotation + .label = annotated with lifetime here + +parser_field_expression_with_generic = field expressions cannot have generic arguments + +parser_macro_invocation_with_qualified_path = macros cannot use qualified paths + +parser_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label + +parser_require_colon_after_labeled_expression = labeled expression must be followed by `:` + .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them + .label = the label + .suggestion = add `:` after the label + +parser_do_catch_syntax_removed = found removed `do catch` syntax + .note = following RFC #2388, the new non-placeholder syntax is `try` + .suggestion = replace with the new syntax + +parser_float_literal_requires_integer_part = float literals must have an integer part + .suggestion = must have an integer part + +parser_invalid_int_literal_width = invalid width `{$width}` for integer literal + .help = valid widths are 8, 16, 32, 64 and 128 + +parser_invalid_num_literal_base_prefix = invalid base prefix for number literal + .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase + .suggestion = try making the prefix lowercase + +parser_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal + .label = invalid suffix `{$suffix}` + .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +parser_invalid_float_literal_width = invalid width `{$width}` for float literal + .help = valid widths are 32 and 64 + +parser_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal + .label = invalid suffix `{$suffix}` + .help = valid suffixes are `f32` and `f64` + +parser_int_literal_too_large = integer literal is too large + +parser_missing_semicolon_before_array = expected `;`, found `[` + .suggestion = consider adding `;` here + +parser_invalid_block_macro_segment = cannot use a `block` macro fragment here + .label = the `block` fragment is within this context + +parser_if_expression_missing_then_block = this `if` expression is missing a block after the condition + .add_then_block = add a block here + .condition_possibly_unfinished = this binary operation is possibly unfinished + +parser_if_expression_missing_condition = missing condition for `if` expression + .condition_label = expected condition here + .block_label = if this block is the condition of the `if` expression, then it must be followed by another block + +parser_expected_expression_found_let = expected expression, found `let` statement + +parser_expected_else_block = expected `{"{"}`, found {$first_tok} + .label = expected an `if` or a block after this `else` + .suggestion = add an `if` if this is the condition of a chained `else if` statement + +parser_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches + .branch_label = the attributes are attached to this branch + .ctx_label = the branch belongs to this `{$ctx}` + .suggestion = remove the attributes + +parser_missing_in_in_for_loop = missing `in` in `for` loop + .use_in_not_of = try using `in` here instead + .add_in = try adding `in` here + +parser_missing_comma_after_match_arm = expected `,` following `match` arm + .suggestion = missing a comma here to end this `match` arm + +parser_catch_after_try = keyword `catch` cannot follow a `try` block + .help = try using `match` on the result of the `try` block instead + +parser_comma_after_base_struct = cannot use a comma after the base struct + .note = the base struct must always be the last field + .suggestion = remove this comma + +parser_eq_field_init = expected `:`, found `=` + .suggestion = replace equals symbol with a colon + +parser_dotdotdot = unexpected token: `...` + .suggest_exclusive_range = use `..` for an exclusive range + .suggest_inclusive_range = or `..=` for an inclusive range + +parser_left_arrow_operator = unexpected token: `<-` + .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-` diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 0a660ef30c88e..443626d14b9f6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -364,8 +364,8 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> { /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` /// works well. #[derive(Clone)] -struct PatStack<'p, 'tcx> { - pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, +pub(crate) struct PatStack<'p, 'tcx> { + pub(crate) pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, } impl<'p, 'tcx> PatStack<'p, 'tcx> { @@ -403,6 +403,21 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { }) } + // Recursively expand all patterns into their subpatterns and push each `PatStack` to matrix. + fn expand_and_extend<'a>(&'a self, matrix: &mut Matrix<'p, 'tcx>) { + if !self.is_empty() && self.head().is_or_pat() { + for pat in self.head().iter_fields() { + let mut new_patstack = PatStack::from_pattern(pat); + new_patstack.pats.extend_from_slice(&self.pats[1..]); + if !new_patstack.is_empty() && new_patstack.head().is_or_pat() { + new_patstack.expand_and_extend(matrix); + } else if !new_patstack.is_empty() { + matrix.push(new_patstack); + } + } + } + } + /// This computes `S(self.head().ctor(), self)`. See top of the file for explanations. /// /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing @@ -436,7 +451,7 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> { /// A 2D matrix. #[derive(Clone)] pub(super) struct Matrix<'p, 'tcx> { - patterns: Vec>, + pub patterns: Vec>, } impl<'p, 'tcx> Matrix<'p, 'tcx> { @@ -453,7 +468,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { /// expands it. fn push(&mut self, row: PatStack<'p, 'tcx>) { if !row.is_empty() && row.head().is_or_pat() { - self.patterns.extend(row.expand_or_pat()); + row.expand_and_extend(self); } else { self.patterns.push(row); } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index d7facb29714bc..2c9f9a2c2c200 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -363,6 +363,349 @@ pub enum InvalidVariableDeclarationSub { UseLetNotVar(#[primary_span] Span), } +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_comparison_operator)] +pub(crate) struct InvalidComparisonOperator { + #[primary_span] + pub span: Span, + pub invalid: String, + #[subdiagnostic] + pub sub: InvalidComparisonOperatorSub, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum InvalidComparisonOperatorSub { + #[suggestion_short( + parser::use_instead, + applicability = "machine-applicable", + code = "{correct}" + )] + Correctable { + #[primary_span] + span: Span, + invalid: String, + correct: String, + }, + #[label(parser::spaceship_operator_invalid)] + Spaceship(#[primary_span] Span), +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_logical_operator)] +#[note] +pub(crate) struct InvalidLogicalOperator { + #[primary_span] + pub span: Span, + pub incorrect: String, + #[subdiagnostic] + pub sub: InvalidLogicalOperatorSub, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum InvalidLogicalOperatorSub { + #[suggestion_short( + parser::use_amp_amp_for_conjunction, + applicability = "machine-applicable", + code = "&&" + )] + Conjunction(#[primary_span] Span), + #[suggestion_short( + parser::use_pipe_pipe_for_disjunction, + applicability = "machine-applicable", + code = "||" + )] + Disjunction(#[primary_span] Span), +} + +#[derive(SessionDiagnostic)] +#[diag(parser::tilde_is_not_unary_operator)] +pub(crate) struct TildeAsUnaryOperator( + #[primary_span] + #[suggestion_short(applicability = "machine-applicable", code = "!")] + pub Span, +); + +#[derive(SessionDiagnostic)] +#[diag(parser::unexpected_token_after_not)] +pub(crate) struct NotAsNegationOperator { + #[primary_span] + pub negated: Span, + pub negated_desc: String, + #[suggestion_short(applicability = "machine-applicable", code = "!")] + pub not: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::malformed_loop_label)] +pub(crate) struct MalformedLoopLabel { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "{correct_label}")] + pub span: Span, + pub correct_label: Ident, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::lifetime_in_borrow_expression)] +pub(crate) struct LifetimeInBorrowExpression { + #[primary_span] + pub span: Span, + #[suggestion(applicability = "machine-applicable", code = "")] + #[label] + pub lifetime_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::field_expression_with_generic)] +pub(crate) struct FieldExpressionWithGeneric(#[primary_span] pub Span); + +#[derive(SessionDiagnostic)] +#[diag(parser::macro_invocation_with_qualified_path)] +pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span); + +#[derive(SessionDiagnostic)] +#[diag(parser::unexpected_token_after_label)] +pub(crate) struct UnexpectedTokenAfterLabel( + #[primary_span] + #[label(parser::unexpected_token_after_label)] + pub Span, +); + +#[derive(SessionDiagnostic)] +#[diag(parser::require_colon_after_labeled_expression)] +#[note] +pub(crate) struct RequireColonAfterLabeledExpression { + #[primary_span] + pub span: Span, + #[label] + pub label: Span, + #[suggestion_short(applicability = "machine-applicable", code = ": ")] + pub label_end: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::do_catch_syntax_removed)] +#[note] +pub(crate) struct DoCatchSyntaxRemoved { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "try")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::float_literal_requires_integer_part)] +pub(crate) struct FloatLiteralRequiresIntegerPart { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "{correct}")] + pub span: Span, + pub correct: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_int_literal_width)] +#[help] +pub(crate) struct InvalidIntLiteralWidth { + #[primary_span] + pub span: Span, + pub width: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_num_literal_base_prefix)] +#[note] +pub(crate) struct InvalidNumLiteralBasePrefix { + #[primary_span] + #[suggestion(applicability = "maybe-incorrect", code = "{fixed}")] + pub span: Span, + pub fixed: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_num_literal_suffix)] +#[help] +pub(crate) struct InvalidNumLiteralSuffix { + #[primary_span] + #[label] + pub span: Span, + pub suffix: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_float_literal_width)] +#[help] +pub(crate) struct InvalidFloatLiteralWidth { + #[primary_span] + pub span: Span, + pub width: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_float_literal_suffix)] +#[help] +pub(crate) struct InvalidFloatLiteralSuffix { + #[primary_span] + #[label] + pub span: Span, + pub suffix: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::int_literal_too_large)] +pub(crate) struct IntLiteralTooLarge { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::missing_semicolon_before_array)] +pub(crate) struct MissingSemicolonBeforeArray { + #[primary_span] + pub open_delim: Span, + #[suggestion_verbose(applicability = "maybe-incorrect", code = ";")] + pub semicolon: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_block_macro_segment)] +pub(crate) struct InvalidBlockMacroSegment { + #[primary_span] + pub span: Span, + #[label] + pub context: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::if_expression_missing_then_block)] +pub(crate) struct IfExpressionMissingThenBlock { + #[primary_span] + pub if_span: Span, + #[subdiagnostic] + pub sub: IfExpressionMissingThenBlockSub, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum IfExpressionMissingThenBlockSub { + #[help(parser::condition_possibly_unfinished)] + UnfinishedCondition(#[primary_span] Span), + #[help(parser::add_then_block)] + AddThenBlock(#[primary_span] Span), +} + +#[derive(SessionDiagnostic)] +#[diag(parser::if_expression_missing_condition)] +pub(crate) struct IfExpressionMissingCondition { + #[primary_span] + #[label(parser::condition_label)] + pub if_span: Span, + #[label(parser::block_label)] + pub block_span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::expected_expression_found_let)] +pub(crate) struct ExpectedExpressionFoundLet { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::expected_else_block)] +pub(crate) struct ExpectedElseBlock { + #[primary_span] + pub first_tok_span: Span, + pub first_tok: String, + #[label] + pub else_span: Span, + #[suggestion(applicability = "maybe-incorrect", code = "if ")] + pub condition_start: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::outer_attribute_not_allowed_on_if_else)] +pub(crate) struct OuterAttributeNotAllowedOnIfElse { + #[primary_span] + pub last: Span, + + #[label(parser::branch_label)] + pub branch_span: Span, + + #[label(parser::ctx_label)] + pub ctx_span: Span, + pub ctx: String, + + #[suggestion(applicability = "machine-applicable", code = "")] + pub attributes: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::missing_in_in_for_loop)] +pub(crate) struct MissingInInForLoop { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: MissingInInForLoopSub, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum MissingInInForLoopSub { + // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect + #[suggestion_short(parser::use_in_not_of, applicability = "maybe-incorrect", code = "in")] + InNotOf(#[primary_span] Span), + #[suggestion_short(parser::add_in, applicability = "maybe-incorrect", code = " in ")] + AddIn(#[primary_span] Span), +} + +#[derive(SessionDiagnostic)] +#[diag(parser::missing_comma_after_match_arm)] +pub(crate) struct MissingCommaAfterMatchArm { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = ",")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::catch_after_try)] +#[help] +pub(crate) struct CatchAfterTry { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::comma_after_base_struct)] +#[note] +pub(crate) struct CommaAfterBaseStruct { + #[primary_span] + pub span: Span, + #[suggestion_short(applicability = "machine-applicable", code = "")] + pub comma: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::eq_field_init)] +pub(crate) struct EqFieldInit { + #[primary_span] + pub span: Span, + #[suggestion(applicability = "machine-applicable", code = ":")] + pub eq: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::dotdotdot)] +pub(crate) struct DotDotDot { + #[primary_span] + #[suggestion(parser::suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")] + #[suggestion(parser::suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::left_arrow_operator)] +pub(crate) struct LeftArrowOperator { + #[primary_span] + #[suggestion(applicability = "maybe-incorrect", code = "< -")] + pub span: Span, +} + // SnapshotParser is used to create a snapshot of the parser // without causing duplicate errors being emitted when the `Parser` // is dropped. diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9fb9199231fb0..17117cbc8fbe6 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,4 +1,14 @@ -use super::diagnostics::SnapshotParser; +use super::diagnostics::{ + CatchAfterTry, CommaAfterBaseStruct, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, + ExpectedElseBlock, ExpectedExpressionFoundLet, FieldExpressionWithGeneric, + FloatLiteralRequiresIntegerPart, IfExpressionMissingCondition, IfExpressionMissingThenBlock, + IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator, + InvalidComparisonOperatorSub, InvalidLogicalOperator, InvalidLogicalOperatorSub, + LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, + MalformedLoopLabel, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray, + NotAsNegationOperator, OuterAttributeNotAllowedOnIfElse, RequireColonAfterLabeledExpression, + SnapshotParser, TildeAsUnaryOperator, UnexpectedTokenAfterLabel, +}; use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ @@ -6,6 +16,11 @@ use super::{ SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken, }; use crate::maybe_recover_from_interpolated_ty_qpath; +use crate::parser::diagnostics::{ + IntLiteralTooLarge, InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth, + InvalidIntLiteralWidth, InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix, + MissingCommaAfterMatchArm, +}; use core::mem; use rustc_ast::ptr::P; @@ -20,9 +35,10 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; use rustc_ast::{ClosureBinder, StmtKind}; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult}; +use rustc_errors::{Applicability, Diagnostic, PResult}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_session::lint::BuiltinLintDiagnostics; +use rustc_session::SessionDiagnostic; use rustc_span::source_map::{self, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Pos}; @@ -216,15 +232,18 @@ impl<'a> Parser<'a> { AssocOp::Equal => "==", AssocOp::NotEqual => "!=", _ => unreachable!(), - }; - self.struct_span_err(sp, &format!("invalid comparison operator `{sugg}=`")) - .span_suggestion_short( - sp, - &format!("`{s}=` is not a valid comparison operator, use `{s}`", s = sugg), - sugg, - Applicability::MachineApplicable, - ) - .emit(); + } + .into(); + let invalid = format!("{}=", &sugg); + self.sess.emit_err(InvalidComparisonOperator { + span: sp, + invalid: invalid.clone(), + sub: InvalidComparisonOperatorSub::Correctable { + span: sp, + invalid, + correct: sugg, + }, + }); self.bump(); } @@ -234,14 +253,15 @@ impl<'a> Parser<'a> { && self.prev_token.span.hi() == self.token.span.lo() { let sp = op.span.to(self.token.span); - self.struct_span_err(sp, "invalid comparison operator `<>`") - .span_suggestion_short( - sp, - "`<>` is not a valid comparison operator, use `!=`", - "!=", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(InvalidComparisonOperator { + span: sp, + invalid: "<>".into(), + sub: InvalidComparisonOperatorSub::Correctable { + span: sp, + invalid: "<>".into(), + correct: "!=".into(), + }, + }); self.bump(); } @@ -251,12 +271,11 @@ impl<'a> Parser<'a> { && self.prev_token.span.hi() == self.token.span.lo() { let sp = op.span.to(self.token.span); - self.struct_span_err(sp, "invalid comparison operator `<=>`") - .span_label( - sp, - "`<=>` is not a valid comparison operator, use `std::cmp::Ordering`", - ) - .emit(); + self.sess.emit_err(InvalidComparisonOperator { + span: sp, + invalid: "<=>".into(), + sub: InvalidComparisonOperatorSub::Spaceship(sp), + }); self.bump(); } @@ -430,11 +449,19 @@ impl<'a> Parser<'a> { } (Some(op), _) => (op, self.token.span), (None, Some((Ident { name: sym::and, span }, false))) => { - self.error_bad_logical_op("and", "&&", "conjunction"); + self.sess.emit_err(InvalidLogicalOperator { + span: self.token.span, + incorrect: "and".into(), + sub: InvalidLogicalOperatorSub::Conjunction(self.token.span), + }); (AssocOp::LAnd, span) } (None, Some((Ident { name: sym::or, span }, false))) => { - self.error_bad_logical_op("or", "||", "disjunction"); + self.sess.emit_err(InvalidLogicalOperator { + span: self.token.span, + incorrect: "or".into(), + sub: InvalidLogicalOperatorSub::Disjunction(self.token.span), + }); (AssocOp::LOr, span) } _ => return None, @@ -442,19 +469,6 @@ impl<'a> Parser<'a> { Some(source_map::respan(span, op)) } - /// Error on `and` and `or` suggesting `&&` and `||` respectively. - fn error_bad_logical_op(&self, bad: &str, good: &str, english: &str) { - self.struct_span_err(self.token.span, &format!("`{bad}` is not a logical operator")) - .span_suggestion_short( - self.token.span, - &format!("use `{good}` to perform logical {english}"), - good, - Applicability::MachineApplicable, - ) - .note("unlike in e.g., python and PHP, `&&` and `||` are used for logical operators") - .emit(); - } - /// Checks if this expression is a successfully parsed statement. fn expr_is_complete(&self, e: &Expr) -> bool { self.restrictions.contains(Restrictions::STMT_EXPR) @@ -619,14 +633,7 @@ impl<'a> Parser<'a> { // Recover on `!` suggesting for bitwise negation instead. fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { - self.struct_span_err(lo, "`~` cannot be used as a unary operator") - .span_suggestion_short( - lo, - "use `!` to perform bitwise not", - "!", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(TildeAsUnaryOperator(lo)); self.parse_unary_expr(lo, UnOp::Not) } @@ -652,20 +659,14 @@ impl<'a> Parser<'a> { /// Recover on `not expr` in favor of `!expr`. fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { // Emit the error... - let not_token = self.look_ahead(1, |t| t.clone()); - self.struct_span_err( - not_token.span, - &format!("unexpected {} after identifier", super::token_descr(¬_token)), - ) - .span_suggestion_short( + let negated_token = self.look_ahead(1, |t| t.clone()); + self.sess.emit_err(NotAsNegationOperator { + negated: negated_token.span, + negated_desc: super::token_descr(&negated_token), // Span the `not` plus trailing whitespace to avoid // trailing whitespace after the `!` in our suggestion - self.sess.source_map().span_until_non_whitespace(lo.to(not_token.span)), - "use `!` to perform logical negation", - "!", - Applicability::MachineApplicable, - ) - .emit(); + not: self.sess.source_map().span_until_non_whitespace(lo.to(negated_token.span)), + }); // ...and recover! self.parse_unary_expr(lo, UnOp::Not) @@ -725,14 +726,10 @@ impl<'a> Parser<'a> { match self.parse_labeled_expr(label, false) { Ok(expr) => { type_err.cancel(); - self.struct_span_err(label.ident.span, "malformed loop label") - .span_suggestion( - label.ident.span, - "use the correct loop label format", - label.ident, - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(MalformedLoopLabel { + span: label.ident.span, + correct_label: label.ident, + }); return Ok(expr); } Err(err) => { @@ -910,15 +907,7 @@ impl<'a> Parser<'a> { } fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) { - self.struct_span_err(span, "borrow expressions cannot be annotated with lifetimes") - .span_label(lt_span, "annotated with lifetime here") - .span_suggestion( - lt_span, - "remove the lifetime annotation", - "", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(LifetimeInBorrowExpression { span, lifetime_span: lt_span }); } /// Parse `mut?` or `raw [ const | mut ]`. @@ -1272,11 +1261,7 @@ impl<'a> Parser<'a> { } else { // Field access `expr.f` if let Some(args) = segment.args { - self.struct_span_err( - args.span(), - "field expressions cannot have generic arguments", - ) - .emit(); + self.sess.emit_err(FieldExpressionWithGeneric(args.span())); } let span = lo.to(self.prev_token.span); @@ -1489,7 +1474,7 @@ impl<'a> Parser<'a> { let (span, kind) = if self.eat(&token::Not) { // MACRO INVOCATION expression if qself.is_some() { - self.struct_span_err(path.span, "macros cannot use qualified paths").emit(); + self.sess.emit_err(MacroInvocationWithQualifiedPath(path.span)); } let lo = path.span; let mac = P(MacCall { @@ -1535,11 +1520,11 @@ impl<'a> Parser<'a> { && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt)) { // We're probably inside of a `Path<'a>` that needs a turbofish - let msg = "expected `while`, `for`, `loop` or `{` after a label"; - self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit(); + self.sess.emit_err(UnexpectedTokenAfterLabel(self.token.span)); consume_colon = false; Ok(self.mk_expr_err(lo)) } else { + // FIXME: use UnexpectedTokenAfterLabel, needs multipart suggestions let msg = "expected `while`, `for`, `loop` or `{` after a label"; let mut err = self.struct_span_err(self.token.span, msg); @@ -1604,25 +1589,16 @@ impl<'a> Parser<'a> { }?; if !ate_colon && consume_colon { - self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span); + self.sess.emit_err(RequireColonAfterLabeledExpression { + span: expr.span, + label: lo, + label_end: lo.shrink_to_hi(), + }); } Ok(expr) } - fn error_labeled_expr_must_be_followed_by_colon(&self, lo: Span, span: Span) { - self.struct_span_err(span, "labeled expression must be followed by `:`") - .span_label(lo, "the label") - .span_suggestion_short( - lo.shrink_to_hi(), - "add `:` after the label", - ": ", - Applicability::MachineApplicable, - ) - .note("labels are used before loops and blocks, allowing e.g., `break 'label` to them") - .emit(); - } - /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. fn recover_do_catch(&mut self) -> PResult<'a, P> { let lo = self.token.span; @@ -1630,16 +1606,8 @@ impl<'a> Parser<'a> { self.bump(); // `do` self.bump(); // `catch` - let span_dc = lo.to(self.prev_token.span); - self.struct_span_err(span_dc, "found removed `do catch` syntax") - .span_suggestion( - span_dc, - "replace with the new syntax", - "try", - Applicability::MachineApplicable, - ) - .note("following RFC #2388, the new non-placeholder syntax is `try`") - .emit(); + let span = lo.to(self.prev_token.span); + self.sess.emit_err(DoCatchSyntaxRemoved { span }); self.parse_try_block(lo) } @@ -1834,14 +1802,10 @@ impl<'a> Parser<'a> { } fn error_float_lits_must_have_int_part(&self, token: &Token) { - self.struct_span_err(token.span, "float literals must have an integer part") - .span_suggestion( - token.span, - "must have an integer part", - pprust::token_to_string(token), - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(FloatLiteralRequiresIntegerPart { + span: token.span, + correct: pprust::token_to_string(token).into_owned(), + }); } fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) { @@ -1883,28 +1847,11 @@ impl<'a> Parser<'a> { let suf = suf.as_str(); if looks_like_width_suffix(&['i', 'u'], &suf) { // If it looks like a width, try to be helpful. - let msg = format!("invalid width `{}` for integer literal", &suf[1..]); - self.struct_span_err(span, &msg) - .help("valid widths are 8, 16, 32, 64 and 128") - .emit(); + self.sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }); } else if let Some(fixed) = fix_base_capitalisation(suf) { - let msg = "invalid base prefix for number literal"; - - self.struct_span_err(span, msg) - .note("base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase") - .span_suggestion( - span, - "try making the prefix lowercase", - fixed, - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(InvalidNumLiteralBasePrefix { span, fixed }); } else { - let msg = format!("invalid suffix `{suf}` for number literal"); - self.struct_span_err(span, &msg) - .span_label(span, format!("invalid suffix `{suf}`")) - .help("the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)") - .emit(); + self.sess.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }); } } LitError::InvalidFloatSuffix => { @@ -1912,14 +1859,10 @@ impl<'a> Parser<'a> { let suf = suf.as_str(); if looks_like_width_suffix(&['f'], suf) { // If it looks like a width, try to be helpful. - let msg = format!("invalid width `{}` for float literal", &suf[1..]); - self.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit(); + self.sess + .emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }); } else { - let msg = format!("invalid suffix `{suf}` for float literal"); - self.struct_span_err(span, &msg) - .span_label(span, format!("invalid suffix `{suf}`")) - .help("valid suffixes are `f32` and `f64`") - .emit(); + self.sess.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() }); } } LitError::NonDecimalFloat(base) => { @@ -1934,7 +1877,7 @@ impl<'a> Parser<'a> { .emit(); } LitError::IntTooLarge => { - self.struct_span_err(span, "integer literal is too large").emit(); + self.sess.emit_err(IntLiteralTooLarge { span }); } } } @@ -2046,14 +1989,10 @@ impl<'a> Parser<'a> { .span_to_snippet(snapshot.token.span) .map_or(false, |snippet| snippet == "]") => { - let mut err = self.struct_span_err(open_delim_span, "expected `;`, found `[`"); - err.span_suggestion_verbose( - prev_span.shrink_to_hi(), - "consider adding `;` here", - ';', - Applicability::MaybeIncorrect, - ); - return Err(err); + return Err(MissingSemicolonBeforeArray { + open_delim: open_delim_span, + semicolon: prev_span.shrink_to_hi(), + }.into_diagnostic(self.sess)); } Ok(_) => (), Err(err) => err.cancel(), @@ -2080,9 +2019,10 @@ impl<'a> Parser<'a> { } if self.token.is_whole_block() { - self.struct_span_err(self.token.span, "cannot use a `block` macro fragment here") - .span_label(lo.to(self.token.span), "the `block` fragment is within this context") - .emit(); + self.sess.emit_err(InvalidBlockMacroSegment { + span: self.token.span, + context: lo.to(self.token.span), + }); } let (attrs, blk) = self.parse_block_common(lo, blk_mode)?; @@ -2252,11 +2192,19 @@ impl<'a> Parser<'a> { let block = match &mut cond.kind { ExprKind::Binary(Spanned { span: binop_span, .. }, _, right) if let ExprKind::Block(_, None) = right.kind => { - this.error_missing_if_then_block(lo, cond_span.shrink_to_lo().to(*binop_span), true).emit(); + self.sess.emit_err(IfExpressionMissingThenBlock { + if_span: lo, + sub: IfExpressionMissingThenBlockSub::UnfinishedCondition( + cond_span.shrink_to_lo().to(*binop_span) + ), + }); std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi())) }, ExprKind::Block(_, None) => { - this.error_missing_if_cond(lo, cond_span).emit(); + self.sess.emit_err(IfExpressionMissingCondition { + if_span: self.sess.source_map().next_point(lo), + block_span: self.sess.source_map().start_point(cond_span), + }); std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi())) } _ => { @@ -2274,7 +2222,10 @@ impl<'a> Parser<'a> { if let Some(block) = recover_block_from_condition(self) { block } else { - self.error_missing_if_then_block(lo, cond_span, false).emit(); + self.sess.emit_err(IfExpressionMissingThenBlock { + if_span: lo, + sub: IfExpressionMissingThenBlockSub::AddThenBlock(cond_span.shrink_to_hi()), + }); self.mk_block_err(cond_span.shrink_to_hi()) } } else { @@ -2302,39 +2253,6 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els))) } - fn error_missing_if_then_block( - &self, - if_span: Span, - cond_span: Span, - is_unfinished: bool, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut err = self.struct_span_err( - if_span, - "this `if` expression is missing a block after the condition", - ); - if is_unfinished { - err.span_help(cond_span, "this binary operation is possibly unfinished"); - } else { - err.span_help(cond_span.shrink_to_hi(), "add a block here"); - } - err - } - - fn error_missing_if_cond( - &self, - lo: Span, - span: Span, - ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let next_span = self.sess.source_map().next_point(lo); - let mut err = self.struct_span_err(next_span, "missing condition for `if` expression"); - err.span_label(next_span, "expected condition here"); - err.span_label( - self.sess.source_map().start_point(span), - "if this block is the condition of the `if` expression, then it must be followed by another block" - ); - err - } - /// Parses the condition of a `if` or `while` expression. fn parse_cond_expr(&mut self) -> PResult<'a, P> { self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None) @@ -2350,8 +2268,7 @@ impl<'a> Parser<'a> { TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _) ); if !self.restrictions.contains(Restrictions::ALLOW_LET) || not_in_chain { - self.struct_span_err(self.token.span, "expected expression, found `let` statement") - .emit(); + self.sess.emit_err(ExpectedExpressionFoundLet { span: self.token.span }); } self.bump(); // Eat `let` token @@ -2389,15 +2306,12 @@ impl<'a> Parser<'a> { if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) && classify::expr_requires_semi_to_be_stmt(&cond) => { - self.struct_span_err(first_tok_span, format!("expected `{{`, found {first_tok}")) - .span_label(else_span, "expected an `if` or a block after this `else`") - .span_suggestion( - cond.span.shrink_to_lo(), - "add an `if` if this is the condition of a chained `else if` statement", - "if ", - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(ExpectedElseBlock { + first_tok_span, + first_tok, + else_span, + condition_start: cond.span.shrink_to_lo(), + }); self.parse_if_after_cond(cond.span.shrink_to_lo(), cond)? } Err(e) => { @@ -2422,16 +2336,18 @@ impl<'a> Parser<'a> { branch_span: Span, attrs: &[ast::Attribute], ) { - let (span, last) = match attrs { + let (attributes, last) = match attrs { [] => return, [x0 @ xn] | [x0, .., xn] => (x0.span.to(xn.span), xn.span), }; let ctx = if is_ctx_else { "else" } else { "if" }; - self.struct_span_err(last, "outer attributes are not allowed on `if` and `else` branches") - .span_label(branch_span, "the attributes are attached to this branch") - .span_label(ctx_span, format!("the branch belongs to this `{ctx}`")) - .span_suggestion(span, "remove the attributes", "", Applicability::MachineApplicable) - .emit(); + self.sess.emit_err(OuterAttributeNotAllowedOnIfElse { + last, + branch_span, + ctx_span, + ctx: ctx.to_string(), + attributes, + }); } /// Parses `for in ` (`for` token already eaten). @@ -2465,23 +2381,16 @@ impl<'a> Parser<'a> { } fn error_missing_in_for_loop(&mut self) { - let (span, msg, sugg) = if self.token.is_ident_named(sym::of) { + let (span, sub): (_, fn(_) -> _) = if self.token.is_ident_named(sym::of) { // Possibly using JS syntax (#75311). let span = self.token.span; self.bump(); - (span, "try using `in` here instead", "in") + (span, MissingInInForLoopSub::InNotOf) } else { - (self.prev_token.span.between(self.token.span), "try adding `in` here", " in ") + (self.prev_token.span.between(self.token.span), MissingInInForLoopSub::AddIn) }; - self.struct_span_err(span, "missing `in` in `for` loop") - .span_suggestion_short( - span, - msg, - sugg, - // Has been misleading, at least in the past (closed Issue #48492). - Applicability::MaybeIncorrect, - ) - .emit(); + + self.sess.emit_err(MissingInInForLoop { span, sub: sub(span) }); } /// Parses a `while` or `while let` expression (`while` token already eaten). @@ -2787,17 +2696,9 @@ impl<'a> Parser<'a> { .is_ok(); if pattern_follows && snapshot.check(&TokenKind::FatArrow) { err.cancel(); - this.struct_span_err( - hi.shrink_to_hi(), - "expected `,` following `match` arm", - ) - .span_suggestion( - hi.shrink_to_hi(), - "missing a comma here to end this `match` arm", - ",", - Applicability::MachineApplicable, - ) - .emit(); + this.sess.emit_err(MissingCommaAfterMatchArm { + span: hi.shrink_to_hi(), + }); return Ok(true); } } @@ -2827,13 +2728,7 @@ impl<'a> Parser<'a> { fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P> { let (attrs, body) = self.parse_inner_attrs_and_block()?; if self.eat_keyword(kw::Catch) { - let mut error = self.struct_span_err( - self.prev_token.span, - "keyword `catch` cannot follow a `try` block", - ); - error.help("try using `match` on the result of the `try` block instead"); - error.emit(); - Err(error) + Err(CatchAfterTry { span: self.prev_token.span }.into_diagnostic(self.sess)) } else { let span = span_lo.to(body.span); self.sess.gated_spans.gate(sym::try_blocks, span); @@ -3082,18 +2977,10 @@ impl<'a> Parser<'a> { if self.token != token::Comma { return; } - self.struct_span_err( - span.to(self.prev_token.span), - "cannot use a comma after the base struct", - ) - .span_suggestion_short( - self.token.span, - "remove this comma", - "", - Applicability::MachineApplicable, - ) - .note("the base struct must always be the last field") - .emit(); + self.sess.emit_err(CommaAfterBaseStruct { + span: span.to(self.prev_token.span), + comma: self.token.span, + }); self.recover_stmt(); } @@ -3139,43 +3026,18 @@ impl<'a> Parser<'a> { return; } - self.struct_span_err(self.token.span, "expected `:`, found `=`") - .span_suggestion( - field_name.span.shrink_to_hi().to(self.token.span), - "replace equals symbol with a colon", - ":", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(EqFieldInit { + span: self.token.span, + eq: field_name.span.shrink_to_hi().to(self.token.span), + }); } fn err_dotdotdot_syntax(&self, span: Span) { - self.struct_span_err(span, "unexpected token: `...`") - .span_suggestion( - span, - "use `..` for an exclusive range", - "..", - Applicability::MaybeIncorrect, - ) - .span_suggestion( - span, - "or `..=` for an inclusive range", - "..=", - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(DotDotDot { span }); } fn err_larrow_operator(&self, span: Span) { - self.struct_span_err(span, "unexpected token: `<-`") - .span_suggestion( - span, - "if you meant to write a comparison against a negative value, add a \ - space in between `<` and `-`", - "< -", - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(LeftArrowOperator { span }); } fn mk_assign_op(&self, binop: BinOp, lhs: P, rhs: P) -> ExprKind { diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index b4b6fe8eeada3..ed653f0f9c82d 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -69,9 +69,11 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { ) { let cause = traits::ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)); + // for a type to be WF, we do not need to check if const trait predicates satisfy. + let param_env = self.param_env.without_const(); self.ocx.register_obligation(traits::Obligation::new( cause, - self.param_env, + param_env, ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx()), )); } @@ -1449,7 +1451,13 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| { - traits::wf::predicate_obligations(infcx, wfcx.param_env, wfcx.body_id, p, sp) + traits::wf::predicate_obligations( + infcx, + wfcx.param_env.without_const(), + wfcx.body_id, + p, + sp, + ) }); let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 197e7aaaccf3d..4583bc9a158ef 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -1010,7 +1010,8 @@ impl BinaryHeap { /// current length. The allocator may reserve more space to speculatively /// avoid frequent allocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional` if it returns - /// `Ok(())`. Does nothing if capacity is already sufficient. + /// `Ok(())`. Does nothing if capacity is already sufficient. This method + /// preserves the contents even if an error occurs. /// /// # Errors /// diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 57ab74e01590b..347a938fd0c58 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -794,7 +794,8 @@ impl VecDeque { /// in the given deque. The collection may reserve more space to speculatively avoid /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional` if it returns - /// `Ok(())`. Does nothing if capacity is already sufficient. + /// `Ok(())`. Does nothing if capacity is already sufficient. This method + /// preserves the contents even if an error occurs. /// /// # Errors /// diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 7bee894d3e404..e28ace4795f99 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1080,7 +1080,8 @@ impl String { /// current length. The allocator may reserve more space to speculatively /// avoid frequent allocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional` if it returns - /// `Ok(())`. Does nothing if capacity is already sufficient. + /// `Ok(())`. Does nothing if capacity is already sufficient. This method + /// preserves the contents even if an error occurs. /// /// # Errors /// diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index e02ad391a595f..4351548811d2e 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -148,7 +148,7 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option { - if self.ptr as *const _ == self.end { + if self.ptr == self.end { None } else if mem::size_of::() == 0 { // purposefully don't use 'ptr.offset' because for diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index cea943602f770..2c786fd511ead 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -875,7 +875,8 @@ impl Vec { /// in the given `Vec`. The collection may reserve more space to speculatively avoid /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional` if it returns - /// `Ok(())`. Does nothing if capacity is already sufficient. + /// `Ok(())`. Does nothing if capacity is already sufficient. This method + /// preserves the contents even if an error occurs. /// /// # Errors /// @@ -2927,6 +2928,8 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec { #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] impl const Default for Vec { /// Creates an empty `Vec`. + /// + /// The vector will not allocate until elements are pushed onto it. fn default() -> Vec { Vec::new() } diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index d83cd29ddbad9..99bfb2a45ed90 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -38,6 +38,7 @@ #![feature(const_str_from_utf8)] #![feature(nonnull_slice_from_raw_parts)] #![feature(panic_update_hook)] +#![feature(pointer_is_aligned)] #![feature(slice_flatten)] #![feature(thin_box)] #![feature(bench_black_box)] diff --git a/library/alloc/tests/thin_box.rs b/library/alloc/tests/thin_box.rs index 368aa564f9436..e008b0cc35718 100644 --- a/library/alloc/tests/thin_box.rs +++ b/library/alloc/tests/thin_box.rs @@ -48,11 +48,11 @@ fn verify_aligned(ptr: *const T) { // practice these checks are mostly just smoke-detectors for an extremely // broken `ThinBox` impl, since it's an extremely subtle piece of code. let ptr = core::hint::black_box(ptr); - let align = core::mem::align_of::(); assert!( - (ptr.addr() & (align - 1)) == 0 && !ptr.is_null(), - "misaligned ThinBox data; valid pointers to `{}` should be aligned to {align}: {ptr:p}", - core::any::type_name::(), + ptr.is_aligned() && !ptr.is_null(), + "misaligned ThinBox data; valid pointers to `{ty}` should be aligned to {align}: {ptr:p}", + ty = core::any::type_name::(), + align = core::mem::align_of::(), ); } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 3d7b875eac15d..441d238268693 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2139,7 +2139,7 @@ pub(crate) use assert_unsafe_precondition; /// Checks whether `ptr` is properly aligned with respect to /// `align_of::()`. pub(crate) fn is_aligned_and_not_null(ptr: *const T) -> bool { - !ptr.is_null() && ptr.addr() % mem::align_of::() == 0 + !ptr.is_null() && ptr.is_aligned() } /// Checks whether the regions of memory starting at `src` and `dst` of size diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index a0a5c003d281a..80ed34157e6dc 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -290,7 +290,8 @@ impl OsString { /// in the given `OsString`. The string may reserve more space to speculatively avoid /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional` if it returns `Ok(())`. - /// Does nothing if capacity is already sufficient. + /// Does nothing if capacity is already sufficient. This method preserves + /// the contents even if an error occurs. /// /// See the main `OsString` documentation information about encoding and capacity units. /// diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5029023121fc2..71bbf4317e0a5 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -296,6 +296,7 @@ #![feature(panic_can_unwind)] #![feature(panic_info_message)] #![feature(panic_internals)] +#![feature(pointer_is_aligned)] #![feature(portable_simd)] #![feature(prelude_2024)] #![feature(provide_any)] diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 189754a161e71..6004810655ebb 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -620,25 +620,31 @@ impl Ipv4Addr { matches!(self.octets(), [169, 254, ..]) } - /// Returns [`true`] if the address appears to be globally routable. - /// See [iana-ipv4-special-registry][ipv4-sr]. + /// Returns [`true`] if the address appears to be globally reachable + /// as specified by the [IANA IPv4 Special-Purpose Address Registry]. + /// Whether or not an address is practically reachable will depend on your network configuration. + /// + /// Most IPv4 addresses are globally reachable; + /// unless they are specifically defined as *not* globally reachable. /// - /// The following return [`false`]: + /// Non-exhaustive list of notable addresses that are not globally reachable: /// - /// - private addresses (see [`Ipv4Addr::is_private()`]) - /// - the loopback address (see [`Ipv4Addr::is_loopback()`]) - /// - the link-local address (see [`Ipv4Addr::is_link_local()`]) - /// - the broadcast address (see [`Ipv4Addr::is_broadcast()`]) - /// - addresses used for documentation (see [`Ipv4Addr::is_documentation()`]) - /// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole - /// `0.0.0.0/8` block - /// - addresses reserved for future protocols, except - /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable - /// - addresses reserved for future use (see [`Ipv4Addr::is_reserved()`] - /// - addresses reserved for networking devices benchmarking (see - /// [`Ipv4Addr::is_benchmarking()`]) + /// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified)) + /// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private)) + /// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared)) + /// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback)) + /// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local)) + /// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation)) + /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking)) + /// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved)) + /// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast)) /// - /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml + /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry]. + /// + /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml + /// [unspecified address]: Ipv4Addr::UNSPECIFIED + /// [broadcast address]: Ipv4Addr::BROADCAST + /// /// # Examples /// @@ -647,71 +653,61 @@ impl Ipv4Addr { /// /// use std::net::Ipv4Addr; /// - /// // private addresses are not global + /// // Most IPv4 addresses are globally reachable: + /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); + /// + /// // However some addresses have been assigned a special meaning + /// // that makes them not globally reachable. Some examples are: + /// + /// // The unspecified address (`0.0.0.0`) + /// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false); + /// + /// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16) /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false); /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false); /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false); /// - /// // the 0.0.0.0/8 block is not global - /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false); - /// // in particular, the unspecified address is not global - /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false); + /// // Addresses in the shared address space (`100.64.0.0/10`) + /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); /// - /// // the loopback address is not global - /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false); + /// // The loopback addresses (`127.0.0.0/8`) + /// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false); /// - /// // link local addresses are not global + /// // Link-local addresses (`169.254.0.0/16`) /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false); /// - /// // the broadcast address is not global - /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false); - /// - /// // the address space designated for documentation is not global + /// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`) /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false); /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false); /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false); /// - /// // shared addresses are not global - /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false); - /// - /// // addresses reserved for protocol assignment are not global - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false); - /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false); + /// // Addresses reserved for benchmarking (`198.18.0.0/15`) + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); /// - /// // addresses reserved for future use are not global + /// // Reserved addresses (`240.0.0.0/4`) /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false); /// - /// // addresses reserved for network devices benchmarking are not global - /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false); + /// // The broadcast address (`255.255.255.255`) + /// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false); /// - /// // All the other addresses are global - /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); - /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); + /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry. /// ``` #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] pub const fn is_global(&self) -> bool { - // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two - // globally routable addresses in the 192.0.0.0/24 range. - if u32::from_be_bytes(self.octets()) == 0xc0000009 - || u32::from_be_bytes(self.octets()) == 0xc000000a - { - return true; - } - !self.is_private() - && !self.is_loopback() - && !self.is_link_local() - && !self.is_broadcast() - && !self.is_documentation() - && !self.is_shared() + !(self.octets()[0] == 0 // "This network" + || self.is_private() + || self.is_shared() + || self.is_loopback() + || self.is_link_local() // addresses reserved for future protocols (`192.0.0.0/24`) - && !(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0) - && !self.is_reserved() - && !self.is_benchmarking() - // Make sure the address is not in 0.0.0.0/8 - && self.octets()[0] != 0 + ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0) + || self.is_documentation() + || self.is_benchmarking() + || self.is_reserved() + || self.is_broadcast()) } /// Returns [`true`] if this address is part of the Shared Address Space defined in @@ -1300,13 +1296,33 @@ impl Ipv6Addr { u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) } - /// Returns [`true`] if the address appears to be globally routable. + /// Returns [`true`] if the address appears to be globally reachable + /// as specified by the [IANA IPv6 Special-Purpose Address Registry]. + /// Whether or not an address is practically reachable will depend on your network configuration. /// - /// The following return [`false`]: + /// Most IPv6 addresses are globally reachable; + /// unless they are specifically defined as *not* globally reachable. /// - /// - the loopback address - /// - link-local and unique local unicast addresses - /// - interface-, link-, realm-, admin- and site-local multicast addresses + /// Non-exhaustive list of notable addresses that are not globally reachable: + /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified)) + /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback)) + /// - IPv4-mapped addresses + /// - Addresses reserved for benchmarking + /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation)) + /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local)) + /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local)) + /// + /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry]. + /// + /// Note that an address having global scope is not the same as being globally reachable, + /// and there is no direct relation between the two concepts: There exist addresses with global scope + /// that are not globally reachable (for example unique local addresses), + /// and addresses that are globally reachable without having global scope + /// (multicast addresses with non-global scope). + /// + /// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml + /// [unspecified address]: Ipv6Addr::UNSPECIFIED + /// [loopback address]: Ipv6Addr::LOCALHOST /// /// # Examples /// @@ -1315,20 +1331,65 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true); - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); - /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); + /// // Most IPv6 addresses are globally reachable: + /// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true); + /// + /// // However some addresses have been assigned a special meaning + /// // that makes them not globally reachable. Some examples are: + /// + /// // The unspecified address (`::`) + /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false); + /// + /// // The loopback address (`::1`) + /// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false); + /// + /// // IPv4-mapped addresses (`::ffff:0:0/96`) + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false); + /// + /// // Addresses reserved for benchmarking (`2001:2::/48`) + /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false); + /// + /// // Addresses reserved for documentation (`2001:db8::/32`) + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false); + /// + /// // Unique local addresses (`fc00::/7`) + /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false); + /// + /// // Unicast addresses with link-local scope (`fe80::/10`) + /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false); + /// + /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry. /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] pub const fn is_global(&self) -> bool { - match self.multicast_scope() { - Some(Ipv6MulticastScope::Global) => true, - None => self.is_unicast_global(), - _ => false, - } + !(self.is_unspecified() + || self.is_loopback() + // IPv4-mapped Address (`::ffff:0:0/96`) + || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _]) + // IPv4-IPv6 Translat. (`64:ff9b:1::/48`) + || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _]) + // Discard-Only Address Block (`100::/64`) + || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _]) + // IETF Protocol Assignments (`2001::/23`) + || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200) + && !( + // Port Control Protocol Anycast (`2001:1::1`) + u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001 + // Traversal Using Relays around NAT Anycast (`2001:1::2`) + || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002 + // AMT (`2001:3::/32`) + || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _]) + // AS112-v6 (`2001:4:112::/48`) + || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _]) + // ORCHIDv2 (`2001:20::/28`) + || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F) + )) + || self.is_documentation() + || self.is_unique_local() + || self.is_unicast_link_local()) } /// Returns [`true`] if this is a unique local address (`fc00::/7`). @@ -1525,6 +1586,7 @@ impl Ipv6Addr { && !self.is_unique_local() && !self.is_unspecified() && !self.is_documentation() + && !self.is_benchmarking() } /// Returns the address's multicast scope if the address is multicast. diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index c29509331d7a9..7c3430b2b217c 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -321,15 +321,15 @@ fn ip_properties() { check!("fe80:ffff::"); check!("febf:ffff::"); check!("fec0::", global); - check!("ff01::", multicast); - check!("ff02::", multicast); - check!("ff03::", multicast); - check!("ff04::", multicast); - check!("ff05::", multicast); - check!("ff08::", multicast); + check!("ff01::", global | multicast); + check!("ff02::", global | multicast); + check!("ff03::", global | multicast); + check!("ff04::", global | multicast); + check!("ff05::", global | multicast); + check!("ff08::", global | multicast); check!("ff0e::", global | multicast); check!("2001:db8:85a3::8a2e:370:7334", doc); - check!("2001:2::ac32:23ff:21", global | benchmarking); + check!("2001:2::ac32:23ff:21", benchmarking); check!("102:304:506:708:90a:b0c:d0e:f10", global); } @@ -609,6 +609,60 @@ fn ipv6_properties() { check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); + check!( + "::ffff:127.0.0.1", + &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1], + unicast_global + ); + + check!( + "64:ff9b:1::", + &[0, 0x64, 0xff, 0x9b, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_global + ); + + check!("100::", &[0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); + + check!("2001::", &[0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); + + check!( + "2001:1::1", + &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + global | unicast_global + ); + + check!( + "2001:1::2", + &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], + global | unicast_global + ); + + check!( + "2001:3::", + &[0x20, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + + check!( + "2001:4:112::", + &[0x20, 1, 0, 4, 1, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + + check!( + "2001:20::", + &[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + + check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); + + check!( + "2001:200::", + &[0x20, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local); check!( @@ -666,21 +720,37 @@ fn ipv6_properties() { check!( "ff01::", &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_interface_local + multicast_interface_local | global ); - check!("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_link_local); + check!( + "ff02::", + &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_link_local | global + ); - check!("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_realm_local); + check!( + "ff03::", + &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_realm_local | global + ); - check!("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_admin_local); + check!( + "ff04::", + &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_admin_local | global + ); - check!("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_site_local); + check!( + "ff05::", + &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_site_local | global + ); check!( "ff08::", &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_organization_local + multicast_organization_local | global ); check!( @@ -698,7 +768,7 @@ fn ipv6_properties() { check!( "2001:2::ac32:23ff:21", &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21], - global | unicast_global | benchmarking + benchmarking ); check!( diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index fe8392f78cd1e..5409bd1777c2a 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -117,7 +117,7 @@ pub unsafe trait UserSafe { /// * the pointer is null. /// * the pointed-to range is not in user memory. unsafe fn check_ptr(ptr: *const Self) { - let is_aligned = |p: *const u8| -> bool { 0 == p.addr() & (Self::align_of() - 1) }; + let is_aligned = |p: *const u8| -> bool { p.is_aligned_to(Self::align_of()) }; assert!(is_aligned(ptr as *const u8)); assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr }))); @@ -386,7 +386,7 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) unsafe { copy_bytewise_to_userspace(src, dst, len); } - } else if len % 8 == 0 && dst as usize % 8 == 0 { + } else if len % 8 == 0 && dst.is_aligned_to(8) { // Copying 8-byte aligned quadwords: copy quad word per quad word unsafe { copy_quadwords(src, dst, len); diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 57fa4989358a4..33e20756163fd 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -236,7 +236,8 @@ impl Wtf8Buf { /// in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to avoid /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional`. Does nothing if - /// capacity is already sufficient. + /// capacity is already sufficient. This method preserves the contents even + /// if an error occurs. /// /// # Errors /// diff --git a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff index 836443bf4d293..04378dbf374d9 100644 --- a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff @@ -24,7 +24,7 @@ + _1 = const 1_i32; // scope 0 at $DIR/aggregate.rs:+1:13: +1:28 StorageDead(_2); // scope 0 at $DIR/aggregate.rs:+1:27: +1:28 StorageDead(_3); // scope 0 at $DIR/aggregate.rs:+1:28: +1:29 - nop; // scope 0 at $DIR/aggregate.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/aggregate.rs:+0:11: +2:2 StorageDead(_1); // scope 0 at $DIR/aggregate.rs:+2:1: +2:2 return; // scope 0 at $DIR/aggregate.rs:+2:2: +2:2 } diff --git a/src/test/mir-opt/const_prop/aggregate.rs b/src/test/mir-opt/const_prop/aggregate.rs index 7a3b26a731727..493d0508a046d 100644 --- a/src/test/mir-opt/const_prop/aggregate.rs +++ b/src/test/mir-opt/const_prop/aggregate.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp // compile-flags: -O // EMIT_MIR aggregate.main.ConstProp.diff diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff index bb9abdd10200d..439b2a3e16b45 100644 --- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff @@ -18,11 +18,12 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:+1:18: +1:30 StorageLive(_3); // scope 0 at $DIR/array_index.rs:+1:31: +1:32 _3 = const 2_usize; // scope 0 at $DIR/array_index.rs:+1:31: +1:32 - _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 +- _4 = Len(_2); // scope 0 at $DIR/array_index.rs:+1:18: +1:33 - _5 = Lt(_3, _4); // scope 0 at $DIR/array_index.rs:+1:18: +1:33 - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 ++ _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 + _5 = const true; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 } bb1: { @@ -30,7 +31,7 @@ + _1 = const 2_u32; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 StorageDead(_3); // scope 0 at $DIR/array_index.rs:+1:33: +1:34 StorageDead(_2); // scope 0 at $DIR/array_index.rs:+1:33: +1:34 - nop; // scope 0 at $DIR/array_index.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/array_index.rs:+0:11: +2:2 StorageDead(_1); // scope 0 at $DIR/array_index.rs:+2:1: +2:2 return; // scope 0 at $DIR/array_index.rs:+2:2: +2:2 } diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff index bb9abdd10200d..439b2a3e16b45 100644 --- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff @@ -18,11 +18,12 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:+1:18: +1:30 StorageLive(_3); // scope 0 at $DIR/array_index.rs:+1:31: +1:32 _3 = const 2_usize; // scope 0 at $DIR/array_index.rs:+1:31: +1:32 - _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 +- _4 = Len(_2); // scope 0 at $DIR/array_index.rs:+1:18: +1:33 - _5 = Lt(_3, _4); // scope 0 at $DIR/array_index.rs:+1:18: +1:33 - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 ++ _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 + _5 = const true; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 } bb1: { @@ -30,7 +31,7 @@ + _1 = const 2_u32; // scope 0 at $DIR/array_index.rs:+1:18: +1:33 StorageDead(_3); // scope 0 at $DIR/array_index.rs:+1:33: +1:34 StorageDead(_2); // scope 0 at $DIR/array_index.rs:+1:33: +1:34 - nop; // scope 0 at $DIR/array_index.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/array_index.rs:+0:11: +2:2 StorageDead(_1); // scope 0 at $DIR/array_index.rs:+2:1: +2:2 return; // scope 0 at $DIR/array_index.rs:+2:2: +2:2 } diff --git a/src/test/mir-opt/const_prop/array_index.rs b/src/test/mir-opt/const_prop/array_index.rs index 2c5254b5deba0..d31c2827b4e0a 100644 --- a/src/test/mir-opt/const_prop/array_index.rs +++ b/src/test/mir-opt/const_prop/array_index.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR array_index.main.ConstProp.diff diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff index 45134a3fdff3c..bea32a67ef4a0 100644 --- a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff @@ -24,10 +24,9 @@ StorageLive(_3); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19 - _3 = _1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19 - _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -- assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 + _3 = const 0_i32; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19 + _4 = const true; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -+ assert(!const true, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 + assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 } bb1: { @@ -38,14 +37,13 @@ + _5 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 + _6 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 + _7 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -+ assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 ++ assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 } bb2: { -- _2 = Div(const 1_i32, move _3); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 -+ _2 = Div(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 + _2 = Div(const 1_i32, move _3); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19 StorageDead(_3); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19 - nop; // scope 0 at $DIR/bad_op_div_by_zero.rs:+0:11: +3:2 + _0 = const (); // scope 0 at $DIR/bad_op_div_by_zero.rs:+0:11: +3:2 StorageDead(_2); // scope 1 at $DIR/bad_op_div_by_zero.rs:+3:1: +3:2 StorageDead(_1); // scope 0 at $DIR/bad_op_div_by_zero.rs:+3:1: +3:2 return; // scope 0 at $DIR/bad_op_div_by_zero.rs:+3:2: +3:2 diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs b/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs index 6f39209b970d2..a6fd325ece035 100644 --- a/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs +++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp // EMIT_MIR bad_op_div_by_zero.main.ConstProp.diff #[allow(unconditional_panic)] fn main() { diff --git a/src/test/mir-opt/const_prop/boolean_identities.rs b/src/test/mir-opt/const_prop/boolean_identities.rs index 57164e3e794d2..c7b609949cd15 100644 --- a/src/test/mir-opt/const_prop/boolean_identities.rs +++ b/src/test/mir-opt/const_prop/boolean_identities.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp // compile-flags: -O -Zmir-opt-level=4 // EMIT_MIR boolean_identities.test.ConstProp.diff diff --git a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff index 73fdf14049896..cb82a7bea1493 100644 --- a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff @@ -24,12 +24,11 @@ StorageLive(_3); // scope 0 at $DIR/boxes.rs:+1:14: +1:22 - _4 = SizeOf(i32); // scope 2 at $DIR/boxes.rs:+1:14: +1:22 - _5 = AlignOf(i32); // scope 2 at $DIR/boxes.rs:+1:14: +1:22 -- _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:+1:14: +1:22 + _4 = const 4_usize; // scope 2 at $DIR/boxes.rs:+1:14: +1:22 + _5 = const 4_usize; // scope 2 at $DIR/boxes.rs:+1:14: +1:22 -+ _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> bb1; // scope 2 at $DIR/boxes.rs:+1:14: +1:22 + _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:+1:14: +1:22 // mir::Constant - // + span: $DIR/boxes.rs:12:14: 12:22 + // + span: $DIR/boxes.rs:13:14: 13:22 // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } } @@ -53,7 +52,7 @@ bb2: { StorageDead(_3); // scope 0 at $DIR/boxes.rs:+1:26: +1:27 - nop; // scope 0 at $DIR/boxes.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/boxes.rs:+0:11: +2:2 StorageDead(_1); // scope 0 at $DIR/boxes.rs:+2:1: +2:2 return; // scope 0 at $DIR/boxes.rs:+2:2: +2:2 } diff --git a/src/test/mir-opt/const_prop/boxes.rs b/src/test/mir-opt/const_prop/boxes.rs index fea666a4455ed..d287830db5a56 100644 --- a/src/test/mir-opt/const_prop/boxes.rs +++ b/src/test/mir-opt/const_prop/boxes.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp // compile-flags: -O // ignore-emscripten compiled with panic=abort by default // ignore-wasm32 diff --git a/src/test/mir-opt/const_prop/cast.main.ConstProp.diff b/src/test/mir-opt/const_prop/cast.main.ConstProp.diff index 5698a612fe2d2..e040a4b3a53e9 100644 --- a/src/test/mir-opt/const_prop/cast.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/cast.main.ConstProp.diff @@ -19,7 +19,7 @@ StorageLive(_2); // scope 1 at $DIR/cast.rs:+3:9: +3:10 - _2 = const 42_u32 as u8 (Misc); // scope 1 at $DIR/cast.rs:+3:13: +3:24 + _2 = const 42_u8; // scope 1 at $DIR/cast.rs:+3:13: +3:24 - nop; // scope 0 at $DIR/cast.rs:+0:11: +4:2 + _0 = const (); // scope 0 at $DIR/cast.rs:+0:11: +4:2 StorageDead(_2); // scope 1 at $DIR/cast.rs:+4:1: +4:2 StorageDead(_1); // scope 0 at $DIR/cast.rs:+4:1: +4:2 return; // scope 0 at $DIR/cast.rs:+4:2: +4:2 diff --git a/src/test/mir-opt/const_prop/cast.rs b/src/test/mir-opt/const_prop/cast.rs index 680cab0074082..984086eda48b0 100644 --- a/src/test/mir-opt/const_prop/cast.rs +++ b/src/test/mir-opt/const_prop/cast.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp // EMIT_MIR cast.main.ConstProp.diff fn main() { diff --git a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff index 5e33d054207b0..96d0d25664a41 100644 --- a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff @@ -20,7 +20,7 @@ bb1: { - _1 = move (_2.0: u32); // scope 0 at $DIR/checked_add.rs:+1:18: +1:23 + _1 = const 2_u32; // scope 0 at $DIR/checked_add.rs:+1:18: +1:23 - nop; // scope 0 at $DIR/checked_add.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/checked_add.rs:+0:11: +2:2 StorageDead(_1); // scope 0 at $DIR/checked_add.rs:+2:1: +2:2 return; // scope 0 at $DIR/checked_add.rs:+2:2: +2:2 } diff --git a/src/test/mir-opt/const_prop/checked_add.rs b/src/test/mir-opt/const_prop/checked_add.rs index 08d59b6fbc36f..b9860da4c8220 100644 --- a/src/test/mir-opt/const_prop/checked_add.rs +++ b/src/test/mir-opt/const_prop/checked_add.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp // compile-flags: -C overflow-checks=on // EMIT_MIR checked_add.main.ConstProp.diff diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff index c21b24591d88e..2cb071deab13f 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff @@ -18,7 +18,7 @@ StorageLive(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16 _3 = const FOO; // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16 // mir::Constant - // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 + // + span: $DIR/const_prop_fails_gracefully.rs:8:13: 8:16 // + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) } _2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16 _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:39 @@ -29,14 +29,14 @@ _5 = _1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:10: +3:11 _4 = read(move _5) -> bb1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:5: +3:12 // mir::Constant - // + span: $DIR/const_prop_fails_gracefully.rs:8:5: 8:9 + // + span: $DIR/const_prop_fails_gracefully.rs:9:5: 9:9 // + literal: Const { ty: fn(usize) {read}, val: Value() } } bb1: { StorageDead(_5); // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:11: +3:12 StorageDead(_4); // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:12: +3:13 - nop; // scope 0 at $DIR/const_prop_fails_gracefully.rs:+0:11: +4:2 + _0 = const (); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+0:11: +4:2 StorageDead(_1); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+4:1: +4:2 return; // scope 0 at $DIR/const_prop_fails_gracefully.rs:+4:2: +4:2 } diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs index 8bd68527f3703..0a3dcbd380fa8 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp #[inline(never)] fn read(_: usize) { } diff --git a/src/test/mir-opt/const_prop/control-flow-simplification.rs b/src/test/mir-opt/const_prop/control-flow-simplification.rs index aa4ce19f620fe..7dbe8e7344b12 100644 --- a/src/test/mir-opt/const_prop/control-flow-simplification.rs +++ b/src/test/mir-opt/const_prop/control-flow-simplification.rs @@ -1,10 +1,11 @@ +// unit-test: ConstProp // compile-flags: -Zmir-opt-level=1 -trait NeedsDrop:Sized{ - const NEEDS:bool=std::mem::needs_drop::(); +trait NeedsDrop: Sized { + const NEEDS: bool = std::mem::needs_drop::(); } -impl NeedsDrop for This{} +impl NeedsDrop for This {} // EMIT_MIR control_flow_simplification.hello.ConstProp.diff // EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff index 5b4ecaa80f1f1..6b29bb59c40da 100644 --- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff @@ -44,7 +44,7 @@ _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/discriminant.rs:+1:13: +1:68 StorageDead(_2); // scope 0 at $DIR/discriminant.rs:+1:67: +1:68 StorageDead(_3); // scope 0 at $DIR/discriminant.rs:+1:68: +1:69 - nop; // scope 0 at $DIR/discriminant.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/discriminant.rs:+0:11: +2:2 StorageDead(_1); // scope 0 at $DIR/discriminant.rs:+2:1: +2:2 return; // scope 0 at $DIR/discriminant.rs:+2:2: +2:2 } diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff index 5b4ecaa80f1f1..6b29bb59c40da 100644 --- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff @@ -44,7 +44,7 @@ _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/discriminant.rs:+1:13: +1:68 StorageDead(_2); // scope 0 at $DIR/discriminant.rs:+1:67: +1:68 StorageDead(_3); // scope 0 at $DIR/discriminant.rs:+1:68: +1:69 - nop; // scope 0 at $DIR/discriminant.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/discriminant.rs:+0:11: +2:2 StorageDead(_1); // scope 0 at $DIR/discriminant.rs:+2:1: +2:2 return; // scope 0 at $DIR/discriminant.rs:+2:2: +2:2 } diff --git a/src/test/mir-opt/const_prop/discriminant.rs b/src/test/mir-opt/const_prop/discriminant.rs index 67538b3c7a563..fdd67ca8ac44f 100644 --- a/src/test/mir-opt/const_prop/discriminant.rs +++ b/src/test/mir-opt/const_prop/discriminant.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp // compile-flags: -O // FIXME(wesleywiser): Ideally, we could const-prop away all of this and just be left with diff --git a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff index 2e1e32545a286..948bb7f56fe85 100644 --- a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff @@ -18,14 +18,14 @@ - assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:+1:13: +1:29 + _2 = const 2_u8; // scope 0 at $DIR/indirect.rs:+1:13: +1:25 + _3 = const (3_u8, false); // scope 0 at $DIR/indirect.rs:+1:13: +1:29 -+ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:+1:13: +1:29 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:+1:13: +1:29 } bb1: { - _1 = move (_3.0: u8); // scope 0 at $DIR/indirect.rs:+1:13: +1:29 + _1 = const 3_u8; // scope 0 at $DIR/indirect.rs:+1:13: +1:29 StorageDead(_2); // scope 0 at $DIR/indirect.rs:+1:28: +1:29 - nop; // scope 0 at $DIR/indirect.rs:+0:11: +2:2 + _0 = const (); // scope 0 at $DIR/indirect.rs:+0:11: +2:2 StorageDead(_1); // scope 0 at $DIR/indirect.rs:+2:1: +2:2 return; // scope 0 at $DIR/indirect.rs:+2:2: +2:2 } diff --git a/src/test/mir-opt/const_prop/indirect.rs b/src/test/mir-opt/const_prop/indirect.rs index 37217ca813407..44916cbfe743a 100644 --- a/src/test/mir-opt/const_prop/indirect.rs +++ b/src/test/mir-opt/const_prop/indirect.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp // compile-flags: -C overflow-checks=on // EMIT_MIR indirect.main.ConstProp.diff diff --git a/src/test/mir-opt/const_prop/issue-66971.rs b/src/test/mir-opt/const_prop/issue-66971.rs index 81eccae46b97e..6ca03438ef396 100644 --- a/src/test/mir-opt/const_prop/issue-66971.rs +++ b/src/test/mir-opt/const_prop/issue-66971.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp // compile-flags: -Z mir-opt-level=3 // Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected diff --git a/src/test/mir-opt/const_prop/issue-67019.rs b/src/test/mir-opt/const_prop/issue-67019.rs index c78b8b971783f..ffc6fa1f290f3 100644 --- a/src/test/mir-opt/const_prop/issue-67019.rs +++ b/src/test/mir-opt/const_prop/issue-67019.rs @@ -1,3 +1,4 @@ +// unit-test: ConstProp // compile-flags: -Z mir-opt-level=3 // This used to ICE in const-prop diff --git a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff index b3d5980aa7336..9d541dcabbb2c 100644 --- a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff @@ -19,7 +19,7 @@ StorageDead(_3); // scope 0 at $DIR/issue-66971.rs:+1:21: +1:22 _1 = encode(move _2) -> bb1; // scope 0 at $DIR/issue-66971.rs:+1:5: +1:23 // mir::Constant - // + span: $DIR/issue-66971.rs:16:5: 16:11 + // + span: $DIR/issue-66971.rs:17:5: 17:11 // + literal: Const { ty: fn(((), u8, u8)) {encode}, val: Value() } } diff --git a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff index 8330b50529f73..b79d814760d9e 100644 --- a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff @@ -20,7 +20,7 @@ StorageDead(_3); // scope 0 at $DIR/issue-67019.rs:+1:18: +1:19 _1 = test(move _2) -> bb1; // scope 0 at $DIR/issue-67019.rs:+1:5: +1:20 // mir::Constant - // + span: $DIR/issue-67019.rs:11:5: 11:9 + // + span: $DIR/issue-67019.rs:12:5: 12:9 // + literal: Const { ty: fn(((u8, u8),)) {test}, val: Value() } } diff --git a/src/test/mir-opt/const_prop/mult_by_zero.rs b/src/test/mir-opt/const_prop/mult_by_zero.rs index b0ecdf1818e4d..c839f92f2ceb1 100644 --- a/src/test/mir-opt/const_prop/mult_by_zero.rs +++ b/src/test/mir-opt/const_prop/mult_by_zero.rs @@ -1,3 +1,4 @@ +// unit-test // compile-flags: -O -Zmir-opt-level=4 // EMIT_MIR mult_by_zero.test.ConstProp.diff diff --git a/src/test/mir-opt/const_prop/mutable_variable.rs b/src/test/mir-opt/const_prop/mutable_variable.rs index 801e7a9fcbb7b..cb01719dd77a9 100644 --- a/src/test/mir-opt/const_prop/mutable_variable.rs +++ b/src/test/mir-opt/const_prop/mutable_variable.rs @@ -1,3 +1,4 @@ +// unit-test // compile-flags: -O // EMIT_MIR mutable_variable.main.ConstProp.diff diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs index e0b4b77bac476..d4ff8d8907342 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs @@ -1,3 +1,4 @@ +// unit-test // compile-flags: -O // EMIT_MIR mutable_variable_aggregate.main.ConstProp.diff diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs index 79ac497c783fb..9060f7e9bd3e6 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs @@ -1,3 +1,4 @@ +// unit-test // compile-flags: -O // EMIT_MIR mutable_variable_aggregate_mut_ref.main.ConstProp.diff diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff index c678f7b032763..6eda503c1eec4 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff @@ -16,7 +16,7 @@ StorageLive(_1); // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+1:9: +1:14 _1 = foo() -> bb1; // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+1:29: +1:34 // mir::Constant - // + span: $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:32 + // + span: $DIR/mutable_variable_aggregate_partial_read.rs:6:29: 6:32 // + literal: Const { ty: fn() -> (i32, i32) {foo}, val: Value() } } diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs index 9bb62b8973cbd..cb59509ff1061 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs @@ -1,3 +1,4 @@ +// unit-test // compile-flags: -O // EMIT_MIR mutable_variable_aggregate_partial_read.main.ConstProp.diff diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff index 4c2ba9a099815..eb3a7bc96d882 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff @@ -25,7 +25,7 @@ StorageLive(_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19 _4 = const {alloc1: *mut u32}; // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19 // mir::Constant - // + span: $DIR/mutable_variable_no_prop.rs:9:13: 9:19 + // + span: $DIR/mutable_variable_no_prop.rs:10:13: 10:19 // + literal: Const { ty: *mut u32, val: Value(Scalar(alloc1)) } _3 = (*_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19 _1 = move _3; // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:9: +3:19 diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs b/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs index 4126fb3c68c4f..8c23c5fcf0f88 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs +++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs @@ -1,3 +1,4 @@ +// unit-test // compile-flags: -O static mut STATIC: u32 = 42; diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff index 5328792b32388..4f205667be0e2 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff @@ -25,7 +25,7 @@ StorageLive(_1); // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10 _1 = foo() -> bb1; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:13: +1:18 // mir::Constant - // + span: $DIR/mutable_variable_unprop_assign.rs:5:13: 5:16 + // + span: $DIR/mutable_variable_unprop_assign.rs:6:13: 6:16 // + literal: Const { ty: fn() -> i32 {foo}, val: Value() } } diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs index 13f1b3f47f241..b077cfd3e0ae7 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs +++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs @@ -1,3 +1,4 @@ +// unit-test // compile-flags: -O // EMIT_MIR mutable_variable_unprop_assign.main.ConstProp.diff diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.rs b/src/test/mir-opt/const_prop/optimizes_into_variable.rs index 17265b7eb858e..c0fbd2558cd98 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.rs +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.rs @@ -1,3 +1,4 @@ +// unit-test // compile-flags: -C overflow-checks=on struct Point { diff --git a/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff b/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff index 89f43d7513815..b9c283a54821b 100644 --- a/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff @@ -18,7 +18,7 @@ StorageLive(_3); // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16 _3 = const {alloc1: &u8}; // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16 // mir::Constant - // + span: $DIR/read_immutable_static.rs:7:13: 7:16 + // + span: $DIR/read_immutable_static.rs:8:13: 8:16 // + literal: Const { ty: &u8, val: Value(Scalar(alloc1)) } - _2 = (*_3); // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16 + _2 = const 2_u8; // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16 @@ -26,7 +26,7 @@ StorageLive(_5); // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22 _5 = const {alloc1: &u8}; // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22 // mir::Constant - // + span: $DIR/read_immutable_static.rs:7:19: 7:22 + // + span: $DIR/read_immutable_static.rs:8:19: 8:22 // + literal: Const { ty: &u8, val: Value(Scalar(alloc1)) } - _4 = (*_5); // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22 - _1 = Add(move _2, move _4); // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:22 diff --git a/src/test/mir-opt/const_prop/read_immutable_static.rs b/src/test/mir-opt/const_prop/read_immutable_static.rs index 8a5f12c6f3da9..4f7afe6cad4a1 100644 --- a/src/test/mir-opt/const_prop/read_immutable_static.rs +++ b/src/test/mir-opt/const_prop/read_immutable_static.rs @@ -1,3 +1,4 @@ +// unit-test // compile-flags: -O static FOO: u8 = 2; diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff index f0c89caeac645..84ec5c8bb1db1 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff @@ -13,7 +13,7 @@ StorageLive(_2); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 // mir::Constant - // + span: $DIR/ref_deref_project.rs:5:6: 5:17 + // + span: $DIR/ref_deref_project.rs:6:6: 6:17 // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) } _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff index d2554028792c1..6f3a060a1260a 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff @@ -16,7 +16,7 @@ - _2 = &(_3.1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 + _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 + // mir::Constant -+ // + span: $DIR/ref_deref_project.rs:5:6: 5:17 ++ // + span: $DIR/ref_deref_project.rs:6:6: 6:17 + // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) } + _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.rs b/src/test/mir-opt/const_prop/ref_deref_project.rs index c7cc73651f634..659c11d9b0c29 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.rs +++ b/src/test/mir-opt/const_prop/ref_deref_project.rs @@ -1,3 +1,4 @@ +// unit-test // EMIT_MIR ref_deref_project.main.PromoteTemps.diff // EMIT_MIR ref_deref_project.main.ConstProp.diff diff --git a/src/test/ui/or-patterns/inner-or-pat.or3.stderr b/src/test/ui/or-patterns/inner-or-pat.or3.stderr new file mode 100644 index 0000000000000..2236a38c37b2b --- /dev/null +++ b/src/test/ui/or-patterns/inner-or-pat.or3.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/inner-or-pat.rs:38:54 + | +LL | match x { + | - this expression has type `&str` +LL | x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) | + | ^^ expected `str`, found `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/inner-or-pat.or4.stderr b/src/test/ui/or-patterns/inner-or-pat.or4.stderr new file mode 100644 index 0000000000000..058873ff5ff9e --- /dev/null +++ b/src/test/ui/or-patterns/inner-or-pat.or4.stderr @@ -0,0 +1,11 @@ +error[E0408]: variable `x` is not bound in all patterns + --> $DIR/inner-or-pat.rs:53:37 + | +LL | (x @ "red" | (x @ "blue" | "red")) => { + | - ^^^^^ pattern doesn't bind `x` + | | + | variable not in all patterns + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0408`. diff --git a/src/test/ui/or-patterns/inner-or-pat.rs b/src/test/ui/or-patterns/inner-or-pat.rs new file mode 100644 index 0000000000000..f4cf4b0c18890 --- /dev/null +++ b/src/test/ui/or-patterns/inner-or-pat.rs @@ -0,0 +1,73 @@ +// revisions: or1 or2 or3 or4 or5 +// [or1] run-pass +// [or2] run-pass +// [or5] run-pass + +#![allow(unreachable_patterns)] +#![allow(unused_variables)] +#![allow(unused_parens)] +#![allow(dead_code)] + + + +fn foo() { + let x = "foo"; + match x { + x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | "no" | "nop") | ("hey" | "gg")) | + x @ ("black" | "pink") | + x @ ("red" | "blue") => { + } + _ => (), + } +} + +fn bar() { + let x = "foo"; + match x { + x @ ("foo" | "bar") | + (x @ "red" | (x @ "blue" | x @ "red")) => { + } + _ => (), + } +} + +#[cfg(or3)] +fn zot() { + let x = "foo"; + match x { + x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) | + //[or3]~^ ERROR mismatched types + x @ ("black" | "pink") | + x @ ("red" | "blue") => { + } + _ => (), + } +} + + +#[cfg(or4)] +fn hey() { + let x = "foo"; + match x { + x @ ("foo" | "bar") | + (x @ "red" | (x @ "blue" | "red")) => { + //[or4]~^ variable `x` is not bound in all patterns + } + _ => (), + } +} + +fn don() { + enum Foo { + A, + B, + C, + } + + match Foo::A { + | _foo @ (Foo::A | Foo::B) => {} + Foo::C => {} + }; +} + +fn main(){} diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs new file mode 100644 index 0000000000000..1004bb28c59e7 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs @@ -0,0 +1,29 @@ +// revisions: nn ny yn yy +// check-pass +#![feature(const_trait_impl, associated_type_defaults, const_mut_refs)] + +#[cfg_attr(any(yn, yy), const_trait)] +pub trait Index { + type Output; +} + +#[cfg_attr(any(ny, yy), const_trait)] +pub trait IndexMut where Self: Index { + const C: ::Output; + type Assoc = ::Output; + fn foo(&mut self, x: ::Output) -> ::Output; +} + +impl Index for () { type Output = (); } + +impl const IndexMut for <() as Index>::Output { + const C: ::Output = (); + type Assoc = ::Output; + fn foo(&mut self, x: ::Output) -> ::Output + where ::Output:, + {} +} + +const C: <() as Index>::Output = (); + +fn main() {}