From 815d3703469194355d6fae6bc5844a1f7bbae4e1 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 25 Nov 2022 15:02:53 +0000 Subject: [PATCH 01/14] Add documentation for `has_escaping_bound_vars` --- compiler/rustc_middle/src/ty/visit.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index b04afe549ac55..4cdfd9e594042 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -72,12 +72,18 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone { self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break() } - /// Returns `true` if this `self` has any regions that escape `binder` (and + /// Returns `true` if this type has any regions that escape `binder` (and /// hence are not bound by it). fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool { self.has_vars_bound_at_or_above(binder.shifted_in(1)) } + /// Return `true` if this type has regions that are not a part of the type. + /// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)` + /// would return `true`. The latter can occur when traversing through the + /// former. + /// + /// See [`HasEscapingVarsVisitor`] for more information. fn has_escaping_bound_vars(&self) -> bool { self.has_vars_bound_at_or_above(ty::INNERMOST) } From 77071f7e3ac76ae6734aa3ce7cfc964b3da4939f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 26 Nov 2022 10:10:34 +0100 Subject: [PATCH 02/14] interpret: remove PartialOrd from a bunch of types that do not have or need a sensible order --- compiler/rustc_middle/src/mir/interpret/allocation.rs | 4 ++-- .../rustc_middle/src/mir/interpret/allocation/init_mask.rs | 2 +- .../src/mir/interpret/allocation/provenance_map.rs | 2 +- compiler/rustc_middle/src/mir/interpret/pointer.rs | 2 +- compiler/rustc_middle/src/mir/interpret/value.rs | 4 ++-- src/tools/miri/src/concurrency/data_race.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index f8a69f3c7d53f..5f911d5884a33 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -36,7 +36,7 @@ pub use init_mask::{InitChunk, InitChunkIter}; /// module provides higher-level access. // Note: for performance reasons when interning, some of the `Allocation` fields can be partially // hashed. (see the `Hash` impl below for more details), so the impl is not derived. -#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Clone, Eq, PartialEq, TyEncodable, TyDecodable)] #[derive(HashStable)] pub struct Allocation { /// The actual bytes of the allocation. @@ -108,7 +108,7 @@ impl hash::Hash for Allocation { /// Here things are different because only const allocations are interned. This /// means that both the inner type (`Allocation`) and the outer type /// (`ConstAllocation`) are used quite a bit. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] pub struct ConstAllocation<'tcx>(pub Interned<'tcx, Allocation>); diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs index d88a0c19e5937..82e9a961a2bfb 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs @@ -12,7 +12,7 @@ type Block = u64; /// is initialized. If it is `false` the byte is uninitialized. // Note: for performance reasons when interning, some of the `InitMask` fields can be partially // hashed. (see the `Hash` impl below for more details), so the impl is not derived. -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable)] #[derive(HashStable)] pub struct InitMask { blocks: Vec, diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 19ee209e552d2..ddd3f394358a3 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -10,7 +10,7 @@ use super::{alloc_range, AllocError, AllocId, AllocRange, AllocResult, Provenanc use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; /// Stores the provenance information of pointers stored in memory. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug)] #[derive(HashStable)] pub struct ProvenanceMap { /// Provenance in this map applies from the given offset for an entire pointer-size worth of diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 4e59f1b248216..9c270ba1ec179 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -173,7 +173,7 @@ impl Provenance for AllocId { /// Represents a pointer in the Miri engine. /// /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] pub struct Pointer { pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Prov` type) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 770c3ed05e8d2..48a137162952e 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -28,7 +28,7 @@ pub struct ConstAlloc<'tcx> { /// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for /// array length computations, enum discriminants and the pattern matching logic. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash)] #[derive(HashStable, Lift)] pub enum ConstValue<'tcx> { /// Used only for types with `layout::abi::Scalar` ABI. @@ -110,7 +110,7 @@ impl<'tcx> ConstValue<'tcx> { /// /// These variants would be private if there was a convenient way to achieve that in Rust. /// Do *not* match on a `Scalar`! Use the various `to_*` methods instead. -#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)] +#[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] pub enum Scalar { /// The raw bytes of a simple value. diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index b0f766462127f..ebfd3bca736cf 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -158,7 +158,7 @@ impl ThreadClockSet { /// Error returned by finding a data race /// should be elaborated upon. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct DataRace; /// Externally stored memory cell clocks From 89afda781149e5779c38d1ee1d5bf4d633a27d61 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 26 Nov 2022 09:46:05 +0000 Subject: [PATCH 03/14] Ignore bivariant parameters in test_type_match. --- .../src/infer/outlives/test_type_match.rs | 7 +- src/test/ui/impl-trait/issues/issue-104815.rs | 66 +++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/impl-trait/issues/issue-104815.rs diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 5d204dd70ed0c..10b474efd5aeb 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -155,14 +155,17 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { bug!() } + #[instrument(level = "trace", skip(self))] fn relate_with_variance>( &mut self, - _: ty::Variance, + variance: ty::Variance, _: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { - self.relate(a, b) + // Opaque types substs have lifetime parameters. + // We must not check them to be equal, as we never insert anything to make them so. + if variance != ty::Bivariant { self.relate(a, b) } else { Ok(a) } } #[instrument(skip(self), level = "debug")] diff --git a/src/test/ui/impl-trait/issues/issue-104815.rs b/src/test/ui/impl-trait/issues/issue-104815.rs new file mode 100644 index 0000000000000..7a9826a8dff91 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-104815.rs @@ -0,0 +1,66 @@ +// check-pass + +struct It; + +struct Data { + items: Vec, +} + +impl Data { + fn new() -> Self { + Self { + items: vec![It, It], + } + } + + fn content(&self) -> impl Iterator { + self.items.iter() + } +} + +struct Container<'a> { + name: String, + resolver: Box, +} + +impl<'a> Container<'a> { + fn new(name: &str, resolver: R) -> Self { + Self { + name: name.to_owned(), + resolver: Box::new(resolver), + } + } +} + +trait Resolver {} + +impl Resolver for &R {} + +impl Resolver for It {} + +fn get<'a>(mut items: impl Iterator) -> impl Resolver + 'a { + items.next().unwrap() +} + +fn get2<'a, 'b: 'b>(mut items: impl Iterator) -> impl Resolver + 'a { + items.next().unwrap() +} + +fn main() { + let data = Data::new(); + let resolver = get(data.content()); + + let _ = ["a", "b"] + .iter() + .map(|&n| Container::new(n, &resolver)) + .map(|c| c.name) + .collect::>(); + + let resolver = get2(data.content()); + + let _ = ["a", "b"] + .iter() + .map(|&n| Container::new(n, &resolver)) + .map(|c| c.name) + .collect::>(); +} From ee6f18ef595df21cfe167834f59c768985d74d4c Mon Sep 17 00:00:00 2001 From: Vincenzo Palazzo Date: Sat, 26 Nov 2022 22:23:27 +0100 Subject: [PATCH 04/14] make simple check of prinf function. With this commit we start to make some simple check when the name resolution fails, and we generate some helper message in case the name is a C name like in the case of the `printf` and suggest the correct rust method. Signed-off-by: Vincenzo Palazzo --- compiler/rustc_resolve/src/late/diagnostics.rs | 8 ++++++++ .../ui/suggestions/seggest_print_over_printf.rs | 9 +++++++++ .../suggestions/seggest_print_over_printf.stderr | 14 ++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 src/test/ui/suggestions/seggest_print_over_printf.rs create mode 100644 src/test/ui/suggestions/seggest_print_over_printf.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9c95adc628bc6..5b9513ebc0da4 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -282,6 +282,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { "you may want to use a bool value instead", format!("{}", item_typo), )) + // FIXME(vicnenzopalazzo): make the check smarter, + // and maybe expand with levenshtein distance checks + } else if item_str.as_str() == "printf" { + Some(( + item_span, + "you may have meant to use the `print` macro", + "print!".to_owned(), + )) } else { suggestion }; diff --git a/src/test/ui/suggestions/seggest_print_over_printf.rs b/src/test/ui/suggestions/seggest_print_over_printf.rs new file mode 100644 index 0000000000000..25566cd7f2aeb --- /dev/null +++ b/src/test/ui/suggestions/seggest_print_over_printf.rs @@ -0,0 +1,9 @@ +// Suggest to a user to use the print macros +// instead to use the printf. + +fn main() { + let x = 4; + printf("%d", x); + //~^ ERROR cannot find function `printf` in this scope + //~| HELP you may have meant to use the `print` macro +} diff --git a/src/test/ui/suggestions/seggest_print_over_printf.stderr b/src/test/ui/suggestions/seggest_print_over_printf.stderr new file mode 100644 index 0000000000000..7b1ce047a9274 --- /dev/null +++ b/src/test/ui/suggestions/seggest_print_over_printf.stderr @@ -0,0 +1,14 @@ +error[E0425]: cannot find function `printf` in this scope + --> $DIR/seggest_print_over_printf.rs:6:5 + | +LL | printf("%d", x); + | ^^^^^^ not found in this scope + | +help: you may have meant to use the `print` macro + | +LL | print!("%d", x); + | ~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. From 60d5d65a4d7931ffa022453a433f433d395afdb9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 27 Nov 2022 15:20:26 +0100 Subject: [PATCH 05/14] interpret: get rid of run() function --- compiler/rustc_const_eval/src/const_eval/eval_queries.rs | 2 +- compiler/rustc_const_eval/src/interpret/step.rs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index c777a840f3fb6..c27790d8887a3 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -66,7 +66,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( )?; // The main interpreter loop. - ecx.run()?; + while ecx.step()? {} // Intern the result let intern_kind = if cid.promoted.is_some() { diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 73f8bf4362e60..60578246eedcc 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -32,11 +32,6 @@ fn binop_right_homogeneous(op: mir::BinOp) -> bool { } impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - pub fn run(&mut self) -> InterpResult<'tcx> { - while self.step()? {} - Ok(()) - } - /// Returns `true` as long as there are more things to do. /// /// This is used by [priroda](https://github.com/oli-obk/priroda) From bb273a17f81853a7d6ecc7649f5f15f5bacbe463 Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Sun, 27 Nov 2022 17:18:38 -0800 Subject: [PATCH 06/14] Update my mailmap --- .mailmap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index f887d29096e03..4ef723e51468a 100644 --- a/.mailmap +++ b/.mailmap @@ -229,7 +229,7 @@ Jacob Jacob Greenfield Jacob Pratt Jake Vossen -Jakob Degen +Jakob Degen Jakob Lautrup Nysom Jakub Adam Wieczorek Jakub Adam Wieczorek From 7a378dd0fb2b383be75722666d8a3c761882af15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20A=2E=20Muci=C3=B1o?= Date: Sun, 27 Nov 2022 20:50:13 -0600 Subject: [PATCH 07/14] Avoid ICE if the Clone trait is not found while building error suggestions --- .../src/diagnostics/conflict_errors.rs | 16 +++++++------- .../missing-clone-for-suggestion.rs | 20 ++++++++++++++++++ .../missing-clone-for-suggestion.stderr | 21 +++++++++++++++++++ 3 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/lang-items/missing-clone-for-suggestion.rs create mode 100644 src/test/ui/lang-items/missing-clone-for-suggestion.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 5ec9c5f5c1b55..d221da5c17ed0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -732,13 +732,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let tcx = self.infcx.tcx; // Try to find predicates on *generic params* that would allow copying `ty` let infcx = tcx.infer_ctxt().build(); - if infcx - .type_implements_trait( - tcx.lang_items().clone_trait().unwrap(), - [tcx.erase_regions(ty)], - self.param_env, - ) - .must_apply_modulo_regions() + + if let Some(clone_trait_def) = tcx.lang_items().clone_trait() + && infcx + .type_implements_trait( + clone_trait_def, + [tcx.erase_regions(ty)], + self.param_env, + ) + .must_apply_modulo_regions() { err.span_suggestion_verbose( span.shrink_to_hi(), diff --git a/src/test/ui/lang-items/missing-clone-for-suggestion.rs b/src/test/ui/lang-items/missing-clone-for-suggestion.rs new file mode 100644 index 0000000000000..e8290c0098afd --- /dev/null +++ b/src/test/ui/lang-items/missing-clone-for-suggestion.rs @@ -0,0 +1,20 @@ +// Avoid panicking if the Clone trait is not found while building error suggestions +// See #104870 + +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +fn g(x: T) {} + +fn f(x: *mut u8) { + g(x); + g(x); //~ ERROR use of moved value: `x` +} + +fn main() {} diff --git a/src/test/ui/lang-items/missing-clone-for-suggestion.stderr b/src/test/ui/lang-items/missing-clone-for-suggestion.stderr new file mode 100644 index 0000000000000..35783a1be78ad --- /dev/null +++ b/src/test/ui/lang-items/missing-clone-for-suggestion.stderr @@ -0,0 +1,21 @@ +error[E0382]: use of moved value: `x` + --> $DIR/missing-clone-for-suggestion.rs:17:7 + | +LL | fn f(x: *mut u8) { + | - move occurs because `x` has type `*mut u8`, which does not implement the `Copy` trait +LL | g(x); + | - value moved here +LL | g(x); + | ^ value used here after move + | +note: consider changing this parameter type in function `g` to borrow instead if owning the value isn't necessary + --> $DIR/missing-clone-for-suggestion.rs:13:12 + | +LL | fn g(x: T) {} + | - ^ this parameter takes ownership of the value + | | + | in this function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. From 8cfc8153da71c599ba6e118279d366b74638057e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 23 Nov 2022 17:00:37 +1100 Subject: [PATCH 08/14] Remove `Lit::from_included_bytes`. `Lit::from_included_bytes` calls `Lit::from_lit_kind`, but the two call sites only need the resulting `token::Lit`, not the full `ast::Lit`. This commit changes those call sites to use `LitKind::to_token_lit`, which means `from_included_bytes` can be removed. --- compiler/rustc_ast/src/util/literal.rs | 8 -------- compiler/rustc_ast_pretty/src/pprust/state/expr.rs | 4 ++-- compiler/rustc_expand/src/proc_macro_server.rs | 4 ++-- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index db2ac9626afd5..8eec869fbe5f0 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -2,7 +2,6 @@ use crate::ast::{self, Lit, LitKind}; use crate::token::{self, Token}; -use rustc_data_structures::sync::Lrc; use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; @@ -215,13 +214,6 @@ impl Lit { Lit { token_lit: kind.to_token_lit(), kind, span } } - /// Recovers an AST literal from a string of bytes produced by `include_bytes!`. - /// This requires ASCII-escaping the string, which can result in poor performance - /// for very large strings of bytes. - pub fn from_included_bytes(bytes: &Lrc<[u8]>, span: Span) -> Lit { - Self::from_lit_kind(LitKind::ByteStr(bytes.clone()), span) - } - /// Losslessly convert an AST literal into a token. pub fn to_token(&self) -> Token { let kind = match self.token_lit.kind { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 949d98f96ab6a..f4d77549eff4c 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -328,8 +328,8 @@ impl<'a> State<'a> { self.print_token_literal(token_lit, expr.span); } ast::ExprKind::IncludedBytes(ref bytes) => { - let lit = ast::Lit::from_included_bytes(bytes, expr.span); - self.print_literal(&lit) + let lit = ast::LitKind::ByteStr(bytes.clone()).to_token_lit(); + self.print_token_literal(lit, expr.span) } ast::ExprKind::Cast(ref expr, ref ty) => { let prec = AssocOp::As.precedence() as i8; diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 2e832deeecda0..b69556c0e7cc2 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -526,9 +526,9 @@ impl server::TokenStream for Rustc<'_, '_> { Ok(tokenstream::TokenStream::token_alone(token::Literal(*token_lit), expr.span)) } ast::ExprKind::IncludedBytes(bytes) => { - let lit = ast::Lit::from_included_bytes(bytes, expr.span); + let lit = ast::LitKind::ByteStr(bytes.clone()).to_token_lit(); Ok(tokenstream::TokenStream::token_alone( - token::TokenKind::Literal(lit.token_lit), + token::TokenKind::Literal(lit), expr.span, )) } From aa10aad1ac5058e8278d8871c1cb4473134d3d54 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Nov 2022 13:47:57 +1100 Subject: [PATCH 09/14] Factor out a repeated expression in `lower_attr_args`. --- compiler/rustc_ast_lowering/src/lib.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a123a58a8fbfa..530cf7d978796 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -948,15 +948,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => { // In valid code the value always ends up as a single literal. Otherwise, a dummy // literal suffices because the error is handled elsewhere. - let lit = if let ExprKind::Lit(token_lit) = expr.kind { - match Lit::from_token_lit(token_lit, expr.span) { - Ok(lit) => lit, - Err(_err) => Lit { - token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None), - kind: LitKind::Err, - span: DUMMY_SP, - }, - } + let lit = if let ExprKind::Lit(token_lit) = expr.kind + && let Ok(lit) = Lit::from_token_lit(token_lit, expr.span) + { + lit } else { Lit { token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None), From e4a9150872a08db286208d07f5a6a90e466ca39c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 23 Nov 2022 15:39:42 +1100 Subject: [PATCH 10/14] Rename `ast::Lit` as `ast::MetaItemLit`. --- compiler/rustc_ast/src/ast.rs | 21 ++++++++------- compiler/rustc_ast/src/attr/mod.rs | 18 ++++++------- compiler/rustc_ast/src/util/literal.rs | 24 ++++++++--------- compiler/rustc_ast_lowering/src/lib.rs | 6 ++--- compiler/rustc_ast_pretty/src/pprust/state.rs | 12 ++++----- compiler/rustc_attr/src/builtin.rs | 12 +++++---- compiler/rustc_builtin_macros/src/derive.rs | 4 +-- .../rustc_expand/src/proc_macro_server.rs | 5 +--- compiler/rustc_hir_analysis/src/collect.rs | 6 +++-- compiler/rustc_middle/src/ty/context.rs | 5 ++-- compiler/rustc_parse/src/parser/attr.rs | 9 ++++--- compiler/rustc_parse/src/parser/expr.rs | 27 ++++++++++--------- compiler/rustc_parse/src/parser/stmt.rs | 2 +- compiler/rustc_parse/src/validate_attr.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 7 +++-- src/tools/clippy/clippy_lints/src/attrs.rs | 4 +-- src/tools/rustfmt/src/attr.rs | 11 +++++--- src/tools/rustfmt/src/modules/visitor.rs | 12 ++++++--- 18 files changed, 103 insertions(+), 84 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 8bb4442d1bb27..5d470f1c453fe 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -13,7 +13,7 @@ //! - [`FnDecl`], [`FnHeader`] and [`Param`]: Metadata associated with a function declaration. //! - [`Generics`], [`GenericParam`], [`WhereClause`]: Metadata associated with generic parameters. //! - [`EnumDef`] and [`Variant`]: Enum declaration. -//! - [`Lit`] and [`LitKind`]: Literal expressions. +//! - [`MetaItemLit`] and [`LitKind`]: Literal expressions. //! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`], [`MacDelimiter`]: Macro definition and invocation. //! - [`Attribute`]: Metadata associated with item. //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators. @@ -489,7 +489,7 @@ pub enum NestedMetaItem { /// A literal. /// /// E.g., `"foo"`, `64`, `true`. - Literal(Lit), + Literal(MetaItemLit), } /// A spanned compile-time attribute item. @@ -518,7 +518,7 @@ pub enum MetaItemKind { /// Name value meta item. /// /// E.g., `feature = "foo"` as in `#[feature = "foo"]`. - NameValue(Lit), + NameValue(MetaItemLit), } /// A block (`{ .. }`). @@ -1599,12 +1599,12 @@ pub enum AttrArgs { } // The RHS of an `AttrArgs::Eq` starts out as an expression. Once macro -// expansion is completed, all cases end up either as a literal, which is the -// form used after lowering to HIR, or as an error. +// expansion is completed, all cases end up either as a meta item literal, +// which is the form used after lowering to HIR, or as an error. #[derive(Clone, Encodable, Decodable, Debug)] pub enum AttrArgsEq { Ast(P), - Hir(Lit), + Hir(MetaItemLit), } impl AttrArgs { @@ -1726,14 +1726,13 @@ pub enum StrStyle { Raw(u8), } -/// An AST literal. +/// A literal in a meta item. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] -pub struct Lit { +pub struct MetaItemLit { /// The original literal token as written in source code. pub token_lit: token::Lit, /// The "semantic" representation of the literal lowered from the original tokens. /// Strings are unescaped, hexadecimal forms are eliminated, etc. - /// FIXME: Remove this and only create the semantic representation during lowering to HIR. pub kind: LitKind, pub span: Span, } @@ -1783,6 +1782,8 @@ pub enum LitFloatType { Unsuffixed, } +/// This type is used within both `ast::MetaItemLit` and `hir::Lit`. +/// /// Note that the entire literal (including the suffix) is considered when /// deciding the `LitKind`. This means that float literals like `1f32` are /// classified by this type as `Float`. This is different to `token::LitKind` @@ -3096,9 +3097,9 @@ mod size_asserts { static_assert_size!(Impl, 184); static_assert_size!(Item, 184); static_assert_size!(ItemKind, 112); - static_assert_size!(Lit, 48); static_assert_size!(LitKind, 24); static_assert_size!(Local, 72); + static_assert_size!(MetaItemLit, 48); static_assert_size!(Param, 40); static_assert_size!(Pat, 88); static_assert_size!(Path, 24); diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index c948faeb35835..a31fe36dac705 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -2,7 +2,7 @@ use crate::ast; use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, Attribute}; -use crate::ast::{DelimArgs, Lit, LitKind}; +use crate::ast::{DelimArgs, LitKind, MetaItemLit}; use crate::ast::{MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Path, PathSegment}; use crate::ptr::P; @@ -50,8 +50,8 @@ impl NestedMetaItem { } } - /// Returns the `Lit` if `self` is a `NestedMetaItem::Literal`s. - pub fn literal(&self) -> Option<&Lit> { + /// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s. + pub fn literal(&self) -> Option<&MetaItemLit> { match self { NestedMetaItem::Literal(lit) => Some(lit), _ => None, @@ -78,7 +78,7 @@ impl NestedMetaItem { } /// Returns a name and single literal value tuple of the `MetaItem`. - pub fn name_value_literal(&self) -> Option<(Symbol, &Lit)> { + pub fn name_value_literal(&self) -> Option<(Symbol, &MetaItemLit)> { self.meta_item().and_then(|meta_item| { meta_item.meta_item_list().and_then(|meta_item_list| { if meta_item_list.len() == 1 @@ -179,7 +179,7 @@ impl MetaItem { /// #[attribute(name = "value")] /// ^^^^^^^^^^^^^^ /// ``` - pub fn name_value_literal(&self) -> Option<&Lit> { + pub fn name_value_literal(&self) -> Option<&MetaItemLit> { match &self.kind { MetaItemKind::NameValue(v) => Some(v), _ => None, @@ -334,7 +334,7 @@ pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> Meta } pub fn mk_name_value_item(ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem { - let lit = Lit::from_lit_kind(lit_kind, lit_span); + let lit = MetaItemLit::from_lit_kind(lit_kind, lit_span); let span = ident.span.to(lit_span); MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) } } @@ -604,7 +604,7 @@ impl MetaItemKind { MetaItemKind::name_value_from_tokens(&mut inner_tokens.into_trees()) } Some(TokenTree::Token(token, _)) => { - Lit::from_token(&token).map(MetaItemKind::NameValue) + MetaItemLit::from_token(&token).map(MetaItemKind::NameValue) } _ => None, } @@ -622,7 +622,7 @@ impl MetaItemKind { AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => match expr.kind { ast::ExprKind::Lit(token_lit) => { // Turn failures to `None`, we'll get parse errors elsewhere. - Lit::from_token_lit(token_lit, expr.span) + MetaItemLit::from_token_lit(token_lit, expr.span) .ok() .map(|lit| MetaItemKind::NameValue(lit)) } @@ -674,7 +674,7 @@ impl NestedMetaItem { { match tokens.peek() { Some(TokenTree::Token(token, _)) - if let Some(lit) = Lit::from_token(token) => + if let Some(lit) = MetaItemLit::from_token(token) => { tokens.next(); return Some(NestedMetaItem::Literal(lit)); diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 8eec869fbe5f0..42cba07fcef8d 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -1,6 +1,6 @@ //! Code related to parsing literals. -use crate::ast::{self, Lit, LitKind}; +use crate::ast::{self, LitKind, MetaItemLit}; use crate::token::{self, Token}; use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode}; use rustc_span::symbol::{kw, sym, Symbol}; @@ -195,26 +195,26 @@ impl LitKind { } } -impl Lit { - /// Converts literal token into an AST literal. - pub fn from_token_lit(token_lit: token::Lit, span: Span) -> Result { - Ok(Lit { token_lit, kind: LitKind::from_token_lit(token_lit)?, span }) +impl MetaItemLit { + /// Converts token literal into a meta item literal. + pub fn from_token_lit(token_lit: token::Lit, span: Span) -> Result { + Ok(MetaItemLit { token_lit, kind: LitKind::from_token_lit(token_lit)?, span }) } - /// Converts an arbitrary token into an AST literal. - pub fn from_token(token: &Token) -> Option { + /// Converts an arbitrary token into meta item literal. + pub fn from_token(token: &Token) -> Option { token::Lit::from_token(token) - .and_then(|token_lit| Lit::from_token_lit(token_lit, token.span).ok()) + .and_then(|token_lit| MetaItemLit::from_token_lit(token_lit, token.span).ok()) } - /// Attempts to recover an AST literal from semantic literal. + /// Attempts to create a meta item literal from a `LitKind`. /// This function is used when the original token doesn't exist (e.g. the literal is created /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). - pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit { - Lit { token_lit: kind.to_token_lit(), kind, span } + pub fn from_lit_kind(kind: LitKind, span: Span) -> MetaItemLit { + MetaItemLit { token_lit: kind.to_token_lit(), kind, span } } - /// Losslessly convert an AST literal into a token. + /// Losslessly convert a meta item literal into a token. pub fn to_token(&self) -> Token { let kind = match self.token_lit.kind { token::Bool => token::Ident(self.token_lit.symbol, false), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 530cf7d978796..ad6e72d015695 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -948,12 +948,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => { // In valid code the value always ends up as a single literal. Otherwise, a dummy // literal suffices because the error is handled elsewhere. - let lit = if let ExprKind::Lit(token_lit) = expr.kind - && let Ok(lit) = Lit::from_token_lit(token_lit, expr.span) + let lit = if let ExprKind::Lit(token_lit) = expr.kind + && let Ok(lit) = MetaItemLit::from_token_lit(token_lit, expr.span) { lit } else { - Lit { + MetaItemLit { token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None), kind: LitKind::Err, span: DUMMY_SP, diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 991f6e0ba2243..27faef25e6745 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -371,7 +371,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } } - fn print_literal(&mut self, lit: &ast::Lit) { + fn print_meta_item_lit(&mut self, lit: &ast::MetaItemLit) { self.print_token_literal(lit.token_lit, lit.span) } @@ -488,7 +488,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.print_path(&item.path, false, 0); self.space(); self.word_space("="); - let token_str = self.literal_to_string(lit); + let token_str = self.meta_item_lit_to_string(lit); self.word(token_str); } } @@ -498,7 +498,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) { match item { ast::NestedMetaItem::MetaItem(ref mi) => self.print_meta_item(mi), - ast::NestedMetaItem::Literal(ref lit) => self.print_literal(lit), + ast::NestedMetaItem::Literal(ref lit) => self.print_meta_item_lit(lit), } } @@ -510,7 +510,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.print_path(&item.path, false, 0); self.space(); self.word_space("="); - self.print_literal(value); + self.print_meta_item_lit(value); } ast::MetaItemKind::List(ref items) => { self.print_path(&item.path, false, 0); @@ -825,8 +825,8 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere Self::to_string(|s| s.print_expr(e)) } - fn literal_to_string(&self, lit: &ast::Lit) -> String { - Self::to_string(|s| s.print_literal(lit)) + fn meta_item_lit_to_string(&self, lit: &ast::MetaItemLit) -> String { + Self::to_string(|s| s.print_meta_item_lit(lit)) } fn tt_to_string(&self, tt: &TokenTree) -> String { diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 753f62dd589d0..ee2498a5724a1 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1,7 +1,7 @@ //! Parsing and validation of builtin attributes use rustc_ast as ast; -use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem, NodeId}; +use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId}; use rustc_ast_pretty::pprust; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; use rustc_macros::HashStable_Generic; @@ -658,11 +658,13 @@ pub fn eval_condition( ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => { try_gate_cfg(sym::version, cfg.span, sess, features); let (min_version, span) = match &mis[..] { - [NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => { - (sym, span) - } [ - NestedMetaItem::Literal(Lit { span, .. }) + NestedMetaItem::Literal(MetaItemLit { + kind: LitKind::Str(sym, ..), span, .. + }), + ] => (sym, span), + [ + NestedMetaItem::Literal(MetaItemLit { span, .. }) | NestedMetaItem::MetaItem(MetaItem { span, .. }), ] => { sess.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 01f237e6ab5fa..b9b3163acca6a 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -50,7 +50,7 @@ impl MultiItemModifier for Expander { NestedMetaItem::MetaItem(meta) => Some(meta), NestedMetaItem::Literal(lit) => { // Reject `#[derive("Debug")]`. - report_unexpected_literal(sess, &lit); + report_unexpected_meta_item_lit(sess, &lit); None } }) @@ -127,7 +127,7 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool { bad_target } -fn report_unexpected_literal(sess: &Session, lit: &ast::Lit) { +fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) { let help_msg = match lit.token_lit.kind { token::Str if rustc_lexer::is_ident(lit.token_lit.symbol.as_str()) => { format!("try using `#[derive({})]`", lit.token_lit.symbol) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index b69556c0e7cc2..7616579611711 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -527,10 +527,7 @@ impl server::TokenStream for Rustc<'_, '_> { } ast::ExprKind::IncludedBytes(bytes) => { let lit = ast::LitKind::ByteStr(bytes.clone()).to_token_lit(); - Ok(tokenstream::TokenStream::token_alone( - token::TokenKind::Literal(lit), - expr.span, - )) + Ok(tokenstream::TokenStream::token_alone(token::TokenKind::Literal(lit), expr.span)) } ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind { ast::ExprKind::Lit(token_lit) => match token_lit { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 4c1d95a452d5e..9e92ca8243cc3 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -2145,7 +2145,7 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { - use rustc_ast::{Lit, LitIntType, LitKind}; + use rustc_ast::{LitIntType, LitKind, MetaItemLit}; if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" { feature_err( &tcx.sess.parse_sess, @@ -2168,7 +2168,9 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { } _ => None, }; - if let Some(Lit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = sole_meta_list { + if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = + sole_meta_list + { // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, // the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index bf30a403d9b94..74c58e4fc4821 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1191,8 +1191,9 @@ impl<'tcx> TyCtxt<'tcx> { debug!("layout_scalar_valid_range: attr={:?}", attr); if let Some( &[ - ast::NestedMetaItem::Literal(ast::Lit { - kind: ast::LitKind::Int(a, _), .. + ast::NestedMetaItem::Literal(ast::MetaItemLit { + kind: ast::LitKind::Int(a, _), + .. }), ], ) = attr.meta_item_list().as_deref() diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 0ed24fe849c07..c825554e2ffd2 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -315,8 +315,9 @@ impl<'a> Parser<'a> { Ok(attrs) } - pub(crate) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { - let lit = self.parse_ast_lit()?; + // Note: must be unsuffixed. + pub(crate) fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'a, ast::MetaItemLit> { + let lit = self.parse_meta_item_lit()?; debug!("checking if {:?} is unsuffixed", lit); if !lit.kind.is_unsuffixed() { @@ -391,7 +392,7 @@ impl<'a> Parser<'a> { pub(crate) fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { Ok(if self.eat(&token::Eq) { - ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?) + ast::MetaItemKind::NameValue(self.parse_unsuffixed_meta_item_lit()?) } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`. let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?; @@ -403,7 +404,7 @@ impl<'a> Parser<'a> { /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`. fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { - match self.parse_unsuffixed_lit() { + match self.parse_unsuffixed_meta_item_lit() { Ok(lit) => return Ok(ast::NestedMetaItem::Literal(lit)), Err(err) => err.cancel(), } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9f2267efb8287..e0443a697b504 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -33,10 +33,10 @@ use rustc_ast::util::case::Case; use rustc_ast::util::classify; use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; use rustc_ast::visit::Visitor; -use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, Lit, UnOp, DUMMY_NODE_ID}; +use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, UnOp, DUMMY_NODE_ID}; use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind}; use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; -use rustc_ast::{ClosureBinder, StmtKind}; +use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind}; use rustc_ast_pretty::pprust; use rustc_errors::{ Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult, @@ -1631,7 +1631,7 @@ impl<'a> Parser<'a> { &self, lifetime: Ident, err: impl FnOnce(&Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>, - ) -> ast::Lit { + ) -> ast::MetaItemLit { if let Some(mut diag) = self.sess.span_diagnostic.steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar) { @@ -1653,7 +1653,7 @@ impl<'a> Parser<'a> { .emit(); } let name = lifetime.without_first_quote().name; - ast::Lit { + ast::MetaItemLit { token_lit: token::Lit::new(token::LitKind::Char, name, None), kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')), span: lifetime.span, @@ -1768,8 +1768,8 @@ impl<'a> Parser<'a> { /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. - pub fn parse_str_lit(&mut self) -> Result> { - match self.parse_opt_ast_lit() { + pub fn parse_str_lit(&mut self) -> Result> { + match self.parse_opt_meta_item_lit() { Some(lit) => match lit.kind { ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit { style, @@ -1784,7 +1784,7 @@ impl<'a> Parser<'a> { } } - fn handle_missing_lit(&mut self) -> PResult<'a, Lit> { + fn handle_missing_lit(&mut self) -> PResult<'a, MetaItemLit> { if let token::Interpolated(inner) = &self.token.kind { let expr = match inner.as_ref() { token::NtExpr(expr) => Some(expr), @@ -1820,8 +1820,8 @@ impl<'a> Parser<'a> { .or_else(|()| self.handle_missing_lit().map(|lit| (lit.token_lit, lit.span))) } - pub(super) fn parse_ast_lit(&mut self) -> PResult<'a, Lit> { - self.parse_opt_ast_lit().ok_or(()).or_else(|()| self.handle_missing_lit()) + pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> { + self.parse_opt_meta_item_lit().ok_or(()).or_else(|()| self.handle_missing_lit()) } fn recover_after_dot(&mut self) -> Option { @@ -1867,12 +1867,12 @@ impl<'a> Parser<'a> { /// Matches `lit = true | false | token_lit`. /// Returns `None` if the next token is not a literal. - pub(super) fn parse_opt_ast_lit(&mut self) -> Option { + pub(super) fn parse_opt_meta_item_lit(&mut self) -> Option { let recovered = self.recover_after_dot(); let token = recovered.as_ref().unwrap_or(&self.token); match token::Lit::from_token(token) { Some(token_lit) => { - match Lit::from_token_lit(token_lit, token.span) { + match MetaItemLit::from_token_lit(token_lit, token.span) { Ok(lit) => { self.bump(); Some(lit) @@ -1889,7 +1889,10 @@ impl<'a> Parser<'a> { let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); let symbol = Symbol::intern(&suffixless_lit.to_string()); let lit = token::Lit::new(token::Err, symbol, lit.suffix); - Some(Lit::from_token_lit(lit, span).unwrap_or_else(|_| unreachable!())) + Some( + MetaItemLit::from_token_lit(lit, span) + .unwrap_or_else(|_| unreachable!()), + ) } } } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1b56cd72db079..ff1ddfd97dfc6 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -358,7 +358,7 @@ impl<'a> Parser<'a> { /// report error for `let 1x = 123` pub fn report_invalid_identifier_error(&mut self) -> PResult<'a, ()> { if let token::Literal(lit) = self.token.uninterpolate().kind && - rustc_ast::Lit::from_token(&self.token).is_none() && + rustc_ast::MetaItemLit::from_token(&self.token).is_none() && (lit.kind == token::LitKind::Integer || lit.kind == token::LitKind::Float) && self.look_ahead(1, |t| matches!(t.kind, token::Eq) || matches!(t.kind, token::Colon ) ) { return Err(self.sess.create_err(InvalidIdentiferStartsWithNumber { span: self.token.span })); diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index e2f95d74a3d22..59e564114e5cf 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -51,7 +51,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta } AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => { if let ast::ExprKind::Lit(token_lit) = expr.kind - && let Ok(lit) = ast::Lit::from_token_lit(token_lit, expr.span) + && let Ok(lit) = ast::MetaItemLit::from_token_lit(token_lit, expr.span) { if token_lit.suffix.is_some() { let mut err = sess.span_diagnostic.struct_span_err( diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index acb9bd8e78a4a..c3794660d5c94 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -8,7 +8,7 @@ use crate::errors::{ self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr, OnlyHasEffectOn, TransparentIncompatible, UnrecognizedReprHint, }; -use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; +use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{fluent, Applicability, MultiSpan}; use rustc_expand::base::resolve_path; @@ -1355,7 +1355,10 @@ impl CheckAttrVisitor<'_> { return false; }; - if matches!(&list[..], &[NestedMetaItem::Literal(Lit { kind: LitKind::Int(..), .. })]) { + if matches!( + &list[..], + &[NestedMetaItem::Literal(MetaItemLit { kind: LitKind::Int(..), .. })] + ) { true } else { self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span }); diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index ecf8e83375dbf..018f10f258867 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -6,7 +6,7 @@ use clippy_utils::msrvs; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; use clippy_utils::{extract_msrv_attr, meets_msrv}; use if_chain::if_chain; -use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; +use rustc_ast::{AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_errors::Applicability; use rustc_hir::{ Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind, @@ -576,7 +576,7 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut } } -fn check_semver(cx: &LateContext<'_>, span: Span, lit: &Lit) { +fn check_semver(cx: &LateContext<'_>, span: Span, lit: &MetaItemLit) { if let LitKind::Str(is, _) = lit.kind { if Version::parse(is.as_str()).is_ok() { return; diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 23f55db773e6c..8cba2a850e5bc 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -527,14 +527,19 @@ pub(crate) trait MetaVisitor<'ast> { fn visit_meta_word(&mut self, _meta_item: &'ast ast::MetaItem) {} - fn visit_meta_name_value(&mut self, _meta_item: &'ast ast::MetaItem, _lit: &'ast ast::Lit) {} + fn visit_meta_name_value( + &mut self, + _meta_item: &'ast ast::MetaItem, + _lit: &'ast ast::MetaItemLit, + ) { + } fn visit_nested_meta_item(&mut self, nm: &'ast ast::NestedMetaItem) { match nm { ast::NestedMetaItem::MetaItem(ref meta_item) => self.visit_meta_item(meta_item), - ast::NestedMetaItem::Literal(ref lit) => self.visit_literal(lit), + ast::NestedMetaItem::Literal(ref lit) => self.visit_meta_item_lit(lit), } } - fn visit_literal(&mut self, _lit: &'ast ast::Lit) {} + fn visit_meta_item_lit(&mut self, _lit: &'ast ast::MetaItemLit) {} } diff --git a/src/tools/rustfmt/src/modules/visitor.rs b/src/tools/rustfmt/src/modules/visitor.rs index ea67977c17a2b..48431693332a6 100644 --- a/src/tools/rustfmt/src/modules/visitor.rs +++ b/src/tools/rustfmt/src/modules/visitor.rs @@ -84,15 +84,19 @@ impl PathVisitor { } impl<'ast> MetaVisitor<'ast> for PathVisitor { - fn visit_meta_name_value(&mut self, meta_item: &'ast ast::MetaItem, lit: &'ast ast::Lit) { + fn visit_meta_name_value( + &mut self, + meta_item: &'ast ast::MetaItem, + lit: &'ast ast::MetaItemLit, + ) { if meta_item.has_name(Symbol::intern("path")) && lit.kind.is_str() { - self.paths.push(lit_to_str(lit)); + self.paths.push(meta_item_lit_to_str(lit)); } } } #[cfg(not(windows))] -fn lit_to_str(lit: &ast::Lit) -> String { +fn meta_item_lit_to_str(lit: &ast::MetaItemLit) -> String { match lit.kind { ast::LitKind::Str(symbol, ..) => symbol.to_string(), _ => unreachable!(), @@ -100,7 +104,7 @@ fn lit_to_str(lit: &ast::Lit) -> String { } #[cfg(windows)] -fn lit_to_str(lit: &ast::Lit) -> String { +fn meta_item_lit_to_str(lit: &ast::MetaItemLit) -> String { match lit.kind { ast::LitKind::Str(symbol, ..) => symbol.as_str().replace("/", "\\"), _ => unreachable!(), From 1c65264f3cbfb9b6e4b06ff0a89fc706f2d20a85 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 25 Nov 2022 08:18:57 +1100 Subject: [PATCH 11/14] Adjust comments on `StrLit`. --- compiler/rustc_ast/src/ast.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5d470f1c453fe..3b6716de710b0 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1737,7 +1737,7 @@ pub struct MetaItemLit { pub span: Span, } -/// Same as `Lit`, but restricted to string literals. +/// Similar to `MetaItemLit`, but restricted to string literals. #[derive(Clone, Copy, Encodable, Decodable, Debug)] pub struct StrLit { /// The original literal token as written in source code. @@ -1746,7 +1746,6 @@ pub struct StrLit { pub suffix: Option, pub span: Span, /// The unescaped "semantic" representation of the literal lowered from the original token. - /// FIXME: Remove this and only create the semantic representation during lowering to HIR. pub symbol_unescaped: Symbol, } From a60e337c884f3201e693e6a5111b663bbc54de27 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Nov 2022 15:00:09 +1100 Subject: [PATCH 12/14] Rename `NestedMetaItem::[Ll]iteral` as `NestedMetaItem::[Ll]it`. We already use a mix of `Literal` and `Lit`. The latter is better because it is shorter without causing any ambiguity. --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_ast/src/attr/mod.rs | 12 ++++++------ compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- compiler/rustc_attr/src/builtin.rs | 14 ++++++-------- compiler/rustc_builtin_macros/src/derive.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 2 +- compiler/rustc_interface/src/interface.rs | 2 +- compiler/rustc_lint/src/internal.rs | 4 ++-- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_parse/src/parser/attr.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 9 +++------ compiler/rustc_resolve/src/lib.rs | 2 +- src/librustdoc/clean/cfg.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/types.rs | 2 +- src/tools/rustfmt/src/attr.rs | 6 ++---- src/tools/rustfmt/src/overflow.rs | 4 ++-- src/tools/rustfmt/src/utils.rs | 2 +- 19 files changed, 34 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3b6716de710b0..d0bb05c36549b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -489,7 +489,7 @@ pub enum NestedMetaItem { /// A literal. /// /// E.g., `"foo"`, `64`, `true`. - Literal(MetaItemLit), + Lit(MetaItemLit), } /// A spanned compile-time attribute item. diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index a31fe36dac705..7a86b471ba298 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -51,9 +51,9 @@ impl NestedMetaItem { } /// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s. - pub fn literal(&self) -> Option<&MetaItemLit> { + pub fn lit(&self) -> Option<&MetaItemLit> { match self { - NestedMetaItem::Literal(lit) => Some(lit), + NestedMetaItem::Lit(lit) => Some(lit), _ => None, } } @@ -83,7 +83,7 @@ impl NestedMetaItem { meta_item.meta_item_list().and_then(|meta_item_list| { if meta_item_list.len() == 1 && let Some(ident) = meta_item.ident() - && let Some(lit) = meta_item_list[0].literal() + && let Some(lit) = meta_item_list[0].lit() { return Some((ident.name, lit)); } @@ -655,14 +655,14 @@ impl NestedMetaItem { pub fn span(&self) -> Span { match self { NestedMetaItem::MetaItem(item) => item.span, - NestedMetaItem::Literal(lit) => lit.span, + NestedMetaItem::Lit(lit) => lit.span, } } fn token_trees(&self) -> Vec { match self { NestedMetaItem::MetaItem(item) => item.token_trees(), - NestedMetaItem::Literal(lit) => { + NestedMetaItem::Lit(lit) => { vec![TokenTree::Token(lit.to_token(), Spacing::Alone)] } } @@ -677,7 +677,7 @@ impl NestedMetaItem { if let Some(lit) = MetaItemLit::from_token(token) => { tokens.next(); - return Some(NestedMetaItem::Literal(lit)); + return Some(NestedMetaItem::Lit(lit)); } Some(TokenTree::Delimited(_, Delimiter::Invisible, inner_tokens)) => { let inner_tokens = inner_tokens.clone(); diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 11def67c46365..cb3c54fa03ce5 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -628,7 +628,7 @@ pub fn noop_visit_macro_def(macro_def: &mut MacroDef, vis: &mut T pub fn noop_visit_meta_list_item(li: &mut NestedMetaItem, vis: &mut T) { match li { NestedMetaItem::MetaItem(mi) => vis.visit_meta_item(mi), - NestedMetaItem::Literal(_lit) => {} + NestedMetaItem::Lit(_lit) => {} } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 27faef25e6745..7a9243c511b92 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -498,7 +498,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) { match item { ast::NestedMetaItem::MetaItem(ref mi) => self.print_meta_item(mi), - ast::NestedMetaItem::Literal(ref lit) => self.print_meta_item_lit(lit), + ast::NestedMetaItem::Lit(ref lit) => self.print_meta_item_lit(lit), } } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index ee2498a5724a1..13b48d8f89ab4 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -486,7 +486,7 @@ where continue 'outer; } }, - NestedMetaItem::Literal(lit) => { + NestedMetaItem::Lit(lit) => { handle_errors( &sess.parse_sess, lit.span, @@ -658,13 +658,11 @@ pub fn eval_condition( ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => { try_gate_cfg(sym::version, cfg.span, sess, features); let (min_version, span) = match &mis[..] { + [NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { + (sym, span) + } [ - NestedMetaItem::Literal(MetaItemLit { - kind: LitKind::Str(sym, ..), span, .. - }), - ] => (sym, span), - [ - NestedMetaItem::Literal(MetaItemLit { span, .. }) + NestedMetaItem::Lit(MetaItemLit { span, .. }) | NestedMetaItem::MetaItem(MetaItem { span, .. }), ] => { sess.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); @@ -901,7 +899,7 @@ where continue 'outer; } }, - NestedMetaItem::Literal(lit) => { + NestedMetaItem::Lit(lit) => { handle_errors( &sess.parse_sess, lit.span, diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index b9b3163acca6a..c8a2fca00e800 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -48,7 +48,7 @@ impl MultiItemModifier for Expander { .into_iter() .filter_map(|nested_meta| match nested_meta { NestedMetaItem::MetaItem(meta) => Some(meta), - NestedMetaItem::Literal(lit) => { + NestedMetaItem::Lit(lit) => { // Reject `#[derive("Debug")]`. report_unexpected_meta_item_lit(sess, &lit); None diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 9e92ca8243cc3..638dd6d756b58 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -2158,7 +2158,7 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { let meta_item_list = attr.meta_item_list(); let meta_item_list = meta_item_list.as_deref(); let sole_meta_list = match meta_item_list { - Some([item]) => item.literal(), + Some([item]) => item.lit(), Some(_) => { tcx.sess .struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`") diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 99c934862c480..4c22ab68a5681 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -194,7 +194,7 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { for val in values { if let Some(LitKind::Str(s, _)) = - val.literal().map(|lit| &lit.kind) + val.lit().map(|lit| &lit.kind) { ident_values.insert(s.to_string()); } else { diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 293f1c5c471a2..a6c7e819482c2 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -462,8 +462,8 @@ impl LateLintPass<'_> for BadOptAccess { let Some(attr) = cx.tcx.get_attr(field.did, sym::rustc_lint_opt_deny_field_access) && let Some(items) = attr.meta_item_list() && let Some(item) = items.first() && - let Some(literal) = item.literal() && - let ast::LitKind::Str(val, _) = literal.kind + let Some(lit) = item.lit() && + let ast::LitKind::Str(val, _) = lit.kind { cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, val.as_str(), |lint| lint diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 74c58e4fc4821..297433d37c4f3 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1191,7 +1191,7 @@ impl<'tcx> TyCtxt<'tcx> { debug!("layout_scalar_valid_range: attr={:?}", attr); if let Some( &[ - ast::NestedMetaItem::Literal(ast::MetaItemLit { + ast::NestedMetaItem::Lit(ast::MetaItemLit { kind: ast::LitKind::Int(a, _), .. }), diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index c825554e2ffd2..c7d239b647f35 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -405,7 +405,7 @@ impl<'a> Parser<'a> { /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`. fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { match self.parse_unsuffixed_meta_item_lit() { - Ok(lit) => return Ok(ast::NestedMetaItem::Literal(lit)), + Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)), Err(err) => err.cancel(), } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c3794660d5c94..2e2874dbccb9e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -715,7 +715,7 @@ impl CheckAttrVisitor<'_> { if let Some(values) = meta.meta_item_list() { let mut errors = 0; for v in values { - match v.literal() { + match v.lit() { Some(l) => match l.kind { LitKind::Str(s, _) => { if !self.check_doc_alias_value(v, s, hir_id, target, true, aliases) { @@ -1355,10 +1355,7 @@ impl CheckAttrVisitor<'_> { return false; }; - if matches!( - &list[..], - &[NestedMetaItem::Literal(MetaItemLit { kind: LitKind::Int(..), .. })] - ) { + if matches!(&list[..], &[NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) { true } else { self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span }); @@ -1421,7 +1418,7 @@ impl CheckAttrVisitor<'_> { let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128; let mut invalid_args = vec![]; for meta in list { - if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) { + if let Some(LitKind::Int(val, _)) = meta.lit().map(|lit| &lit.kind) { if *val >= arg_count { let span = meta.span(); self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndexExceed { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 82214d4c3c438..4ef89cfb2554f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1989,7 +1989,7 @@ impl<'a> Resolver<'a> { .find(|a| a.has_name(sym::rustc_legacy_const_generics))?; let mut ret = Vec::new(); for meta in attr.meta_item_list()? { - match meta.literal()?.kind { + match meta.lit()?.kind { LitKind::Int(a, _) => ret.push(a as usize), _ => panic!("invalid arg index"), } diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index f33f5d27d1a9f..1843a21205cfa 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -50,7 +50,7 @@ impl Cfg { ) -> Result, InvalidCfgError> { match nested_cfg { NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude), - NestedMetaItem::Literal(ref lit) => { + NestedMetaItem::Lit(ref lit) => { Err(InvalidCfgError { msg: "unexpected literal", span: lit.span }) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 582586d33febe..42328222fd382 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -893,7 +893,7 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib .filter(|a| a.has_name(sym::rustc_legacy_const_generics)) .filter_map(|a| a.meta_item_list()) { - for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.literal()).enumerate() { + for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.lit()).enumerate() { match literal.kind { ast::LitKind::Int(a, _) => { let gen = func.generics.params.remove(0); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2894b19877cc7..ed4e9508f4309 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1305,7 +1305,7 @@ impl Attributes { for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) { if let Some(values) = attr.meta_item_list() { for l in values { - match l.literal().unwrap().kind { + match l.lit().unwrap().kind { ast::LitKind::Str(s, _) => { aliases.insert(s); } diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 8cba2a850e5bc..2ac703b957b86 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -260,9 +260,7 @@ impl Rewrite for ast::NestedMetaItem { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { match self { ast::NestedMetaItem::MetaItem(ref meta_item) => meta_item.rewrite(context, shape), - ast::NestedMetaItem::Literal(ref l) => { - rewrite_literal(context, l.token_lit, l.span, shape) - } + ast::NestedMetaItem::Lit(ref l) => rewrite_literal(context, l.token_lit, l.span, shape), } } } @@ -537,7 +535,7 @@ pub(crate) trait MetaVisitor<'ast> { fn visit_nested_meta_item(&mut self, nm: &'ast ast::NestedMetaItem) { match nm { ast::NestedMetaItem::MetaItem(ref meta_item) => self.visit_meta_item(meta_item), - ast::NestedMetaItem::Literal(ref lit) => self.visit_meta_item_lit(lit), + ast::NestedMetaItem::Lit(ref lit) => self.visit_meta_item_lit(lit), } } diff --git a/src/tools/rustfmt/src/overflow.rs b/src/tools/rustfmt/src/overflow.rs index 6bf8cd0c70be0..af0b95430a197 100644 --- a/src/tools/rustfmt/src/overflow.rs +++ b/src/tools/rustfmt/src/overflow.rs @@ -125,7 +125,7 @@ impl<'a> OverflowableItem<'a> { OverflowableItem::MacroArg(MacroArg::Keyword(..)) => true, OverflowableItem::MacroArg(MacroArg::Expr(expr)) => is_simple_expr(expr), OverflowableItem::NestedMetaItem(nested_meta_item) => match nested_meta_item { - ast::NestedMetaItem::Literal(..) => true, + ast::NestedMetaItem::Lit(..) => true, ast::NestedMetaItem::MetaItem(ref meta_item) => { matches!(meta_item.kind, ast::MetaItemKind::Word) } @@ -169,7 +169,7 @@ impl<'a> OverflowableItem<'a> { }, OverflowableItem::NestedMetaItem(nested_meta_item) if len == 1 => { match nested_meta_item { - ast::NestedMetaItem::Literal(..) => false, + ast::NestedMetaItem::Lit(..) => false, ast::NestedMetaItem::MetaItem(..) => true, } } diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 136a2c7fce24a..3e884419f1a32 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -263,7 +263,7 @@ fn is_skip(meta_item: &MetaItem) -> bool { fn is_skip_nested(meta_item: &NestedMetaItem) -> bool { match meta_item { NestedMetaItem::MetaItem(ref mi) => is_skip(mi), - NestedMetaItem::Literal(_) => false, + NestedMetaItem::Lit(_) => false, } } From 58dd62a756b634ee705d4133684b4cf48d48df3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Nov 2022 10:45:12 +0100 Subject: [PATCH 13/14] sanity_check_layout: less rightwards drift --- .../rustc_ty_utils/src/layout_sanity_check.rs | 527 +++++++++--------- 1 file changed, 265 insertions(+), 262 deletions(-) diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs index 9eb8f684bdb59..3339e910d7c77 100644 --- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs +++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs @@ -20,283 +20,286 @@ pub(super) fn sanity_check_layout<'tcx>( bug!("size is not a multiple of align, in the following layout:\n{layout:#?}"); } - if cfg!(debug_assertions) { - /// Yields non-ZST fields of the type - fn non_zst_fields<'tcx, 'a>( - cx: &'a LayoutCx<'tcx, TyCtxt<'tcx>>, - layout: &'a TyAndLayout<'tcx>, - ) -> impl Iterator)> + 'a { - (0..layout.layout.fields().count()).filter_map(|i| { - let field = layout.field(cx, i); - // Also checking `align == 1` here leads to test failures in - // `layout/zero-sized-array-union.rs`, where a type has a zero-size field with - // alignment 4 that still gets ignored during layout computation (which is okay - // since other fields already force alignment 4). - let zst = field.is_zst(); - (!zst).then(|| (layout.fields.offset(i), field)) - }) - } + if !cfg!(debug_assertions) { + // Stop here, the rest is kind of expensive. + return; + } - fn skip_newtypes<'tcx>( - cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, - layout: &TyAndLayout<'tcx>, - ) -> TyAndLayout<'tcx> { - if matches!(layout.layout.variants(), Variants::Multiple { .. }) { - // Definitely not a newtype of anything. - return *layout; - } - let mut fields = non_zst_fields(cx, layout); - let Some(first) = fields.next() else { - // No fields here, so this could be a primitive or enum -- either way it's not a newtype around a thing - return *layout - }; - if fields.next().is_none() { - let (offset, first) = first; - if offset == Size::ZERO && first.layout.size() == layout.size { - // This is a newtype, so keep recursing. - // FIXME(RalfJung): I don't think it would be correct to do any checks for - // alignment here, so we don't. Is that correct? - return skip_newtypes(cx, &first); - } + /// Yields non-ZST fields of the type + fn non_zst_fields<'tcx, 'a>( + cx: &'a LayoutCx<'tcx, TyCtxt<'tcx>>, + layout: &'a TyAndLayout<'tcx>, + ) -> impl Iterator)> + 'a { + (0..layout.layout.fields().count()).filter_map(|i| { + let field = layout.field(cx, i); + // Also checking `align == 1` here leads to test failures in + // `layout/zero-sized-array-union.rs`, where a type has a zero-size field with + // alignment 4 that still gets ignored during layout computation (which is okay + // since other fields already force alignment 4). + let zst = field.is_zst(); + (!zst).then(|| (layout.fields.offset(i), field)) + }) + } + + fn skip_newtypes<'tcx>( + cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, + layout: &TyAndLayout<'tcx>, + ) -> TyAndLayout<'tcx> { + if matches!(layout.layout.variants(), Variants::Multiple { .. }) { + // Definitely not a newtype of anything. + return *layout; + } + let mut fields = non_zst_fields(cx, layout); + let Some(first) = fields.next() else { + // No fields here, so this could be a primitive or enum -- either way it's not a newtype around a thing + return *layout + }; + if fields.next().is_none() { + let (offset, first) = first; + if offset == Size::ZERO && first.layout.size() == layout.size { + // This is a newtype, so keep recursing. + // FIXME(RalfJung): I don't think it would be correct to do any checks for + // alignment here, so we don't. Is that correct? + return skip_newtypes(cx, &first); } - // No more newtypes here. - *layout } + // No more newtypes here. + *layout + } - fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLayout<'tcx>) { - match layout.layout.abi() { - Abi::Scalar(scalar) => { - // No padding in scalars. - let size = scalar.size(cx); - let align = scalar.align(cx).abi; - assert_eq!( - layout.layout.size(), - size, - "size mismatch between ABI and layout in {layout:#?}" - ); - assert_eq!( - layout.layout.align().abi, - align, - "alignment mismatch between ABI and layout in {layout:#?}" - ); - // Check that this matches the underlying field. - let inner = skip_newtypes(cx, layout); - assert!( - matches!(inner.layout.abi(), Abi::Scalar(_)), - "`Scalar` type {} is newtype around non-`Scalar` type {}", - layout.ty, - inner.ty - ); - match inner.layout.fields() { - FieldsShape::Primitive => { - // Fine. - } - FieldsShape::Union(..) => { - // FIXME: I guess we could also check something here? Like, look at all fields? - return; - } - FieldsShape::Arbitrary { .. } => { - // Should be an enum, the only field is the discriminant. - assert!( - inner.ty.is_enum(), - "`Scalar` layout for non-primitive non-enum type {}", - inner.ty - ); - assert_eq!( - inner.layout.fields().count(), - 1, - "`Scalar` layout for multiple-field type in {inner:#?}", - ); - let offset = inner.layout.fields().offset(0); - let field = inner.field(cx, 0); - // The field should be at the right offset, and match the `scalar` layout. - assert_eq!( - offset, - Size::ZERO, - "`Scalar` field at non-0 offset in {inner:#?}", - ); - assert_eq!( - field.size, size, - "`Scalar` field with bad size in {inner:#?}", - ); - assert_eq!( - field.align.abi, align, - "`Scalar` field with bad align in {inner:#?}", - ); - assert!( - matches!(field.abi, Abi::Scalar(_)), - "`Scalar` field with bad ABI in {inner:#?}", - ); - } - _ => { - panic!("`Scalar` layout for non-primitive non-enum type {}", inner.ty); - } + fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLayout<'tcx>) { + match layout.layout.abi() { + Abi::Scalar(scalar) => { + // No padding in scalars. + let size = scalar.size(cx); + let align = scalar.align(cx).abi; + assert_eq!( + layout.layout.size(), + size, + "size mismatch between ABI and layout in {layout:#?}" + ); + assert_eq!( + layout.layout.align().abi, + align, + "alignment mismatch between ABI and layout in {layout:#?}" + ); + // Check that this matches the underlying field. + let inner = skip_newtypes(cx, layout); + assert!( + matches!(inner.layout.abi(), Abi::Scalar(_)), + "`Scalar` type {} is newtype around non-`Scalar` type {}", + layout.ty, + inner.ty + ); + match inner.layout.fields() { + FieldsShape::Primitive => { + // Fine. } - } - Abi::ScalarPair(scalar1, scalar2) => { - // Sanity-check scalar pairs. These are a bit more flexible and support - // padding, but we can at least ensure both fields actually fit into the layout - // and the alignment requirement has not been weakened. - let size1 = scalar1.size(cx); - let align1 = scalar1.align(cx).abi; - let size2 = scalar2.size(cx); - let align2 = scalar2.align(cx).abi; - assert!( - layout.layout.align().abi >= cmp::max(align1, align2), - "alignment mismatch between ABI and layout in {layout:#?}", - ); - let field2_offset = size1.align_to(align2); - assert!( - layout.layout.size() >= field2_offset + size2, - "size mismatch between ABI and layout in {layout:#?}" - ); - // Check that the underlying pair of fields matches. - let inner = skip_newtypes(cx, layout); - assert!( - matches!(inner.layout.abi(), Abi::ScalarPair(..)), - "`ScalarPair` type {} is newtype around non-`ScalarPair` type {}", - layout.ty, - inner.ty - ); - if matches!(inner.layout.variants(), Variants::Multiple { .. }) { - // FIXME: ScalarPair for enums is enormously complicated and it is very hard - // to check anything about them. + FieldsShape::Union(..) => { + // FIXME: I guess we could also check something here? Like, look at all fields? return; } - match inner.layout.fields() { - FieldsShape::Arbitrary { .. } => { - // Checked below. - } - FieldsShape::Union(..) => { - // FIXME: I guess we could also check something here? Like, look at all fields? - return; - } - _ => { - panic!("`ScalarPair` layout with unexpected field shape in {inner:#?}"); - } + FieldsShape::Arbitrary { .. } => { + // Should be an enum, the only field is the discriminant. + assert!( + inner.ty.is_enum(), + "`Scalar` layout for non-primitive non-enum type {}", + inner.ty + ); + assert_eq!( + inner.layout.fields().count(), + 1, + "`Scalar` layout for multiple-field type in {inner:#?}", + ); + let offset = inner.layout.fields().offset(0); + let field = inner.field(cx, 0); + // The field should be at the right offset, and match the `scalar` layout. + assert_eq!( + offset, + Size::ZERO, + "`Scalar` field at non-0 offset in {inner:#?}", + ); + assert_eq!(field.size, size, "`Scalar` field with bad size in {inner:#?}",); + assert_eq!( + field.align.abi, align, + "`Scalar` field with bad align in {inner:#?}", + ); + assert!( + matches!(field.abi, Abi::Scalar(_)), + "`Scalar` field with bad ABI in {inner:#?}", + ); + } + _ => { + panic!("`Scalar` layout for non-primitive non-enum type {}", inner.ty); } - let mut fields = non_zst_fields(cx, &inner); - let (offset1, field1) = fields.next().unwrap_or_else(|| { - panic!("`ScalarPair` layout for type with not even one non-ZST field: {inner:#?}") - }); - let (offset2, field2) = fields.next().unwrap_or_else(|| { - panic!("`ScalarPair` layout for type with less than two non-ZST fields: {inner:#?}") - }); - assert!( - fields.next().is_none(), - "`ScalarPair` layout for type with at least three non-ZST fields: {inner:#?}" - ); - // The fields might be in opposite order. - let (offset1, field1, offset2, field2) = if offset1 <= offset2 { - (offset1, field1, offset2, field2) - } else { - (offset2, field2, offset1, field1) - }; - // The fields should be at the right offset, and match the `scalar` layout. - assert_eq!( - offset1, - Size::ZERO, - "`ScalarPair` first field at non-0 offset in {inner:#?}", - ); - assert_eq!( - field1.size, size1, - "`ScalarPair` first field with bad size in {inner:#?}", - ); - assert_eq!( - field1.align.abi, align1, - "`ScalarPair` first field with bad align in {inner:#?}", - ); - assert!( - matches!(field1.abi, Abi::Scalar(_)), - "`ScalarPair` first field with bad ABI in {inner:#?}", - ); - assert_eq!( - offset2, field2_offset, - "`ScalarPair` second field at bad offset in {inner:#?}", - ); - assert_eq!( - field2.size, size2, - "`ScalarPair` second field with bad size in {inner:#?}", - ); - assert_eq!( - field2.align.abi, align2, - "`ScalarPair` second field with bad align in {inner:#?}", - ); - assert!( - matches!(field2.abi, Abi::Scalar(_)), - "`ScalarPair` second field with bad ABI in {inner:#?}", - ); } - Abi::Vector { count, element } => { - // No padding in vectors. Alignment can be strengthened, though. - assert!( - layout.layout.align().abi >= element.align(cx).abi, - "alignment mismatch between ABI and layout in {layout:#?}" - ); - let size = element.size(cx) * count; - assert_eq!( - layout.layout.size(), - size.align_to(cx.data_layout().vector_align(size).abi), - "size mismatch between ABI and layout in {layout:#?}" - ); + } + Abi::ScalarPair(scalar1, scalar2) => { + // Sanity-check scalar pairs. These are a bit more flexible and support + // padding, but we can at least ensure both fields actually fit into the layout + // and the alignment requirement has not been weakened. + let size1 = scalar1.size(cx); + let align1 = scalar1.align(cx).abi; + let size2 = scalar2.size(cx); + let align2 = scalar2.align(cx).abi; + assert!( + layout.layout.align().abi >= cmp::max(align1, align2), + "alignment mismatch between ABI and layout in {layout:#?}", + ); + let field2_offset = size1.align_to(align2); + assert!( + layout.layout.size() >= field2_offset + size2, + "size mismatch between ABI and layout in {layout:#?}" + ); + // Check that the underlying pair of fields matches. + let inner = skip_newtypes(cx, layout); + assert!( + matches!(inner.layout.abi(), Abi::ScalarPair(..)), + "`ScalarPair` type {} is newtype around non-`ScalarPair` type {}", + layout.ty, + inner.ty + ); + if matches!(inner.layout.variants(), Variants::Multiple { .. }) { + // FIXME: ScalarPair for enums is enormously complicated and it is very hard + // to check anything about them. + return; + } + match inner.layout.fields() { + FieldsShape::Arbitrary { .. } => { + // Checked below. + } + FieldsShape::Union(..) => { + // FIXME: I guess we could also check something here? Like, look at all fields? + return; + } + _ => { + panic!("`ScalarPair` layout with unexpected field shape in {inner:#?}"); + } } - Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check. + let mut fields = non_zst_fields(cx, &inner); + let (offset1, field1) = fields.next().unwrap_or_else(|| { + panic!( + "`ScalarPair` layout for type with not even one non-ZST field: {inner:#?}" + ) + }); + let (offset2, field2) = fields.next().unwrap_or_else(|| { + panic!( + "`ScalarPair` layout for type with less than two non-ZST fields: {inner:#?}" + ) + }); + assert!( + fields.next().is_none(), + "`ScalarPair` layout for type with at least three non-ZST fields: {inner:#?}" + ); + // The fields might be in opposite order. + let (offset1, field1, offset2, field2) = if offset1 <= offset2 { + (offset1, field1, offset2, field2) + } else { + (offset2, field2, offset1, field1) + }; + // The fields should be at the right offset, and match the `scalar` layout. + assert_eq!( + offset1, + Size::ZERO, + "`ScalarPair` first field at non-0 offset in {inner:#?}", + ); + assert_eq!( + field1.size, size1, + "`ScalarPair` first field with bad size in {inner:#?}", + ); + assert_eq!( + field1.align.abi, align1, + "`ScalarPair` first field with bad align in {inner:#?}", + ); + assert!( + matches!(field1.abi, Abi::Scalar(_)), + "`ScalarPair` first field with bad ABI in {inner:#?}", + ); + assert_eq!( + offset2, field2_offset, + "`ScalarPair` second field at bad offset in {inner:#?}", + ); + assert_eq!( + field2.size, size2, + "`ScalarPair` second field with bad size in {inner:#?}", + ); + assert_eq!( + field2.align.abi, align2, + "`ScalarPair` second field with bad align in {inner:#?}", + ); + assert!( + matches!(field2.abi, Abi::Scalar(_)), + "`ScalarPair` second field with bad ABI in {inner:#?}", + ); } + Abi::Vector { count, element } => { + // No padding in vectors. Alignment can be strengthened, though. + assert!( + layout.layout.align().abi >= element.align(cx).abi, + "alignment mismatch between ABI and layout in {layout:#?}" + ); + let size = element.size(cx) * count; + assert_eq!( + layout.layout.size(), + size.align_to(cx.data_layout().vector_align(size).abi), + "size mismatch between ABI and layout in {layout:#?}" + ); + } + Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check. } + } - check_layout_abi(cx, layout); + check_layout_abi(cx, layout); - if let Variants::Multiple { variants, .. } = &layout.variants { - for variant in variants.iter() { - // No nested "multiple". - assert!(matches!(variant.variants, Variants::Single { .. })); - // Variants should have the same or a smaller size as the full thing, - // and same for alignment. - if variant.size > layout.size { - bug!( - "Type with size {} bytes has variant with size {} bytes: {layout:#?}", - layout.size.bytes(), - variant.size.bytes(), - ) - } - if variant.align.abi > layout.align.abi { - bug!( - "Type with alignment {} bytes has variant with alignment {} bytes: {layout:#?}", - layout.align.abi.bytes(), - variant.align.abi.bytes(), - ) - } - // Skip empty variants. - if variant.size == Size::ZERO - || variant.fields.count() == 0 - || variant.abi.is_uninhabited() - { - // These are never actually accessed anyway, so we can skip the coherence check - // for them. They also fail that check, since they have - // `Aggregate`/`Uninhbaited` ABI even when the main type is - // `Scalar`/`ScalarPair`. (Note that sometimes, variants with fields have size - // 0, and sometimes, variants without fields have non-0 size.) - continue; - } - // The top-level ABI and the ABI of the variants should be coherent. - let scalar_coherent = |s1: Scalar, s2: Scalar| { - s1.size(cx) == s2.size(cx) && s1.align(cx) == s2.align(cx) - }; - let abi_coherent = match (layout.abi, variant.abi) { - (Abi::Scalar(s1), Abi::Scalar(s2)) => scalar_coherent(s1, s2), - (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => { - scalar_coherent(a1, a2) && scalar_coherent(b1, b2) - } - (Abi::Uninhabited, _) => true, - (Abi::Aggregate { .. }, _) => true, - _ => false, - }; - if !abi_coherent { - bug!( - "Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}", - variant - ); + if let Variants::Multiple { variants, .. } = &layout.variants { + for variant in variants.iter() { + // No nested "multiple". + assert!(matches!(variant.variants, Variants::Single { .. })); + // Variants should have the same or a smaller size as the full thing, + // and same for alignment. + if variant.size > layout.size { + bug!( + "Type with size {} bytes has variant with size {} bytes: {layout:#?}", + layout.size.bytes(), + variant.size.bytes(), + ) + } + if variant.align.abi > layout.align.abi { + bug!( + "Type with alignment {} bytes has variant with alignment {} bytes: {layout:#?}", + layout.align.abi.bytes(), + variant.align.abi.bytes(), + ) + } + // Skip empty variants. + if variant.size == Size::ZERO + || variant.fields.count() == 0 + || variant.abi.is_uninhabited() + { + // These are never actually accessed anyway, so we can skip the coherence check + // for them. They also fail that check, since they have + // `Aggregate`/`Uninhbaited` ABI even when the main type is + // `Scalar`/`ScalarPair`. (Note that sometimes, variants with fields have size + // 0, and sometimes, variants without fields have non-0 size.) + continue; + } + // The top-level ABI and the ABI of the variants should be coherent. + let scalar_coherent = + |s1: Scalar, s2: Scalar| s1.size(cx) == s2.size(cx) && s1.align(cx) == s2.align(cx); + let abi_coherent = match (layout.abi, variant.abi) { + (Abi::Scalar(s1), Abi::Scalar(s2)) => scalar_coherent(s1, s2), + (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => { + scalar_coherent(a1, a2) && scalar_coherent(b1, b2) } + (Abi::Uninhabited, _) => true, + (Abi::Aggregate { .. }, _) => true, + _ => false, + }; + if !abi_coherent { + bug!( + "Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}", + variant + ); } } } From 891a4da4f3cf99d5ee6413d9a6948031306179af Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Nov 2022 10:45:22 +0100 Subject: [PATCH 14/14] stricter alignment enforcement for ScalarPair and Vector --- .../rustc_ty_utils/src/layout_sanity_check.rs | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs index 3339e910d7c77..a5311dbd1b770 100644 --- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs +++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs @@ -135,22 +135,24 @@ pub(super) fn sanity_check_layout<'tcx>( } } Abi::ScalarPair(scalar1, scalar2) => { - // Sanity-check scalar pairs. These are a bit more flexible and support - // padding, but we can at least ensure both fields actually fit into the layout - // and the alignment requirement has not been weakened. + // Sanity-check scalar pairs. Computing the expected size and alignment is a bit of work. let size1 = scalar1.size(cx); let align1 = scalar1.align(cx).abi; let size2 = scalar2.size(cx); let align2 = scalar2.align(cx).abi; - assert!( - layout.layout.align().abi >= cmp::max(align1, align2), - "alignment mismatch between ABI and layout in {layout:#?}", - ); + let align = cmp::max(align1, align2); let field2_offset = size1.align_to(align2); - assert!( - layout.layout.size() >= field2_offset + size2, + let size = (field2_offset + size2).align_to(align); + assert_eq!( + layout.layout.size(), + size, "size mismatch between ABI and layout in {layout:#?}" ); + assert_eq!( + layout.layout.align().abi, + align, + "alignment mismatch between ABI and layout in {layout:#?}", + ); // Check that the underlying pair of fields matches. let inner = skip_newtypes(cx, layout); assert!( @@ -233,17 +235,22 @@ pub(super) fn sanity_check_layout<'tcx>( ); } Abi::Vector { count, element } => { - // No padding in vectors. Alignment can be strengthened, though. - assert!( - layout.layout.align().abi >= element.align(cx).abi, - "alignment mismatch between ABI and layout in {layout:#?}" - ); + // No padding in vectors, except possibly for trailing padding to make the size a multiple of align. let size = element.size(cx) * count; + let align = cx.data_layout().vector_align(size).abi; + let size = size.align_to(align); // needed e.g. for vectors of size 3 + assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`. assert_eq!( layout.layout.size(), - size.align_to(cx.data_layout().vector_align(size).abi), + size, "size mismatch between ABI and layout in {layout:#?}" ); + assert_eq!( + layout.layout.align().abi, + align, + "alignment mismatch between ABI and layout in {layout:#?}" + ); + // FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair. } Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check. }