diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast/src/tokenstream.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/visit.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/deprecation.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/repr.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/stability.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/context.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/parser.rs | 62 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/intravisit.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/thir/visit.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_monomorphize/src/mono_checks/abi_check.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/tokenstream/tests.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_target/src/callconv/mod.rs | 27 |
13 files changed, 56 insertions, 111 deletions
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 636c26bcde0..3c231be20dc 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -57,7 +57,9 @@ impl TokenTree { match (self, other) { (TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind, (TokenTree::Delimited(.., delim, tts), TokenTree::Delimited(.., delim2, tts2)) => { - delim == delim2 && tts.eq_unspanned(tts2) + delim == delim2 + && tts.len() == tts2.len() + && tts.iter().zip(tts2.iter()).all(|(a, b)| a.eq_unspanned(b)) } _ => false, } @@ -694,18 +696,6 @@ impl TokenStream { TokenStreamIter::new(self) } - /// Compares two `TokenStream`s, checking equality without regarding span information. - pub fn eq_unspanned(&self, other: &TokenStream) -> bool { - let mut iter1 = self.iter(); - let mut iter2 = other.iter(); - for (tt1, tt2) in iter::zip(&mut iter1, &mut iter2) { - if !tt1.eq_unspanned(tt2) { - return false; - } - } - iter1.next().is_none() && iter2.next().is_none() - } - /// Create a token stream containing a single token with alone spacing. The /// spacing used for the final token in a constructed stream doesn't matter /// because it's never used. In practice we arbitrarily use diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 908d9fd4bda..1f7c97380dc 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -121,6 +121,10 @@ pub enum LifetimeCtxt { /// explicitly, you need to override each method. (And you also need /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) +/// +/// Every `walk_*` method uses deconstruction to access fields of structs and +/// enums. This will result in a compile error if a field is added, which makes +/// it more likely the appropriate visit call will be added for it. pub trait Visitor<'ast>: Sized { /// The result type of the `visit_*` methods. Can be either `()`, /// or `ControlFlow<T>`. diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index b9b6ca26119..d0465546b73 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -53,7 +53,7 @@ fn parse_unstable<'a>( for param in list.mixed() { let param_span = param.span(); - if let Some(ident) = param.meta_item().and_then(|i| i.path_without_args().word()) { + if let Some(ident) = param.meta_item().and_then(|i| i.path().word()) { res.push(ident.name); } else { cx.emit_err(session_diagnostics::ExpectsFeatures { diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 1775770ec68..006c1fe3b9c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -79,7 +79,7 @@ impl SingleAttributeParser for DeprecationParser { return None; }; - let ident_name = param.path_without_args().word_sym(); + let ident_name = param.path().word_sym(); match ident_name { Some(name @ sym::since) => { @@ -102,7 +102,7 @@ impl SingleAttributeParser for DeprecationParser { _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param_span, - item: param.path_without_args().to_string(), + item: param.path().to_string(), expected: if features.deprecated_suggestion() { &["since", "note", "suggestion"] } else { diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index ab523ce0038..69316541e19 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -96,7 +96,7 @@ fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option<Repr // FIXME(jdonszelmann): invert the parsing here to match on the word first and then the // structure. - let (name, ident_span) = if let Some(ident) = param.path_without_args().word() { + let (name, ident_span) = if let Some(ident) = param.path().word() { (Some(ident.name), ident.span) } else { (None, DUMMY_SP) diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index e30d7e7238e..ce69a54513d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -204,7 +204,7 @@ fn insert_value_into_option_or_error( if item.is_some() { cx.emit_err(session_diagnostics::MultipleItem { span: param.span(), - item: param.path_without_args().to_string(), + item: param.path().to_string(), }); None } else if let Some(v) = param.args().name_value() @@ -242,13 +242,13 @@ pub(crate) fn parse_stability( return None; }; - match param.path_without_args().word_sym() { + match param.path().word_sym() { Some(sym::feature) => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, Some(sym::since) => insert_value_into_option_or_error(cx, ¶m, &mut since)?, _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param_span, - item: param.path_without_args().to_string(), + item: param.path().to_string(), expected: &["feature", "since"], }); return None; @@ -310,7 +310,7 @@ pub(crate) fn parse_unstability( return None; }; - match param.path_without_args().word_sym() { + match param.path().word_sym() { Some(sym::feature) => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, Some(sym::reason) => insert_value_into_option_or_error(cx, ¶m, &mut reason)?, Some(sym::issue) => { @@ -349,7 +349,7 @@ pub(crate) fn parse_unstability( _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param.span(), - item: param.path_without_args().to_string(), + item: param.path().to_string(), expected: &["feature", "reason", "issue", "soft", "implied_by"], }); return None; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 1360fc68714..c02760d830c 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -264,7 +264,8 @@ impl<'sess> AttributeParser<'sess> { // } ast::AttrKind::Normal(n) => { let parser = MetaItemParser::from_attr(n, self.dcx()); - let (path, args) = parser.deconstruct(); + let path = parser.path(); + let args = parser.args(); let parts = path.segments().map(|i| i.name).collect::<Vec<_>>(); if let Some(accept) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) { diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index f433d3574e1..e10e3b511db 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -252,35 +252,18 @@ impl<'a> MetaItemParser<'a> { } } - /// Gets just the path, without the args. - pub fn path_without_args(&self) -> PathParser<'a> { - self.path.clone() - } - - /// Gets just the args parser, without caring about the path. - pub fn args(&self) -> &ArgParser<'a> { - &self.args - } - - pub fn deconstruct(&self) -> (PathParser<'a>, &ArgParser<'a>) { - (self.path_without_args(), self.args()) - } - - /// Asserts that this MetaItem starts with a path. Some examples: + /// Gets just the path, without the args. Some examples: /// /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path /// - `#[inline]`: `inline` is a single segment path - pub fn path(&self) -> (PathParser<'a>, &ArgParser<'a>) { - self.deconstruct() + pub fn path(&self) -> &PathParser<'a> { + &self.path } - /// Asserts that this MetaItem starts with a word, or single segment path. - /// Doesn't return the args parser. - /// - /// For examples. see [`Self::word`] - pub fn word_without_args(&self) -> Option<Ident> { - Some(self.word()?.0) + /// Gets just the args parser, without caring about the path. + pub fn args(&self) -> &ArgParser<'a> { + &self.args } /// Asserts that this MetaItem starts with a word, or single segment path. @@ -289,23 +272,8 @@ impl<'a> MetaItemParser<'a> { /// - `#[inline]`: `inline` is a word /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path, /// and not a word and should instead be parsed using [`path`](Self::path) - pub fn word(&self) -> Option<(Ident, &ArgParser<'a>)> { - let (path, args) = self.deconstruct(); - Some((path.word()?, args)) - } - - /// Asserts that this MetaItem starts with some specific word. - /// - /// See [`word`](Self::word) for examples of what a word is. pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> { - self.path_without_args().word_is(sym).then(|| self.args()) - } - - /// Asserts that this MetaItem starts with some specific path. - /// - /// See [`word`](Self::path) for examples of what a word is. - pub fn path_is(&self, segments: &[Symbol]) -> Option<&ArgParser<'a>> { - self.path_without_args().segments_is(segments).then(|| self.args()) + self.path().word_is(sym).then(|| self.args()) } } @@ -548,7 +516,7 @@ impl<'a> MetaItemListParser<'a> { } /// Lets you pick and choose as what you want to parse each element in the list - pub fn mixed<'s>(&'s self) -> impl Iterator<Item = &'s MetaItemOrLitParser<'a>> + 's { + pub fn mixed(&self) -> impl Iterator<Item = &MetaItemOrLitParser<'a>> { self.sub_parsers.iter() } @@ -560,20 +528,6 @@ impl<'a> MetaItemListParser<'a> { self.len() == 0 } - /// Asserts that every item in the list is another list starting with a word. - /// - /// See [`MetaItemParser::word`] for examples of words. - pub fn all_word_list<'s>(&'s self) -> Option<Vec<(Ident, &'s ArgParser<'a>)>> { - self.mixed().map(|i| i.meta_item()?.word()).collect() - } - - /// Asserts that every item in the list is another list starting with a full path. - /// - /// See [`MetaItemParser::path`] for examples of paths. - pub fn all_path_list<'s>(&'s self) -> Option<Vec<(PathParser<'a>, &'s ArgParser<'a>)>> { - self.mixed().map(|i| Some(i.meta_item()?.path())).collect() - } - /// Returns Some if the list contains only a single element. /// /// Inside the Some is the parser to parse this single element. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index d12050ea4bb..bebac3a4b78 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -200,6 +200,10 @@ use nested_filter::NestedFilter; /// explicitly, you need to override each method. (And you also need /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) +/// +/// Every `walk_*` method uses deconstruction to access fields of structs and +/// enums. This will result in a compile error if a field is added, which makes +/// it more likely the appropriate visit call will be added for it. pub trait Visitor<'v>: Sized { // This type should not be overridden, it exists for convenient usage as `Self::MaybeTyCtxt`. type MaybeTyCtxt: HirTyCtxt<'v> = <Self::NestedFilter as NestedFilter<'v>>::MaybeTyCtxt; @@ -1201,7 +1205,6 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>( visitor: &mut V, trait_item: &'v TraitItem<'v>, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item; let hir_id = trait_item.hir_id(); try_visit!(visitor.visit_ident(ident)); @@ -1240,7 +1243,6 @@ pub fn walk_trait_item_ref<'v, V: Visitor<'v>>( visitor: &mut V, trait_item_ref: &'v TraitItemRef, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let TraitItemRef { id, ident, ref kind, span: _ } = *trait_item_ref; try_visit!(visitor.visit_nested_trait_item(id)); try_visit!(visitor.visit_ident(ident)); @@ -1251,7 +1253,6 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>( visitor: &mut V, impl_item: &'v ImplItem<'v>, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let ImplItem { owner_id: _, ident, @@ -1286,7 +1287,6 @@ pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>( visitor: &mut V, foreign_item_ref: &'v ForeignItemRef, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let ForeignItemRef { id, ident, span: _ } = *foreign_item_ref; try_visit!(visitor.visit_nested_foreign_item(id)); visitor.visit_ident(ident) @@ -1296,7 +1296,6 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>( visitor: &mut V, impl_item_ref: &'v ImplItemRef, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let ImplItemRef { id, ident, ref kind, span: _, trait_item_def_id: _ } = *impl_item_ref; try_visit!(visitor.visit_nested_impl_item(id)); try_visit!(visitor.visit_ident(ident)); diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 4da4dc3c02e..d8743814d79 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -3,6 +3,9 @@ use super::{ Pat, PatKind, Stmt, StmtKind, Thir, }; +/// Every `walk_*` method uses deconstruction to access fields of structs and +/// enums. This will result in a compile error if a field is added, which makes +/// it more likely the appropriate visit call will be added for it. pub trait Visitor<'thir, 'tcx: 'thir>: Sized { fn thir(&self) -> &'thir Thir<'tcx>; diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 5478e54a606..8dbbb4d1713 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -35,8 +35,6 @@ fn do_check_simd_vector_abi<'tcx>( is_call: bool, loc: impl Fn() -> (Span, HirId), ) { - // We check this on all functions, including those using the "Rust" ABI. - // For the "Rust" ABI it would be a bug if the lint ever triggered, but better safe than sorry. let feature_def = tcx.sess.target.features_for_correct_vector_abi(); let codegen_attrs = tcx.codegen_fn_attrs(def_id); let have_feature = |feat: Symbol| { @@ -123,8 +121,9 @@ fn do_check_wasm_abi<'tcx>( is_call: bool, loc: impl Fn() -> (Span, HirId), ) { - // Only proceed for `extern "C" fn` on wasm32-unknown-unknown (same check as what `adjust_for_foreign_abi` uses to call `compute_wasm_abi_info`), - // and only proceed if `wasm_c_abi_opt` indicates we should emit the lint. + // Only proceed for `extern "C" fn` on wasm32-unknown-unknown (same check as what + // `adjust_for_foreign_abi` uses to call `compute_wasm_abi_info`), and only proceed if + // `wasm_c_abi_opt` indicates we should emit the lint. if !(tcx.sess.target.arch == "wasm32" && tcx.sess.target.os == "unknown" && tcx.wasm_c_abi_opt() == WasmCAbi::Legacy { with_lint: true } @@ -157,8 +156,15 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { else { // An error will be reported during codegen if we cannot determine the ABI of this // function. + tcx.dcx().delayed_bug("ABI computation failure should lead to compilation failure"); return; }; + // Unlike the call-site check, we do also check "Rust" ABI functions here. + // This should never trigger, *except* if we start making use of vector registers + // for the "Rust" ABI and the user disables those vector registers (which should trigger a + // warning as that's clearly disabling a "required" target feature for this target). + // Using such a function is where disabling the vector register actually can start leading + // to soundness issues, so erroring here seems good. let loc = || { let def_id = instance.def_id(); ( @@ -179,7 +185,8 @@ fn check_call_site_abi<'tcx>( loc: impl Fn() -> (Span, HirId) + Copy, ) { if callee.fn_sig(tcx).abi().is_rustic_abi() { - // we directly handle the soundness of Rust ABIs + // We directly handle the soundness of Rust ABIs -- so let's skip the majority of + // call sites to avoid a perf regression. return; } let typing_env = ty::TypingEnv::fully_monomorphized(); diff --git a/compiler/rustc_parse/src/parser/tokenstream/tests.rs b/compiler/rustc_parse/src/parser/tokenstream/tests.rs index aac75323ff3..19b2c98f5af 100644 --- a/compiler/rustc_parse/src/parser/tokenstream/tests.rs +++ b/compiler/rustc_parse/src/parser/tokenstream/tests.rs @@ -14,6 +14,10 @@ fn sp(a: u32, b: u32) -> Span { Span::with_root_ctxt(BytePos(a), BytePos(b)) } +fn cmp_token_stream(a: &TokenStream, b: &TokenStream) -> bool { + a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.eq_unspanned(y)) +} + #[test] fn test_concat() { create_default_session_globals_then(|| { @@ -25,7 +29,7 @@ fn test_concat() { eq_res.push_stream(test_snd); assert_eq!(test_res.iter().count(), 5); assert_eq!(eq_res.iter().count(), 5); - assert_eq!(test_res.eq_unspanned(&eq_res), true); + assert_eq!(cmp_token_stream(&test_res, &eq_res), true); }) } @@ -104,7 +108,7 @@ fn test_dotdotdot() { stream.push_tree(TokenTree::token_joint(token::Dot, sp(0, 1))); stream.push_tree(TokenTree::token_joint(token::Dot, sp(1, 2))); stream.push_tree(TokenTree::token_alone(token::Dot, sp(2, 3))); - assert!(stream.eq_unspanned(&string_to_ts("..."))); + assert!(cmp_token_stream(&stream, &string_to_ts("..."))); assert_eq!(stream.iter().count(), 1); }) } diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index d2e49cea647..dcb79cce759 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -7,7 +7,7 @@ use rustc_abi::{ use rustc_macros::HashStable_Generic; pub use crate::spec::AbiMap; -use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, RustcAbi, WasmCAbi}; +use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi}; mod aarch64; mod amdgpu; @@ -696,24 +696,6 @@ impl<'a, Ty> FnAbi<'a, Ty> { _ => {} }; - // Decides whether we can pass the given SIMD argument via `PassMode::Direct`. - // May only return `true` if the target will always pass those arguments the same way, - // no matter what the user does with `-Ctarget-feature`! In other words, whatever - // target features are required to pass a SIMD value in registers must be listed in - // the `abi_required_features` for the current target and ABI. - let can_pass_simd_directly = |arg: &ArgAbi<'_, Ty>| match &*spec.arch { - // On x86, if we have SSE2 (which we have by default for x86_64), we can always pass up - // to 128-bit-sized vectors. - "x86" if spec.rustc_abi == Some(RustcAbi::X86Sse2) => arg.layout.size.bits() <= 128, - "x86_64" if spec.rustc_abi != Some(RustcAbi::X86Softfloat) => { - // FIXME once https://github.com/bytecodealliance/wasmtime/issues/10254 is fixed - // accept vectors up to 128bit rather than vectors of exactly 128bit. - arg.layout.size.bits() == 128 - } - // So far, we haven't implemented this logic for any other target. - _ => false, - }; - for (arg_idx, arg) in self .args .iter_mut() @@ -813,9 +795,10 @@ impl<'a, Ty> FnAbi<'a, Ty> { // target feature sets. Some more information about this // issue can be found in #44367. // - // Note that the intrinsic ABI is exempt here as those are not - // real functions anyway, and the backend expects very specific types. - if spec.simd_types_indirect && !can_pass_simd_directly(arg) { + // We *could* do better in some cases, e.g. on x86_64 targets where SSE2 is + // required. However, it turns out that that makes LLVM worse at optimizing this + // code, so we pass things indirectly even there. See #139029 for more on that. + if spec.simd_types_indirect { arg.make_indirect(); } } |
