Auto merge of #100881 - Dylan-DPC:rollup-q9rr658, r=Dylan-DPC

Rollup of 8 pull requests

Successful merges:

 - #98200 (Expand potential inner `Or` pattern for THIR)
 - #99770 (Make some const prop mir-opt tests `unit-test`s)
 - #99957 (Rework Ipv6Addr::is_global to check for global reachability rather than global scope - rebase)
 - #100331 (Guarantee `try_reserve` preserves the contents on error)
 - #100336 (Fix two const_trait_impl issues)
 - #100713 (Convert diagnostics in parser/expr to SessionDiagnostic)
 - #100820 (Use pointer `is_aligned*` methods)
 - #100872 (Add guarantee that Vec::default() does not alloc)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-08-22 17:46:57 +00:00
commit a785176741
65 changed files with 1052 additions and 427 deletions

View File

@ -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 `-`

View File

@ -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<PatStack<'p, 'tcx>>,
pub patterns: Vec<PatStack<'p, 'tcx>>,
}
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);
}

View File

@ -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.

View File

@ -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(&not_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<Expr>> {
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<Expr>> {
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 <src_pat> in <src_expr> <src_loop_block>` (`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<Expr>> {
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<Expr>, rhs: P<Expr>) -> ExprKind {

View File

@ -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();

View File

@ -1010,7 +1010,8 @@ impl<T> BinaryHeap<T> {
/// 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
///

View File

@ -794,7 +794,8 @@ impl<T, A: Allocator> VecDeque<T, A> {
/// 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
///

View File

@ -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
///

View File

@ -148,7 +148,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
#[inline]
fn next(&mut self) -> Option<T> {
if self.ptr as *const _ == self.end {
if self.ptr == self.end {
None
} else if mem::size_of::<T>() == 0 {
// purposefully don't use 'ptr.offset' because for

View File

@ -875,7 +875,8 @@ impl<T, A: Allocator> Vec<T, A> {
/// in the given `Vec<T>`. 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<T, A> {
#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
impl<T> const Default for Vec<T> {
/// Creates an empty `Vec<T>`.
///
/// The vector will not allocate until elements are pushed onto it.
fn default() -> Vec<T> {
Vec::new()
}

View File

@ -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)]

View File

@ -48,11 +48,11 @@ fn verify_aligned<T>(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::<T>();
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::<T>(),
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::<T>(),
align = core::mem::align_of::<T>(),
);
}

View File

@ -2139,7 +2139,7 @@ pub(crate) use assert_unsafe_precondition;
/// Checks whether `ptr` is properly aligned with respect to
/// `align_of::<T>()`.
pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
!ptr.is_null() && ptr.addr() % mem::align_of::<T>() == 0
!ptr.is_null() && ptr.is_aligned()
}
/// Checks whether the regions of memory starting at `src` and `dst` of size

View File

@ -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.
///

View File

@ -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)]

View File

@ -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.
///
/// The following return [`false`]:
/// Most IPv4 addresses are globally reachable;
/// unless they are specifically defined as *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()`])
/// Non-exhaustive list of notable addresses that are not globally reachable:
///
/// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
/// - 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))
///
/// 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 future use are not global
/// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false);
///
/// // addresses reserved for network devices benchmarking are not global
/// // Addresses reserved for benchmarking (`198.18.0.0/15`)
/// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).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);
/// // Reserved addresses (`240.0.0.0/4`)
/// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false);
///
/// // The broadcast address (`255.255.255.255`)
/// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false);
///
/// // 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.

View File

@ -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!(

View File

@ -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);

View File

@ -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
///

View File

@ -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
}

View File

@ -1,3 +1,4 @@
// unit-test: ConstProp
// compile-flags: -O
// EMIT_MIR aggregate.main.ConstProp.diff

View File

@ -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
}

View File

@ -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
}

View File

@ -1,3 +1,4 @@
// unit-test: ConstProp
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR array_index.main.ConstProp.diff

View File

@ -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

View File

@ -1,3 +1,4 @@
// unit-test: ConstProp
// EMIT_MIR bad_op_div_by_zero.main.ConstProp.diff
#[allow(unconditional_panic)]
fn main() {

View File

@ -1,3 +1,4 @@
// unit-test: ConstProp
// compile-flags: -O -Zmir-opt-level=4
// EMIT_MIR boolean_identities.test.ConstProp.diff

View File

@ -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(<ZST>) }
}
@ -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
}

View File

@ -1,3 +1,4 @@
// unit-test: ConstProp
// compile-flags: -O
// ignore-emscripten compiled with panic=abort by default
// ignore-wasm32

View File

@ -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

View File

@ -1,3 +1,4 @@
// unit-test: ConstProp
// EMIT_MIR cast.main.ConstProp.diff
fn main() {

View File

@ -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
}

View File

@ -1,3 +1,4 @@
// unit-test: ConstProp
// compile-flags: -C overflow-checks=on
// EMIT_MIR checked_add.main.ConstProp.diff

View File

@ -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(<ZST>) }
}
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
}

View File

@ -1,3 +1,4 @@
// unit-test: ConstProp
#[inline(never)]
fn read(_: usize) { }

View File

@ -1,10 +1,11 @@
// unit-test: ConstProp
// compile-flags: -Zmir-opt-level=1
trait NeedsDrop:Sized{
const NEEDS:bool=std::mem::needs_drop::<Self>();
trait NeedsDrop: Sized {
const NEEDS: bool = std::mem::needs_drop::<Self>();
}
impl<This> NeedsDrop for This{}
impl<This> NeedsDrop for This {}
// EMIT_MIR control_flow_simplification.hello.ConstProp.diff
// EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -1,3 +1,4 @@
// unit-test: ConstProp
// compile-flags: -C overflow-checks=on
// EMIT_MIR indirect.main.ConstProp.diff

View File

@ -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

View File

@ -1,3 +1,4 @@
// unit-test: ConstProp
// compile-flags: -Z mir-opt-level=3
// This used to ICE in const-prop

View File

@ -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(<ZST>) }
}

View File

@ -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(<ZST>) }
}

View File

@ -1,3 +1,4 @@
// unit-test
// compile-flags: -O -Zmir-opt-level=4
// EMIT_MIR mult_by_zero.test.ConstProp.diff

View File

@ -1,3 +1,4 @@
// unit-test
// compile-flags: -O
// EMIT_MIR mutable_variable.main.ConstProp.diff

View File

@ -1,3 +1,4 @@
// unit-test
// compile-flags: -O
// EMIT_MIR mutable_variable_aggregate.main.ConstProp.diff

View File

@ -1,3 +1,4 @@
// unit-test
// compile-flags: -O
// EMIT_MIR mutable_variable_aggregate_mut_ref.main.ConstProp.diff

View File

@ -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(<ZST>) }
}

View File

@ -1,3 +1,4 @@
// unit-test
// compile-flags: -O
// EMIT_MIR mutable_variable_aggregate_partial_read.main.ConstProp.diff

View File

@ -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

View File

@ -1,3 +1,4 @@
// unit-test
// compile-flags: -O
static mut STATIC: u32 = 42;

View File

@ -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(<ZST>) }
}

View File

@ -1,3 +1,4 @@
// unit-test
// compile-flags: -O
// EMIT_MIR mutable_variable_unprop_assign.main.ConstProp.diff

View File

@ -1,3 +1,4 @@
// unit-test
// compile-flags: -C overflow-checks=on
struct Point {

View File

@ -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

View File

@ -1,3 +1,4 @@
// unit-test
// compile-flags: -O
static FOO: u8 = 2;

View File

@ -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

View File

@ -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

View File

@ -1,3 +1,4 @@
// unit-test
// EMIT_MIR ref_deref_project.main.PromoteTemps.diff
// EMIT_MIR ref_deref_project.main.ConstProp.diff

View File

@ -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`.

View File

@ -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`.

View File

@ -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(){}

View File

@ -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: <Self as Index>::Output;
type Assoc = <Self as Index>::Output;
fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output;
}
impl Index for () { type Output = (); }
impl const IndexMut for <() as Index>::Output {
const C: <Self as Index>::Output = ();
type Assoc = <Self as Index>::Output;
fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
where <Self as Index>::Output:,
{}
}
const C: <() as Index>::Output = ();
fn main() {}