diff options
401 files changed, 5410 insertions, 4209 deletions
diff --git a/Cargo.lock b/Cargo.lock index f5aacba20cd..afe1814de67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2509,9 +2509,9 @@ dependencies = [ [[package]] name = "object" -version = "0.28.1" +version = "0.28.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ce8b38d41f9f3618fc23f908faae61510f8d8ce2d99cbe910641e8f1971f084" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" dependencies = [ "crc32fast", "flate2", @@ -3617,7 +3617,7 @@ dependencies = [ "itertools", "jobserver", "libc", - "object 0.28.1", + "object 0.28.4", "pathdiff", "regex", "rustc_apfloat", @@ -5207,7 +5207,7 @@ checksum = "dd95b4559c196987c8451b4e14d08a4c796c2844f9adf4d2a2dbc9b3142843be" dependencies = [ "gimli 0.26.1", "hashbrown 0.11.2", - "object 0.28.1", + "object 0.28.4", "tracing", ] diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 0e8af549692..2774bda24f1 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -396,37 +396,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - // Check for unstable modifiers on `#[link(..)]` attribute - if attr.has_name(sym::link) { - for nested_meta in attr.meta_item_list().unwrap_or_default() { - if nested_meta.has_name(sym::modifiers) { - if let Some(modifiers) = nested_meta.value_str() { - for modifier in modifiers.as_str().split(',') { - if let Some(modifier) = modifier.strip_prefix(&['+', '-']) { - macro_rules! gate_modifier { ($($name:literal => $feature:ident)*) => { - $(if modifier == $name { - let msg = concat!("`#[link(modifiers=\"", $name, "\")]` is unstable"); - gate_feature_post!( - self, - $feature, - nested_meta.name_value_literal_span().unwrap(), - msg - ); - })* - }} - - gate_modifier!( - "bundle" => native_link_modifiers_bundle - "verbatim" => native_link_modifiers_verbatim - "as-needed" => native_link_modifiers_as_needed - ); - } - } - } - } - } - } - // Emit errors for non-staged-api crates. if !self.features.staged_api { if attr.has_name(sym::rustc_deprecated) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 5a79cf68f11..3d4bd222715 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -868,177 +868,180 @@ impl IntType { /// structure layout, `packed` to remove padding, and `transparent` to delegate representation /// concerns to the only non-ZST field. pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { - use ReprAttr::*; + if attr.has_name(sym::repr) { parse_repr_attr(sess, attr) } else { Vec::new() } +} +pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { + assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {:?}", attr); + use ReprAttr::*; let mut acc = Vec::new(); let diagnostic = &sess.parse_sess.span_diagnostic; - if attr.has_name(sym::repr) { - if let Some(items) = attr.meta_item_list() { - for item in items { - let mut recognised = false; - if item.is_word() { - let hint = match item.name_or_empty() { - sym::C => Some(ReprC), - sym::packed => Some(ReprPacked(1)), - sym::simd => Some(ReprSimd), - sym::transparent => Some(ReprTransparent), - sym::no_niche => Some(ReprNoNiche), - sym::align => { - let mut err = struct_span_err!( - diagnostic, - item.span(), - E0589, - "invalid `repr(align)` attribute: `align` needs an argument" - ); - err.span_suggestion( - item.span(), - "supply an argument here", - "align(...)".to_string(), - Applicability::HasPlaceholders, - ); - err.emit(); - recognised = true; - None - } - name => int_type_of_word(name).map(ReprInt), - }; - if let Some(h) = hint { + if let Some(items) = attr.meta_item_list() { + for item in items { + let mut recognised = false; + if item.is_word() { + let hint = match item.name_or_empty() { + sym::C => Some(ReprC), + sym::packed => Some(ReprPacked(1)), + sym::simd => Some(ReprSimd), + sym::transparent => Some(ReprTransparent), + sym::no_niche => Some(ReprNoNiche), + sym::align => { + let mut err = struct_span_err!( + diagnostic, + item.span(), + E0589, + "invalid `repr(align)` attribute: `align` needs an argument" + ); + err.span_suggestion( + item.span(), + "supply an argument here", + "align(...)".to_string(), + Applicability::HasPlaceholders, + ); + err.emit(); recognised = true; - acc.push(h); + None } - } else if let Some((name, value)) = item.name_value_literal() { - let mut literal_error = None; - if name == sym::align { - recognised = true; - match parse_alignment(&value.kind) { - Ok(literal) => acc.push(ReprAlign(literal)), - Err(message) => literal_error = Some(message), - }; - } else if name == sym::packed { - recognised = true; - match parse_alignment(&value.kind) { - Ok(literal) => acc.push(ReprPacked(literal)), - Err(message) => literal_error = Some(message), - }; - } else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche) - || int_type_of_word(name).is_some() - { - recognised = true; - struct_span_err!( + name => int_type_of_word(name).map(ReprInt), + }; + + if let Some(h) = hint { + recognised = true; + acc.push(h); + } + } else if let Some((name, value)) = item.name_value_literal() { + let mut literal_error = None; + if name == sym::align { + recognised = true; + match parse_alignment(&value.kind) { + Ok(literal) => acc.push(ReprAlign(literal)), + Err(message) => literal_error = Some(message), + }; + } else if name == sym::packed { + recognised = true; + match parse_alignment(&value.kind) { + Ok(literal) => acc.push(ReprPacked(literal)), + Err(message) => literal_error = Some(message), + }; + } else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche) + || int_type_of_word(name).is_some() + { + recognised = true; + struct_span_err!( diagnostic, item.span(), E0552, "invalid representation hint: `{}` does not take a parenthesized argument list", name.to_ident_string(), ).emit(); - } - if let Some(literal_error) = literal_error { - struct_span_err!( + } + if let Some(literal_error) = literal_error { + struct_span_err!( + diagnostic, + item.span(), + E0589, + "invalid `repr({})` attribute: {}", + name.to_ident_string(), + literal_error + ) + .emit(); + } + } else if let Some(meta_item) = item.meta_item() { + if let MetaItemKind::NameValue(ref value) = meta_item.kind { + if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) { + let name = meta_item.name_or_empty().to_ident_string(); + recognised = true; + let mut err = struct_span_err!( diagnostic, item.span(), - E0589, - "invalid `repr({})` attribute: {}", - name.to_ident_string(), - literal_error - ) - .emit(); - } - } else if let Some(meta_item) = item.meta_item() { - if let MetaItemKind::NameValue(ref value) = meta_item.kind { - if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) { - let name = meta_item.name_or_empty().to_ident_string(); - recognised = true; - let mut err = struct_span_err!( - diagnostic, - item.span(), - E0693, - "incorrect `repr({})` attribute format", - name, - ); - match value.kind { - ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { - err.span_suggestion( - item.span(), - "use parentheses instead", - format!("{}({})", name, int), - Applicability::MachineApplicable, - ); - } - ast::LitKind::Str(s, _) => { - err.span_suggestion( - item.span(), - "use parentheses instead", - format!("{}({})", name, s), - Applicability::MachineApplicable, - ); - } - _ => {} + E0693, + "incorrect `repr({})` attribute format", + name, + ); + match value.kind { + ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { + err.span_suggestion( + item.span(), + "use parentheses instead", + format!("{}({})", name, int), + Applicability::MachineApplicable, + ); } - err.emit(); - } else { - if matches!( - meta_item.name_or_empty(), - sym::C | sym::simd | sym::transparent | sym::no_niche - ) || int_type_of_word(meta_item.name_or_empty()).is_some() - { - recognised = true; - struct_span_err!( - diagnostic, - meta_item.span, - E0552, - "invalid representation hint: `{}` does not take a value", - meta_item.name_or_empty().to_ident_string(), - ) - .emit(); + ast::LitKind::Str(s, _) => { + err.span_suggestion( + item.span(), + "use parentheses instead", + format!("{}({})", name, s), + Applicability::MachineApplicable, + ); } + _ => {} } - } else if let MetaItemKind::List(_) = meta_item.kind { - if meta_item.has_name(sym::align) { + err.emit(); + } else { + if matches!( + meta_item.name_or_empty(), + sym::C | sym::simd | sym::transparent | sym::no_niche + ) || int_type_of_word(meta_item.name_or_empty()).is_some() + { recognised = true; struct_span_err!( diagnostic, meta_item.span, - E0693, - "incorrect `repr(align)` attribute format: \ - `align` takes exactly one argument in parentheses" + E0552, + "invalid representation hint: `{}` does not take a value", + meta_item.name_or_empty().to_ident_string(), ) .emit(); - } else if meta_item.has_name(sym::packed) { - recognised = true; - struct_span_err!( - diagnostic, - meta_item.span, - E0552, - "incorrect `repr(packed)` attribute format: \ + } + } + } else if let MetaItemKind::List(_) = meta_item.kind { + if meta_item.has_name(sym::align) { + recognised = true; + struct_span_err!( + diagnostic, + meta_item.span, + E0693, + "incorrect `repr(align)` attribute format: \ + `align` takes exactly one argument in parentheses" + ) + .emit(); + } else if meta_item.has_name(sym::packed) { + recognised = true; + struct_span_err!( + diagnostic, + meta_item.span, + E0552, + "incorrect `repr(packed)` attribute format: \ `packed` takes exactly one parenthesized argument, \ or no parentheses at all" - ) - .emit(); - } else if matches!( - meta_item.name_or_empty(), - sym::C | sym::simd | sym::transparent | sym::no_niche - ) || int_type_of_word(meta_item.name_or_empty()).is_some() - { - recognised = true; - struct_span_err!( + ) + .emit(); + } else if matches!( + meta_item.name_or_empty(), + sym::C | sym::simd | sym::transparent | sym::no_niche + ) || int_type_of_word(meta_item.name_or_empty()).is_some() + { + recognised = true; + struct_span_err!( diagnostic, meta_item.span, E0552, "invalid representation hint: `{}` does not take a parenthesized argument list", meta_item.name_or_empty().to_ident_string(), ).emit(); - } } } - if !recognised { - // Not a word we recognize. This will be caught and reported by - // the `check_mod_attrs` pass, but this pass doesn't always run - // (e.g. if we only pretty-print the source), so we have to gate - // the `delay_span_bug` call as follows: - if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) { - diagnostic.delay_span_bug(item.span(), "unrecognized representation hint"); - } + } + if !recognised { + // Not a word we recognize. This will be caught and reported by + // the `check_mod_attrs` pass, but this pass doesn't always run + // (e.g. if we only pretty-print the source), so we have to gate + // the `delay_span_bug` call as follows: + if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) { + diagnostic.delay_span_bug(item.span(), "unrecognized representation hint"); } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index bbb631730d3..a3c9da30212 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -13,7 +13,9 @@ use rustc_middle::mir::{ FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; -use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty}; +use rustc_middle::ty::{ + self, subst::Subst, suggest_constraining_type_params, EarlyBinder, PredicateKind, Ty, +}; use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; use rustc_span::symbol::sym; use rustc_span::{BytePos, Span}; @@ -336,7 +338,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let find_fn_kind_from_did = |predicates: &[(ty::Predicate<'tcx>, Span)], substs| { predicates.iter().find_map(|(pred, _)| { let pred = if let Some(substs) = substs { - pred.subst(tcx, substs).kind().skip_binder() + EarlyBinder(*pred).subst(tcx, substs).kind().skip_binder() } else { pred.kind().skip_binder() }; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index f3d37a6be7b..81073758791 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,11 +1,8 @@ -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; use rustc_hir::def_id::DefId; use rustc_hir::OpaqueTyOrigin; use rustc_infer::infer::InferCtxt; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, TyCtxt, TypeFoldable}; -use rustc_span::Span; use rustc_trait_selection::opaque_types::InferCtxtExt; use super::RegionInferenceContext; @@ -107,21 +104,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { let opaque_type_key = OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs }; - let remapped_type = infcx.infer_opaque_definition_from_instantiation( + let ty = infcx.infer_opaque_definition_from_instantiation( opaque_type_key, universal_concrete_type, origin, ); - let ty = if check_opaque_type_parameter_valid( - infcx.tcx, - opaque_type_key, - origin, - concrete_type.span, - ) { - remapped_type - } else { - infcx.tcx.ty_error() - }; // Sometimes two opaque types are the same only after we remap the generic parameters // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)` // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that @@ -184,95 +171,3 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } } - -fn check_opaque_type_parameter_valid( - tcx: TyCtxt<'_>, - opaque_type_key: OpaqueTypeKey<'_>, - origin: OpaqueTyOrigin, - span: Span, -) -> bool { - match origin { - // No need to check return position impl trait (RPIT) - // because for type and const parameters they are correct - // by construction: we convert - // - // fn foo<P0..Pn>() -> impl Trait - // - // into - // - // type Foo<P0...Pn> - // fn foo<P0..Pn>() -> Foo<P0...Pn>. - // - // For lifetime parameters we convert - // - // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> - // - // into - // - // type foo::<'p0..'pn>::Foo<'q0..'qm> - // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>. - // - // which would error here on all of the `'static` args. - OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true, - // Check these - OpaqueTyOrigin::TyAlias => {} - } - let opaque_generics = tcx.generics_of(opaque_type_key.def_id); - let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); - for (i, arg) in opaque_type_key.substs.iter().enumerate() { - let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - GenericArgKind::Lifetime(lt) if lt.is_static() => { - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_label( - tcx.def_span(opaque_generics.param_at(i, tcx).def_id), - "cannot use static lifetime; use a bound lifetime \ - instead or remove the lifetime parameter from the \ - opaque type", - ) - .emit(); - return false; - } - GenericArgKind::Lifetime(lt) => { - matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_)) - } - GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)), - }; - - if arg_is_param { - seen_params.entry(arg).or_default().push(i); - } else { - // Prevent `fn foo() -> Foo<u32>` from being defining. - let opaque_param = opaque_generics.param_at(i, tcx); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note( - tcx.def_span(opaque_param.def_id), - &format!( - "used non-generic {} `{}` for generic parameter", - opaque_param.kind.descr(), - arg, - ), - ) - .emit(); - return false; - } - } - - for (_, indices) in seen_params { - if indices.len() > 1 { - let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); - let spans: Vec<_> = indices - .into_iter() - .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) - .collect(); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note(spans, &format!("{} used multiple times", descr)) - .emit(); - return false; - } - } - true -} diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index c06fe881410..0fcac9a1c6c 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -477,8 +477,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { .infcx .tcx .mk_region(ty::ReVar(self.infcx.next_nll_region_var(FR).to_region_vid())); - let va_list_ty = - self.infcx.tcx.type_of(va_list_did).subst(self.infcx.tcx, &[region.into()]); + let va_list_ty = self + .infcx + .tcx + .bound_type_of(va_list_did) + .subst(self.infcx.tcx, &[region.into()]); unnormalized_input_tys = self.infcx.tcx.mk_type_list( unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)), diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 3aba528abfd..aa556a21bf8 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -10,7 +10,7 @@ jobs: timeout-minutes: 10 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install rustfmt run: | @@ -39,7 +39,7 @@ jobs: TARGET_TRIPLE: aarch64-unknown-linux-gnu steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache cargo installed crates uses: actions/cache@v2 @@ -127,7 +127,7 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 #- name: Cache cargo installed crates # uses: actions/cache@v2 diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml index a019793edd8..0a3e7ca073b 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml @@ -11,7 +11,7 @@ jobs: timeout-minutes: 60 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache cargo installed crates uses: actions/cache@v2 @@ -34,7 +34,7 @@ jobs: sed -i 's/cranelift-jit = { version = "\w*.\w*.\w*", optional = true }/cranelift-jit = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", optional = true }/' Cargo.toml sed -i 's/cranelift-object = "\w*.\w*.\w*"/cranelift-object = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml - sed -i 's/gimli = { version = "0.25.0", default-features = false, features = \["write"\]}/gimli = { version = "0.26.1", default-features = false, features = ["write"] }/' Cargo.toml + sed -i 's/object = { version = "0.27.0"/object = { version = "0.28.0"/' Cargo.toml cat Cargo.toml diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml index 1c08e5ece33..b8a98b83ebe 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache cargo installed crates uses: actions/cache@v2 @@ -46,7 +46,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache cargo installed crates uses: actions/cache@v2 diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json index 74fde9c27c0..ecb20f22d8c 100644 --- a/compiler/rustc_codegen_cranelift/.vscode/settings.json +++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json @@ -5,7 +5,7 @@ "rust-analyzer.assist.importEnforceGranularity": true, "rust-analyzer.assist.importPrefix": "crate", "rust-analyzer.cargo.runBuildScripts": true, - "rust-analyzer.cargo.features": ["unstable-features"] + "rust-analyzer.cargo.features": ["unstable-features"], "rust-analyzer.linkedProjects": [ "./Cargo.toml", //"./build_sysroot/sysroot_src/src/libstd/Cargo.toml", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 74f50808a98..18d7f41cf40 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -41,15 +41,5 @@ unstable-features = ["jit", "inline_asm"] jit = ["cranelift-jit", "libloading"] inline_asm = [] -# Disable optimizations and debuginfo of build scripts and some of the heavy build deps, as the -# execution time of build scripts is so fast that optimizing them slows down the total build time. -[profile.release.build-override] -opt-level = 0 -debug = false - -[profile.release.package.cranelift-codegen-meta] -opt-level = 0 -debug = false - [package.metadata.rust-analyzer] rustc_private = true diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index 51ba0dbfcc7..efee6ef3f37 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -112,9 +112,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -134,18 +134,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.124" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" dependencies = [ "rustc-std-workspace-core", ] [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs index 0a56eb131ed..48faec8bc4b 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs @@ -34,18 +34,6 @@ pub(crate) fn build_backend( _ => unreachable!(), } - // Set the rpath to make the cg_clif executable find librustc_codegen_cranelift without changing - // LD_LIBRARY_PATH - if cfg!(unix) { - if cfg!(target_os = "macos") { - rustflags += " -Csplit-debuginfo=unpacked \ - -Clink-arg=-Wl,-rpath,@loader_path/../lib \ - -Zosx-rpath-install-name"; - } else { - rustflags += " -Clink-arg=-Wl,-rpath=$ORIGIN/../lib "; - } - } - cmd.env("RUSTFLAGS", rustflags); eprintln!("[BUILD] rustc_codegen_cranelift"); diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs index c9c003d4610..8682204f4fd 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs @@ -1,4 +1,3 @@ -use std::env; use std::fs; use std::path::{Path, PathBuf}; use std::process::{self, Command}; @@ -22,35 +21,28 @@ pub(crate) fn build_sysroot( fs::create_dir_all(target_dir.join("lib")).unwrap(); // Copy the backend - for file in ["cg_clif", "cg_clif_build_sysroot"] { - try_hard_link( - cg_clif_build_dir.join(get_file_name(file, "bin")), - target_dir.join("bin").join(get_file_name(file, "bin")), - ); - } - let cg_clif_dylib = get_file_name("rustc_codegen_cranelift", "dylib"); - try_hard_link( - cg_clif_build_dir.join(&cg_clif_dylib), - target_dir - .join(if cfg!(windows) { - // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the - // binaries. - "bin" - } else { - "lib" - }) - .join(cg_clif_dylib), - ); - - // Build and copy cargo wrapper - let mut build_cargo_wrapper_cmd = Command::new("rustc"); - build_cargo_wrapper_cmd - .arg("scripts/cargo-clif.rs") - .arg("-o") - .arg(target_dir.join("cargo-clif")) - .arg("-g"); - spawn_and_wait(build_cargo_wrapper_cmd); + let cg_clif_dylib_path = target_dir + .join(if cfg!(windows) { + // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the + // binaries. + "bin" + } else { + "lib" + }) + .join(&cg_clif_dylib); + try_hard_link(cg_clif_build_dir.join(cg_clif_dylib), &cg_clif_dylib_path); + + // Build and copy rustc and cargo wrappers + for wrapper in ["rustc-clif", "cargo-clif"] { + let mut build_cargo_wrapper_cmd = Command::new("rustc"); + build_cargo_wrapper_cmd + .arg(PathBuf::from("scripts").join(format!("{wrapper}.rs"))) + .arg("-o") + .arg(target_dir.join(wrapper)) + .arg("-g"); + spawn_and_wait(build_cargo_wrapper_cmd); + } let default_sysroot = super::rustc_info::get_default_sysroot(); @@ -117,7 +109,13 @@ pub(crate) fn build_sysroot( } } SysrootKind::Clif => { - build_clif_sysroot_for_triple(channel, target_dir, host_triple, None); + build_clif_sysroot_for_triple( + channel, + target_dir, + host_triple, + &cg_clif_dylib_path, + None, + ); if host_triple != target_triple { // When cross-compiling it is often necessary to manually pick the right linker @@ -126,14 +124,21 @@ pub(crate) fn build_sysroot( } else { None }; - build_clif_sysroot_for_triple(channel, target_dir, target_triple, linker); + build_clif_sysroot_for_triple( + channel, + target_dir, + target_triple, + &cg_clif_dylib_path, + linker, + ); } // Copy std for the host to the lib dir. This is necessary for the jit mode to find // libstd. for file in fs::read_dir(host_rustlib_lib).unwrap() { let file = file.unwrap().path(); - if file.file_name().unwrap().to_str().unwrap().contains("std-") { + let filename = file.file_name().unwrap().to_str().unwrap(); + if filename.contains("std-") && !filename.contains(".rlib") { try_hard_link(&file, target_dir.join("lib").join(file.file_name().unwrap())); } } @@ -145,6 +150,7 @@ fn build_clif_sysroot_for_triple( channel: &str, target_dir: &Path, triple: &str, + cg_clif_dylib_path: &Path, linker: Option<&str>, ) { match fs::read_to_string(Path::new("build_sysroot").join("rustc_version")) { @@ -168,18 +174,18 @@ fn build_clif_sysroot_for_triple( let build_dir = Path::new("build_sysroot").join("target").join(triple).join(channel); if !super::config::get_bool("keep_sysroot") { - // Cleanup the target dir with the exception of build scripts and the incremental cache - for dir in ["build", "deps", "examples", "native"] { - if build_dir.join(dir).exists() { - fs::remove_dir_all(build_dir.join(dir)).unwrap(); - } + // Cleanup the deps dir, but keep build scripts and the incremental cache for faster + // recompilation as they are not affected by changes in cg_clif. + if build_dir.join("deps").exists() { + fs::remove_dir_all(build_dir.join("deps")).unwrap(); } } // Build sysroot let mut build_cmd = Command::new("cargo"); build_cmd.arg("build").arg("--target").arg(triple).current_dir("build_sysroot"); - let mut rustflags = "--clif -Zforce-unstable-if-unmarked".to_string(); + let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string(); + rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap())); if channel == "release" { build_cmd.arg("--release"); rustflags.push_str(" -Zmir-opt-level=3"); @@ -189,10 +195,6 @@ fn build_clif_sysroot_for_triple( write!(rustflags, " -Clinker={}", linker).unwrap(); } build_cmd.env("RUSTFLAGS", rustflags); - build_cmd.env( - "RUSTC", - env::current_dir().unwrap().join(target_dir).join("bin").join("cg_clif_build_sysroot"), - ); build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif"); spawn_and_wait(build_cmd); diff --git a/compiler/rustc_codegen_cranelift/build_system/mod.rs b/compiler/rustc_codegen_cranelift/build_system/mod.rs index b228da3981f..b897b7fbacf 100644 --- a/compiler/rustc_codegen_cranelift/build_system/mod.rs +++ b/compiler/rustc_codegen_cranelift/build_system/mod.rs @@ -86,6 +86,7 @@ pub fn main() { arg => arg_error!("Unexpected argument {}", arg), } } + target_dir = std::env::current_dir().unwrap().join(target_dir); let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") { host_triple diff --git a/compiler/rustc_codegen_cranelift/docs/usage.md b/compiler/rustc_codegen_cranelift/docs/usage.md index 785c7383783..33f146e7ba2 100644 --- a/compiler/rustc_codegen_cranelift/docs/usage.md +++ b/compiler/rustc_codegen_cranelift/docs/usage.md @@ -19,7 +19,7 @@ This will build your project with rustc_codegen_cranelift instead of the usual L > You should prefer using the Cargo method. ```bash -$ $cg_clif_dir/build/bin/cg_clif my_crate.rs +$ $cg_clif_dir/build/rustc-clif my_crate.rs ``` ## Jit mode @@ -38,7 +38,7 @@ $ $cg_clif_dir/build/cargo-clif jit or ```bash -$ $cg_clif_dir/build/bin/cg_clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs +$ $cg_clif_dir/build/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs ``` There is also an experimental lazy jit mode. In this mode functions are only compiled once they are @@ -54,7 +54,7 @@ These are a few functions that allow you to easily run rust code from the shell ```bash function jit_naked() { - echo "$@" | $cg_clif_dir/build/bin/cg_clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic + echo "$@" | $cg_clif_dir/build/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic } function jit() { diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch index 8e6652af374..ce1c6c99b40 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch @@ -21,7 +21,7 @@ index 092b7cf..158cf71 100644 -#[cfg(target_has_atomic_load_store = "128")] -#[unstable(feature = "integer_atomics", issue = "32976")] -impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {} - + #[cfg(target_has_atomic_load_store = "ptr")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] @@ -235,9 +232,6 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicU32 {} @@ -31,14 +31,14 @@ index 092b7cf..158cf71 100644 -#[cfg(target_has_atomic_load_store = "128")] -#[unstable(feature = "integer_atomics", issue = "32976")] -impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {} - + #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index d9de37e..8293fce 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs -@@ -2234,44 +2234,6 @@ atomic_int! { +@@ -2234,46 +2234,6 @@ atomic_int! { "AtomicU64::new(0)", u64 AtomicU64 ATOMIC_U64_INIT } @@ -54,6 +54,7 @@ index d9de37e..8293fce 100644 - unstable(feature = "integer_atomics", issue = "32976"), - rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), - unstable(feature = "integer_atomics", issue = "32976"), +- cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"), - "i128", - "#![feature(integer_atomics)]\n\n", - atomic_min, atomic_max, @@ -73,6 +74,7 @@ index d9de37e..8293fce 100644 - unstable(feature = "integer_atomics", issue = "32976"), - rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), - unstable(feature = "integer_atomics", issue = "32976"), +- cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"), - "u128", - "#![feature(integer_atomics)]\n\n", - atomic_umin, atomic_umax, @@ -98,6 +100,6 @@ index b735957..ea728b6 100644 #[cfg(target_has_atomic = "ptr")] assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>()); #[cfg(target_has_atomic = "ptr")] --- +-- 2.26.2.7.g19db9cfb68 diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 966097c248b..e98e92e468e 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-04-21" +channel = "nightly-2022-05-15" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs index 41d82b581cd..9362b47fa6d 100644 --- a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs +++ b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs @@ -5,20 +5,11 @@ use std::path::PathBuf; use std::process::Command; fn main() { - if env::var("RUSTC_WRAPPER").map_or(false, |wrapper| wrapper.contains("sccache")) { - eprintln!( - "\x1b[1;93m=== Warning: Unsetting RUSTC_WRAPPER to prevent interference with sccache ===\x1b[0m" - ); - env::remove_var("RUSTC_WRAPPER"); - } - let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap()); - env::set_var("RUSTC", sysroot.join("bin/cg_clif".to_string() + env::consts::EXE_SUFFIX)); - - let mut rustdoc_flags = env::var("RUSTDOCFLAGS").unwrap_or(String::new()); - rustdoc_flags.push_str(" -Cpanic=abort -Zpanic-abort-tests -Zcodegen-backend="); - rustdoc_flags.push_str( + let mut rustflags = String::new(); + rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests -Zcodegen-backend="); + rustflags.push_str( sysroot .join(if cfg!(windows) { "bin" } else { "lib" }) .join( @@ -29,9 +20,10 @@ fn main() { .to_str() .unwrap(), ); - rustdoc_flags.push_str(" --sysroot "); - rustdoc_flags.push_str(sysroot.to_str().unwrap()); - env::set_var("RUSTDOCFLAGS", rustdoc_flags); + rustflags.push_str(" --sysroot "); + rustflags.push_str(sysroot.to_str().unwrap()); + env::set_var("RUSTFLAGS", env::var("RUSTFLAGS").unwrap_or(String::new()) + &rustflags); + env::set_var("RUSTDOCFLAGS", env::var("RUSTDOCFLAGS").unwrap_or(String::new()) + &rustflags); // Ensure that the right toolchain is used env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN")); @@ -46,7 +38,7 @@ fn main() { .chain(env::args().skip(2)) .chain([ "--".to_string(), - "-Zunstable-features".to_string(), + "-Zunstable-options".to_string(), "-Cllvm-args=mode=jit".to_string(), ]) .collect() @@ -60,7 +52,7 @@ fn main() { .chain(env::args().skip(2)) .chain([ "--".to_string(), - "-Zunstable-features".to_string(), + "-Zunstable-options".to_string(), "-Cllvm-args=mode=jit-lazy".to_string(), ]) .collect() diff --git a/compiler/rustc_codegen_cranelift/scripts/config.sh b/compiler/rustc_codegen_cranelift/scripts/config.sh deleted file mode 100644 index 53ada369b08..00000000000 --- a/compiler/rustc_codegen_cranelift/scripts/config.sh +++ /dev/null @@ -1,6 +0,0 @@ -# Note to people running shellcheck: this file should only be sourced, not executed directly. - -set -e - -export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH" -export DYLD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH" diff --git a/compiler/rustc_codegen_cranelift/scripts/ext_config.sh b/compiler/rustc_codegen_cranelift/scripts/ext_config.sh deleted file mode 100644 index 11d6c4c8318..00000000000 --- a/compiler/rustc_codegen_cranelift/scripts/ext_config.sh +++ /dev/null @@ -1,32 +0,0 @@ -# Note to people running shellcheck: this file should only be sourced, not executed directly. - -# Various env vars that should only be set for the build system - -set -e - -export CG_CLIF_DISPLAY_CG_TIME=1 -export CG_CLIF_DISABLE_INCR_CACHE=1 - -export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") -export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE} - -export RUN_WRAPPER='' -export JIT_SUPPORTED=1 -if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then - export JIT_SUPPORTED=0 - if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then - # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. - export RUSTFLAGS='-Clinker=aarch64-linux-gnu-gcc '$RUSTFLAGS - export RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu' - elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then - # We are cross-compiling for Windows. Run tests in wine. - export RUN_WRAPPER='wine' - else - echo "Unknown non-native platform" - fi -fi - -# FIXME fix `#[linkage = "extern_weak"]` without this -if [[ "$(uname)" == 'Darwin' ]]; then - export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup" -fi diff --git a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs index f4e863e5494..e6f60d1c0cb 100755 --- a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs +++ b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs @@ -2,8 +2,7 @@ #![forbid(unsafe_code)]/* This line is ignored by bash # This block is ignored by rustc pushd $(dirname "$0")/../ -source scripts/config.sh -RUSTC="$(pwd)/build/bin/cg_clif" +RUSTC="$(pwd)/build/rustc-clif" popd PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0 #*/ diff --git a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs new file mode 100644 index 00000000000..3abfcd8ddc8 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs @@ -0,0 +1,36 @@ +use std::env; +use std::ffi::OsString; +#[cfg(unix)] +use std::os::unix::process::CommandExt; +use std::path::PathBuf; +use std::process::Command; + +fn main() { + let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap()); + + let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join( + env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX, + ); + + let mut args = std::env::args_os().skip(1).collect::<Vec<_>>(); + args.push(OsString::from("-Cpanic=abort")); + args.push(OsString::from("-Zpanic-abort-tests")); + let mut codegen_backend_arg = OsString::from("-Zcodegen-backend="); + codegen_backend_arg.push(cg_clif_dylib_path); + args.push(codegen_backend_arg); + if !args.contains(&OsString::from("--sysroot")) { + args.push(OsString::from("--sysroot")); + args.push(OsString::from(sysroot.to_str().unwrap())); + } + + // Ensure that the right toolchain is used + env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN")); + + #[cfg(unix)] + Command::new("rustc").args(args).exec(); + + #[cfg(not(unix))] + std::process::exit( + Command::new("rustc").args(args).spawn().unwrap().wait().unwrap().code().unwrap_or(1), + ); +} diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index cabbaaa8922..4d0dfa16c5e 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -2,7 +2,6 @@ set -e ./y.rs build --no-unstable-features -source scripts/config.sh echo "[SETUP] Rust fork" git clone https://github.com/rust-lang/rust.git || true @@ -26,21 +25,6 @@ index d95b5b7f17f..00b6f0e3635 100644 [dev-dependencies] rand = "0.7" rand_xorshift = "0.2" -diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs -index 887d27fd6dca4..2c2239f2b83d1 100644 ---- a/src/tools/compiletest/src/header.rs -+++ b/src/tools/compiletest/src/header.rs -@@ -806,8 +806,8 @@ pub fn make_test_description<R: Read>( - cfg: Option<&str>, - ) -> test::TestDesc { - let mut ignore = false; - #[cfg(not(bootstrap))] -- let ignore_message: Option<String> = None; -+ let ignore_message: Option<&str> = None; - let mut should_fail = false; - - let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some(); - diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 8431aa7b818..a3ff7e68ce5 100644 --- a/src/tools/compiletest/src/runtest.rs @@ -67,7 +51,7 @@ changelog-seen = 2 ninja = false [build] -rustc = "$(pwd)/../build/bin/cg_clif" +rustc = "$(pwd)/../build/rustc-clif" cargo = "$(rustup which cargo)" full-bootstrap = true local-rebuild = true diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 4cf24c02235..9bdb9f22c54 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -101,11 +101,10 @@ rm src/test/incremental/spike-neg1.rs # errors out for some reason rm src/test/incremental/spike-neg2.rs # same rm src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs rm src/test/ui/mir/ssa-analysis-regression-50041.rs # produces ICE +rm src/test/ui/type-alias-impl-trait/assoc-projection-ice.rs # produces ICE rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors -rm src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs # wrong result from `Location::caller()` - # bugs in the test suite # ====================== rm src/test/ui/backtrace.rs # TODO warning diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh index aae626081f6..9b5ffa40960 100755 --- a/compiler/rustc_codegen_cranelift/scripts/tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh @@ -2,10 +2,43 @@ set -e -source scripts/config.sh -source scripts/ext_config.sh -export RUSTC=false # ensure that cg_llvm isn't accidentally used -MY_RUSTC="$(pwd)/build/bin/cg_clif $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2" +export CG_CLIF_DISPLAY_CG_TIME=1 +export CG_CLIF_DISABLE_INCR_CACHE=1 + +export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") +export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE} + +export RUN_WRAPPER='' + +case "$TARGET_TRIPLE" in + x86_64*) + export JIT_SUPPORTED=1 + ;; + *) + export JIT_SUPPORTED=0 + ;; +esac + +if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then + export JIT_SUPPORTED=0 + if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then + # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. + export RUSTFLAGS='-Clinker=aarch64-linux-gnu-gcc '$RUSTFLAGS + export RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu' + elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then + # We are cross-compiling for Windows. Run tests in wine. + export RUN_WRAPPER='wine' + else + echo "Unknown non-native platform" + fi +fi + +# FIXME fix `#[linkage = "extern_weak"]` without this +if [[ "$(uname)" == 'Darwin' ]]; then + export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup" +fi + +MY_RUSTC="$(pwd)/build/rustc-clif $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2" function no_sysroot_tests() { echo "[BUILD] mini_core" @@ -39,7 +72,7 @@ function base_sysroot_tests() { $MY_RUSTC example/issue-91827-extern-types.rs --crate-name issue_91827_extern_types --crate-type bin --target "$TARGET_TRIPLE" $RUN_WRAPPER ./target/out/issue_91827_extern_types - echo "[AOT] alloc_system" + echo "[BUILD] alloc_system" $MY_RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE" echo "[AOT] alloc_example" @@ -56,14 +89,14 @@ function base_sysroot_tests() { echo "[JIT] std_example (skipped)" fi - echo "[AOT] dst_field_align" - $MY_RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target "$TARGET_TRIPLE" - $RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false) - echo "[AOT] std_example" $MY_RUSTC example/std_example.rs --crate-type bin --target "$TARGET_TRIPLE" $RUN_WRAPPER ./target/out/std_example arg + echo "[AOT] dst_field_align" + $MY_RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target "$TARGET_TRIPLE" + $RUN_WRAPPER ./target/out/dst_field_align + echo "[AOT] subslice-patterns-const-eval" $MY_RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE" $RUN_WRAPPER ./target/out/subslice-patterns-const-eval @@ -97,7 +130,7 @@ function extended_sysroot_tests() { if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then echo "[BENCH COMPILE] ebobby/simple-raytracer" hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo-clif clean" \ - "RUSTC=rustc RUSTFLAGS='' cargo build" \ + "RUSTFLAGS='' cargo build" \ "../build/cargo-clif build" echo "[BENCH RUN] ebobby/simple-raytracer" diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index ef56fb191bf..b163a426191 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -309,7 +309,7 @@ fn codegen_call_argument_operand<'tcx>( pub(crate) fn codegen_terminator_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - span: Span, + source_info: mir::SourceInfo, func: &Operand<'tcx>, args: &[Operand<'tcx>], mir_dest: Option<(Place<'tcx>, BasicBlock)>, @@ -340,7 +340,13 @@ pub(crate) fn codegen_terminator_call<'tcx>( match instance.def { InstanceDef::Intrinsic(_) => { - crate::intrinsics::codegen_intrinsic_call(fx, instance, args, destination, span); + crate::intrinsics::codegen_intrinsic_call( + fx, + instance, + args, + destination, + source_info, + ); return; } InstanceDef::DropGlue(_, None) => { @@ -402,7 +408,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( // Pass the caller location for `#[track_caller]`. if instance.map(|inst| inst.def.requires_caller_location(fx.tcx)).unwrap_or(false) { - let caller_location = fx.get_caller_location(span); + let caller_location = fx.get_caller_location(source_info); args.push(CallArgument { value: caller_location, is_owned: false }); } @@ -479,9 +485,10 @@ pub(crate) fn codegen_terminator_call<'tcx>( // FIXME find a cleaner way to support varargs if fn_sig.c_variadic { if !matches!(fn_sig.abi, Abi::C { .. }) { - fx.tcx - .sess - .span_fatal(span, &format!("Variadic call for non-C abi {:?}", fn_sig.abi)); + fx.tcx.sess.span_fatal( + source_info.span, + &format!("Variadic call for non-C abi {:?}", fn_sig.abi), + ); } let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap(); let abi_params = call_args @@ -490,9 +497,10 @@ pub(crate) fn codegen_terminator_call<'tcx>( let ty = fx.bcx.func.dfg.value_type(arg); if !ty.is_int() { // FIXME set %al to upperbound on float args once floats are supported - fx.tcx - .sess - .span_fatal(span, &format!("Non int ty {:?} for variadic call", ty)); + fx.tcx.sess.span_fatal( + source_info.span, + &format!("Non int ty {:?} for variadic call", ty), + ); } AbiParam::new(ty) }) @@ -513,7 +521,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( pub(crate) fn codegen_drop<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - span: Span, + source_info: mir::SourceInfo, drop_place: CPlace<'tcx>, ) { let ty = drop_place.layout().ty; @@ -560,7 +568,7 @@ pub(crate) fn codegen_drop<'tcx>( if drop_instance.def.requires_caller_location(fx.tcx) { // Pass the caller location for `#[track_caller]`. - let caller_location = fx.get_caller_location(span); + let caller_location = fx.get_caller_location(source_info); call_args.extend( adjust_arg_for_abi(fx, caller_location, &fn_abi.args[1], false).into_iter(), ); diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 65346cb3962..65e5812a8a5 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -325,7 +325,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) { AssertKind::BoundsCheck { ref len, ref index } => { let len = codegen_operand(fx, len).load_scalar(fx); let index = codegen_operand(fx, index).load_scalar(fx); - let location = fx.get_caller_location(source_info.span).load_scalar(fx); + let location = fx.get_caller_location(source_info).load_scalar(fx); codegen_panic_inner( fx, @@ -336,7 +336,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) { } _ => { let msg_str = msg.description(); - codegen_panic(fx, msg_str, source_info.span); + codegen_panic(fx, msg_str, source_info); } } } @@ -398,7 +398,13 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) { from_hir_call: _, } => { fx.tcx.sess.time("codegen call", || { - crate::abi::codegen_terminator_call(fx, *fn_span, func, args, *destination) + crate::abi::codegen_terminator_call( + fx, + mir::SourceInfo { span: *fn_span, ..source_info }, + func, + args, + *destination, + ) }); } TerminatorKind::InlineAsm { @@ -450,7 +456,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) { } TerminatorKind::Drop { place, target, unwind: _ } => { let drop_place = codegen_place(fx, *place); - crate::abi::codegen_drop(fx, source_info.span, drop_place); + crate::abi::codegen_drop(fx, source_info, drop_place); let target_block = fx.get_block(*target); fx.bcx.ins().jump(target_block, &[]); @@ -471,7 +477,7 @@ fn codegen_stmt<'tcx>( fx.set_debug_loc(stmt.source_info); - #[cfg(disabled)] + #[cfg(any())] // This is never true match &stmt.kind { StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful _ => { @@ -898,14 +904,18 @@ pub(crate) fn codegen_operand<'tcx>( } } -pub(crate) fn codegen_panic<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, span: Span) { - let location = fx.get_caller_location(span).load_scalar(fx); +pub(crate) fn codegen_panic<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + msg_str: &str, + source_info: mir::SourceInfo, +) { + let location = fx.get_caller_location(source_info).load_scalar(fx); let msg_ptr = fx.anonymous_str(msg_str); let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); let args = [msg_ptr, msg_len, location]; - codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, span); + codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, source_info.span); } pub(crate) fn codegen_panic_inner<'tcx>( diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs deleted file mode 100644 index 5984ec8412a..00000000000 --- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs +++ /dev/null @@ -1,94 +0,0 @@ -#![feature(rustc_private)] -#![warn(rust_2018_idioms)] -#![warn(unused_lifetimes)] -#![warn(unreachable_pub)] - -extern crate rustc_data_structures; -extern crate rustc_driver; -extern crate rustc_interface; -extern crate rustc_session; -extern crate rustc_target; - -use std::panic; - -use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; -use rustc_interface::interface; -use rustc_session::config::{ErrorOutputType, TrimmedDefPaths}; -use rustc_session::early_error; -use rustc_target::spec::PanicStrategy; - -// FIXME use std::lazy::SyncLazy once it stabilizes -use once_cell::sync::Lazy; - -const BUG_REPORT_URL: &str = "https://github.com/bjorn3/rustc_codegen_cranelift/issues/new"; - -static DEFAULT_HOOK: Lazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> = - Lazy::new(|| { - let hook = panic::take_hook(); - panic::set_hook(Box::new(|info| { - // Invoke the default handler, which prints the actual panic message and optionally a backtrace - (*DEFAULT_HOOK)(info); - - // Separate the output with an empty line - eprintln!(); - - // Print the ICE message - rustc_driver::report_ice(info, BUG_REPORT_URL); - })); - hook - }); - -#[derive(Default)] -pub struct CraneliftPassesCallbacks { - time_passes: bool, -} - -impl rustc_driver::Callbacks for CraneliftPassesCallbacks { - fn config(&mut self, config: &mut interface::Config) { - // If a --prints=... option has been given, we don't print the "total" - // time because it will mess up the --prints output. See #64339. - self.time_passes = config.opts.prints.is_empty() - && (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time); - - config.opts.cg.panic = Some(PanicStrategy::Abort); - config.opts.debugging_opts.panic_abort_tests = true; - config.opts.maybe_sysroot = Some(config.opts.maybe_sysroot.clone().unwrap_or_else(|| { - std::env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_owned() - })); - - config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath; - } -} - -fn main() { - let start_time = std::time::Instant::now(); - let start_rss = get_resident_set_size(); - rustc_driver::init_rustc_env_logger(); - let mut callbacks = CraneliftPassesCallbacks::default(); - Lazy::force(&DEFAULT_HOOK); // Install ice hook - let exit_code = rustc_driver::catch_with_exit_code(|| { - let args = std::env::args_os() - .enumerate() - .map(|(i, arg)| { - arg.into_string().unwrap_or_else(|arg| { - early_error( - ErrorOutputType::default(), - &format!("Argument {} is not valid Unicode: {:?}", i, arg), - ) - }) - }) - .collect::<Vec<_>>(); - let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks); - run_compiler.set_make_codegen_backend(Some(Box::new(move |_| { - Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None }) - }))); - run_compiler.run() - }); - - if callbacks.time_passes { - let end_rss = get_resident_set_size(); - print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss); - } - - std::process::exit(exit_code) -} diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs deleted file mode 100644 index bde4d71b9a3..00000000000 --- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! The only difference between this and cg_clif.rs is that this binary defaults to using cg_llvm -//! instead of cg_clif and requires `--clif` to use cg_clif and that this binary doesn't have JIT -//! support. -//! This is necessary as with Cargo `RUSTC` applies to both target crates and host crates. The host -//! crates must be built with cg_llvm as we are currently building a sysroot for cg_clif. -//! `RUSTFLAGS` however is only applied to target crates, so `--clif` would only be passed to the -//! target crates. - -#![feature(rustc_private)] -#![warn(rust_2018_idioms)] -#![warn(unused_lifetimes)] -#![warn(unreachable_pub)] - -extern crate rustc_driver; -extern crate rustc_interface; -extern crate rustc_session; -extern crate rustc_target; - -use std::path::PathBuf; - -use rustc_interface::interface; -use rustc_session::config::ErrorOutputType; -use rustc_session::early_error; -use rustc_target::spec::PanicStrategy; - -fn find_sysroot() -> String { - // Taken from https://github.com/Manishearth/rust-clippy/pull/911. - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - match (home, toolchain) { - (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => option_env!("RUST_SYSROOT") - .expect("need to specify RUST_SYSROOT env var or use rustup or multirust") - .to_owned(), - } -} - -pub struct CraneliftPassesCallbacks { - use_clif: bool, -} - -impl rustc_driver::Callbacks for CraneliftPassesCallbacks { - fn config(&mut self, config: &mut interface::Config) { - if !self.use_clif { - config.opts.maybe_sysroot = Some(PathBuf::from(find_sysroot())); - return; - } - - config.opts.cg.panic = Some(PanicStrategy::Abort); - config.opts.debugging_opts.panic_abort_tests = true; - config.opts.maybe_sysroot = - Some(std::env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_owned()); - } -} - -fn main() { - rustc_driver::init_rustc_env_logger(); - rustc_driver::install_ice_hook(); - let exit_code = rustc_driver::catch_with_exit_code(|| { - let mut use_clif = false; - - let args = std::env::args_os() - .enumerate() - .map(|(i, arg)| { - arg.into_string().unwrap_or_else(|arg| { - early_error( - ErrorOutputType::default(), - &format!("Argument {} is not valid Unicode: {:?}", i, arg), - ) - }) - }) - .filter(|arg| { - if arg == "--clif" { - use_clif = true; - false - } else { - true - } - }) - .collect::<Vec<_>>(); - - let mut callbacks = CraneliftPassesCallbacks { use_clif }; - - let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks); - if use_clif { - run_compiler.set_make_codegen_backend(Some(Box::new(move |_| { - Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None }) - }))); - } - run_compiler.run() - }); - std::process::exit(exit_code) -} diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index ffa629ca16c..f9dc1b5169e 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -340,22 +340,46 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { self.bcx.set_srcloc(SourceLoc::new(index as u32)); } - pub(crate) fn get_caller_location(&mut self, span: Span) -> CValue<'tcx> { - if let Some(loc) = self.caller_location { - // `#[track_caller]` is used; return caller location instead of current location. - return loc; + // Note: must be kept in sync with get_caller_location from cg_ssa + pub(crate) fn get_caller_location(&mut self, mut source_info: mir::SourceInfo) -> CValue<'tcx> { + let span_to_caller_location = |fx: &mut FunctionCx<'_, '_, 'tcx>, span: Span| { + let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); + let caller = fx.tcx.sess.source_map().lookup_char_pos(topmost.lo()); + let const_loc = fx.tcx.const_caller_location(( + rustc_span::symbol::Symbol::intern( + &caller.file.name.prefer_remapped().to_string_lossy(), + ), + caller.line as u32, + caller.col_display as u32 + 1, + )); + crate::constant::codegen_const_value(fx, const_loc, fx.tcx.caller_location_ty()) + }; + + // Walk up the `SourceScope`s, in case some of them are from MIR inlining. + // If so, the starting `source_info.span` is in the innermost inlined + // function, and will be replaced with outer callsite spans as long + // as the inlined functions were `#[track_caller]`. + loop { + let scope_data = &self.mir.source_scopes[source_info.scope]; + + if let Some((callee, callsite_span)) = scope_data.inlined { + // Stop inside the most nested non-`#[track_caller]` function, + // before ever reaching its caller (which is irrelevant). + if !callee.def.requires_caller_location(self.tcx) { + return span_to_caller_location(self, source_info.span); + } + source_info.span = callsite_span; + } + + // Skip past all of the parents with `inlined: None`. + match scope_data.inlined_parent_scope { + Some(parent) => source_info.scope = parent, + None => break, + } } - let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); - let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); - let const_loc = self.tcx.const_caller_location(( - rustc_span::symbol::Symbol::intern( - &caller.file.name.prefer_remapped().to_string_lossy(), - ), - caller.line as u32, - caller.col_display as u32 + 1, - )); - crate::constant::codegen_const_value(self, const_loc, self.tcx.caller_location_ty()) + // No inlined `SourceScope`s, or all of them were `#[track_caller]`. + self.caller_location.unwrap_or_else(|| span_to_caller_location(self, source_info.span)) } pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value { diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 7f15bc75fda..1b01f4edbb3 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -74,6 +74,7 @@ fn create_jit_module<'tcx>( jit_builder.hotswap(hotswap); crate::compiler_builtins::register_functions_for_jit(&mut jit_builder); jit_builder.symbols(imported_symbols); + jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8); let mut jit_module = JITModule::new(jit_builder); let mut cx = crate::CodegenCx::new( @@ -210,8 +211,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { } } -#[no_mangle] -extern "C" fn __clif_jit_fn( +extern "C" fn clif_jit_fn( instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8, ) -> *const u8 { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index f7a83373e87..29b3f36b2be 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -218,7 +218,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( instance: Instance<'tcx>, args: &[mir::Operand<'tcx>], destination: Option<(CPlace<'tcx>, BasicBlock)>, - span: Span, + source_info: mir::SourceInfo, ) { let intrinsic = fx.tcx.item_name(instance.def_id()); let substs = instance.substs; @@ -232,7 +232,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( fx.bcx.ins().trap(TrapCode::User(0)); } sym::transmute => { - crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span); + crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info); } _ => unimplemented!("unsupported instrinsic {}", intrinsic), } @@ -241,7 +241,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( }; if intrinsic.as_str().starts_with("simd_") { - self::simd::codegen_simd_intrinsic_call(fx, intrinsic, substs, args, ret, span); + self::simd::codegen_simd_intrinsic_call(fx, intrinsic, substs, args, ret, source_info.span); let ret_block = fx.get_block(destination.expect("SIMD intrinsics don't diverge").1); fx.bcx.ins().jump(ret_block, &[]); } else if codegen_float_intrinsic_call(fx, intrinsic, args, ret) { @@ -255,7 +255,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( substs, args, ret, - span, + source_info, destination, ); } @@ -339,7 +339,7 @@ fn codegen_regular_intrinsic_call<'tcx>( substs: SubstsRef<'tcx>, args: &[mir::Operand<'tcx>], ret: CPlace<'tcx>, - span: Span, + source_info: mir::SourceInfo, destination: Option<(CPlace<'tcx>, BasicBlock)>, ) { let usize_layout = fx.layout_of(fx.tcx.types.usize); @@ -347,7 +347,7 @@ fn codegen_regular_intrinsic_call<'tcx>( intrinsic_match! { fx, intrinsic, args, _ => { - fx.tcx.sess.span_fatal(span, &format!("unsupported intrinsic {}", intrinsic)); + fx.tcx.sess.span_fatal(source_info.span, &format!("unsupported intrinsic {}", intrinsic)); }; assume, (c _a) {}; @@ -658,7 +658,7 @@ fn codegen_regular_intrinsic_call<'tcx>( crate::base::codegen_panic( fx, &format!("attempted to instantiate uninhabited type `{}`", layout.ty), - span, + source_info, ) }); return; @@ -669,7 +669,7 @@ fn codegen_regular_intrinsic_call<'tcx>( crate::base::codegen_panic( fx, &format!("attempted to zero-initialize type `{}`, which is invalid", layout.ty), - span, + source_info, ); }); return; @@ -680,7 +680,7 @@ fn codegen_regular_intrinsic_call<'tcx>( crate::base::codegen_panic( fx, &format!("attempted to leave type `{}` uninitialized, which is invalid", layout.ty), - span, + source_info, ) }); return; @@ -715,19 +715,19 @@ fn codegen_regular_intrinsic_call<'tcx>( ptr_offset_from | ptr_offset_from_unsigned, (v ptr, v base) { let ty = substs.type_at(0); - let isize_layout = fx.layout_of(fx.tcx.types.isize); let pointee_size: u64 = fx.layout_of(ty).size.bytes(); let diff_bytes = fx.bcx.ins().isub(ptr, base); // FIXME this can be an exact division. - let diff = if intrinsic == sym::ptr_offset_from_unsigned { + let val = if intrinsic == sym::ptr_offset_from_unsigned { + let usize_layout = fx.layout_of(fx.tcx.types.usize); // Because diff_bytes ULE isize::MAX, this would be fine as signed, // but unsigned is slightly easier to codegen, so might as well. - fx.bcx.ins().udiv_imm(diff_bytes, pointee_size as i64) + CValue::by_val(fx.bcx.ins().udiv_imm(diff_bytes, pointee_size as i64), usize_layout) } else { - fx.bcx.ins().sdiv_imm(diff_bytes, pointee_size as i64) + let isize_layout = fx.layout_of(fx.tcx.types.isize); + CValue::by_val(fx.bcx.ins().sdiv_imm(diff_bytes, pointee_size as i64), isize_layout) }; - let val = CValue::by_val(diff, isize_layout); ret.write_cvalue(fx, val); }; @@ -742,7 +742,7 @@ fn codegen_regular_intrinsic_call<'tcx>( }; caller_location, () { - let caller_location = fx.get_caller_location(span); + let caller_location = fx.get_caller_location(source_info); ret.write_cvalue(fx, caller_location); }; @@ -765,12 +765,12 @@ fn codegen_regular_intrinsic_call<'tcx>( fx.bcx.ins().jump(ret_block, &[]); return; } else { - fx.tcx.sess.span_fatal(span, "128bit atomics not yet supported"); + fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported"); } } ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, ty); return; } } @@ -793,12 +793,12 @@ fn codegen_regular_intrinsic_call<'tcx>( fx.bcx.ins().jump(ret_block, &[]); return; } else { - fx.tcx.sess.span_fatal(span, "128bit atomics not yet supported"); + fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported"); } } ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, ty); return; } } @@ -812,7 +812,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, layout.ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return; } } @@ -830,7 +830,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, layout.ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return; } } @@ -850,7 +850,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, layout.ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return; } } @@ -868,7 +868,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, layout.ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return; } } @@ -886,7 +886,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, layout.ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return; } } @@ -904,7 +904,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, layout.ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return; } } @@ -922,7 +922,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, layout.ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return; } } @@ -940,7 +940,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, layout.ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return; } } @@ -958,7 +958,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, layout.ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return; } } @@ -976,7 +976,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, layout.ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return; } } @@ -994,7 +994,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, layout.ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return; } } @@ -1012,7 +1012,7 @@ fn codegen_regular_intrinsic_call<'tcx>( match layout.ty.kind() { ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { - report_atomic_type_validation_error(fx, intrinsic, span, layout.ty); + report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return; } } diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 8f80b02ae0d..a68225de58b 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -828,6 +828,7 @@ pub(crate) fn assert_assignable<'tcx>( } } } + (ty::Array(a, _), ty::Array(b, _)) => assert_assignable(fx, *a, *b), _ => { assert_eq!( from_ty, to_ty, diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index c098ce36f02..9394d60134f 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -6,6 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::OptLevel; +use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector}; use smallvec::SmallVec; @@ -329,9 +330,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( ) { let span = cx .tcx - .get_attrs(instance.def_id()) - .iter() - .find(|a| a.has_name(rustc_span::sym::target_feature)) + .get_attr(instance.def_id(), sym::target_feature) .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); let msg = format!( "the target features {} must all be either enabled or disabled together", diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index f814cc93043..8f6438e85ad 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -152,8 +152,10 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { }; let target = &self.config.sess.target; - let mingw_gnu_toolchain = - target.vendor == "pc" && target.os == "windows" && target.env == "gnu"; + let mingw_gnu_toolchain = target.vendor == "pc" + && target.os == "windows" + && target.env == "gnu" + && target.abi.is_empty(); let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports .iter() diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 87d0680bf6f..93b10a07e44 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -41,6 +41,6 @@ rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } [dependencies.object] -version = "0.28.0" +version = "0.28.4" default-features = false features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"] diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 2e422728056..6aa96f9f403 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -20,7 +20,7 @@ use rustc_metadata::EncodedMetadata; use rustc_session::cstore::MetadataLoader; use rustc_session::Session; use rustc_target::abi::Endian; -use rustc_target::spec::Target; +use rustc_target::spec::{RelocModel, Target}; use crate::METADATA_FILENAME; @@ -132,15 +132,23 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static let mut file = write::Object::new(binary_format, architecture, endianness); match architecture { Architecture::Mips => { - // copied from `mipsel-linux-gnu-gcc foo.c -c` and - // inspecting the resulting `e_flags` field. - let e_flags = elf::EF_MIPS_CPIC - | elf::EF_MIPS_PIC - | if sess.target.options.cpu.contains("r6") { - elf::EF_MIPS_ARCH_32R6 | elf::EF_MIPS_NAN2008 - } else { - elf::EF_MIPS_ARCH_32R2 - }; + let arch = match sess.target.options.cpu.as_ref() { + "mips1" => elf::EF_MIPS_ARCH_1, + "mips2" => elf::EF_MIPS_ARCH_2, + "mips3" => elf::EF_MIPS_ARCH_3, + "mips4" => elf::EF_MIPS_ARCH_4, + "mips5" => elf::EF_MIPS_ARCH_5, + s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6, + _ => elf::EF_MIPS_ARCH_32R2, + }; + // The only ABI LLVM supports for 32-bit MIPS CPUs is o32. + let mut e_flags = elf::EF_MIPS_CPIC | elf::EF_MIPS_ABI_O32 | arch; + if sess.target.options.relocation_model != RelocModel::Static { + e_flags |= elf::EF_MIPS_PIC; + } + if sess.target.options.cpu.contains("r6") { + e_flags |= elf::EF_MIPS_NAN2008; + } file.flags = FileFlags::Elf { e_flags }; } Architecture::Mips64 => { 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 38fecf7232e..5c56e6ee5f5 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -13,7 +13,7 @@ use rustc_middle::mir::pretty::display_allocation; use rustc_middle::traits::Reveal; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, subst::Subst, TyCtxt}; +use rustc_middle::ty::{self, subst::Subst, EarlyBinder, TyCtxt}; use rustc_span::source_map::Span; use rustc_target::abi::{self, Abi}; use std::borrow::Cow; @@ -47,7 +47,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( "Unexpected DefKind: {:?}", ecx.tcx.def_kind(cid.instance.def_id()) ); - let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; + let layout = ecx.layout_of(EarlyBinder(body.return_ty()).subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ret = ecx.allocate(layout, MemoryKind::Stack)?; diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index d57504deeab..c5a11aaceaf 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -18,7 +18,7 @@ use rustc_target::spec::abi::Abi; use crate::interpret::{ self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult, - OpTy, PlaceTy, Scalar, StackPopUnwind, + OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind, }; use super::error::*; @@ -444,6 +444,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } #[inline(always)] + fn expose_ptr( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ptr: Pointer<AllocId>, + ) -> InterpResult<'tcx> { + Err(ConstEvalErrKind::NeedsRfc("exposing pointers".to_string()).into()) + } + + #[inline(always)] fn init_frame_extra( ecx: &mut InterpCx<'mir, 'tcx, Self>, frame: Frame<'mir, 'tcx>, diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 374179d0cc2..f57f25c19f9 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -58,7 +58,9 @@ fn slice_branches<'tcx>( ecx: &CompileTimeEvalContext<'tcx, 'tcx>, place: &MPlaceTy<'tcx>, ) -> Option<ty::ValTree<'tcx>> { - let n = place.len(&ecx.tcx.tcx).expect(&format!("expected to use len of place {:?}", place)); + let n = place + .len(&ecx.tcx.tcx) + .unwrap_or_else(|_| panic!("expected to use len of place {:?}", place)); let branches = (0..n).map(|i| { let place_elem = ecx.mplace_index(place, i).unwrap(); const_to_valtree_inner(ecx, &place_elem) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 3ea3729dbcd..92eeafc5df0 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -98,7 +98,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } pub fn misc_cast( - &self, + &mut self, src: &ImmTy<'tcx, M::PointerTag>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate<M::PointerTag>> { @@ -139,7 +139,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) { assert!(src.layout.is_zst()); let discr_layout = self.layout_of(discr.ty)?; - return Ok(self.cast_from_int_like(discr.val, discr_layout, cast_ty).into()); + + let scalar = Scalar::from_uint(discr.val, discr_layout.layout.size()); + return Ok(self.cast_from_int_like(scalar, discr_layout, cast_ty)?.into()); } } Variants::Multiple { .. } => {} @@ -170,38 +172,65 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // # The remaining source values are scalar and "int-like". + let scalar = src.to_scalar()?; + + // If we are casting from a pointer to something + // that is not a pointer, mark the pointer as exposed + if src.layout.ty.is_any_ptr() && !cast_ty.is_any_ptr() { + let ptr = self.scalar_to_ptr(scalar)?; + + match ptr.into_pointer_or_addr() { + Ok(ptr) => { + M::expose_ptr(self, ptr)?; + } + Err(_) => { + // do nothing, exposing an invalid pointer + // has no meaning + } + }; + } - // For all remaining casts, we either - // (a) cast a raw ptr to usize, or - // (b) cast from an integer-like (including bool, char, enums). - // In both cases we want the bits. - let bits = src.to_scalar()?.to_bits(src.layout.size)?; - Ok(self.cast_from_int_like(bits, src.layout, cast_ty).into()) + Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) } - fn cast_from_int_like( + pub fn cast_from_int_like( &self, - v: u128, // raw bits (there is no ScalarTy so we separate data+layout) + scalar: Scalar<M::PointerTag>, // input value (there is no ScalarTy so we separate data+layout) src_layout: TyAndLayout<'tcx>, cast_ty: Ty<'tcx>, - ) -> Scalar<M::PointerTag> { + ) -> InterpResult<'tcx, Scalar<M::PointerTag>> { // Let's make sure v is sign-extended *if* it has a signed type. let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`. + + let v = scalar.to_bits(src_layout.size)?; let v = if signed { self.sign_extend(v, src_layout) } else { v }; trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty); use rustc_middle::ty::TyKind::*; - match *cast_ty.kind() { - Int(_) | Uint(_) | RawPtr(_) => { + + Ok(match *cast_ty.kind() { + Int(_) | Uint(_) => { let size = match *cast_ty.kind() { Int(t) => Integer::from_int_ty(self, t).size(), Uint(t) => Integer::from_uint_ty(self, t).size(), - RawPtr(_) => self.pointer_size(), _ => bug!(), }; let v = size.truncate(v); Scalar::from_uint(v, size) } + RawPtr(_) => { + assert!(src_layout.ty.is_integral()); + + let size = self.pointer_size(); + let addr = u64::try_from(size.truncate(v)).unwrap(); + + let ptr = M::ptr_from_addr_cast(&self, addr); + if addr == 0 { + assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId"); + } + Scalar::from_maybe_pointer(ptr, self) + } + Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value), Float(FloatTy::F64) if signed => Scalar::from_f64(Double::from_i128(v as i128).value), Float(FloatTy::F32) => Scalar::from_f32(Single::from_u128(v).value), @@ -214,7 +243,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Casts to bool are not permitted by rustc, no need to handle them here. _ => span_bug!(self.cur_span(), "invalid int to {:?} cast", cast_ty), - } + }) } fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::PointerTag> diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 827959113b9..dfb81a2afc4 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -905,7 +905,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { trace!( "deallocating local {:?}: {:?}", local, - self.dump_alloc(ptr.provenance.unwrap().get_alloc_id()) + // Locals always have a `alloc_id` (they are never the result of a int2ptr). + self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap()) ); self.deallocate_ptr(ptr, None, MemoryKind::Stack)?; }; @@ -1013,9 +1014,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug } } - write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs)) + write!( + fmt, + ": {:?}", + self.ecx.dump_allocs(allocs.into_iter().filter_map(|x| x).collect()) + ) } - Place::Ptr(mplace) => match mplace.ptr.provenance.map(Provenance::get_alloc_id) { + Place::Ptr(mplace) => match mplace.ptr.provenance.and_then(Provenance::get_alloc_id) { Some(alloc_id) => write!( fmt, "by align({}) ref {:?}: {:?}", diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs index 058903dcdee..5ece19d7fb3 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs @@ -95,7 +95,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Allocate memory for `CallerLocation` struct. let loc_ty = self .tcx - .type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None)) + .bound_type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None)) .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter())); let loc_layout = self.layout_of(loc_ty).unwrap(); // This can fail if rustc runs out of memory right here. Trying to emit an error would be diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 7721485771b..a79751ccb55 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -286,19 +286,36 @@ pub trait Machine<'mir, 'tcx>: Sized { ) -> Pointer<Self::PointerTag>; /// "Int-to-pointer cast" - fn ptr_from_addr( + fn ptr_from_addr_cast( ecx: &InterpCx<'mir, 'tcx, Self>, addr: u64, ) -> Pointer<Option<Self::PointerTag>>; + // FIXME: Transmuting an integer to a pointer should just always return a `None` + // provenance, but that causes problems with function pointers in Miri. + /// Hook for returning a pointer from a transmute-like operation on an addr. + fn ptr_from_addr_transmute( + ecx: &InterpCx<'mir, 'tcx, Self>, + addr: u64, + ) -> Pointer<Option<Self::PointerTag>>; + + /// Marks a pointer as exposed, allowing it's provenance + /// to be recovered. "Pointer-to-int cast" + fn expose_ptr( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + ptr: Pointer<Self::PointerTag>, + ) -> InterpResult<'tcx>; + /// Convert a pointer with provenance into an allocation-offset pair /// and extra provenance info. /// /// The returned `AllocId` must be the same as `ptr.provenance.get_alloc_id()`. + /// + /// When this fails, that means the pointer does not point to a live allocation. fn ptr_get_alloc( ecx: &InterpCx<'mir, 'tcx, Self>, ptr: Pointer<Self::PointerTag>, - ) -> (AllocId, Size, Self::TagExtra); + ) -> Option<(AllocId, Size, Self::TagExtra)>; /// Called to initialize the "extra" state of an allocation and make the pointers /// it contains (in relocations) tagged. The way we construct allocations is @@ -480,7 +497,18 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { } #[inline(always)] - fn ptr_from_addr(_ecx: &InterpCx<$mir, $tcx, Self>, addr: u64) -> Pointer<Option<AllocId>> { + fn ptr_from_addr_transmute( + _ecx: &InterpCx<$mir, $tcx, Self>, + addr: u64, + ) -> Pointer<Option<AllocId>> { + Pointer::new(None, Size::from_bytes(addr)) + } + + #[inline(always)] + fn ptr_from_addr_cast( + _ecx: &InterpCx<$mir, $tcx, Self>, + addr: u64, + ) -> Pointer<Option<AllocId>> { Pointer::new(None, Size::from_bytes(addr)) } @@ -488,9 +516,9 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { fn ptr_get_alloc( _ecx: &InterpCx<$mir, $tcx, Self>, ptr: Pointer<AllocId>, - ) -> (AllocId, Size, Self::TagExtra) { + ) -> Option<(AllocId, Size, Self::TagExtra)> { // We know `offset` is relative to the allocation, so we can use `into_parts`. let (alloc_id, offset) = ptr.into_parts(); - (alloc_id, offset, ()) + Some((alloc_id, offset, ())) } } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index b1d7ab6a098..33162a01ed2 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -770,7 +770,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if reachable.insert(id) { // This is a new allocation, add its relocations to `todo`. if let Some((_, alloc)) = self.memory.alloc_map.get(id) { - todo.extend(alloc.relocations().values().map(|tag| tag.get_alloc_id())); + todo.extend( + alloc.relocations().values().filter_map(|tag| tag.get_alloc_id()), + ); } } } @@ -805,7 +807,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, allocs_to_print: &mut VecDeque<AllocId>, alloc: &Allocation<Tag, Extra>, ) -> std::fmt::Result { - for alloc_id in alloc.relocations().values().map(|tag| tag.get_alloc_id()) { + for alloc_id in alloc.relocations().values().filter_map(|tag| tag.get_alloc_id()) { allocs_to_print.push_back(alloc_id); } write!(fmt, "{}", display_allocation(tcx, alloc)) @@ -1142,7 +1144,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Err(ptr) => ptr.into(), Ok(bits) => { let addr = u64::try_from(bits).unwrap(); - let ptr = M::ptr_from_addr(&self, addr); + let ptr = M::ptr_from_addr_transmute(&self, addr); if addr == 0 { assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId"); } @@ -1182,10 +1184,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ptr: Pointer<Option<M::PointerTag>>, ) -> Result<(AllocId, Size, M::TagExtra), u64> { match ptr.into_pointer_or_addr() { - Ok(ptr) => { - let (alloc_id, offset, extra) = M::ptr_get_alloc(self, ptr); - Ok((alloc_id, offset, extra)) - } + Ok(ptr) => match M::ptr_get_alloc(self, ptr) { + Some((alloc_id, offset, extra)) => Ok((alloc_id, offset, extra)), + None => { + assert!(M::PointerTag::OFFSET_IS_ADDR); + let (_, addr) = ptr.into_parts(); + Err(addr.bytes()) + } + }, Err(addr) => Err(addr.bytes()), } } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index d627ddb39d0..5c85c86107f 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -741,17 +741,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Figure out which discriminant and variant this corresponds to. Ok(match *tag_encoding { TagEncoding::Direct => { + let scalar = tag_val.to_scalar()?; // Generate a specific error if `tag_val` is not an integer. // (`tag_bits` itself is only used for error messages below.) - let tag_bits = tag_val - .to_scalar()? + let tag_bits = scalar .try_to_int() .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))? .assert_bits(tag_layout.size); // Cast bits from tag layout to discriminant layout. - // After the checks we did above, this cannot fail. + // After the checks we did above, this cannot fail, as + // discriminants are int-like. let discr_val = - self.misc_cast(&tag_val, discr_layout.ty).unwrap().to_scalar().unwrap(); + self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap(); let discr_bits = discr_val.assert_bits(discr_layout.size); // Convert discriminant to variant index, and catch invalid discriminants. let index = match *op.layout.ty.kind() { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 80d129d4d7e..1104bbf4716 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -312,11 +312,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { Status::Unstable(gate) if self.tcx.features().enabled(gate) => { let unstable_in_stable = self.ccx.is_const_stable_const_fn() - && !super::rustc_allow_const_fn_unstable( - self.tcx, - self.def_id().to_def_id(), - gate, - ); + && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate); if unstable_in_stable { emit_unstable_in_stable_error(self.ccx, span, gate); } @@ -711,7 +707,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { match &terminator.kind { TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => { let ConstCx { tcx, body, param_env, .. } = *self.ccx; - let caller = self.def_id().to_def_id(); + let caller = self.def_id(); let fn_ty = func.ty(body, tcx); @@ -795,7 +791,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // trait. let callee_trait = tcx.trait_of_item(callee); if callee_trait.is_some() - && tcx.has_attr(caller, sym::default_method_body_is_const) + && tcx.has_attr(caller.to_def_id(), sym::default_method_body_is_const) && callee_trait == tcx.trait_of_item(caller) // Can only call methods when it's `<Self as TheTrait>::f`. && tcx.types.self_param == substs.type_at(0) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index 25ba97ee605..23e2afae791 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -66,8 +66,12 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { } } -pub fn rustc_allow_const_fn_unstable(tcx: TyCtxt<'_>, def_id: DefId, feature_gate: Symbol) -> bool { - let attrs = tcx.get_attrs(def_id); +pub fn rustc_allow_const_fn_unstable( + tcx: TyCtxt<'_>, + def_id: LocalDefId, + feature_gate: Symbol, +) -> bool { + let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id)); attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate) } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index ba248a3b6cb..122471b208d 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -1,5 +1,6 @@ //! Concrete error types for all operations which may be invalid in a certain const context. +use hir::def_id::LocalDefId; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -95,7 +96,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { /// A function call where the callee is not marked as `const`. #[derive(Debug, Clone, Copy)] pub struct FnCallNonConst<'tcx> { - pub caller: DefId, + pub caller: LocalDefId, pub callee: DefId, pub substs: SubstsRef<'tcx>, pub span: Span, @@ -117,13 +118,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { match self_ty.kind() { Param(param_ty) => { debug!(?param_ty); - if let Some(generics) = caller - .as_local() - .map(|id| tcx.hir().local_def_id_to_hir_id(id)) - .map(|id| tcx.hir().get(id)) - .as_ref() - .and_then(|node| node.generics()) - { + let caller_hir_id = tcx.hir().local_def_id_to_hir_id(caller); + if let Some(generics) = tcx.hir().get(caller_hir_id).generics() { let constraint = with_no_trimmed_paths!(format!( "~const {}", trait_ref.print_only_trait_path() diff --git a/compiler/rustc_error_codes/src/error_codes/E0455.md b/compiler/rustc_error_codes/src/error_codes/E0455.md index 84689b3ece6..437dacaff22 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0455.md +++ b/compiler/rustc_error_codes/src/error_codes/E0455.md @@ -1,6 +1,11 @@ +Some linking kinds are target-specific and not supported on all platforms. + Linking with `kind=framework` is only supported when targeting macOS, as frameworks are specific to that operating system. +Similarly, `kind=raw-dylib` is only supported when targeting Windows-like +platforms. + Erroneous code example: ```ignore (should-compile_fail-but-cannot-doctest-conditionally-without-macos) diff --git a/compiler/rustc_error_codes/src/error_codes/E0458.md b/compiler/rustc_error_codes/src/error_codes/E0458.md index 359aeb6fd9a..1b280cba44f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0458.md +++ b/compiler/rustc_error_codes/src/error_codes/E0458.md @@ -12,3 +12,4 @@ Please specify a valid "kind" value, from one of the following: * static * dylib * framework +* raw-dylib diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 29f354d5728..ddfbef945ef 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -76,6 +76,7 @@ crate use ParseResult::*; use crate::mbe::{KleeneOp, TokenTree}; use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token}; +use rustc_lint_defs::pluralize; use rustc_parse::parser::{NtOrTt, Parser}; use rustc_span::symbol::MacroRulesNormalizedIdent; use rustc_span::Span; @@ -668,8 +669,7 @@ impl TtParser { self.macro_name, match self.next_mps.len() { 0 => format!("built-in NTs {}.", nts), - 1 => format!("built-in NTs {} or 1 other option.", nts), - n => format!("built-in NTs {} or {} other options.", nts, n), + n => format!("built-in NTs {} or {n} other option{s}.", nts, s = pluralize!(n)), } ), ) diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index ba0b35470b6..4cc3169180e 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -175,7 +175,7 @@ impl TTMacroExpander for MacroRulesMacroExpander { if !self.valid { return DummyResult::any(sp); } - generic_extension( + expand_macro( cx, sp, self.span, @@ -202,8 +202,9 @@ fn trace_macros_note(cx_expansions: &mut FxHashMap<Span, Vec<String>>, sp: Span, cx_expansions.entry(sp).or_default().push(message); } -/// Given `lhses` and `rhses`, this is the new macro we create -fn generic_extension<'cx, 'tt>( +/// Expands the rules based macro defined by `lhses` and `rhses` for a given +/// input `arg`. +fn expand_macro<'cx, 'tt>( cx: &'cx mut ExtCtxt<'_>, sp: Span, def_span: Span, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c5f42aa7af7..097493e8985 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -147,6 +147,16 @@ pub enum AttributeDuplicates { FutureWarnPreceding, } +/// A conveniece macro to deal with `$($expr)?`. +macro_rules! or_default { + ($default:expr,) => { + $default + }; + ($default:expr, $next:expr) => { + $next + }; +} + /// A convenience macro for constructing attribute templates. /// E.g., `template!(Word, List: "description")` means that the attribute /// supports forms `#[attr]` and `#[attr(description)]`. @@ -168,9 +178,10 @@ macro_rules! template { } macro_rules! ungated { - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)? $(,)?) => { BuiltinAttribute { name: sym::$attr, + only_local: or_default!(false, $($only_local)?), type_: $typ, template: $tpl, gate: Ungated, @@ -180,18 +191,20 @@ macro_rules! ungated { } macro_rules! gated { - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $gate:ident, $msg:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $gate:ident, $msg:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, + only_local: or_default!(false, $($only_local)?), type_: $typ, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), } }; - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $msg:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $msg:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, + only_local: or_default!(false, $($only_local)?), type_: $typ, template: $tpl, duplicates: $duplicates, @@ -201,12 +214,13 @@ macro_rules! gated { } macro_rules! rustc_attr { - (TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr $(,)?) => { + (TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr $(, @only_local: $only_local:expr)? $(,)?) => { rustc_attr!( $attr, $typ, $tpl, $duplicate, + $(@only_local: $only_local,)? concat!( "the `#[", stringify!($attr), @@ -215,9 +229,10 @@ macro_rules! rustc_attr { ), ) }; - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $msg:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $msg:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, + only_local: or_default!(false, $($only_local)?), type_: $typ, template: $tpl, duplicates: $duplicates, @@ -237,6 +252,10 @@ const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never b pub struct BuiltinAttribute { pub name: Symbol, + /// Whether this attribute is only used in the local crate. + /// + /// If so, it is not encoded in the crate metadata. + pub only_local: bool, pub type_: AttributeType, pub template: AttributeTemplate, pub duplicates: AttributeDuplicates, @@ -295,7 +314,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing), gated!( must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, - must_not_suspend, experimental!(must_not_suspend) + experimental!(must_not_suspend) ), ungated!( deprecated, Normal, @@ -324,8 +343,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(repr, Normal, template!(List: "C"), DuplicatesOk), ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), - ungated!(no_mangle, Normal, template!(Word), WarnFollowing), - ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing), + ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true), + ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, @only_local: true), // Limits: ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing), @@ -358,8 +377,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(panic_handler, Normal, template!(Word), WarnFollowing), // RFC 2070 // Code generation: - ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing), - ungated!(cold, Normal, template!(Word), WarnFollowing), + ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, @only_local: true), + ungated!(cold, Normal, template!(Word), WarnFollowing, @only_local: true), ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing), ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk), ungated!(track_caller, Normal, template!(Word), WarnFollowing), @@ -385,7 +404,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // Linking: - gated!(naked, Normal, template!(Word), WarnFollowing, naked_functions, experimental!(naked)), + gated!(naked, Normal, template!(Word), WarnFollowing, @only_local: true, naked_functions, experimental!(naked)), gated!( link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, raw_dylib, experimental!(link_ordinal) @@ -394,6 +413,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Plugins: BuiltinAttribute { name: sym::plugin, + only_local: false, type_: CrateLevel, template: template!(List: "name"), duplicates: DuplicatesOk, @@ -475,7 +495,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // DuplicatesOk since it has its own validation ungated!( - stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk + stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, ), ungated!( unstable, Normal, @@ -546,11 +566,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // ========================================================================== gated!( - linkage, Normal, template!(NameValueStr: "external|internal|..."), ErrorPreceding, + linkage, Normal, template!(NameValueStr: "external|internal|..."), ErrorPreceding, @only_local: true, "the `linkage` attribute is experimental and not portable across platforms", ), rustc_attr!( - rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE + rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, @only_local: true, INTERNAL_UNSTABLE ), // ========================================================================== @@ -633,7 +653,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Internal attributes, Misc: // ========================================================================== gated!( - lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, lang_items, + lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, @only_local: true, lang_items, "language items are subject to change", ), rustc_attr!( @@ -642,11 +662,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." ), rustc_attr!( - rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, + rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true, "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`." ), rustc_attr!( - rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, + rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true, "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." ), rustc_attr!( @@ -656,6 +676,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), BuiltinAttribute { name: sym::rustc_diagnostic_item, + // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. + only_local: false, type_: Normal, template: template!(NameValueStr: "name"), duplicates: ErrorFollowing, @@ -676,7 +698,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "unboxed_closures are still evolving", ), rustc_attr!( - rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, + rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, @only_local: true, "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ overflow checking behavior of several libcore functions that are inlined \ across crates and will never be stable", @@ -778,6 +800,10 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() } +pub fn is_builtin_only_local(name: Symbol) -> bool { + BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local) +} + pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy<FxHashMap<Symbol, &BuiltinAttribute>> = SyncLazy::new(|| { let mut map = FxHashMap::default(); diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 940c4ecdcc2..26e0538b0eb 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -149,7 +149,8 @@ pub use accepted::ACCEPTED_FEATURES; pub use active::{Features, ACTIVE_FEATURES, INCOMPATIBLE_FEATURES}; pub use builtin_attrs::AttributeDuplicates; pub use builtin_attrs::{ - deprecated_attributes, find_gated_cfg, is_builtin_attr_name, AttributeGate, AttributeTemplate, - AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, + deprecated_attributes, find_gated_cfg, is_builtin_attr_name, is_builtin_only_local, + AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, GatedCfg, + BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, }; pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index e318090ebe1..676c66f41a9 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -4,18 +4,16 @@ //! use with [Graphviz](https://www.graphviz.org/) by walking a labeled //! graph. (Graphviz can then automatically lay out the nodes and edges //! of the graph, and also optionally render the graph as an image or -//! other [output formats]( -//! https://www.graphviz.org/content/output-formats), such as SVG.) +//! other [output formats](https://www.graphviz.org/docs/outputs), such as SVG.) //! //! Rather than impose some particular graph data structure on clients, //! this library exposes two traits that clients can implement on their //! own structs before handing them over to the rendering function. //! //! Note: This library does not yet provide access to the full -//! expressiveness of the [DOT language]( -//! https://www.graphviz.org/doc/info/lang.html). For example, there are -//! many [attributes](https://www.graphviz.org/content/attrs) related to -//! providing layout hints (e.g., left-to-right versus top-down, which +//! expressiveness of the [DOT language](https://www.graphviz.org/doc/info/lang.html). +//! For example, there are many [attributes](https://www.graphviz.org/doc/info/attrs.html) +//! related to providing layout hints (e.g., left-to-right versus top-down, which //! algorithm to use, etc). The current intention of this library is to //! emit a human-readable .dot file with very regular structure suitable //! for easy post-processing. @@ -292,7 +290,7 @@ pub enum LabelText<'a> { LabelStr(Cow<'a, str>), /// This kind of label uses the graphviz label escString type: - /// <https://www.graphviz.org/content/attrs#kescString> + /// <https://www.graphviz.org/docs/attr-types/escString> /// /// Occurrences of backslashes (`\`) are not escaped; instead they /// are interpreted as initiating an escString escape sequence. @@ -307,12 +305,12 @@ pub enum LabelText<'a> { /// printed exactly as given, but between `<` and `>`. **No /// escaping is performed.** /// - /// [html]: https://www.graphviz.org/content/node-shapes#html + /// [html]: https://www.graphviz.org/doc/info/shapes.html#html HtmlStr(Cow<'a, str>), } /// The style for a node or edge. -/// See <https://www.graphviz.org/doc/info/attrs.html#k:style> for descriptions. +/// See <https://www.graphviz.org/docs/attr-types/style/> for descriptions. /// Note that some of these are not valid for edges. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Style { @@ -439,7 +437,7 @@ pub trait Labeller<'a> { /// Maps `n` to one of the [graphviz `shape` names][1]. If `None` /// is returned, no `shape` attribute is specified. /// - /// [1]: https://www.graphviz.org/content/node-shapes + /// [1]: https://www.graphviz.org/doc/info/shapes.html fn node_shape(&'a self, _node: &Self::Node) -> Option<LabelText<'a>> { None } diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index bce9ba12ac0..5c32dd372dd 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -261,14 +261,16 @@ pub enum DefPathData { // they are treated specially by the `def_path` function. /// The crate root (marker). CrateRoot, - // Catch-all for random `DefId` things like `DUMMY_NODE_ID`. - Misc, // Different kinds of items and item-like things: /// An impl. Impl, /// An `extern` block. ForeignMod, + /// A `use` item. + Use, + /// A global asm item. + GlobalAsm, /// Something in the type namespace. TypeNs(Symbol), /// Something in the value namespace. @@ -443,9 +445,8 @@ impl DefPathData { match *self { TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), - Impl | ForeignMod | CrateRoot | Misc | ClosureExpr | Ctor | AnonConst | ImplTrait => { - None - } + Impl | ForeignMod | CrateRoot | Use | GlobalAsm | ClosureExpr | Ctor | AnonConst + | ImplTrait => None, } } @@ -459,7 +460,8 @@ impl DefPathData { CrateRoot => DefPathDataName::Anon { namespace: kw::Crate }, Impl => DefPathDataName::Anon { namespace: kw::Impl }, ForeignMod => DefPathDataName::Anon { namespace: kw::Extern }, - Misc => DefPathDataName::Anon { namespace: sym::misc }, + Use => DefPathDataName::Anon { namespace: kw::Use }, + GlobalAsm => DefPathDataName::Anon { namespace: sym::global_asm }, ClosureExpr => DefPathDataName::Anon { namespace: sym::closure }, Ctor => DefPathDataName::Anon { namespace: sym::constructor }, AnonConst => DefPathDataName::Anon { namespace: sym::constant }, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 977c0eb3cd2..1254d3a1618 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1,7 +1,40 @@ //! HIR walker for walking the contents of nodes. //! -//! **For an overview of the visitor strategy, see the docs on the -//! `super::itemlikevisit::ItemLikeVisitor` trait.** +//! Here are the three available patterns for the visitor strategy, +//! in roughly the order of desirability: +//! +//! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR. +//! - Example: find all items with a `#[foo]` attribute on them. +//! - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids +//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir().item*(id)` to filter and +//! access actual item-like thing, respectively. +//! - Pro: Efficient; just walks the lists of item ids and gives users control whether to access +//! the hir_owners themselves or not. +//! - Con: Don't get information about nesting +//! - Con: Don't have methods for specific bits of HIR, like "on +//! every expr, do this". +//! 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within +//! an item, but don't care about how item-like things are nested +//! within one another. +//! - Example: Examine each expression to look for its type and do some check or other. +//! - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to +//! `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use +//! `tcx.hir().deep_visit_all_item_likes(&mut visitor)`. Within your +//! `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke +//! `intravisit::walk_expr()` to keep walking the subparts). +//! - Pro: Visitor methods for any kind of HIR node, not just item-like things. +//! - Pro: Integrates well into dependency tracking. +//! - Con: Don't get information about nesting between items +//! 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between +//! item-like things. +//! - Example: Lifetime resolution, which wants to bring lifetimes declared on the +//! impl into scope while visiting the impl-items, and then back out again. +//! - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to +//! `nested_filter::All` (and implement `nested_visit_map`). Walk your crate with +//! `tcx.hir().walk_toplevel_module(visitor)` invoked on `tcx.hir().krate()`. +//! - Pro: Visitor methods for any kind of HIR node, not just item-like things. +//! - Pro: Preserves nesting information +//! - Con: Does not integrate well into dependency tracking. //! //! If you have decided to use this visitor, here are some general //! notes on how to do so: @@ -32,43 +65,12 @@ //! example generator inference, and possibly also HIR borrowck. use crate::hir::*; -use crate::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor}; +use crate::itemlikevisit::ParItemLikeVisitor; use rustc_ast::walk_list; use rustc_ast::{Attribute, Label}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; -pub struct DeepVisitor<'v, V> { - visitor: &'v mut V, -} - -impl<'v, V> DeepVisitor<'v, V> { - pub fn new(base: &'v mut V) -> Self { - DeepVisitor { visitor: base } - } -} - -impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V> -where - V: Visitor<'hir>, -{ - fn visit_item(&mut self, item: &'hir Item<'hir>) { - self.visitor.visit_item(item); - } - - fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>) { - self.visitor.visit_trait_item(trait_item); - } - - fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>) { - self.visitor.visit_impl_item(impl_item); - } - - fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>) { - self.visitor.visit_foreign_item(foreign_item); - } -} - pub trait IntoVisitor<'hir> { type Visitor: Visitor<'hir>; fn into_visitor(&self) -> Self::Visitor; @@ -315,16 +317,6 @@ pub trait Visitor<'v>: Sized { walk_body(self, b); } - /// When invoking `visit_all_item_likes()`, you need to supply an - /// item-like visitor. This method converts an "intra-visit" - /// visitor into an item-like visitor that walks the entire tree. - /// If you use this, you probably don't want to process the - /// contents of nested item-like things, since the outer loop will - /// visit them as well. - fn as_deep_visitor(&mut self) -> DeepVisitor<'_, Self> { - DeepVisitor::new(self) - } - /////////////////////////////////////////////////////////////////////////// fn visit_id(&mut self, _hir_id: HirId) { diff --git a/compiler/rustc_hir/src/itemlikevisit.rs b/compiler/rustc_hir/src/itemlikevisit.rs index b2c6ca1354f..a490268dc9f 100644 --- a/compiler/rustc_hir/src/itemlikevisit.rs +++ b/compiler/rustc_hir/src/itemlikevisit.rs @@ -1,55 +1,5 @@ use super::{ForeignItem, ImplItem, Item, TraitItem}; -/// The "item-like visitor" defines only the top-level methods -/// that can be invoked by `Crate::visit_all_item_likes()`. Whether -/// this trait is the right one to implement will depend on the -/// overall pattern you need. Here are the three available patterns, -/// in roughly the order of desirability: -/// -/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR. -/// - Example: find all items with a `#[foo]` attribute on them. -/// - How: Implement `ItemLikeVisitor` and call `tcx.hir().visit_all_item_likes()`. -/// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves. -/// - Con: Don't get information about nesting -/// - Con: Don't have methods for specific bits of HIR, like "on -/// every expr, do this". -/// 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within -/// an item, but don't care about how item-like things are nested -/// within one another. -/// - Example: Examine each expression to look for its type and do some check or other. -/// - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to -/// `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use -/// `tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within your -/// `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke -/// `intravisit::walk_expr()` to keep walking the subparts). -/// - Pro: Visitor methods for any kind of HIR node, not just item-like things. -/// - Pro: Integrates well into dependency tracking. -/// - Con: Don't get information about nesting between items -/// 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between -/// item-like things. -/// - Example: Lifetime resolution, which wants to bring lifetimes declared on the -/// impl into scope while visiting the impl-items, and then back out again. -/// - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to -/// `nested_filter::All` (and implement `nested_visit_map`). Walk your crate with -/// `tcx.hir().walk_toplevel_module(visitor)` invoked on `tcx.hir().krate()`. -/// - Pro: Visitor methods for any kind of HIR node, not just item-like things. -/// - Pro: Preserves nesting information -/// - Con: Does not integrate well into dependency tracking. -/// -/// Note: the methods of `ItemLikeVisitor` intentionally have no -/// defaults, so that as we expand the list of item-like things, we -/// revisit the various visitors to see if they need to change. This -/// is harder to do with `intravisit::Visitor`, so when you add a new -/// `visit_nested_foo()` method, it is recommended that you search for -/// existing `fn visit_nested` methods to see where changes are -/// needed. -pub trait ItemLikeVisitor<'hir> { - fn visit_item(&mut self, item: &'hir Item<'hir>); - fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>); - fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>); - fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>); -} - /// A parallel variant of `ItemLikeVisitor`. pub trait ParItemLikeVisitor<'hir> { fn visit_item(&self, item: &'hir Item<'hir>); diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index f69ae8ebe41..a89b9eafaa6 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -75,7 +75,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) { let mut visitor = IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] }; visitor.process_attrs(hir::CRATE_HIR_ID); - tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor()); + tcx.hir().deep_visit_all_item_likes(&mut visitor); (visitor.if_this_changed, visitor.then_this_would_need) }; diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index aaf24636598..424164d8760 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -183,10 +183,7 @@ pub struct DirtyCleanVisitor<'tcx> { impl<'tcx> DirtyCleanVisitor<'tcx> { /// Possibly "deserialize" the attribute into a clean/dirty assertion fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> { - if !attr.has_name(sym::rustc_clean) { - // skip: not rustc_clean/dirty - return None; - } + assert!(attr.has_name(sym::rustc_clean)); if !check_config(self.tcx, attr) { // skip: not the correct `cfg=` return None; @@ -384,7 +381,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { fn check_item(&mut self, item_id: LocalDefId) { let item_span = self.tcx.def_span(item_id.to_def_id()); let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id()); - for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() { + for attr in self.tcx.get_attrs(item_id.to_def_id(), sym::rustc_clean) { let Some(assertion) = self.assertion_maybe(item_id, attr) else { continue; }; diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs index ed504938e8a..347c8856022 100644 --- a/compiler/rustc_index/src/interval.rs +++ b/compiler/rustc_index/src/interval.rs @@ -70,7 +70,7 @@ impl<I: Idx> IntervalSet<I> { /// Returns true if we increased the number of elements present. pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool { let start = inclusive_start(range.clone()); - let Some(mut end) = inclusive_end(self.domain, range) else { + let Some(end) = inclusive_end(self.domain, range) else { // empty range return false; }; @@ -78,59 +78,56 @@ impl<I: Idx> IntervalSet<I> { return false; } - loop { - // This condition looks a bit weird, but actually makes sense. - // - // if r.0 == end + 1, then we're actually adjacent, so we want to - // continue to the next range. We're looking here for the first - // range which starts *non-adjacently* to our end. - let next = self.map.partition_point(|r| r.0 <= end + 1); - if let Some(last) = next.checked_sub(1) { - let (prev_start, prev_end) = &mut self.map[last]; - if *prev_end + 1 >= start { - // If the start for the inserted range is adjacent to the - // end of the previous, we can extend the previous range. - if start < *prev_start { - // Our range starts before the one we found. We'll need - // to *remove* it, and then try again. - // - // FIXME: This is not so efficient; we may need to - // recurse a bunch of times here. Instead, it's probably - // better to do something like drain_filter(...) on the - // map to be able to delete or modify all the ranges in - // start..=end and then potentially re-insert a new - // range. - end = std::cmp::max(end, *prev_end); - self.map.remove(last); - } else { - // We overlap with the previous range, increase it to - // include us. - // - // Make sure we're actually going to *increase* it though -- - // it may be that end is just inside the previously existing - // set. - return if end > *prev_end { - *prev_end = end; - true - } else { - false - }; + // This condition looks a bit weird, but actually makes sense. + // + // if r.0 == end + 1, then we're actually adjacent, so we want to + // continue to the next range. We're looking here for the first + // range which starts *non-adjacently* to our end. + let next = self.map.partition_point(|r| r.0 <= end + 1); + if let Some(right) = next.checked_sub(1) { + let (prev_start, prev_end) = self.map[right]; + if prev_end + 1 >= start { + // If the start for the inserted range is adjacent to the + // end of the previous, we can extend the previous range. + if start < prev_start { + // The first range which ends *non-adjacently* to our start. + // And we can ensure that left <= right. + let left = self.map.partition_point(|l| l.1 + 1 < start); + let min = std::cmp::min(self.map[left].0, start); + let max = std::cmp::max(prev_end, end); + self.map[right] = (min, max); + if left != right { + self.map.drain(left..right); } - } else { - // Otherwise, we don't overlap, so just insert - self.map.insert(last + 1, (start, end)); return true; - } - } else { - if self.map.is_empty() { - // Quite common in practice, and expensive to call memcpy - // with length zero. - self.map.push((start, end)); } else { - self.map.insert(next, (start, end)); + // We overlap with the previous range, increase it to + // include us. + // + // Make sure we're actually going to *increase* it though -- + // it may be that end is just inside the previously existing + // set. + return if end > prev_end { + self.map[right].1 = end; + true + } else { + false + }; } + } else { + // Otherwise, we don't overlap, so just insert + self.map.insert(right + 1, (start, end)); return true; } + } else { + if self.map.is_empty() { + // Quite common in practice, and expensive to call memcpy + // with length zero. + self.map.push((start, end)); + } else { + self.map.insert(next, (start, end)); + } + return true; } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index af81f5cde2c..02caae7a90a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -70,7 +70,7 @@ use rustc_middle::ty::{ self, error::TypeError, subst::{GenericArgKind, Subst, SubstsRef}, - Binder, List, Region, Ty, TyCtxt, TypeFoldable, + Binder, EarlyBinder, List, Region, Ty, TyCtxt, TypeFoldable, }; use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; @@ -961,12 +961,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { for (def_id, actual) in iter::zip(default_params, substs.iter().rev()) { match actual.unpack() { GenericArgKind::Const(c) => { - if self.tcx.const_param_default(def_id).subst(self.tcx, substs) != c { + if EarlyBinder(self.tcx.const_param_default(def_id)).subst(self.tcx, substs) + != c + { break; } } GenericArgKind::Type(ty) => { - if self.tcx.type_of(def_id).subst(self.tcx, substs) != ty { + if self.tcx.bound_type_of(def_id).subst(self.tcx, substs) != ty { break; } } @@ -1383,8 +1385,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { - let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); - let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); + let sig1 = self.tcx.bound_fn_sig(*did1).subst(self.tcx, substs1); + let sig2 = self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2); let mut values = self.cmp_fn_sig(&sig1, &sig2); let path1 = format!(" {{{}}}", self.tcx.def_path_str_with_substs(*did1, substs1)); let path2 = format!(" {{{}}}", self.tcx.def_path_str_with_substs(*did2, substs2)); @@ -1395,7 +1397,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } (ty::FnDef(did1, substs1), ty::FnPtr(sig2)) => { - let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); + let sig1 = self.tcx.bound_fn_sig(*did1).subst(self.tcx, substs1); let mut values = self.cmp_fn_sig(&sig1, sig2); values.0.push_highlighted(format!( " {{{}}}", @@ -1405,7 +1407,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } (ty::FnPtr(sig1), ty::FnDef(did2, substs2)) => { - let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); + let sig2 = self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2); let mut values = self.cmp_fn_sig(sig1, &sig2); values.1.push_normal(format!( " {{{}}}", @@ -1847,9 +1849,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Future::Output let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; - let bounds = self.tcx.explicit_item_bounds(*def_id); + let bounds = self.tcx.bound_explicit_item_bounds(*def_id); - for (predicate, _) in bounds { + for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) { let predicate = predicate.subst(self.tcx, substs); let output = predicate .kind() diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index d25484efabc..92c0ed84057 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -561,9 +561,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations; } - let item_bounds = tcx.explicit_item_bounds(def_id); + let item_bounds = tcx.bound_explicit_item_bounds(def_id); - for (predicate, _) in item_bounds { + for predicate in item_bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) { debug!(?predicate); let predicate = predicate.subst(tcx, substs); diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index ab565d43961..1c521c90686 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -4,7 +4,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::sso::SsoHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` /// obligation into a series of `'a: 'b` constraints and "verifys", as @@ -290,7 +290,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { debug!("projection_bounds(projection_ty={:?})", projection_ty); let tcx = self.tcx; self.region_bounds_declared_on_associated_item(projection_ty.item_def_id) - .map(move |r| r.subst(tcx, projection_ty.substs)) + .map(move |r| EarlyBinder(r).subst(tcx, projection_ty.substs)) } /// Given the `DefId` of an associated item, returns any region diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 85bb727a6c8..4df4de21a0f 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -69,7 +69,7 @@ impl<'tcx> PredicateObligation<'tcx> { } } -impl TraitObligation<'_> { +impl<'tcx> TraitObligation<'tcx> { /// Returns `true` if the trait predicate is considered `const` in its ParamEnv. pub fn is_const(&self) -> bool { match (self.predicate.skip_binder().constness, self.param_env.constness()) { @@ -77,6 +77,13 @@ impl TraitObligation<'_> { _ => false, } } + + pub fn derived_cause( + &self, + variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, + ) -> ObligationCause<'tcx> { + self.cause.clone().derived_cause(self.predicate, variant) + } } // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 22ab62ac372..136f0443fa0 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -258,10 +258,7 @@ impl<'tcx> Queries<'tcx> { /// an error. fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) { let Some((def_id, _)) = tcx.entry_fn(()) else { return }; - - let attrs = &*tcx.get_attrs(def_id); - let attrs = attrs.iter().filter(|attr| attr.has_name(sym::rustc_error)); - for attr in attrs { + for attr in tcx.get_attrs(def_id, sym::rustc_error) { match attr.meta_item_list() { // Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`. Some(list) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 694b5cfc181..585edfc47e1 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -551,7 +551,7 @@ impl MissingDoc { } } - let attrs = cx.tcx.get_attrs(def_id.to_def_id()); + let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id)); let has_doc = attrs.iter().any(has_doc); if !has_doc { cx.struct_span_lint( @@ -2736,11 +2736,7 @@ impl ClashingExternDeclarations { // bottleneck, this does just fine. ( overridden_link_name, - tcx.get_attrs(fi.def_id.to_def_id()) - .iter() - .find(|at| at.has_name(sym::link_name)) - .unwrap() - .span, + tcx.get_attr(fi.def_id.to_def_id(), sym::link_name).unwrap().span, ) }) { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index dfce30171ff..62d427fcd02 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -668,7 +668,7 @@ enum FfiResult<'tcx> { } crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: ty::AdtDef<'tcx>) -> bool { - tcx.get_attrs(def.did()).iter().any(|a| a.has_name(sym::rustc_nonnull_optimization_guaranteed)) + tcx.has_attr(def.did(), sym::rustc_nonnull_optimization_guaranteed) } /// `repr(transparent)` structs can have a single non-ZST field, this function returns that diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 494bdaa1e2b..8cae95f46dc 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -303,26 +303,25 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_pre_path: &str, descr_post_path: &str, ) -> bool { - for attr in cx.tcx.get_attrs(def_id).iter() { - if attr.has_name(sym::must_use) { - cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - let msg = format!( - "unused {}`{}`{} that must be used", - descr_pre_path, - cx.tcx.def_path_str(def_id), - descr_post_path - ); - let mut err = lint.build(&msg); - // check for #[must_use = "..."] - if let Some(note) = attr.value_str() { - err.note(note.as_str()); - } - err.emit(); - }); - return true; - } + if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) { + cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { + let msg = format!( + "unused {}`{}`{} that must be used", + descr_pre_path, + cx.tcx.def_path_str(def_id), + descr_post_path + ); + let mut err = lint.build(&msg); + // check for #[must_use = "..."] + if let Some(note) = attr.value_str() { + err.note(note.as_str()); + } + err.emit(); + }); + true + } else { + false } - false } } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 7ebb1e85cdb..f9429702783 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -790,6 +790,7 @@ declare_lint! { /// ### Example /// /// ```rust + /// #[warn(unused_macro_rules)] /// macro_rules! unused_empty { /// (hello) => { println!("Hello, world!") }; // This rule is unused /// () => { println!("empty") }; // This rule is used @@ -814,7 +815,7 @@ declare_lint! { /// /// [`macro_export` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope pub UNUSED_MACRO_RULES, - Warn, + Allow, "detects macro rules that were not used" } diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index ac758c15cca..7729ec6bef4 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -324,9 +324,10 @@ fn main() { let stdcppname = if target.contains("openbsd") { if target.contains("sparc64") { "estdc++" } else { "c++" } - } else if target.contains("freebsd") { - "c++" - } else if target.contains("darwin") { + } else if target.contains("darwin") + || target.contains("freebsd") + || target.contains("windows-gnullvm") + { "c++" } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() { // NetBSD uses a separate library when relocation is required @@ -365,7 +366,7 @@ fn main() { // Libstdc++ depends on pthread which Rust doesn't link on MinGW // since nothing else requires it. - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { println!("cargo:rustc-link-lib=static:-bundle=pthread"); } } diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index dfed9dd15a7..2d13675e615 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,7 +1,9 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(crate_visibility_modifier)] +#![feature(decl_macro)] #![feature(drain_filter)] #![feature(generators)] +#![feature(let_chains)] #![feature(let_else)] #![feature(nll)] #![feature(once_cell)] diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index f468399930d..628516fa138 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -1,4 +1,4 @@ -use rustc_ast::CRATE_NODE_ID; +use rustc_ast::{NestedMetaItem, CRATE_NODE_ID}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; @@ -9,8 +9,7 @@ use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib}; use rustc_session::parse::feature_err; use rustc_session::utils::NativeLibKind; use rustc_session::Session; -use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; +use rustc_span::symbol::{sym, Symbol}; use rustc_target::spec::abi::Abi; crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> { @@ -51,283 +50,315 @@ impl<'tcx> Collector<'tcx> { // Process all of the #[link(..)]-style arguments let sess = &self.tcx.sess; + let features = self.tcx.features(); for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| a.has_name(sym::link)) { let Some(items) = m.meta_item_list() else { continue; }; - let mut lib = NativeLib { - name: None, - kind: NativeLibKind::Unspecified, - cfg: None, - foreign_module: Some(it.def_id.to_def_id()), - wasm_import_module: None, - verbatim: None, - dll_imports: Vec::new(), - }; - let mut kind_specified = false; + let mut name = None; + let mut kind = None; + let mut modifiers = None; + let mut cfg = None; + let mut wasm_import_module = None; for item in items.iter() { - if item.has_name(sym::kind) { - kind_specified = true; - let Some(kind) = item.value_str() else { - continue; // skip like historical compilers - }; - lib.kind = match kind.as_str() { - "static" => NativeLibKind::Static { bundle: None, whole_archive: None }, - "static-nobundle" => { - sess.struct_span_warn( - item.span(), - "library kind `static-nobundle` has been superseded by specifying \ - modifier `-bundle` with library kind `static`", - ) - .emit(); - if !self.tcx.features().static_nobundle { - feature_err( - &self.tcx.sess.parse_sess, - sym::static_nobundle, - item.span(), - "kind=\"static-nobundle\" is unstable", - ) - .emit(); - } - NativeLibKind::Static { bundle: Some(false), whole_archive: None } + match item.name_or_empty() { + sym::name => { + if name.is_some() { + let msg = "multiple `name` arguments in a single `#[link]` attribute"; + sess.span_err(item.span(), msg); + continue; } - "dylib" => NativeLibKind::Dylib { as_needed: None }, - "framework" => NativeLibKind::Framework { as_needed: None }, - "raw-dylib" => NativeLibKind::RawDylib, - k => { - struct_span_err!(sess, item.span(), E0458, "unknown kind: `{}`", k) - .span_label(item.span(), "unknown kind") - .span_label(m.span, "") + let Some(link_name) = item.value_str() else { + let msg = "link name must be of the form `name = \"string\"`"; + sess.span_err(item.span(), msg); + continue; + }; + let span = item.name_value_literal_span().unwrap(); + if link_name.is_empty() { + struct_span_err!(sess, span, E0454, "link name must not be empty") + .span_label(span, "empty link name") .emit(); - NativeLibKind::Unspecified } - }; - } else if item.has_name(sym::name) { - lib.name = item.value_str(); - } else if item.has_name(sym::cfg) { - let Some(cfg) = item.meta_item_list() else { - continue; // skip like historical compilers - }; - if cfg.is_empty() { - sess.span_err(item.span(), "`cfg()` must have an argument"); - } else if let cfg @ Some(..) = cfg[0].meta_item() { - lib.cfg = cfg.cloned(); - } else { - sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`"); + name = Some((link_name, span)); } - } else if item.has_name(sym::wasm_import_module) { - match item.value_str() { - Some(s) => lib.wasm_import_module = Some(s), - None => { - let msg = "must be of the form `#[link(wasm_import_module = \"...\")]`"; + sym::kind => { + if kind.is_some() { + let msg = "multiple `kind` arguments in a single `#[link]` attribute"; sess.span_err(item.span(), msg); + continue; } - } - } else { - // currently, like past compilers, ignore unknown - // directives here. - } - } - - // Do this outside the above loop so we don't depend on modifiers coming - // after kinds - let mut modifiers_count = 0; - for item in items.iter().filter(|item| item.has_name(sym::modifiers)) { - if let Some(modifiers) = item.value_str() { - modifiers_count += 1; - let span = item.name_value_literal_span().unwrap(); - let mut has_duplicate_modifiers = false; - for modifier in modifiers.as_str().split(',') { - let (modifier, value) = match modifier.strip_prefix(&['+', '-']) { - Some(m) => (m, modifier.starts_with('+')), - None => { - // Note: this error also excludes the case with empty modifier - // string, like `modifiers = ""`. - sess.span_err( - span, - "invalid linking modifier syntax, expected '+' or '-' prefix \ - before one of: bundle, verbatim, whole-archive, as-needed", - ); - continue; - } + let Some(link_kind) = item.value_str() else { + let msg = "link kind must be of the form `kind = \"string\"`"; + sess.span_err(item.span(), msg); + continue; }; - match (modifier, &mut lib.kind) { - ("bundle", NativeLibKind::Static { bundle, .. }) => { - if bundle.is_some() { - has_duplicate_modifiers = true; - } - *bundle = Some(value); - } - ("bundle", _) => { - sess.span_err( + let span = item.name_value_literal_span().unwrap(); + let link_kind = match link_kind.as_str() { + "static" => NativeLibKind::Static { bundle: None, whole_archive: None }, + "static-nobundle" => { + sess.struct_span_warn( span, - "bundle linking modifier is only compatible with \ - `static` linking kind", - ); - } - - ("verbatim", _) => { - if lib.verbatim.is_some() { - has_duplicate_modifiers = true; + "link kind `static-nobundle` has been superseded by specifying \ + modifier `-bundle` with link kind `static`", + ) + .emit(); + if !features.static_nobundle { + feature_err( + &sess.parse_sess, + sym::static_nobundle, + span, + "link kind `static-nobundle` is unstable", + ) + .emit(); } - lib.verbatim = Some(value); + NativeLibKind::Static { bundle: Some(false), whole_archive: None } } - - ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { - if whole_archive.is_some() { - has_duplicate_modifiers = true; + "dylib" => NativeLibKind::Dylib { as_needed: None }, + "framework" => { + if !sess.target.is_like_osx { + struct_span_err!( + sess, + span, + E0455, + "link kind `framework` is only supported on Apple targets" + ) + .emit(); } - *whole_archive = Some(value); + NativeLibKind::Framework { as_needed: None } } - ("whole-archive", _) => { - sess.span_err( - span, - "whole-archive linking modifier is only compatible with \ - `static` linking kind", - ); - } - - ("as-needed", NativeLibKind::Dylib { as_needed }) - | ("as-needed", NativeLibKind::Framework { as_needed }) => { - if as_needed.is_some() { - has_duplicate_modifiers = true; + "raw-dylib" => { + if !sess.target.is_like_windows { + struct_span_err!( + sess, + span, + E0455, + "link kind `raw-dylib` is only supported on Windows targets" + ) + .emit(); + } else if !features.raw_dylib { + feature_err( + &sess.parse_sess, + sym::raw_dylib, + span, + "link kind `raw-dylib` is unstable", + ) + .emit(); } - *as_needed = Some(value); + NativeLibKind::RawDylib } - ("as-needed", _) => { - sess.span_err( - span, - "as-needed linking modifier is only compatible with \ - `dylib` and `framework` linking kinds", - ); - } - - _ => { - sess.span_err( - span, - &format!( - "unrecognized linking modifier `{}`, expected one \ - of: bundle, verbatim, whole-archive, as-needed", - modifier - ), + kind => { + let msg = format!( + "unknown link kind `{kind}`, expected one of: \ + static, dylib, framework, raw-dylib" ); + struct_span_err!(sess, span, E0458, "{}", msg) + .span_label(span, "unknown link kind") + .emit(); + continue; } + }; + kind = Some(link_kind); + } + sym::modifiers => { + if modifiers.is_some() { + let msg = + "multiple `modifiers` arguments in a single `#[link]` attribute"; + sess.span_err(item.span(), msg); + continue; + } + let Some(link_modifiers) = item.value_str() else { + let msg = "link modifiers must be of the form `modifiers = \"string\"`"; + sess.span_err(item.span(), msg); + continue; + }; + modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap())); + } + sym::cfg => { + if cfg.is_some() { + let msg = "multiple `cfg` arguments in a single `#[link]` attribute"; + sess.span_err(item.span(), msg); + continue; + } + let Some(link_cfg) = item.meta_item_list() else { + let msg = "link cfg must be of the form `cfg(/* predicate */)`"; + sess.span_err(item.span(), msg); + continue; + }; + let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else { + let msg = "link cfg must have a single predicate argument"; + sess.span_err(item.span(), msg); + continue; + }; + if !features.link_cfg { + feature_err( + &sess.parse_sess, + sym::link_cfg, + item.span(), + "link cfg is unstable", + ) + .emit(); + } + cfg = Some(link_cfg.clone()); + } + sym::wasm_import_module => { + if wasm_import_module.is_some() { + let msg = "multiple `wasm_import_module` arguments \ + in a single `#[link]` attribute"; + sess.span_err(item.span(), msg); + continue; } + let Some(link_wasm_import_module) = item.value_str() else { + let msg = "wasm import module must be of the form \ + `wasm_import_module = \"string\"`"; + sess.span_err(item.span(), msg); + continue; + }; + wasm_import_module = Some((link_wasm_import_module, item.span())); } - if has_duplicate_modifiers { - let msg = - "same modifier is used multiple times in a single `modifiers` argument"; + _ => { + let msg = "unexpected `#[link]` argument, expected one of: \ + name, kind, modifiers, cfg, wasm_import_module"; sess.span_err(item.span(), msg); } - } else { - let msg = "must be of the form `#[link(modifiers = \"...\")]`"; - sess.span_err(item.span(), msg); } } - if modifiers_count > 1 { - let msg = "multiple `modifiers` arguments in a single `#[link]` attribute"; - sess.span_err(m.span, msg); + // Do this outside the above loop so we don't depend on modifiers coming after kinds + let mut verbatim = None; + if let Some((modifiers, span)) = modifiers { + for modifier in modifiers.as_str().split(',') { + let (modifier, value) = match modifier.strip_prefix(&['+', '-']) { + Some(m) => (m, modifier.starts_with('+')), + None => { + sess.span_err( + span, + "invalid linking modifier syntax, expected '+' or '-' prefix \ + before one of: bundle, verbatim, whole-archive, as-needed", + ); + continue; + } + }; + + macro report_unstable_modifier($feature: ident) { + if !features.$feature { + feature_err( + &sess.parse_sess, + sym::$feature, + span, + &format!("linking modifier `{modifier}` is unstable"), + ) + .emit(); + } + } + let assign_modifier = |dst: &mut Option<bool>| { + if dst.is_some() { + let msg = format!( + "multiple `{modifier}` modifiers in a single `modifiers` argument" + ); + sess.span_err(span, &msg); + } else { + *dst = Some(value); + } + }; + match (modifier, &mut kind) { + ("bundle", Some(NativeLibKind::Static { bundle, .. })) => { + report_unstable_modifier!(native_link_modifiers_bundle); + assign_modifier(bundle) + } + ("bundle", _) => { + sess.span_err( + span, + "linking modifier `bundle` is only compatible with \ + `static` linking kind", + ); + } + + ("verbatim", _) => { + report_unstable_modifier!(native_link_modifiers_verbatim); + assign_modifier(&mut verbatim) + } + + ("whole-archive", Some(NativeLibKind::Static { whole_archive, .. })) => { + assign_modifier(whole_archive) + } + ("whole-archive", _) => { + sess.span_err( + span, + "linking modifier `whole-archive` is only compatible with \ + `static` linking kind", + ); + } + + ("as-needed", Some(NativeLibKind::Dylib { as_needed })) + | ("as-needed", Some(NativeLibKind::Framework { as_needed })) => { + report_unstable_modifier!(native_link_modifiers_as_needed); + assign_modifier(as_needed) + } + ("as-needed", _) => { + sess.span_err( + span, + "linking modifier `as-needed` is only compatible with \ + `dylib` and `framework` linking kinds", + ); + } + + _ => { + sess.span_err( + span, + format!( + "unknown linking modifier `{modifier}`, expected one of: \ + bundle, verbatim, whole-archive, as-needed" + ), + ); + } + } + } } - // In general we require #[link(name = "...")] but we allow - // #[link(wasm_import_module = "...")] without the `name`. - let requires_name = kind_specified || lib.wasm_import_module.is_none(); - if lib.name.is_none() && requires_name { + if let Some((_, span)) = wasm_import_module { + if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() { + let msg = "`wasm_import_module` is incompatible with \ + other arguments in `#[link]` attributes"; + sess.span_err(span, msg); + } + } else if name.is_none() { struct_span_err!( sess, m.span, E0459, - "`#[link(...)]` specified without \ - `name = \"foo\"`" + "`#[link]` attribute requires a `name = \"string\"` argument" ) .span_label(m.span, "missing `name` argument") .emit(); } - if lib.kind == NativeLibKind::RawDylib { - lib.dll_imports.extend( + let dll_imports = match kind { + Some(NativeLibKind::RawDylib) => { + if let Some((name, span)) = name && name.as_str().contains('\0') { + sess.span_err( + span, + "link name must not contain NUL characters if link kind is `raw-dylib`", + ); + } foreign_mod_items .iter() - .map(|child_item| self.build_dll_import(abi, child_item)), - ); - } - - self.register_native_lib(Some(m.span), lib); - } - } - - fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) { - if lib.name.as_ref().map_or(false, |&s| s == kw::Empty) { - match span { - Some(span) => { - struct_span_err!( - self.tcx.sess, - span, - E0454, - "`#[link(name = \"\")]` given with empty name" - ) - .span_label(span, "empty name given") - .emit(); - } - None => { - self.tcx.sess.err("empty library name given via `-l`"); - } - } - return; - } - let is_osx = self.tcx.sess.target.is_like_osx; - if matches!(lib.kind, NativeLibKind::Framework { .. }) && !is_osx { - let msg = "native frameworks are only available on macOS targets"; - match span { - Some(span) => { - struct_span_err!(self.tcx.sess, span, E0455, "{}", msg).emit(); - } - None => { - self.tcx.sess.err(msg); + .map(|child_item| self.build_dll_import(abi, child_item)) + .collect() } - } - } - if lib.cfg.is_some() && !self.tcx.features().link_cfg { - feature_err( - &self.tcx.sess.parse_sess, - sym::link_cfg, - span.unwrap(), - "kind=\"link_cfg\" is unstable", - ) - .emit(); - } - // this just unwraps lib.name; we already established that it isn't empty above. - if let (NativeLibKind::RawDylib, Some(lib_name)) = (lib.kind, lib.name) { - let Some(span) = span else { - bug!("raw-dylib libraries are not supported on the command line"); + _ => Vec::new(), }; - - if !self.tcx.sess.target.options.is_like_windows { - self.tcx.sess.span_fatal( - span, - "`#[link(...)]` with `kind = \"raw-dylib\"` only supported on Windows", - ); - } - - if lib_name.as_str().contains('\0') { - self.tcx.sess.span_err(span, "library name may not contain NUL characters"); - } - - if !self.tcx.features().raw_dylib { - feature_err( - &self.tcx.sess.parse_sess, - sym::raw_dylib, - span, - "kind=\"raw-dylib\" is unstable", - ) - .emit(); - } + self.libs.push(NativeLib { + name: name.map(|(name, _)| name), + kind: kind.unwrap_or(NativeLibKind::Unspecified), + cfg, + foreign_module: Some(it.def_id.to_def_id()), + wasm_import_module: wasm_import_module.map(|(name, _)| name), + verbatim, + dll_imports, + }); } - - self.libs.push(lib); } // Process libs passed on the command line @@ -335,6 +366,10 @@ impl<'tcx> Collector<'tcx> { // First, check for errors let mut renames = FxHashSet::default(); for lib in &self.tcx.sess.opts.libs { + if let NativeLibKind::Framework { .. } = lib.kind && !self.tcx.sess.target.is_like_osx { + // Cannot check this when parsing options because the target is not yet available. + self.tcx.sess.err("library kind `framework` is only supported on Apple targets"); + } if let Some(ref new_name) = lib.new_name { let any_duplicate = self .libs @@ -342,19 +377,19 @@ impl<'tcx> Collector<'tcx> { .filter_map(|lib| lib.name.as_ref()) .any(|n| n.as_str() == lib.name); if new_name.is_empty() { - self.tcx.sess.err(&format!( + self.tcx.sess.err(format!( "an empty renaming target was specified for library `{}`", lib.name )); } else if !any_duplicate { - self.tcx.sess.err(&format!( + self.tcx.sess.err(format!( "renaming of the library `{}` was specified, \ however this crate contains no `#[link(...)]` \ attributes referencing this library", lib.name )); } else if !renames.insert(&lib.name) { - self.tcx.sess.err(&format!( + self.tcx.sess.err(format!( "multiple renamings were \ specified for library `{}`", lib.name @@ -404,7 +439,7 @@ impl<'tcx> Collector<'tcx> { if existing.is_empty() { // Add if not found let new_name: Option<&str> = passed_lib.new_name.as_deref(); - let lib = NativeLib { + self.libs.push(NativeLib { name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))), kind: passed_lib.kind, cfg: None, @@ -412,8 +447,7 @@ impl<'tcx> Collector<'tcx> { wasm_import_module: None, verbatim: passed_lib.verbatim, dll_imports: Vec::new(), - }; - self.register_native_lib(None, lib); + }); } else { // Move all existing libraries with the same name to the // end of the command line. diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 367a8b02261..39e6ddb316d 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -14,7 +14,6 @@ use rustc_hir::def_id::{ }; use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items; use rustc_hir::{AnonConst, GenericParamKind}; use rustc_index::bit_set::GrowableBitSet; @@ -453,7 +452,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { return; } - self.tcx.hir().visit_all_item_likes(&mut self.as_deep_visitor()); + self.tcx.hir().deep_visit_all_item_likes(self); } fn encode_def_path_table(&mut self) { @@ -985,11 +984,17 @@ fn should_encode_generics(def_kind: DefKind) -> bool { } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - fn encode_attrs(&mut self, def_id: DefId) { - let attrs = self.tcx.get_attrs(def_id); - record!(self.tables.attributes[def_id] <- attrs); - if attrs.iter().any(|attr| attr.may_have_doc_links()) { - self.tables.may_have_doc_links.set(def_id.index, ()); + fn encode_attrs(&mut self, def_id: LocalDefId) { + let mut attrs = self + .tcx + .hir() + .attrs(self.tcx.hir().local_def_id_to_hir_id(def_id)) + .iter() + .filter(|attr| !rustc_feature::is_builtin_only_local(attr.name_or_empty())); + + record!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone()); + if attrs.any(|attr| attr.may_have_doc_links()) { + self.tables.may_have_doc_links.set(def_id.local_def_index, ()); } } @@ -1005,7 +1010,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let Some(def_kind) = def_kind else { continue }; self.tables.opt_def_kind.set(def_id.index, def_kind); record!(self.tables.def_span[def_id] <- tcx.def_span(def_id)); - self.encode_attrs(def_id); + self.encode_attrs(local_id); record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id)); if def_kind.has_codegen_attrs() { record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id)); @@ -1676,7 +1681,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod); record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id())); - self.encode_attrs(LOCAL_CRATE.as_def_id()); + self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local()); record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id())); if let Some(stability) = stability { record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability); @@ -1717,7 +1722,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def_id = id.to_def_id(); self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind)); record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind)); - self.encode_attrs(def_id); + self.encode_attrs(id); record!(self.tables.def_keys[def_id] <- def_key); record!(self.tables.def_ident_span[def_id] <- span); record!(self.tables.def_span[def_id] <- span); @@ -2246,26 +2251,16 @@ pub fn provide(providers: &mut Providers) { traits_in_crate: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - #[derive(Default)] - struct TraitsVisitor { - traits: Vec<DefId>, - } - impl ItemLikeVisitor<'_> for TraitsVisitor { - fn visit_item(&mut self, item: &hir::Item<'_>) { - if let hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) = item.kind { - self.traits.push(item.def_id.to_def_id()); - } + let mut traits = Vec::new(); + for id in tcx.hir().items() { + if matches!(tcx.def_kind(id.def_id), DefKind::Trait | DefKind::TraitAlias) { + traits.push(id.def_id.to_def_id()) } - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} - fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} } - let mut visitor = TraitsVisitor::default(); - tcx.hir().visit_all_item_likes(&mut visitor); // Bring everything into deterministic order. - visitor.traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); - tcx.arena.alloc_slice(&visitor.traits) + traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); + tcx.arena.alloc_slice(&traits) }, ..*providers diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 20c8b0bb70f..9976b0e9862 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -9,7 +9,6 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::*; use rustc_index::vec::Idx; use rustc_middle::hir::nested_filter; @@ -161,6 +160,10 @@ impl<'hir> Map<'hir> { self.tcx.hir_crate_items(()).items.iter().copied() } + pub fn module_items(self, module: LocalDefId) -> impl Iterator<Item = ItemId> + 'hir { + self.tcx.hir_module_items(module).items() + } + pub fn par_for_each_item(self, f: impl Fn(ItemId) + Sync + Send) { par_for_each_in(&self.tcx.hir_crate_items(()).items[..], |id| f(*id)); } @@ -603,16 +606,16 @@ impl<'hir> Map<'hir> { } /// Visits all items in the crate in some deterministic (but - /// unspecified) order. If you just need to process every item, - /// but don't care about nesting, this method is the best choice. + /// unspecified) order. If you need to process every item, + /// and care about nesting -- usually because your algorithm + /// follows lexical scoping rules -- then this method is the best choice. + /// If you don't care about nesting, you should use the `tcx.hir_crate_items()` query + /// or `items()` instead. /// - /// If you do care about nesting -- usually because your algorithm - /// follows lexical scoping rules -- then you want a different - /// approach. You should override `visit_nested_item` in your - /// visitor and then call `intravisit::walk_crate` instead. - pub fn visit_all_item_likes<V>(self, visitor: &mut V) + /// Please see the notes in `intravisit.rs` for more information. + pub fn deep_visit_all_item_likes<V>(self, visitor: &mut V) where - V: itemlikevisit::ItemLikeVisitor<'hir>, + V: Visitor<'hir>, { let krate = self.krate(); for owner in krate.owners.iter().filter_map(|i| i.as_owner()) { @@ -643,9 +646,12 @@ impl<'hir> Map<'hir> { }) } - pub fn visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V) + /// If you don't care about nesting, you should use the + /// `tcx.hir_module_items()` query or `module_items()` instead. + /// Please see notes in `deep_visit_all_item_likes`. + pub fn deep_visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V) where - V: ItemLikeVisitor<'hir>, + V: Visitor<'hir>, { let module = self.tcx.hir_module_items(module); @@ -666,7 +672,7 @@ impl<'hir> Map<'hir> { } } - pub fn for_each_module(self, f: impl Fn(LocalDefId)) { + pub fn for_each_module(self, mut f: impl FnMut(LocalDefId)) { let crate_items = self.tcx.hir_crate_items(()); for module in crate_items.submodules.iter() { f(*module) diff --git a/compiler/rustc_middle/src/hir/nested_filter.rs b/compiler/rustc_middle/src/hir/nested_filter.rs index 48efae8045b..d56e87bbb47 100644 --- a/compiler/rustc_middle/src/hir/nested_filter.rs +++ b/compiler/rustc_middle/src/hir/nested_filter.rs @@ -8,7 +8,7 @@ use rustc_hir::intravisit::nested_filter::NestedFilter; /// constant arguments of types, e.g. in `let _: [(); /* HERE */];`. /// /// **This is the most common choice.** A very common pattern is -/// to use `visit_all_item_likes()` as an outer loop, +/// to use `deep_visit_all_item_likes()` as an outer loop, /// and to have the visitor that visits the contents of each item /// using this setting. pub struct OnlyBodies(()); diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index c71aea417ec..26da93b9dce 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -120,9 +120,11 @@ pub trait Provenance: Copy + fmt::Debug { where Self: Sized; - /// Provenance must always be able to identify the allocation this ptr points to. + /// If `OFFSET_IS_ADDR == false`, provenance must always be able to + /// identify the allocation this ptr points to (i.e., this must return `Some`). + /// Otherwise this function is best-effort (but must agree with `Machine::ptr_get_alloc`). /// (Identifying the offset in that allocation, however, is harder -- use `Memory::ptr_get_alloc` for that.) - fn get_alloc_id(self) -> AllocId; + fn get_alloc_id(self) -> Option<AllocId>; } impl Provenance for AllocId { @@ -147,8 +149,8 @@ impl Provenance for AllocId { Ok(()) } - fn get_alloc_id(self) -> AllocId { - self + fn get_alloc_id(self) -> Option<AllocId> { + Some(self) } } diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 9cffdf2993e..eeee170f43f 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -344,7 +344,8 @@ impl<'tcx, Tag: Provenance> Scalar<Tag> { } else { // We know `offset` is relative, since `OFFSET_IS_ADDR == false`. let (tag, offset) = ptr.into_parts(); - Err(Scalar::Ptr(Pointer::new(tag.get_alloc_id(), offset), sz)) + // Because `OFFSET_IS_ADDR == false`, this unwrap can never fail. + Err(Scalar::Ptr(Pointer::new(tag.get_alloc_id().unwrap(), offset), sz)) } } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 20ab3536222..af18adac2ff 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2393,7 +2393,7 @@ impl<'tcx> Operand<'tcx> { substs: SubstsRef<'tcx>, span: Span, ) -> Self { - let ty = tcx.type_of(def_id).subst(tcx, substs); + let ty = tcx.bound_type_of(def_id).subst(tcx, substs); Operand::Constant(Box::new(Constant { span, user_ty: None, diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index f1d5201454d..c93b7a95502 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -202,7 +202,9 @@ impl<'tcx> Rvalue<'tcx> { Rvalue::Aggregate(ref ak, ref ops) => match **ak { AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64), AggregateKind::Tuple => tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx))), - AggregateKind::Adt(did, _, substs, _, _) => tcx.type_of(did).subst(tcx, substs), + AggregateKind::Adt(did, _, substs, _, _) => { + tcx.bound_type_of(did).subst(tcx, substs) + } AggregateKind::Closure(did, substs) => tcx.mk_closure(did, substs), AggregateKind::Generator(did, substs, movability) => { tcx.mk_generator(did, substs, movability) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 8458d690847..f133494caaa 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1072,6 +1072,9 @@ rustc_queries! { desc { |tcx| "checking whether `{}` is `doc(hidden)`", tcx.def_path_str(def_id) } } + /// Returns the attributes on the item at `def_id`. + /// + /// Do not use this directly, use `tcx.get_attrs` instead. query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] { desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) } separate_provide_extern diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 8c660e38a7f..26374939085 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -97,9 +97,7 @@ pub struct ObligationCause<'tcx> { /// information. pub body_id: hir::HirId, - /// `None` for `MISC_OBLIGATION_CAUSE_CODE` (a common case, occurs ~60% of - /// the time). `Some` otherwise. - code: Option<Lrc<ObligationCauseCode<'tcx>>>, + code: InternedObligationCauseCode<'tcx>, } // This custom hash function speeds up hashing for `Obligation` deduplication @@ -123,11 +121,7 @@ impl<'tcx> ObligationCause<'tcx> { body_id: hir::HirId, code: ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx> { - ObligationCause { - span, - body_id, - code: if code == MISC_OBLIGATION_CAUSE_CODE { None } else { Some(Lrc::new(code)) }, - } + ObligationCause { span, body_id, code: code.into() } } pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> { @@ -136,15 +130,12 @@ impl<'tcx> ObligationCause<'tcx> { #[inline(always)] pub fn dummy() -> ObligationCause<'tcx> { - ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: None } + ObligationCause::dummy_with_span(DUMMY_SP) } + #[inline(always)] pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> { - ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: None } - } - - pub fn make_mut_code(&mut self) -> &mut ObligationCauseCode<'tcx> { - Lrc::make_mut(self.code.get_or_insert_with(|| Lrc::new(MISC_OBLIGATION_CAUSE_CODE))) + ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: Default::default() } } pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span { @@ -164,14 +155,37 @@ impl<'tcx> ObligationCause<'tcx> { #[inline] pub fn code(&self) -> &ObligationCauseCode<'tcx> { - self.code.as_deref().unwrap_or(&MISC_OBLIGATION_CAUSE_CODE) + &self.code } - pub fn clone_code(&self) -> Lrc<ObligationCauseCode<'tcx>> { - match &self.code { - Some(code) => code.clone(), - None => Lrc::new(MISC_OBLIGATION_CAUSE_CODE), - } + pub fn map_code( + &mut self, + f: impl FnOnce(InternedObligationCauseCode<'tcx>) -> ObligationCauseCode<'tcx>, + ) { + self.code = f(std::mem::take(&mut self.code)).into(); + } + + pub fn derived_cause( + mut self, + parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, + ) -> ObligationCause<'tcx> { + /*! + * Creates a cause for obligations that are derived from + * `obligation` by a recursive search (e.g., for a builtin + * bound, or eventually a `auto trait Foo`). If `obligation` + * is itself a derived obligation, this is just a clone, but + * otherwise we create a "derived obligation" cause so as to + * keep track of the original root obligation for error + * reporting. + */ + + // NOTE(flaper87): As of now, it keeps track of the whole error + // chain. Ideally, we should have a way to configure this either + // by using -Z verbose or just a CLI argument. + self.code = + variant(DerivedObligationCause { parent_trait_pred, parent_code: self.code }).into(); + self } } @@ -182,6 +196,30 @@ pub struct UnifyReceiverContext<'tcx> { pub substs: SubstsRef<'tcx>, } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, Default)] +pub struct InternedObligationCauseCode<'tcx> { + /// `None` for `MISC_OBLIGATION_CAUSE_CODE` (a common case, occurs ~60% of + /// the time). `Some` otherwise. + code: Option<Lrc<ObligationCauseCode<'tcx>>>, +} + +impl<'tcx> ObligationCauseCode<'tcx> { + #[inline(always)] + fn into(self) -> InternedObligationCauseCode<'tcx> { + InternedObligationCauseCode { + code: if let MISC_OBLIGATION_CAUSE_CODE = self { None } else { Some(Lrc::new(self)) }, + } + } +} + +impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> { + type Target = ObligationCauseCode<'tcx>; + + fn deref(&self) -> &Self::Target { + self.code.as_deref().unwrap_or(&MISC_OBLIGATION_CAUSE_CODE) + } +} + #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from the span. @@ -269,7 +307,7 @@ pub enum ObligationCauseCode<'tcx> { /// The node of the function call. call_hir_id: hir::HirId, /// The obligation introduced by this argument. - parent_code: Lrc<ObligationCauseCode<'tcx>>, + parent_code: InternedObligationCauseCode<'tcx>, }, /// Error derived when matching traits/impls; see ObligationCause for more details @@ -404,25 +442,27 @@ pub struct ImplDerivedObligationCause<'tcx> { pub span: Span, } -impl ObligationCauseCode<'_> { +impl<'tcx> ObligationCauseCode<'tcx> { // Return the base obligation, ignoring derived obligations. pub fn peel_derives(&self) -> &Self { let mut base_cause = self; - loop { - match base_cause { - BuiltinDerivedObligation(DerivedObligationCause { parent_code, .. }) - | DerivedObligation(DerivedObligationCause { parent_code, .. }) - | FunctionArgumentObligation { parent_code, .. } => { - base_cause = &parent_code; - } - ImplDerivedObligation(obligation_cause) => { - base_cause = &*obligation_cause.derived.parent_code; - } - _ => break, - } + while let Some((parent_code, _)) = base_cause.parent() { + base_cause = parent_code; } base_cause } + + pub fn parent(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> { + match self { + FunctionArgumentObligation { parent_code, .. } => Some((parent_code, None)), + BuiltinDerivedObligation(derived) + | DerivedObligation(derived) + | ImplDerivedObligation(box ImplDerivedObligationCause { derived, .. }) => { + Some((&derived.parent_code, Some(derived.parent_trait_pred))) + } + _ => None, + } + } } // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -472,7 +512,7 @@ pub struct DerivedObligationCause<'tcx> { pub parent_trait_pred: ty::PolyTraitPredicate<'tcx>, /// The parent trait had this cause. - pub parent_code: Lrc<ObligationCauseCode<'tcx>>, + pub parent_code: InternedObligationCauseCode<'tcx>, } #[derive(Clone, Debug, TypeFoldable, Lift)] diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 2e4c16e39eb..bf7cb610a90 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -230,8 +230,7 @@ impl AdtDefData { flags |= AdtFlags::HAS_CTOR; } - let attrs = tcx.get_attrs(did); - if tcx.sess.contains_name(&attrs, sym::fundamental) { + if tcx.has_attr(did, sym::fundamental) { flags |= AdtFlags::IS_FUNDAMENTAL; } if Some(did) == tcx.lang_items().phantom_data() { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9d3d509eb21..1616b753433 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1148,9 +1148,8 @@ impl<'tcx> TyCtxt<'tcx> { /// `rustc_layout_scalar_valid_range` attribute. // FIXME(eddyb) this is an awkward spot for this method, maybe move it? pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) { - let attrs = self.get_attrs(def_id); let get = |name| { - let Some(attr) = attrs.iter().find(|a| a.has_name(name)) else { + let Some(attr) = self.get_attr(def_id, name) else { return Bound::Unbounded; }; debug!("layout_scalar_valid_range: attr={:?}", attr); @@ -1604,7 +1603,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn caller_location_ty(self) -> Ty<'tcx> { self.mk_imm_ref( self.lifetimes.re_static, - self.type_of(self.require_lang_item(LangItem::PanicLocation, None)) + self.bound_type_of(self.require_lang_item(LangItem::PanicLocation, None)) .subst(self, self.mk_substs([self.lifetimes.re_static.into()].iter())), ) } @@ -2333,7 +2332,7 @@ impl<'tcx> TyCtxt<'tcx> { ty_param.into() } else { assert!(has_default); - self.type_of(param.def_id).subst(self, substs).into() + self.bound_type_of(param.def_id).subst(self, substs).into() } } }); diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index da0934b67c5..a0fe632f11a 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -568,11 +568,8 @@ impl<T> Trait<T> for X { } } TargetFeatureCast(def_id) => { - let attrs = self.get_attrs(*def_id); - let target_spans = attrs - .iter() - .filter(|attr| attr.has_name(sym::target_feature)) - .map(|attr| attr.span); + let target_spans = + self.get_attrs(*def_id, sym::target_feature).map(|attr| attr.span); diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" ); diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 0bd96f8f865..d9b82ee0a76 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -1,6 +1,7 @@ use crate::middle::resolve_lifetime::ObjectLifetimeDefault; use crate::ty; use crate::ty::subst::{Subst, SubstsRef}; +use crate::ty::EarlyBinder; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; @@ -229,7 +230,11 @@ impl<'tcx> GenericPredicates<'tcx> { substs: SubstsRef<'tcx>, ) -> InstantiatedPredicates<'tcx> { InstantiatedPredicates { - predicates: self.predicates.iter().map(|(p, _)| p.subst(tcx, substs)).collect(), + predicates: self + .predicates + .iter() + .map(|(p, _)| EarlyBinder(*p).subst(tcx, substs)) + .collect(), spans: self.predicates.iter().map(|(_, sp)| *sp).collect(), } } @@ -243,7 +248,9 @@ impl<'tcx> GenericPredicates<'tcx> { if let Some(def_id) = self.parent { tcx.predicates_of(def_id).instantiate_into(tcx, instantiated, substs); } - instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p.subst(tcx, substs))); + instantiated + .predicates + .extend(self.predicates.iter().map(|(p, _)| EarlyBinder(*p).subst(tcx, substs))); instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp)); } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 7cf7f897347..f088db00d02 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -1,13 +1,14 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeFoldable}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; use rustc_macros::HashStable; use rustc_middle::ty::normalize_erasing_regions::NormalizationError; +use rustc_span::Symbol; use std::fmt; @@ -185,8 +186,8 @@ impl<'tcx> InstanceDef<'tcx> { } #[inline] - pub fn attrs(&self, tcx: TyCtxt<'tcx>) -> ty::Attributes<'tcx> { - tcx.get_attrs(self.def_id()) + pub fn get_attrs(&self, tcx: TyCtxt<'tcx>, attr: Symbol) -> ty::Attributes<'tcx> { + tcx.get_attrs(self.def_id(), attr) } /// Returns `true` if the LLVM version of this instance is unconditionally @@ -557,7 +558,11 @@ impl<'tcx> Instance<'tcx> { where T: TypeFoldable<'tcx> + Copy, { - if let Some(substs) = self.substs_for_mir_body() { v.subst(tcx, substs) } else { *v } + if let Some(substs) = self.substs_for_mir_body() { + EarlyBinder(*v).subst(tcx, substs) + } else { + *v + } } #[inline(always)] diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c8055100d30..d187146476a 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2,7 +2,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir::{GeneratorLayout, GeneratorSavedLocal}; use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::subst::Subst; -use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeFoldable}; use rustc_ast as ast; use rustc_attr as attr; use rustc_hir as hir; @@ -1706,7 +1706,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { ) -> Result<Layout<'tcx>, LayoutError<'tcx>> { use SavedLocalEligibility::*; let tcx = self.tcx; - let subst_field = |ty: Ty<'tcx>| ty.subst(tcx, substs); + let subst_field = |ty: Ty<'tcx>| EarlyBinder(ty).subst(tcx, substs); let Some(info) = tcx.generator_layout(def_id) else { return Err(LayoutError::Unknown(ty)); @@ -2750,7 +2750,7 @@ impl<'tcx> ty::Instance<'tcx> { // track of a polymorphization `ParamEnv` to allow normalizing later. let mut sig = match *ty.kind() { ty::FnDef(def_id, substs) => tcx - .normalize_erasing_regions(tcx.param_env(def_id), tcx.fn_sig(def_id)) + .normalize_erasing_regions(tcx.param_env(def_id), tcx.bound_fn_sig(def_id)) .subst(tcx, substs), _ => unreachable!(), }; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d847068b5bf..91eea01bfb9 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -14,12 +14,6 @@ pub use self::AssocItemContainer::*; pub use self::BorrowKind::*; pub use self::IntVarValue::*; pub use self::Variance::*; -pub use adt::*; -pub use assoc::*; -pub use generics::*; -use rustc_data_structures::fingerprint::Fingerprint; -pub use vtable::*; - use crate::metadata::ModChild; use crate::middle::privacy::AccessLevels; use crate::mir::{Body, GeneratorLayout}; @@ -28,8 +22,12 @@ use crate::ty; use crate::ty::fast_reject::SimplifiedType; use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::util::Discr; +pub use adt::*; +pub use assoc::*; +pub use generics::*; use rustc_ast as ast; use rustc_attr as attr; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::intern::{Interned, WithStableHash}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -44,6 +42,7 @@ use rustc_session::cstore::CrateStoreDyn; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use rustc_target::abi::Align; +pub use vtable::*; use std::fmt::Debug; use std::hash::Hash; @@ -78,7 +77,7 @@ pub use self::sty::RegionKind::*; pub use self::sty::TyKind::*; pub use self::sty::{ Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind, - CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion, + CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBinder, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, @@ -736,7 +735,7 @@ impl<'tcx> Predicate<'tcx> { let shifted_pred = tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder()); // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1> - let new = shifted_pred.subst(tcx, trait_ref.skip_binder().substs); + let new = EarlyBinder(shifted_pred).subst(tcx, trait_ref.skip_binder().substs); // 3) ['x] + ['b] -> ['x, 'b] let bound_vars = tcx.mk_bound_variable_kinds(trait_bound_vars.iter().chain(pred_bound_vars)); @@ -1818,8 +1817,8 @@ impl ReprOptions { field_shuffle_seed ^= user_seed; } - for attr in tcx.get_attrs(did).iter() { - for r in attr::find_repr_attrs(&tcx.sess, attr) { + for attr in tcx.get_attrs(did, sym::repr) { + for r in attr::parse_repr_attr(&tcx.sess, attr) { flags.insert(match r { attr::ReprC => ReprFlags::IS_C, attr::ReprPacked(pack) => { @@ -1932,7 +1931,7 @@ impl<'tcx> FieldDef { /// Returns the type of this field. The resulting type is not normalized. The `subst` is /// typically obtained via the second field of [`TyKind::Adt`]. pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> { - tcx.type_of(self.did).subst(tcx, subst) + tcx.bound_type_of(self.did).subst(tcx, subst) } /// Computes the `Ident` of this variant by looking up the `Span` @@ -1941,8 +1940,7 @@ impl<'tcx> FieldDef { } } -pub type Attributes<'tcx> = &'tcx [ast::Attribute]; - +pub type Attributes<'tcx> = impl Iterator<Item = &'tcx ast::Attribute>; #[derive(Debug, PartialEq, Eq)] pub enum ImplOverlapKind { /// These impls are always allowed to overlap. @@ -1996,7 +1994,8 @@ impl<'tcx> TyCtxt<'tcx> { .filter(|item| item.kind == AssocKind::Fn && item.defaultness.has_value()) } - fn opt_item_name(self, def_id: DefId) -> Option<Symbol> { + /// Look up the name of a definition across crates. This does not look at HIR. + pub fn opt_item_name(self, def_id: DefId) -> Option<Symbol> { if let Some(cnum) = def_id.as_crate_root() { Some(self.crate_name(cnum)) } else { @@ -2016,16 +2015,11 @@ impl<'tcx> TyCtxt<'tcx> { /// Look up the name of a definition across crates. This does not look at HIR. /// - /// When possible, this function should be used for cross-crate lookups over - /// [`opt_item_name`] to avoid invalidating the incremental cache. If you - /// need to handle items without a name, or HIR items that will not be - /// serialized cross-crate, or if you need the span of the item, use + /// This method will ICE if the corresponding item does not have a name. In these cases, use /// [`opt_item_name`] instead. /// /// [`opt_item_name`]: Self::opt_item_name pub fn item_name(self, id: DefId) -> Symbol { - // Look at cross-crate items first to avoid invalidating the incremental cache - // unless we have to. self.opt_item_name(id).unwrap_or_else(|| { bug!("item_name: no name for {:?}", self.def_path(id)); }) @@ -2186,8 +2180,8 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Gets the attributes of a definition. - pub fn get_attrs(self, did: DefId) -> Attributes<'tcx> { + // FIXME(@lcnr): Remove this function. + pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [ast::Attribute] { if let Some(did) = did.as_local() { self.hir().attrs(self.hir().local_def_id_to_hir_id(did)) } else { @@ -2195,9 +2189,29 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Gets all attributes with the given name. + pub fn get_attrs(self, did: DefId, attr: Symbol) -> ty::Attributes<'tcx> { + let filter_fn = move |a: &&ast::Attribute| a.has_name(attr); + if let Some(did) = did.as_local() { + self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn) + } else if cfg!(debug_assertions) && rustc_feature::is_builtin_only_local(attr) { + bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr); + } else { + self.item_attrs(did).iter().filter(filter_fn) + } + } + + pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> { + self.get_attrs(did, attr).next() + } + /// Determines whether an item is annotated with an attribute. pub fn has_attr(self, did: DefId, attr: Symbol) -> bool { - self.sess.contains_name(&self.get_attrs(did), attr) + if cfg!(debug_assertions) && !did.is_local() && rustc_feature::is_builtin_only_local(attr) { + bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr); + } else { + self.get_attrs(did, attr).next().is_some() + } } /// Returns `true` if this is an `auto trait`. diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 808be446b2a..9bbbd7e2f7c 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -11,7 +11,7 @@ use crate::mir; use crate::traits::query::NoSolution; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder}; use crate::ty::subst::{Subst, SubstsRef}; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, EarlyBinder, Ty, TyCtxt}; #[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)] pub enum NormalizationError<'tcx> { @@ -133,7 +133,7 @@ impl<'tcx> TyCtxt<'tcx> { param_env={:?})", param_substs, value, param_env, ); - let substituted = value.subst(self, param_substs); + let substituted = EarlyBinder(value).subst(self, param_substs); self.normalize_erasing_regions(param_env, substituted) } @@ -157,7 +157,7 @@ impl<'tcx> TyCtxt<'tcx> { param_env={:?})", param_substs, value, param_env, ); - let substituted = value.subst(self, param_substs); + let substituted = EarlyBinder(value).subst(self, param_substs); self.try_normalize_erasing_regions(param_env, substituted) } } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index a1d1b6b3a78..9d8124eb25d 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -115,12 +115,16 @@ pub trait Printer<'tcx>: Sized { DefPathData::Impl => { let generics = self.tcx().generics_of(def_id); - let mut self_ty = self.tcx().type_of(def_id); - let mut impl_trait_ref = self.tcx().impl_trait_ref(def_id); - if substs.len() >= generics.count() { - self_ty = self_ty.subst(self.tcx(), substs); - impl_trait_ref = impl_trait_ref.subst(self.tcx(), substs); - } + let self_ty = self.tcx().bound_type_of(def_id); + let impl_trait_ref = self.tcx().bound_impl_trait_ref(def_id); + let (self_ty, impl_trait_ref) = if substs.len() >= generics.count() { + ( + self_ty.subst(self.tcx(), substs), + impl_trait_ref.map(|i| i.subst(self.tcx(), substs)), + ) + } else { + (self_ty.0, impl_trait_ref.map(|i| i.0)) + }; self.print_impl_path(def_id, substs, self_ty, impl_trait_ref) } @@ -203,7 +207,7 @@ pub trait Printer<'tcx>: Sized { has_default && substs[param.index as usize] == GenericArg::from( - self.tcx().type_of(param.def_id).subst(self.tcx(), substs), + self.tcx().bound_type_of(param.def_id).subst(self.tcx(), substs), ) } ty::GenericParamDefKind::Const { has_default } => { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index eed90337c0a..4c0bc2e4337 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -587,7 +587,7 @@ pub trait PrettyPrinter<'tcx>: p!(")") } ty::FnDef(def_id, substs) => { - let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs); + let sig = self.tcx().bound_fn_sig(def_id).subst(self.tcx(), substs); p!(print(sig), " {{", print_value_path(def_id, substs), "}}"); } ty::FnPtr(ref bare_fn) => p!(print(bare_fn)), @@ -774,13 +774,13 @@ pub trait PrettyPrinter<'tcx>: // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let bounds = self.tcx().explicit_item_bounds(def_id); + let bounds = self.tcx().bound_explicit_item_bounds(def_id); let mut traits = BTreeMap::new(); let mut fn_traits = BTreeMap::new(); let mut is_sized = false; - for (predicate, _) in bounds { + for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) { let predicate = predicate.subst(self.tcx(), substs); let bound_predicate = predicate.kind(); diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 4c1160e21fe..8677405eebe 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -159,7 +159,8 @@ pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>( let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| { let variance = variances[i]; let variance_info = if variance == ty::Invariant { - let ty = *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst)); + let ty = + *cached_ty.get_or_insert_with(|| tcx.bound_type_of(ty_def_id).subst(tcx, a_subst)); ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } } else { ty::VarianceDiagInfo::default() diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 4ef6ff1835f..2c8cd4f933d 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -860,6 +860,27 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { } } +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::EarlyBinder<T> { + fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + self.try_map_bound(|ty| ty.try_fold_with(folder)) + } + + fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { + self.try_map_bound(|ty| ty.try_fold_with(folder)) + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + self.as_ref().0.visit_with(visitor) + } + + fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + self.as_ref().0.visit_with(visitor) + } +} + impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> { fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>( self, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 7969e7aa151..a973a5c9b50 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -713,7 +713,9 @@ impl<'tcx> GeneratorSubsts<'tcx> { ) -> impl Iterator<Item = impl Iterator<Item = Ty<'tcx>> + Captures<'tcx>> { let layout = tcx.generator_layout(def_id).unwrap(); layout.variant_fields.iter().map(move |variant| { - variant.iter().map(move |field| layout.field_tys[*field].subst(tcx, self.substs)) + variant + .iter() + .map(move |field| EarlyBinder(layout.field_tys[*field]).subst(tcx, self.substs)) }) } @@ -1068,6 +1070,69 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { } } +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Encodable, Decodable, HashStable)] +pub struct EarlyBinder<T>(pub T); + +impl<T> EarlyBinder<T> { + pub fn as_ref(&self) -> EarlyBinder<&T> { + EarlyBinder(&self.0) + } + + pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<U> + where + F: FnOnce(&T) -> U, + { + self.as_ref().map_bound(f) + } + + pub fn map_bound<F, U>(self, f: F) -> EarlyBinder<U> + where + F: FnOnce(T) -> U, + { + let value = f(self.0); + EarlyBinder(value) + } + + pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<U>, E> + where + F: FnOnce(T) -> Result<U, E>, + { + let value = f(self.0)?; + Ok(EarlyBinder(value)) + } +} + +impl<T> EarlyBinder<Option<T>> { + pub fn transpose(self) -> Option<EarlyBinder<T>> { + self.0.map(|v| EarlyBinder(v)) + } +} + +impl<T, U> EarlyBinder<(T, U)> { + pub fn transpose_tuple2(self) -> (EarlyBinder<T>, EarlyBinder<U>) { + (EarlyBinder(self.0.0), EarlyBinder(self.0.1)) + } +} + +pub struct EarlyBinderIter<T> { + t: T, +} + +impl<T: IntoIterator> EarlyBinder<T> { + pub fn transpose_iter(self) -> EarlyBinderIter<T::IntoIter> { + EarlyBinderIter { t: self.0.into_iter() } + } +} + +impl<T: Iterator> Iterator for EarlyBinderIter<T> { + type Item = EarlyBinder<T::Item>; + + fn next(&mut self) -> Option<Self::Item> { + self.t.next().map(|i| EarlyBinder(i)) + } +} + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable)] pub enum BoundVariableKind { @@ -2139,7 +2204,7 @@ impl<'tcx> Ty<'tcx> { pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { match self.kind() { - FnDef(def_id, substs) => tcx.fn_sig(*def_id).subst(tcx, substs), + FnDef(def_id, substs) => tcx.bound_fn_sig(*def_id).subst(tcx, substs), FnPtr(f) => *f, Error(_) => { // ignore errors (#54954) @@ -2306,7 +2371,7 @@ impl<'tcx> Ty<'tcx> { ty::Str | ty::Slice(_) => (tcx.types.usize, false), ty::Dynamic(..) => { let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap(); - (tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()]), false) + (tcx.bound_type_of(dyn_metadata).subst(tcx, &[tail.into()]), false) }, // type parameters only have unit metadata if they're sized, so return true diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 5b1fb708729..48c71113d50 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -4,7 +4,7 @@ use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts}; -use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; +use crate::ty::{self, EarlyBinder, Lift, List, ParamConst, Ty, TyCtxt}; use rustc_data_structures::intern::{Interned, WithStableHash}; use rustc_hir::def_id::DefId; @@ -499,14 +499,19 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> { } // Just call `foo.subst(tcx, substs)` to perform a substitution across `foo`. +#[rustc_on_unimplemented(message = "Calling `subst` must now be done through an `EarlyBinder`")] pub trait Subst<'tcx>: Sized { - fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self; + type Inner; + + fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner; } -impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T { - fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T { +impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for EarlyBinder<T> { + type Inner = T; + + fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner { let mut folder = SubstFolder { tcx, substs, binders_passed: 0 }; - self.fold_with(&mut folder) + self.0.fold_with(&mut folder) } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 94f6f300442..3fa5a140090 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -6,7 +6,8 @@ use crate::ty::layout::IntegerExt; use crate::ty::query::TyCtxtAt; use crate::ty::subst::{GenericArgKind, Subst, SubstsRef}; use crate::ty::{ - self, Const, DebruijnIndex, DefIdTree, List, ReEarlyBound, Ty, TyCtxt, TyKind::*, TypeFoldable, + self, Const, DebruijnIndex, DefIdTree, EarlyBinder, List, ReEarlyBound, Ty, TyCtxt, TyKind::*, + TypeFoldable, }; use rustc_apfloat::Float as _; use rustc_ast as ast; @@ -592,6 +593,32 @@ impl<'tcx> TyCtxt<'tcx> { trace!(?expanded_type); if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } + + pub fn bound_type_of(self, def_id: DefId) -> EarlyBinder<Ty<'tcx>> { + EarlyBinder(self.type_of(def_id)) + } + + pub fn bound_fn_sig(self, def_id: DefId) -> EarlyBinder<ty::PolyFnSig<'tcx>> { + EarlyBinder(self.fn_sig(def_id)) + } + + pub fn bound_impl_trait_ref(self, def_id: DefId) -> Option<EarlyBinder<ty::TraitRef<'tcx>>> { + self.impl_trait_ref(def_id).map(|i| EarlyBinder(i)) + } + + pub fn bound_explicit_item_bounds( + self, + def_id: DefId, + ) -> EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> { + EarlyBinder(self.explicit_item_bounds(def_id)) + } + + pub fn bound_item_bounds( + self, + def_id: DefId, + ) -> EarlyBinder<&'tcx ty::List<ty::Predicate<'tcx>>> { + EarlyBinder(self.item_bounds(def_id)) + } } struct OpaqueTypeExpander<'tcx> { @@ -623,7 +650,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) { Some(expanded_ty) => *expanded_ty, None => { - let generic_ty = self.tcx.type_of(def_id); + let generic_ty = self.tcx.bound_type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx, substs); let expanded_ty = self.fold_ty(concrete_ty); self.expanded_cache.insert((def_id, substs), expanded_ty); @@ -1164,9 +1191,8 @@ pub fn normalize_opaque_types<'tcx>( /// Determines whether an item is annotated with `doc(hidden)`. pub fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - tcx.get_attrs(def_id) - .iter() - .filter_map(|attr| if attr.has_name(sym::doc) { attr.meta_item_list() } else { None }) + tcx.get_attrs(def_id, sym::doc) + .filter_map(|attr| attr.meta_item_list()) .any(|items| items.iter().any(|item| item.has_name(sym::hidden))) } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 0e9e9869376..d7993ce1cf4 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -834,7 +834,7 @@ fn trait_method<'tcx>( .find(|item| item.kind == ty::AssocKind::Fn) .expect("trait method not found"); - let method_ty = tcx.type_of(item.def_id); + let method_ty = tcx.bound_type_of(item.def_id); let method_ty = method_ty.subst(tcx, substs); ConstantKind::zero_sized(method_ty) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index ce57e5fe846..a9c8943ec18 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -177,7 +177,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ let ty = if fn_sig.c_variadic && index == fn_sig.inputs().len() { let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(arg.span)); - tcx.type_of(va_list_did).subst(tcx, &[tcx.lifetimes.re_erased.into()]) + tcx.bound_type_of(va_list_did).subst(tcx, &[tcx.lifetimes.re_erased.into()]) } else { fn_sig.inputs()[index] }; @@ -679,7 +679,6 @@ where } else { None }; - debug!("fn_id {:?} has attrs {:?}", fn_def, tcx.get_attrs(fn_def.did.to_def_id())); let mut body = builder.finish(); body.spread_arg = spread_arg; diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 88ed0128a1f..50efb4c1dc4 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -333,14 +333,11 @@ struct RustcMirAttrs { impl RustcMirAttrs { fn parse(tcx: TyCtxt<'_>, def_id: DefId) -> Result<Self, ()> { - let attrs = tcx.get_attrs(def_id); - let mut result = Ok(()); let mut ret = RustcMirAttrs::default(); - let rustc_mir_attrs = attrs - .iter() - .filter(|attr| attr.has_name(sym::rustc_mir)) + let rustc_mir_attrs = tcx + .get_attrs(def_id, sym::rustc_mir) .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter())); for attr in rustc_mir_attrs { diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index d0837bcf754..c1124a533bf 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -14,9 +14,9 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; -use rustc_ast::{self as ast, MetaItem}; -use rustc_middle::ty; -use rustc_session::Session; +use rustc_ast::MetaItem; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; pub use self::drop_flag_effects::{ @@ -49,19 +49,13 @@ pub struct MoveDataParamEnv<'tcx> { pub param_env: ty::ParamEnv<'tcx>, } -pub fn has_rustc_mir_with( - _sess: &Session, - attrs: &[ast::Attribute], - name: Symbol, -) -> Option<MetaItem> { - for attr in attrs { - if attr.has_name(sym::rustc_mir) { - let items = attr.meta_item_list(); - for item in items.iter().flat_map(|l| l.iter()) { - match item.meta_item() { - Some(mi) if mi.has_name(name) => return Some(mi.clone()), - _ => continue, - } +pub fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option<MetaItem> { + for attr in tcx.get_attrs(def_id, sym::rustc_mir) { + let items = attr.meta_item_list(); + for item in items.iter().flat_map(|l| l.iter()) { + match item.meta_item() { + Some(mi) if mi.has_name(name) => return Some(mi.clone()), + _ => continue, } } } diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index d38e679491a..2f884887ad9 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -1,4 +1,3 @@ -use rustc_ast::ast; use rustc_span::symbol::sym; use rustc_span::Span; @@ -30,43 +29,41 @@ impl<'tcx> MirPass<'tcx> for SanityCheck { debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); } - let attributes = tcx.get_attrs(def_id); let param_env = tcx.param_env(def_id); let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap(); let mdpe = MoveDataParamEnv { move_data, param_env }; - let sess = &tcx.sess; - if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_init).is_some() { + if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() { let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe) .into_engine(tcx, body) .iterate_to_fixpoint(); - sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_inits); + sanity_check_via_rustc_peek(tcx, body, &flow_inits); } - if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_uninit).is_some() { + if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() { let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe) .into_engine(tcx, body) .iterate_to_fixpoint(); - sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_uninits); + sanity_check_via_rustc_peek(tcx, body, &flow_uninits); } - if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_definite_init).is_some() { + if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() { let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe) .into_engine(tcx, body) .iterate_to_fixpoint(); - sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_def_inits); + sanity_check_via_rustc_peek(tcx, body, &flow_def_inits); } - if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() { + if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() { let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint(); - sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_liveness); + sanity_check_via_rustc_peek(tcx, body, &flow_liveness); } - if has_rustc_mir_with(sess, &attributes, sym::stop_after_dataflow).is_some() { + if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() { tcx.sess.fatal("stop_after_dataflow ended compilation"); } } @@ -91,7 +88,6 @@ impl<'tcx> MirPass<'tcx> for SanityCheck { pub fn sanity_check_via_rustc_peek<'tcx, A>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - _attributes: &[ast::Attribute], results: &Results<'tcx, A>, ) where A: RustcPeekAt<'tcx>, diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index f7535d338da..54c3cc46b26 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -18,7 +18,9 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ + self, ConstKind, EarlyBinder, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable, +}; use rustc_span::{def_id::DefId, Span}; use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; use rustc_target::spec::abi::Abi; @@ -28,7 +30,8 @@ use crate::MirPass; use rustc_const_eval::interpret::{ self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame, ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy, - Operand as InterpOperand, PlaceTy, Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind, + Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup, + StackPopUnwind, }; /// The maximum number of bytes that we'll allocate space for a local or the return value. @@ -286,6 +289,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> } #[inline(always)] + fn expose_ptr( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ptr: Pointer<AllocId>, + ) -> InterpResult<'tcx> { + throw_machine_stop_str!("exposing pointers isn't supported in ConstProp") + } + + #[inline(always)] fn init_frame_extra( _ecx: &mut InterpCx<'mir, 'tcx, Self>, frame: Frame<'mir, 'tcx>, @@ -374,7 +385,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ); let ret = ecx - .layout_of(body.return_ty().subst(tcx, substs)) + .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs)) .ok() // Don't bother allocating memory for ZST types which have no values // or for large values. diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index aa898cfd3ba..6c0df98bc27 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -18,7 +18,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{ - self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable, + self, ConstInt, ConstKind, EarlyBinder, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable, }; use rustc_session::lint; use rustc_span::{def_id::DefId, Span}; @@ -30,8 +30,8 @@ use crate::MirLint; use rustc_const_eval::const_eval::ConstEvalErr; use rustc_const_eval::interpret::{ self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult, - LocalState, LocalValue, MemPlace, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Scalar, - ScalarMaybeUninit, StackPopCleanup, StackPopUnwind, + LocalState, LocalValue, MemPlace, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, + Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind, }; /// The maximum number of bytes that we'll allocate space for a local or the return value. @@ -281,6 +281,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> } #[inline(always)] + fn expose_ptr( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ptr: Pointer<AllocId>, + ) -> InterpResult<'tcx> { + throw_machine_stop_str!("exposing pointers isn't supported in ConstProp") + } + + #[inline(always)] fn init_frame_extra( _ecx: &mut InterpCx<'mir, 'tcx, Self>, frame: Frame<'mir, 'tcx>, @@ -370,7 +378,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ); let ret = ecx - .layout_of(body.return_ty().subst(tcx, substs)) + .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs)) .ok() // Don't bother allocating memory for ZST types which have no values // or for large values. diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 2ed14b91778..1f9bd90d11f 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -6,7 +6,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{ self, subst::{GenericArgKind, Subst, SubstsRef}, - PredicateKind, Ty, TyCtxt, + EarlyBinder, PredicateKind, Ty, TyCtxt, }; use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES; use rustc_span::{symbol::sym, Span}; @@ -90,7 +90,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { // If the inner type matches the type bound by `Pointer` if inner_ty == bound_ty { // Do a substitution using the parameters from the callsite - let subst_ty = inner_ty.subst(self.tcx, substs_ref); + let subst_ty = EarlyBinder(inner_ty).subst(self.tcx, substs_ref); if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(subst_ty) { diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index d5d4bfa255b..b7dec57b757 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -247,7 +247,7 @@ impl<'tcx> TransformVisitor<'tcx> { assert_eq!(self.state_adt_ref.variant(idx).fields.len(), 1); let ty = self .tcx - .type_of(self.state_adt_ref.variant(idx).fields[0].did) + .bound_type_of(self.state_adt_ref.variant(idx).fields[0].did) .subst(self.tcx, self.state_substs); expand_aggregate( Place::return_place(), diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 441b6207717..5f8e6608ab5 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -260,7 +260,7 @@ impl<'tcx> Inliner<'tcx> { return None; } - let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs); + let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs); return Some(CallSite { callee, diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index ea1ec6249bc..bee6aeebcf8 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -1,5 +1,4 @@ -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sso::SsoHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir::TerminatorKind; @@ -45,7 +44,10 @@ crate fn mir_callgraph_reachable<'tcx>( ) -> bool { trace!(%caller); for &(callee, substs) in tcx.mir_inliner_callees(caller.def) { - let substs = caller.subst_mir_and_normalize_erasing_regions(tcx, param_env, substs); + let Ok(substs) = caller.try_subst_mir_and_normalize_erasing_regions(tcx, param_env, substs) else { + trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping"); + continue; + }; let Some(callee) = ty::Instance::resolve(tcx, param_env, callee, substs).unwrap() else { trace!(?callee, "cannot resolve, skipping"); continue; @@ -150,7 +152,7 @@ crate fn mir_inliner_callees<'tcx>( // Functions from other crates and MIR shims _ => tcx.instance_mir(instance), }; - let mut calls = SsoHashSet::new(); + let mut calls = FxIndexSet::default(); for bb_data in body.basic_blocks() { let terminator = bb_data.terminator(); if let TerminatorKind::Call { func, .. } = &terminator.kind { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 40cc6dafe61..d08382700a8 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -170,7 +170,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> { intravisit::walk_struct_def(self, v) } } - tcx.hir().visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor()); + tcx.hir().deep_visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }); set } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index d10cac2ac76..016b3bc0980 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -4,7 +4,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; use rustc_index::vec::{Idx, IndexVec}; @@ -70,7 +70,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // of this function. Is this intentional? if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(Ty::kind) { let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap(); - let body = body.clone().subst(tcx, substs); + let body = EarlyBinder(body.clone()).subst(tcx, substs); debug!("make_shim({:?}) = {:?}", instance, body); return body; } @@ -151,7 +151,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) } else { InternalSubsts::identity_for_item(tcx, def_id) }; - let sig = tcx.fn_sig(def_id).subst(tcx, substs); + let sig = tcx.bound_fn_sig(def_id).subst(tcx, substs); let sig = tcx.erase_late_bound_regions(sig); let span = tcx.def_span(def_id); @@ -343,7 +343,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { // otherwise going to be TySelf and we can't index // or access fields of a Place of type TySelf. let substs = tcx.mk_substs_trait(self_ty, &[]); - let sig = tcx.fn_sig(def_id).subst(tcx, substs); + let sig = tcx.bound_fn_sig(def_id).subst(tcx, substs); let sig = tcx.erase_late_bound_regions(sig); let span = tcx.def_span(def_id); @@ -541,7 +541,7 @@ fn build_call_shim<'tcx>( assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body()); if let Some(sig_substs) = sig_substs { - sig = sig.subst(tcx, sig_substs); + sig = EarlyBinder(sig).subst(tcx, sig_substs); } if let CallKind::Indirect(fnty) = call_kind { diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index cf13c856a71..3cfd935d8b0 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -197,7 +197,7 @@ fn emit_unused_generic_params_error<'tcx>( unused_parameters: &FiniteBitSet<u32>, ) { let base_def_id = tcx.typeck_root_def_id(def_id); - if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) { + if !tcx.has_attr(base_def_id, sym::rustc_polymorphize_error) { return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8d207e4e1a9..ab3319a1186 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -23,6 +23,7 @@ use rustc_session::lint::builtin::{ use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use rustc_target::spec::abi::Abi; use std::collections::hash_map::Entry; pub(crate) fn target_from_impl_item<'tcx>( @@ -1317,22 +1318,27 @@ impl CheckAttrVisitor<'_> { /// Checks if `#[link]` is applied to an item other than a foreign module. fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { - match target { - Target::ForeignMod => {} - _ => { - self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { - let mut diag = lint.build("attribute should be applied to an `extern` block"); - diag.warn( - "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", - ); + if target == Target::ForeignMod + && let hir::Node::Item(item) = self.tcx.hir().get(hir_id) + && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item + && !matches!(abi, Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic) + { + return; + } - diag.span_label(span, "not an `extern` block"); - diag.emit(); - }); + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + let mut diag = + lint.build("attribute should be applied to an `extern` block with non-Rust ABI"); + diag.warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ); + if target != Target::ForeignMod { + diag.span_label(span, "not an `extern` block"); } - } + diag.emit(); + }); } /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. @@ -2384,7 +2390,7 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { let check_attr_visitor = &mut CheckAttrVisitor { tcx }; - tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor()); + tcx.hir().deep_visit_item_likes_in_module(module_def_id, check_attr_visitor); if module_def_id.is_top_level_module() { check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None); check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs()); diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 9e352fa5cc6..04d6e9f205a 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -57,89 +57,71 @@ impl NonConstExpr { fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { let mut vis = CheckConstVisitor::new(tcx); - tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor()); - tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckConstTraitVisitor::new(tcx)); + tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut vis); } pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_const_bodies, ..*providers }; } -struct CheckConstTraitVisitor<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> CheckConstTraitVisitor<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> Self { - CheckConstTraitVisitor { tcx } - } -} - -impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> { - /// check for const trait impls, and errors if the impl uses provided/default functions - /// of the trait being implemented; as those provided functions can be non-const. - fn visit_item<'hir>(&mut self, item: &'hir hir::Item<'hir>) { - let _: Option<_> = try { - if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness { - let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?; - let ancestors = self - .tcx - .trait_def(trait_def_id) - .ancestors(self.tcx, item.def_id.to_def_id()) - .ok()?; - let mut to_implement = Vec::new(); - - for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order() +fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { + let _: Option<_> = try { + if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness { + let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?; + let ancestors = tcx + .trait_def(trait_def_id) + .ancestors(tcx, item.def_id.to_def_id()) + .ok()?; + let mut to_implement = Vec::new(); + + for trait_item in tcx.associated_items(trait_def_id).in_definition_order() + { + if let ty::AssocItem { + kind: ty::AssocKind::Fn, + defaultness, + def_id: trait_item_id, + .. + } = *trait_item + { + // we can ignore functions that do not have default bodies: + // if those are unimplemented it will be caught by typeck. + if !defaultness.has_value() + || tcx + .has_attr(trait_item_id, sym::default_method_body_is_const) { - if let ty::AssocItem { - kind: ty::AssocKind::Fn, - defaultness, - def_id: trait_item_id, - .. - } = *trait_item - { - // we can ignore functions that do not have default bodies: - // if those are unimplemented it will be caught by typeck. - if !defaultness.has_value() - || self - .tcx - .has_attr(trait_item_id, sym::default_method_body_is_const) - { - continue; - } - - let is_implemented = ancestors - .leaf_def(self.tcx, trait_item_id) - .map(|node_item| !node_item.defining_node.is_from_trait()) - .unwrap_or(false); - - if !is_implemented { - to_implement.push(self.tcx.item_name(trait_item_id).to_string()); - } - } + continue; } - // all nonconst trait functions (not marked with #[default_method_body_is_const]) - // must be implemented - if !to_implement.is_empty() { - self.tcx - .sess - .struct_span_err( - item.span, - "const trait implementations may not use non-const default functions", - ) - .note(&format!("`{}` not implemented", to_implement.join("`, `"))) - .emit(); + let is_implemented = ancestors + .leaf_def(tcx, trait_item_id) + .map(|node_item| !node_item.defining_node.is_from_trait()) + .unwrap_or(false); + + if !is_implemented { + to_implement.push(trait_item_id); } + } } - }; - } - - fn visit_trait_item<'hir>(&mut self, _: &'hir hir::TraitItem<'hir>) {} - - fn visit_impl_item<'hir>(&mut self, _: &'hir hir::ImplItem<'hir>) {} - fn visit_foreign_item<'hir>(&mut self, _: &'hir hir::ForeignItem<'hir>) {} + // all nonconst trait functions (not marked with #[default_method_body_is_const]) + // must be implemented + if !to_implement.is_empty() { + let not_implemented = to_implement + .into_iter() + .map(|did| tcx.item_name(did).to_string()) + .collect::<Vec<_>>() + .join("`, `"); + tcx + .sess + .struct_span_err( + item.span, + "const trait implementations may not use non-const default functions", + ) + .note(&format!("`{}` not implemented", not_implemented)) + .emit(); + } + } + }; } #[derive(Copy, Clone)] @@ -170,7 +152,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { // If `def_id` is `None`, we don't need to consider stability attributes. let def_id = match def_id { - Some(x) => x.to_def_id(), + Some(x) => x, None => return true, }; @@ -182,14 +164,16 @@ impl<'tcx> CheckConstVisitor<'tcx> { // If this crate is not using stability attributes, or this function is not claiming to be a // stable `const fn`, that is all that is required. - if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { + if !tcx.features().staged_api + || tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable) + { return true; } // However, we cannot allow stable `const fn`s to use unstable features without an explicit // opt-in via `rustc_allow_const_fn_unstable`. - attr::rustc_allow_const_fn_unstable(&tcx.sess, &tcx.get_attrs(def_id)) - .any(|name| name == feature_gate) + let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id)); + attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate) }; match required_gates { @@ -268,6 +252,11 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.tcx.hir() } + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + intravisit::walk_item(self, item); + check_item(self.tcx, item); + } + fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) { let kind = Some(hir::ConstContext::Const); self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon)); diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index df28ea4d444..e78d9a59982 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -8,7 +8,6 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -468,7 +467,7 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow } -// This visitor seeds items that +// These check_* functions seeds items that // 1) We want to explicitly consider as live: // * Item annotated with #[allow(dead_code)] // - This is done so that if we want to suppress warnings for a @@ -481,82 +480,95 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { // or // 2) We are not sure to be live or not // * Implementations of traits and trait methods -struct LifeSeeder<'tcx> { - worklist: Vec<LocalDefId>, +fn check_item<'tcx>( tcx: TyCtxt<'tcx>, - // see `MarkSymbolVisitor::struct_constructors` - struct_constructors: FxHashMap<LocalDefId, LocalDefId>, -} - -impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> { - fn visit_item(&mut self, item: &hir::Item<'_>) { - let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx, item.hir_id()); - if allow_dead_code { - self.worklist.push(item.def_id); - } - match item.kind { - hir::ItemKind::Enum(ref enum_def, _) => { - let hir = self.tcx.hir(); + worklist: &mut Vec<LocalDefId>, + struct_constructors: &mut FxHashMap<LocalDefId, LocalDefId>, + id: hir::ItemId, +) { + let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id()); + if allow_dead_code { + worklist.push(id.def_id); + } + + match tcx.def_kind(id.def_id) { + DefKind::Enum => { + let item = tcx.hir().item(id); + if let hir::ItemKind::Enum(ref enum_def, _) = item.kind { + let hir = tcx.hir(); if allow_dead_code { - self.worklist.extend( + worklist.extend( enum_def.variants.iter().map(|variant| hir.local_def_id(variant.id)), ); } for variant in enum_def.variants { if let Some(ctor_hir_id) = variant.data.ctor_hir_id() { - self.struct_constructors + struct_constructors .insert(hir.local_def_id(ctor_hir_id), hir.local_def_id(variant.id)); } } } - hir::ItemKind::Impl(hir::Impl { ref of_trait, items, .. }) => { - if of_trait.is_some() { - self.worklist.push(item.def_id); - } - for impl_item_ref in *items { - let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); - if of_trait.is_some() - || has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id()) - { - self.worklist.push(impl_item_ref.id.def_id); - } + } + DefKind::Impl => { + let of_trait = tcx.impl_trait_ref(id.def_id); + + if of_trait.is_some() { + worklist.push(id.def_id); + } + + // get DefIds from another query + let local_def_ids = tcx + .associated_item_def_ids(id.def_id) + .iter() + .filter_map(|def_id| def_id.as_local()); + + // And we access the Map here to get HirId from LocalDefId + for id in local_def_ids { + if of_trait.is_some() + || has_allow_dead_code_or_lang_attr(tcx, tcx.hir().local_def_id_to_hir_id(id)) + { + worklist.push(id); } } - hir::ItemKind::Struct(ref variant_data, _) => { + } + DefKind::Struct => { + let item = tcx.hir().item(id); + if let hir::ItemKind::Struct(ref variant_data, _) = item.kind { if let Some(ctor_hir_id) = variant_data.ctor_hir_id() { - self.struct_constructors - .insert(self.tcx.hir().local_def_id(ctor_hir_id), item.def_id); + struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id); } } - hir::ItemKind::GlobalAsm(_) => { - // global_asm! is always live. - self.worklist.push(item.def_id); - } - _ => (), } + DefKind::GlobalAsm => { + // global_asm! is always live. + worklist.push(id.def_id); + } + _ => {} } +} - fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) { - use hir::TraitItemKind::{Const, Fn}; +fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, worklist: &mut Vec<LocalDefId>, id: hir::TraitItemId) { + use hir::TraitItemKind::{Const, Fn}; + if matches!(tcx.def_kind(id.def_id), DefKind::AssocConst | DefKind::AssocFn) { + let trait_item = tcx.hir().trait_item(id); if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_))) - && has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id()) + && has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id()) { - self.worklist.push(trait_item.def_id); + worklist.push(trait_item.def_id); } } +} - fn visit_impl_item(&mut self, _item: &hir::ImplItem<'_>) { - // ignore: we are handling this in `visit_item` above - } - - fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) { - use hir::ForeignItemKind::{Fn, Static}; - if matches!(foreign_item.kind, Static(..) | Fn(..)) - && has_allow_dead_code_or_lang_attr(self.tcx, foreign_item.hir_id()) - { - self.worklist.push(foreign_item.def_id); - } +fn check_foreign_item<'tcx>( + tcx: TyCtxt<'tcx>, + worklist: &mut Vec<LocalDefId>, + id: hir::ForeignItemId, +) { + if matches!(tcx.def_kind(id.def_id), DefKind::Static(_) | DefKind::Fn) + && has_allow_dead_code_or_lang_attr(tcx, id.hir_id()) + { + worklist.push(id.def_id); } } @@ -564,7 +576,9 @@ fn create_and_seed_worklist<'tcx>( tcx: TyCtxt<'tcx>, ) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) { let access_levels = &tcx.privacy_access_levels(()); - let worklist = access_levels + // see `MarkSymbolVisitor::struct_constructors` + let mut struct_constructors = Default::default(); + let mut worklist = access_levels .map .iter() .filter_map( @@ -576,11 +590,20 @@ fn create_and_seed_worklist<'tcx>( .chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local())) .collect::<Vec<_>>(); - // Seed implemented trait items - let mut life_seeder = LifeSeeder { worklist, tcx, struct_constructors: Default::default() }; - tcx.hir().visit_all_item_likes(&mut life_seeder); + let crate_items = tcx.hir_crate_items(()); + for id in crate_items.items() { + check_item(tcx, &mut worklist, &mut struct_constructors, id); + } + + for id in crate_items.trait_items() { + check_trait_item(tcx, &mut worklist, id); + } + + for id in crate_items.foreign_items() { + check_foreign_item(tcx, &mut worklist, id); + } - (life_seeder.worklist, life_seeder.struct_constructors) + (worklist, struct_constructors) } fn live_symbols_and_ignored_derived_traits<'tcx>( diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index f89092c57a3..8305830bc98 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -5,8 +5,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::resolve_path; use rustc_hir as hir; use rustc_hir::def_id::CrateNum; -use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::{HirId, Target}; +use rustc_hir::HirId; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LOCAL_CRATE; @@ -14,96 +13,66 @@ use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType}; use std::sync::Arc; -struct DebuggerVisualizerCollector<'tcx> { - debugger_visualizers: FxHashSet<DebuggerVisualizerFile>, +fn check_for_debugger_visualizer<'tcx>( tcx: TyCtxt<'tcx>, -} - -impl<'v, 'tcx> ItemLikeVisitor<'v> for DebuggerVisualizerCollector<'tcx> { - fn visit_item(&mut self, item: &hir::Item<'_>) { - let target = Target::from_item(item); - match target { - Target::Mod => { - self.check_for_debugger_visualizer(item.hir_id()); - } - _ => {} - } - } - - fn visit_trait_item(&mut self, _: &hir::TraitItem<'_>) {} - - fn visit_impl_item(&mut self, _: &hir::ImplItem<'_>) {} - - fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {} -} - -impl<'tcx> DebuggerVisualizerCollector<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> DebuggerVisualizerCollector<'tcx> { - DebuggerVisualizerCollector { tcx, debugger_visualizers: FxHashSet::default() } - } - - fn check_for_debugger_visualizer(&mut self, hir_id: HirId) { - let attrs = self.tcx.hir().attrs(hir_id); - for attr in attrs { - if attr.has_name(sym::debugger_visualizer) { - let list = match attr.meta_item_list() { - Some(list) => list, + hir_id: HirId, + debugger_visualizers: &mut FxHashSet<DebuggerVisualizerFile>, +) { + let attrs = tcx.hir().attrs(hir_id); + for attr in attrs { + if attr.has_name(sym::debugger_visualizer) { + let list = match attr.meta_item_list() { + Some(list) => list, + _ => continue, + }; + + let meta_item = match list.len() { + 1 => match list[0].meta_item() { + Some(meta_item) => meta_item, _ => continue, - }; - - let meta_item = match list.len() { - 1 => match list[0].meta_item() { - Some(meta_item) => meta_item, - _ => continue, - }, - _ => continue, - }; - - let file = match (meta_item.name_or_empty(), meta_item.value_str()) { - (sym::natvis_file, Some(value)) => { - match resolve_path(&self.tcx.sess.parse_sess, value.as_str(), attr.span) { - Ok(file) => file, - Err(mut err) => { - err.emit(); - continue; - } + }, + _ => continue, + }; + + let file = match (meta_item.name_or_empty(), meta_item.value_str()) { + (sym::natvis_file, Some(value)) => { + match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) { + Ok(file) => file, + Err(mut err) => { + err.emit(); + continue; } } - (_, _) => continue, + } + (_, _) => continue, + }; + + if file.is_file() { + let contents = match std::fs::read(&file) { + Ok(contents) => contents, + Err(err) => { + tcx.sess + .struct_span_err( + attr.span, + &format!( + "Unable to read contents of file `{}`. {}", + file.display(), + err + ), + ) + .emit(); + continue; + } }; - if file.is_file() { - let contents = match std::fs::read(&file) { - Ok(contents) => contents, - Err(err) => { - self.tcx - .sess - .struct_span_err( - attr.span, - &format!( - "Unable to read contents of file `{}`. {}", - file.display(), - err - ), - ) - .emit(); - continue; - } - }; - - self.debugger_visualizers.insert(DebuggerVisualizerFile::new( - Arc::from(contents), - DebuggerVisualizerType::Natvis, - )); - } else { - self.tcx - .sess - .struct_span_err( - attr.span, - &format!("{} is not a valid file", file.display()), - ) - .emit(); - } + debugger_visualizers.insert(DebuggerVisualizerFile::new( + Arc::from(contents), + DebuggerVisualizerType::Natvis, + )); + } else { + tcx.sess + .struct_span_err(attr.span, &format!("{} is not a valid file", file.display())) + .emit(); } } } @@ -114,17 +83,21 @@ fn debugger_visualizers<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> Vec<Debugger assert_eq!(cnum, LOCAL_CRATE); // Initialize the collector. - let mut collector = DebuggerVisualizerCollector::new(tcx); + let mut debugger_visualizers = FxHashSet::default(); // Collect debugger visualizers in this crate. - tcx.hir().visit_all_item_likes(&mut collector); + tcx.hir().for_each_module(|id| { + check_for_debugger_visualizer( + tcx, + tcx.hir().local_def_id_to_hir_id(id), + &mut debugger_visualizers, + ) + }); // Collect debugger visualizers on the crate attributes. - collector.check_for_debugger_visualizer(CRATE_HIR_ID); + check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers); // Extract out the found debugger_visualizer items. - let DebuggerVisualizerCollector { debugger_visualizers, .. } = collector; - let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>(); // Sort the visualizers so we always get a deterministic query result. diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 9cbb7917e9a..e6b69d8986c 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -10,49 +10,22 @@ //! * Compiler internal types like `Ty` and `TyCtxt` use rustc_ast as ast; -use rustc_hir as hir; use rustc_hir::diagnostic_items::DiagnosticItems; -use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_span::symbol::{sym, Symbol}; -struct DiagnosticItemCollector<'tcx> { +fn observe_item<'tcx>( tcx: TyCtxt<'tcx>, - diagnostic_items: DiagnosticItems, -} - -impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> { - fn visit_item(&mut self, item: &hir::Item<'_>) { - self.observe_item(item.def_id); - } - - fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) { - self.observe_item(trait_item.def_id); - } - - fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) { - self.observe_item(impl_item.def_id); - } - - fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) { - self.observe_item(foreign_item.def_id); - } -} - -impl<'tcx> DiagnosticItemCollector<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> { - DiagnosticItemCollector { tcx, diagnostic_items: DiagnosticItems::default() } - } - - fn observe_item(&mut self, def_id: LocalDefId) { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - let attrs = self.tcx.hir().attrs(hir_id); - if let Some(name) = extract(attrs) { - // insert into our table - collect_item(self.tcx, &mut self.diagnostic_items, name, def_id.to_def_id()); - } + diagnostic_items: &mut DiagnosticItems, + def_id: LocalDefId, +) { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let attrs = tcx.hir().attrs(hir_id); + if let Some(name) = extract(attrs) { + // insert into our table + collect_item(tcx, diagnostic_items, name, def_id.to_def_id()); } } @@ -83,7 +56,7 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item } } -/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.p +/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes. fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> { attrs.iter().find_map(|attr| { if attr.has_name(sym::rustc_diagnostic_item) { attr.value_str() } else { None } @@ -95,12 +68,28 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems assert_eq!(cnum, LOCAL_CRATE); // Initialize the collector. - let mut collector = DiagnosticItemCollector::new(tcx); + let mut diagnostic_items = DiagnosticItems::default(); // Collect diagnostic items in this crate. - tcx.hir().visit_all_item_likes(&mut collector); + let crate_items = tcx.hir_crate_items(()); + + for id in crate_items.items() { + observe_item(tcx, &mut diagnostic_items, id.def_id); + } + + for id in crate_items.trait_items() { + observe_item(tcx, &mut diagnostic_items, id.def_id); + } + + for id in crate_items.impl_items() { + observe_item(tcx, &mut diagnostic_items, id.def_id); + } + + for id in crate_items.foreign_items() { + observe_item(tcx, &mut diagnostic_items, id.def_id); + } - collector.diagnostic_items + diagnostic_items } /// Traverse and collect all the diagnostic items in all crates. diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index f84b848e08d..b90d44e2af5 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,8 +1,8 @@ use rustc_ast::entry::EntryPointType; use rustc_errors::struct_span_err; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID}; +use rustc_hir::{ItemId, Node, CRATE_HIR_ID}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{DefIdTree, TyCtxt}; use rustc_session::config::{CrateType, EntryFnType}; @@ -25,25 +25,6 @@ struct EntryContext<'tcx> { non_main_fns: Vec<Span>, } -impl<'tcx> ItemLikeVisitor<'tcx> for EntryContext<'tcx> { - fn visit_item(&mut self, item: &'tcx Item<'tcx>) { - let at_root = self.tcx.opt_local_parent(item.def_id) == Some(CRATE_DEF_ID); - find_item(item, self, at_root); - } - - fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem<'tcx>) { - // Entry fn is never a trait item. - } - - fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem<'tcx>) { - // Entry fn is never a trait item. - } - - fn visit_foreign_item(&mut self, _: &'tcx ForeignItem<'tcx>) { - // Entry fn is never a foreign item. - } -} - fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable); if !any_exe { @@ -59,28 +40,35 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { let mut ctxt = EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() }; - tcx.hir().visit_all_item_likes(&mut ctxt); + for id in tcx.hir().items() { + find_item(id, &mut ctxt); + } configure_main(tcx, &ctxt) } // Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs` // (with `ast::Item`), so make sure to keep them in sync. -fn entry_point_type(ctxt: &EntryContext<'_>, item: &Item<'_>, at_root: bool) -> EntryPointType { - let attrs = ctxt.tcx.hir().attrs(item.hir_id()); +// A small optimization was added so that hir::Item is fetched only when needed. +// An equivalent optimization was not applied to the duplicated code in test_harness.rs. +fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType { + let attrs = ctxt.tcx.hir().attrs(id.hir_id()); if ctxt.tcx.sess.contains_name(attrs, sym::start) { EntryPointType::Start } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) { EntryPointType::MainAttr - } else if item.ident.name == sym::main { - if at_root { - // This is a top-level function so can be `main`. - EntryPointType::MainNamed + } else { + if let Some(name) = ctxt.tcx.opt_item_name(id.def_id.to_def_id()) + && name == sym::main { + if at_root { + // This is a top-level function so can be `main`. + EntryPointType::MainNamed + } else { + EntryPointType::OtherMain + } } else { - EntryPointType::OtherMain + EntryPointType::None } - } else { - EntryPointType::None } } @@ -89,11 +77,13 @@ fn throw_attr_err(sess: &Session, span: Span, attr: &str) { .emit(); } -fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) { - match entry_point_type(ctxt, item, at_root) { +fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { + let at_root = ctxt.tcx.opt_local_parent(id.def_id) == Some(CRATE_DEF_ID); + + match entry_point_type(ctxt, id, at_root) { EntryPointType::None => (), - _ if !matches!(item.kind, ItemKind::Fn(..)) => { - let attrs = ctxt.tcx.hir().attrs(item.hir_id()); + _ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => { + let attrs = ctxt.tcx.hir().attrs(id.hir_id()); if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) { throw_attr_err(&ctxt.tcx.sess, attr.span, "start"); } @@ -103,31 +93,39 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) { } EntryPointType::MainNamed => (), EntryPointType::OtherMain => { - ctxt.non_main_fns.push(item.span); + ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id)); } EntryPointType::MainAttr => { if ctxt.attr_main_fn.is_none() { - ctxt.attr_main_fn = Some((item.def_id, item.span)); + ctxt.attr_main_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id()))); } else { struct_span_err!( ctxt.tcx.sess, - item.span, + ctxt.tcx.def_span(id.def_id.to_def_id()), E0137, "multiple functions with a `#[main]` attribute" ) - .span_label(item.span, "additional `#[main]` function") + .span_label( + ctxt.tcx.def_span(id.def_id.to_def_id()), + "additional `#[main]` function", + ) .span_label(ctxt.attr_main_fn.unwrap().1, "first `#[main]` function") .emit(); } } EntryPointType::Start => { if ctxt.start_fn.is_none() { - ctxt.start_fn = Some((item.def_id, item.span)); + ctxt.start_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id()))); } else { - struct_span_err!(ctxt.tcx.sess, item.span, E0138, "multiple `start` functions") - .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here") - .span_label(item.span, "multiple `start` functions") - .emit(); + struct_span_err!( + ctxt.tcx.sess, + ctxt.tcx.def_span(id.def_id.to_def_id()), + E0138, + "multiple `start` functions" + ) + .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here") + .span_label(ctxt.tcx.def_span(id.def_id.to_def_id()), "multiple `start` functions") + .emit(); } } } diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 379a6827c8a..23ff0a91159 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -3,7 +3,6 @@ use rustc_data_structures::sync::Lock; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit; -use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{HirId, ItemLocalId}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; @@ -20,8 +19,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let hir_map = tcx.hir(); hir_map.par_for_each_module(|module_id| { - hir_map - .visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors }) + let mut v = HirIdValidator { + hir_map, + owner: None, + hir_ids_seen: Default::default(), + errors: &errors, + }; + + tcx.hir().deep_visit_item_likes_in_module(module_id, &mut v); }); let errors = errors.into_inner(); @@ -39,13 +44,8 @@ struct HirIdValidator<'a, 'hir> { errors: &'a Lock<Vec<String>>, } -struct OuterVisitor<'a, 'hir> { - hir_map: Map<'hir>, - errors: &'a Lock<Vec<String>>, -} - -impl<'a, 'hir> OuterVisitor<'a, 'hir> { - fn new_inner_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> { +impl<'a, 'hir> HirIdValidator<'a, 'hir> { + fn new_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> { HirIdValidator { hir_map, owner: None, @@ -53,31 +53,7 @@ impl<'a, 'hir> OuterVisitor<'a, 'hir> { errors: self.errors, } } -} - -impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> { - fn visit_item(&mut self, i: &'hir hir::Item<'hir>) { - let mut inner_visitor = self.new_inner_visitor(self.hir_map); - inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i)); - } - - fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) { - let mut inner_visitor = self.new_inner_visitor(self.hir_map); - inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i)); - } - - fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) { - let mut inner_visitor = self.new_inner_visitor(self.hir_map); - inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i)); - } - - fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) { - let mut inner_visitor = self.new_inner_visitor(self.hir_map); - inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i)); - } -} -impl<'a, 'hir> HirIdValidator<'a, 'hir> { #[cold] #[inline(never)] fn error(&self, f: impl FnOnce() -> String) { @@ -146,6 +122,11 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { self.hir_map } + fn visit_item(&mut self, i: &'hir hir::Item<'hir>) { + let mut inner_visitor = self.new_visitor(self.hir_map); + inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i)); + } + fn visit_id(&mut self, hir_id: HirId) { let owner = self.owner.expect("no owner"); @@ -163,17 +144,18 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { self.hir_ids_seen.insert(hir_id.local_id); } - fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) { - // Explicitly do nothing here. ImplItemRefs contain hir::Visibility - // values that actually belong to an ImplItem instead of the ItemKind::Impl - // we are currently in. So for those it's correct that they have a - // different owner. + fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) { + let mut inner_visitor = self.new_visitor(self.hir_map); + inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i)); + } + + fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) { + let mut inner_visitor = self.new_visitor(self.hir_map); + inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i)); } - fn visit_foreign_item_ref(&mut self, _: &'hir hir::ForeignItemRef) { - // Explicitly do nothing here. ForeignItemRefs contain hir::Visibility - // values that actually belong to an ForeignItem instead of the ItemKind::ForeignMod - // we are currently in. So for those it's correct that they have a - // different owner. + fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) { + let mut inner_visitor = self.new_visitor(self.hir_map); + inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i)); } } diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs index e4a1147c7e9..9c840777baf 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -16,7 +16,7 @@ use rustc_target::abi::{Pointer, VariantIdx}; use rustc_target::asm::{InlineAsmRegOrRegClass, InlineAsmType}; fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }.as_deep_visitor()); + tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }); } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 00e8eb5eb2b..fd03f657111 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -1,8 +1,6 @@ use rustc_ast::Attribute; -use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; -use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_hir::ItemKind; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_span::symbol::sym; @@ -12,99 +10,87 @@ use rustc_target::abi::{HasDataLayout, TargetDataLayout}; pub fn test_layout(tcx: TyCtxt<'_>) { if tcx.features().rustc_attrs { // if the `rustc_attrs` feature is not enabled, don't bother testing layout - tcx.hir().visit_all_item_likes(&mut LayoutTest { tcx }); - } -} - -struct LayoutTest<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> ItemLikeVisitor<'tcx> for LayoutTest<'tcx> { - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - match item.kind { - ItemKind::TyAlias(..) - | ItemKind::Enum(..) - | ItemKind::Struct(..) - | ItemKind::Union(..) => { - for attr in self.tcx.get_attrs(item.def_id.to_def_id()).iter() { - if attr.has_name(sym::rustc_layout) { - self.dump_layout_of(item.def_id, item, attr); - } + for id in tcx.hir().items() { + if matches!( + tcx.def_kind(id.def_id), + DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union + ) { + for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) { + dump_layout_of(tcx, id.def_id, attr); } } - _ => {} } } - - fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} - fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} - fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {} } -impl<'tcx> LayoutTest<'tcx> { - fn dump_layout_of(&self, item_def_id: LocalDefId, item: &hir::Item<'tcx>, attr: &Attribute) { - let tcx = self.tcx; - let param_env = self.tcx.param_env(item_def_id); - let ty = self.tcx.type_of(item_def_id); - match self.tcx.layout_of(param_env.and(ty)) { - Ok(ty_layout) => { - // Check out the `#[rustc_layout(..)]` attribute to tell what to dump. - // The `..` are the names of fields to dump. - let meta_items = attr.meta_item_list().unwrap_or_default(); - for meta_item in meta_items { - match meta_item.name_or_empty() { - sym::abi => { - self.tcx.sess.span_err(item.span, &format!("abi: {:?}", ty_layout.abi)); - } +fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attribute) { + let tcx = tcx; + let param_env = tcx.param_env(item_def_id); + let ty = tcx.type_of(item_def_id); + match tcx.layout_of(param_env.and(ty)) { + Ok(ty_layout) => { + // Check out the `#[rustc_layout(..)]` attribute to tell what to dump. + // The `..` are the names of fields to dump. + let meta_items = attr.meta_item_list().unwrap_or_default(); + for meta_item in meta_items { + match meta_item.name_or_empty() { + sym::abi => { + tcx.sess.span_err( + tcx.def_span(item_def_id.to_def_id()), + &format!("abi: {:?}", ty_layout.abi), + ); + } - sym::align => { - self.tcx - .sess - .span_err(item.span, &format!("align: {:?}", ty_layout.align)); - } + sym::align => { + tcx.sess.span_err( + tcx.def_span(item_def_id.to_def_id()), + &format!("align: {:?}", ty_layout.align), + ); + } - sym::size => { - self.tcx - .sess - .span_err(item.span, &format!("size: {:?}", ty_layout.size)); - } + sym::size => { + tcx.sess.span_err( + tcx.def_span(item_def_id.to_def_id()), + &format!("size: {:?}", ty_layout.size), + ); + } - sym::homogeneous_aggregate => { - self.tcx.sess.span_err( - item.span, - &format!( - "homogeneous_aggregate: {:?}", - ty_layout - .homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }), - ), - ); - } + sym::homogeneous_aggregate => { + tcx.sess.span_err( + tcx.def_span(item_def_id.to_def_id()), + &format!( + "homogeneous_aggregate: {:?}", + ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }), + ), + ); + } - sym::debug => { - let normalized_ty = self.tcx.normalize_erasing_regions( - param_env.with_reveal_all_normalized(self.tcx), - ty, - ); - self.tcx.sess.span_err( - item.span, - &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout), - ); - } + sym::debug => { + let normalized_ty = tcx.normalize_erasing_regions( + param_env.with_reveal_all_normalized(tcx), + ty, + ); + tcx.sess.span_err( + tcx.def_span(item_def_id.to_def_id()), + &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout), + ); + } - name => { - self.tcx.sess.span_err( - meta_item.span(), - &format!("unrecognized field name `{}`", name), - ); - } + name => { + tcx.sess.span_err( + meta_item.span(), + &format!("unrecognized field name `{}`", name), + ); } } } + } - Err(layout_error) => { - self.tcx.sess.span_err(item.span, &format!("layout error: {:?}", layout_error)); - } + Err(layout_error) => { + tcx.sess.span_err( + tcx.def_span(item_def_id.to_def_id()), + &format!("layout error: {:?}", layout_error), + ); } } } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 9eba7fb0811..ce5253adf10 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -140,7 +140,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String { } fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx).as_deep_visitor()); + tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx)); } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 02b09daf0a4..e0dac09870d 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -31,9 +31,9 @@ struct CheckLoopVisitor<'a, 'hir> { } fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module( + tcx.hir().deep_visit_item_likes_in_module( module_def_id, - &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }.as_deep_visitor(), + &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }, ); } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index e85720952da..5d7768c8240 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -14,10 +14,7 @@ use rustc_span::Span; use rustc_target::spec::abi::Abi; fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module( - module_def_id, - &mut CheckNakedFunctions { tcx }.as_deep_visitor(), - ); + tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx }); } crate fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index a5133bfd945..0ded6a421f5 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -10,7 +10,6 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::privacy; @@ -314,79 +313,60 @@ impl<'tcx> ReachableContext<'tcx> { } } -// Some methods from non-exported (completely private) trait impls still have to be -// reachable if they are called from inlinable code. Generally, it's not known until -// monomorphization if a specific trait impl item can be reachable or not. So, we -// conservatively mark all of them as reachable. -// FIXME: One possible strategy for pruning the reachable set is to avoid marking impl -// items of non-exported traits (or maybe all local traits?) unless their respective -// trait items are used from inlinable code through method call syntax or UFCS, or their -// trait is a lang item. -struct CollectPrivateImplItemsVisitor<'a, 'tcx> { +fn check_item<'tcx>( tcx: TyCtxt<'tcx>, - access_levels: &'a privacy::AccessLevels, - worklist: &'a mut Vec<LocalDefId>, -} + id: hir::ItemId, + worklist: &mut Vec<LocalDefId>, + access_levels: &privacy::AccessLevels, +) { + if has_custom_linkage(tcx, id.def_id) { + worklist.push(id.def_id); + } -impl CollectPrivateImplItemsVisitor<'_, '_> { - fn push_to_worklist_if_has_custom_linkage(&mut self, def_id: LocalDefId) { - // Anything which has custom linkage gets thrown on the worklist no - // matter where it is in the crate, along with "special std symbols" - // which are currently akin to allocator symbols. - if self.tcx.def_kind(def_id).has_codegen_attrs() { - let codegen_attrs = self.tcx.codegen_fn_attrs(def_id); - if codegen_attrs.contains_extern_indicator() - || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) - // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by - // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their - // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs. - || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) - || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) - { - self.worklist.push(def_id); - } - } + if !matches!(tcx.def_kind(id.def_id), DefKind::Impl) { + return; } -} -impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> { - fn visit_item(&mut self, item: &hir::Item<'_>) { - self.push_to_worklist_if_has_custom_linkage(item.def_id); - - // We need only trait impls here, not inherent impls, and only non-exported ones - if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) = - item.kind - { - if !self.access_levels.is_reachable(item.def_id) { - // FIXME(#53488) remove `let` - let tcx = self.tcx; - self.worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id)); - - let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else { - unreachable!(); - }; + // We need only trait impls here, not inherent impls, and only non-exported ones + let item = tcx.hir().item(id); + if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) = + item.kind + { + if !access_levels.is_reachable(item.def_id) { + // FIXME(#53488) remove `let` + let tcx = tcx; + worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id)); - if !trait_def_id.is_local() { - return; - } + let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else { + unreachable!(); + }; - self.worklist.extend( - tcx.provided_trait_methods(trait_def_id) - .map(|assoc| assoc.def_id.expect_local()), - ); + if !trait_def_id.is_local() { + return; } - } - } - - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} - fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) { - self.push_to_worklist_if_has_custom_linkage(impl_item.def_id); + worklist.extend( + tcx.provided_trait_methods(trait_def_id).map(|assoc| assoc.def_id.expect_local()), + ); + } } +} - fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) { - // We never export foreign functions as they have no body to export. +fn has_custom_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { + // Anything which has custom linkage gets thrown on the worklist no + // matter where it is in the crate, along with "special std symbols" + // which are currently akin to allocator symbols. + if !tcx.def_kind(def_id).has_codegen_attrs() { + return false; } + let codegen_attrs = tcx.codegen_fn_attrs(def_id); + codegen_attrs.contains_extern_indicator() + || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) + // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by + // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their + // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs. + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) } fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> { @@ -418,12 +398,25 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> { } } { - let mut collect_private_impl_items = CollectPrivateImplItemsVisitor { - tcx, - access_levels, - worklist: &mut reachable_context.worklist, - }; - tcx.hir().visit_all_item_likes(&mut collect_private_impl_items); + // Some methods from non-exported (completely private) trait impls still have to be + // reachable if they are called from inlinable code. Generally, it's not known until + // monomorphization if a specific trait impl item can be reachable or not. So, we + // conservatively mark all of them as reachable. + // FIXME: One possible strategy for pruning the reachable set is to avoid marking impl + // items of non-exported traits (or maybe all local traits?) unless their respective + // trait items are used from inlinable code through method call syntax or UFCS, or their + // trait is a lang item. + let crate_items = tcx.hir_crate_items(()); + + for id in crate_items.items() { + check_item(tcx, id, &mut reachable_context.worklist, access_levels); + } + + for id in crate_items.impl_items() { + if has_custom_linkage(tcx, id.def_id) { + reachable_context.worklist.push(id.def_id); + } + } } // Step 2: Mark all symbols that the symbols on the worklist touch. diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 10dc587be6e..58195fce281 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -110,7 +110,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { ) where F: FnOnce(&mut Self), { - let attrs = self.tcx.get_attrs(def_id.to_def_id()); + let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); let depr = attr::find_deprecation(&self.tcx.sess, attrs); @@ -661,7 +661,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { /// Cross-references the feature names of unstable APIs with enabled /// features and possibly prints errors. fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }.as_deep_visitor()); + tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut Checker { tcx }); } pub(crate) fn provide(providers: &mut Providers) { @@ -837,7 +837,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let mut missing = MissingStabilityAnnotations { tcx, access_levels }; missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID)); tcx.hir().walk_toplevel_module(&mut missing); - tcx.hir().visit_all_item_likes(&mut missing.as_deep_visitor()); + tcx.hir().deep_visit_all_item_likes(&mut missing); } let declared_lang_features = &tcx.features().declared_lang_features; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index ee459d9c129..4d3c730dc90 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -14,8 +14,8 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; -use rustc_hir::intravisit::{self, DeepVisitor, Visitor}; -use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind}; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::{AccessLevel, AccessLevels}; @@ -1802,12 +1802,12 @@ impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { } } -struct PrivateItemsInPublicInterfacesVisitor<'tcx> { +struct PrivateItemsInPublicInterfacesChecker<'tcx> { tcx: TyCtxt<'tcx>, old_error_set_ancestry: LocalDefIdSet, } -impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> { +impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { fn check( &self, def_id: LocalDefId, @@ -1841,110 +1841,110 @@ impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> { check.ty(); } } -} - -impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> { - type NestedFilter = nested_filter::OnlyBodies; - - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() - } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + pub fn check_item(&mut self, id: ItemId) { let tcx = self.tcx; - let item_visibility = tcx.visibility(item.def_id); + let item_visibility = tcx.visibility(id.def_id); + let def_kind = tcx.def_kind(id.def_id); - match item.kind { - // Crates are always public. - hir::ItemKind::ExternCrate(..) => {} - // All nested items are checked by `visit_item`. - hir::ItemKind::Mod(..) => {} - // Checked in resolve. - hir::ItemKind::Use(..) => {} - // No subitems. - hir::ItemKind::Macro(..) | hir::ItemKind::GlobalAsm(..) => {} - // Subitems of these items have inherited publicity. - hir::ItemKind::Const(..) - | hir::ItemKind::Static(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::TyAlias(..) => { - self.check(item.def_id, item_visibility).generics().predicates().ty(); + match def_kind { + DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias => { + self.check(id.def_id, item_visibility).generics().predicates().ty(); } - hir::ItemKind::OpaqueTy(..) => { + DefKind::OpaqueTy => { // `ty()` for opaque types is the underlying type, // it's not a part of interface, so we skip it. - self.check(item.def_id, item_visibility).generics().bounds(); + self.check(id.def_id, item_visibility).generics().bounds(); } - hir::ItemKind::Trait(.., trait_item_refs) => { - self.check(item.def_id, item_visibility).generics().predicates(); + DefKind::Trait => { + let item = tcx.hir().item(id); + if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind { + self.check(item.def_id, item_visibility).generics().predicates(); - for trait_item_ref in trait_item_refs { - self.check_assoc_item( - trait_item_ref.id.def_id, - trait_item_ref.kind, - trait_item_ref.defaultness, - item_visibility, - ); - - if let AssocItemKind::Type = trait_item_ref.kind { - self.check(trait_item_ref.id.def_id, item_visibility).bounds(); + for trait_item_ref in trait_item_refs { + self.check_assoc_item( + trait_item_ref.id.def_id, + trait_item_ref.kind, + trait_item_ref.defaultness, + item_visibility, + ); + + if let AssocItemKind::Type = trait_item_ref.kind { + self.check(trait_item_ref.id.def_id, item_visibility).bounds(); + } } } } - hir::ItemKind::TraitAlias(..) => { - self.check(item.def_id, item_visibility).generics().predicates(); + DefKind::TraitAlias => { + self.check(id.def_id, item_visibility).generics().predicates(); } - hir::ItemKind::Enum(ref def, _) => { - self.check(item.def_id, item_visibility).generics().predicates(); + DefKind::Enum => { + let item = tcx.hir().item(id); + if let hir::ItemKind::Enum(ref def, _) = item.kind { + self.check(item.def_id, item_visibility).generics().predicates(); - for variant in def.variants { - for field in variant.data.fields() { - self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility).ty(); + for variant in def.variants { + for field in variant.data.fields() { + self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility) + .ty(); + } } } } // Subitems of foreign modules have their own publicity. - hir::ItemKind::ForeignMod { items, .. } => { - for foreign_item in items { - let vis = tcx.visibility(foreign_item.id.def_id); - self.check(foreign_item.id.def_id, vis).generics().predicates().ty(); + DefKind::ForeignMod => { + let item = tcx.hir().item(id); + if let hir::ItemKind::ForeignMod { items, .. } = item.kind { + for foreign_item in items { + let vis = tcx.visibility(foreign_item.id.def_id); + self.check(foreign_item.id.def_id, vis).generics().predicates().ty(); + } } } // Subitems of structs and unions have their own publicity. - hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { - self.check(item.def_id, item_visibility).generics().predicates(); + DefKind::Struct | DefKind::Union => { + let item = tcx.hir().item(id); + if let hir::ItemKind::Struct(ref struct_def, _) + | hir::ItemKind::Union(ref struct_def, _) = item.kind + { + self.check(item.def_id, item_visibility).generics().predicates(); - for field in struct_def.fields() { - let def_id = tcx.hir().local_def_id(field.hir_id); - let field_visibility = tcx.visibility(def_id); - self.check(def_id, min(item_visibility, field_visibility, tcx)).ty(); + for field in struct_def.fields() { + let def_id = tcx.hir().local_def_id(field.hir_id); + let field_visibility = tcx.visibility(def_id); + self.check(def_id, min(item_visibility, field_visibility, tcx)).ty(); + } } } // An inherent impl is public when its type is public // Subitems of inherent impls have their own publicity. // A trait impl is public when both its type and its trait are public // Subitems of trait impls have inherited publicity. - hir::ItemKind::Impl(ref impl_) => { - let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default()); - // check that private components do not appear in the generics or predicates of inherent impls - // this check is intentionally NOT performed for impls of traits, per #90586 - if impl_.of_trait.is_none() { - self.check(item.def_id, impl_vis).generics().predicates(); - } - for impl_item_ref in impl_.items { - let impl_item_vis = if impl_.of_trait.is_none() { - min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx) - } else { - impl_vis - }; - self.check_assoc_item( - impl_item_ref.id.def_id, - impl_item_ref.kind, - impl_item_ref.defaultness, - impl_item_vis, - ); + DefKind::Impl => { + let item = tcx.hir().item(id); + if let hir::ItemKind::Impl(ref impl_) = item.kind { + let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default()); + // check that private components do not appear in the generics or predicates of inherent impls + // this check is intentionally NOT performed for impls of traits, per #90586 + if impl_.of_trait.is_none() { + self.check(item.def_id, impl_vis).generics().predicates(); + } + for impl_item_ref in impl_.items { + let impl_item_vis = if impl_.of_trait.is_none() { + min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx) + } else { + impl_vis + }; + self.check_assoc_item( + impl_item_ref.id.def_id, + impl_item_ref.kind, + impl_item_ref.defaultness, + impl_item_vis, + ); + } } } + _ => {} } } } @@ -2069,7 +2069,7 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { } // Check for private types and traits in public interfaces. - let mut visitor = PrivateItemsInPublicInterfacesVisitor { + let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, // Only definition IDs are ever searched in `old_error_set_ancestry`, // so we can filter away all non-definition IDs at this point. @@ -2078,5 +2078,8 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { .filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id)) .collect(), }; - tcx.hir().visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); + + for id in tcx.hir().items() { + checker.check_item(id); + } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index e68d6fdeea5..dffec44ddbc 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1268,7 +1268,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }; let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); self.r.set_binding_parent_module(binding, parent_scope.module); - self.r.all_macro_rules.insert(ident.name, res); if is_macro_export { let module = self.r.graph_root; self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport)); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1e8cca6122c..f0861103098 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -109,7 +109,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { visit::walk_item(self, i); return self.visit_macro_invoc(i.id); } - ItemKind::GlobalAsm(..) => DefPathData::Misc, + ItemKind::GlobalAsm(..) => DefPathData::GlobalAsm, ItemKind::Use(..) => { return visit::walk_item(self, i); } @@ -160,11 +160,11 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { } fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { - self.create_def(id, DefPathData::Misc, use_tree.span); + self.create_def(id, DefPathData::Use, use_tree.span); match use_tree.kind { UseTreeKind::Simple(_, id1, id2) => { - self.create_def(id1, DefPathData::Misc, use_tree.prefix.span); - self.create_def(id2, DefPathData::Misc, use_tree.prefix.span); + self.create_def(id1, DefPathData::Use, use_tree.prefix.span); + self.create_def(id2, DefPathData::Use, use_tree.prefix.span); } UseTreeKind::Glob => (), UseTreeKind::Nested(..) => {} diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 030c27af444..700d7c3bfb6 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1025,6 +1025,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } self.uninsert_lifetime_on_error(lifetime, def.unwrap()); } + if let hir::Node::Item(hir::Item { + kind: hir::ItemKind::OpaqueTy { .. }, .. + }) = self.tcx.hir().get(parent_id) + { + if !self.trait_definition_only { + let mut err = self.tcx.sess.struct_span_err( + lifetime.span, + "higher kinded lifetime bounds on nested opaque types are not supported yet", + ); + err.span_note(self.tcx.def_span(def_id), "lifetime declared here"); + err.emit(); + } + self.uninsert_lifetime_on_error(lifetime, def.unwrap()); + } } // We want to start our early-bound indices at the end of the parent scope, @@ -2002,12 +2016,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let parent_def_id = self.tcx.parent(def_id); if let Some(def_id) = parent_def_id.as_local() { // lifetimes in `derive` expansions don't count (Issue #53738) - if self - .tcx - .get_attrs(def_id.to_def_id()) - .iter() - .any(|attr| attr.has_name(sym::automatically_derived)) - { + if self.tcx.has_attr(def_id.to_def_id(), sym::automatically_derived) { continue; } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8d3c46c29a8..6c0148a17a1 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -59,7 +59,7 @@ use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; -use std::{cmp, fmt, mem, ptr}; +use std::{cmp, fmt, ptr}; use tracing::debug; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; @@ -966,8 +966,6 @@ pub struct Resolver<'a> { registered_attrs: FxHashSet<Ident>, registered_tools: RegisteredTools, macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>, - /// FIXME: The only user of this is a doc link resolution hack for rustdoc. - all_macro_rules: FxHashMap<Symbol, Res>, macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>, dummy_ext_bang: Lrc<SyntaxExtension>, dummy_ext_derive: Lrc<SyntaxExtension>, @@ -1360,7 +1358,6 @@ impl<'a> Resolver<'a> { registered_attrs, registered_tools, macro_use_prelude: FxHashMap::default(), - all_macro_rules: Default::default(), macro_map: FxHashMap::default(), dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())), dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(session.edition())), @@ -1912,11 +1909,6 @@ impl<'a> Resolver<'a> { } } - // For rustdoc. - pub fn take_all_macro_rules(&mut self) -> FxHashMap<Symbol, Res> { - mem::take(&mut self.all_macro_rules) - } - /// For rustdoc. /// For local modules returns only reexports, for external modules returns all children. pub fn module_children_or_reexports(&self, def_id: DefId) -> Vec<ModChild> { @@ -1928,8 +1920,12 @@ impl<'a> Resolver<'a> { } /// For rustdoc. - pub fn macro_rules_scope(&self, def_id: LocalDefId) -> MacroRulesScopeRef<'a> { - *self.macro_rules_scopes.get(&def_id).expect("not a `macro_rules` item") + pub fn macro_rules_scope(&self, def_id: LocalDefId) -> (MacroRulesScopeRef<'a>, Res) { + let scope = *self.macro_rules_scopes.get(&def_id).expect("not a `macro_rules` item"); + match scope.get() { + MacroRulesScope::Binding(mb) => (scope, mb.binding.res()), + _ => unreachable!(), + } } /// Retrieves the span of the given `DefId` if `DefId` is in the local crate. diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index e1c9ecc055f..fe417f45e88 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -780,13 +780,18 @@ impl<'tcx> DumpVisitor<'tcx> { variant: &'tcx ty::VariantDef, rest: Option<&'tcx hir::Expr<'tcx>>, ) { - if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) { + if let Some(_ex_res_data) = self.save_ctxt.get_expr_data(ex) { if let hir::QPath::Resolved(_, path) = path { self.write_sub_paths_truncated(path); } - down_cast_data!(struct_lit_data, RefData, ex.span); + // For MyEnum::MyVariant, get_expr_data gives us MyEnum, not MyVariant. + // For recording the span's ref id, we want MyVariant. if !generated_code(ex.span) { - self.dumper.dump_ref(struct_lit_data); + let sub_span = path.last_segment_span(); + let span = self.save_ctxt.span_from_span(sub_span); + let reff = + Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(variant.def_id) }; + self.dumper.dump_ref(reff); } for field in fields { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 530c1a06f8f..e1e398a06ed 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1937,33 +1937,27 @@ fn parse_native_lib_kind( }; let kind = match kind { - "dylib" => NativeLibKind::Dylib { as_needed: None }, - "framework" => NativeLibKind::Framework { as_needed: None }, "static" => NativeLibKind::Static { bundle: None, whole_archive: None }, "static-nobundle" => { early_warn( error_format, "library kind `static-nobundle` has been superseded by specifying \ - `-bundle` on library kind `static`. Try `static:-bundle`", + modifier `-bundle` with library kind `static`. Try `static:-bundle`", ); - if modifiers.is_some() { - early_error( - error_format, - "linking modifier can't be used with library kind `static-nobundle`", - ) - } if !nightly_options::match_is_nightly_build(matches) { early_error( error_format, - "library kind `static-nobundle` are currently unstable and only accepted on \ - the nightly compiler", + "library kind `static-nobundle` is unstable \ + and only accepted on the nightly compiler", ); } NativeLibKind::Static { bundle: Some(false), whole_archive: None } } - s => early_error( + "dylib" => NativeLibKind::Dylib { as_needed: None }, + "framework" => NativeLibKind::Framework { as_needed: None }, + _ => early_error( error_format, - &format!("unknown library kind `{s}`, expected one of dylib, framework, or static"), + &format!("unknown library kind `{kind}`, expected one of: static, dylib, framework"), ), }; match modifiers { @@ -1978,21 +1972,6 @@ fn parse_native_lib_modifiers( error_format: ErrorOutputType, matches: &getopts::Matches, ) -> (NativeLibKind, Option<bool>) { - let report_unstable_modifier = |modifier| { - if !nightly_options::is_unstable_enabled(matches) { - let why = if nightly_options::match_is_nightly_build(matches) { - " and only accepted on the nightly compiler" - } else { - ", the `-Z unstable-options` flag must also be passed to use it" - }; - early_error( - error_format, - &format!("{modifier} linking modifier is currently unstable{why}"), - ) - } - }; - - let mut has_duplicate_modifiers = false; let mut verbatim = None; for modifier in modifiers.split(',') { let (modifier, value) = match modifier.strip_prefix(&['+', '-']) { @@ -2000,56 +1979,63 @@ fn parse_native_lib_modifiers( None => early_error( error_format, "invalid linking modifier syntax, expected '+' or '-' prefix \ - before one of: bundle, verbatim, whole-archive, as-needed", + before one of: bundle, verbatim, whole-archive, as-needed", ), }; + let report_unstable_modifier = || { + if !nightly_options::is_unstable_enabled(matches) { + let why = if nightly_options::match_is_nightly_build(matches) { + " and only accepted on the nightly compiler" + } else { + ", the `-Z unstable-options` flag must also be passed to use it" + }; + early_error( + error_format, + &format!("linking modifier `{modifier}` is unstable{why}"), + ) + } + }; + let assign_modifier = |dst: &mut Option<bool>| { + if dst.is_some() { + let msg = format!("multiple `{modifier}` modifiers in a single `-l` option"); + early_error(error_format, &msg) + } else { + *dst = Some(value); + } + }; match (modifier, &mut kind) { ("bundle", NativeLibKind::Static { bundle, .. }) => { - report_unstable_modifier(modifier); - if bundle.is_some() { - has_duplicate_modifiers = true; - } - *bundle = Some(value); + report_unstable_modifier(); + assign_modifier(bundle) } ("bundle", _) => early_error( error_format, - "bundle linking modifier is only compatible with \ - `static` linking kind", + "linking modifier `bundle` is only compatible with `static` linking kind", ), ("verbatim", _) => { - report_unstable_modifier(modifier); - if verbatim.is_some() { - has_duplicate_modifiers = true; - } - verbatim = Some(value); + report_unstable_modifier(); + assign_modifier(&mut verbatim) } ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { - if whole_archive.is_some() { - has_duplicate_modifiers = true; - } - *whole_archive = Some(value); + assign_modifier(whole_archive) } ("whole-archive", _) => early_error( error_format, - "whole-archive linking modifier is only compatible with \ - `static` linking kind", + "linking modifier `whole-archive` is only compatible with `static` linking kind", ), ("as-needed", NativeLibKind::Dylib { as_needed }) | ("as-needed", NativeLibKind::Framework { as_needed }) => { - report_unstable_modifier(modifier); - if as_needed.is_some() { - has_duplicate_modifiers = true; - } - *as_needed = Some(value); + report_unstable_modifier(); + assign_modifier(as_needed) } ("as-needed", _) => early_error( error_format, - "as-needed linking modifier is only compatible with \ - `dylib` and `framework` linking kinds", + "linking modifier `as-needed` is only compatible with \ + `dylib` and `framework` linking kinds", ), // Note: this error also excludes the case with empty modifier @@ -2057,15 +2043,12 @@ fn parse_native_lib_modifiers( _ => early_error( error_format, &format!( - "unrecognized linking modifier `{modifier}`, expected one \ - of: bundle, verbatim, whole-archive, as-needed" + "unknown linking modifier `{modifier}`, expected one \ + of: bundle, verbatim, whole-archive, as-needed" ), ), } } - if has_duplicate_modifiers { - report_unstable_modifier("duplicating") - } (kind, verbatim) } @@ -2093,6 +2076,9 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec< None => (name, None), Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())), }; + if name.is_empty() { + early_error(error_format, "library name must not be empty"); + } NativeLib { name, new_name, kind, verbatim } }) .collect() diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index 37d1cffa2a5..7249ce04c15 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -49,27 +49,26 @@ struct SymbolNamesTest<'tcx> { impl SymbolNamesTest<'_> { fn process_attrs(&mut self, def_id: LocalDefId) { let tcx = self.tcx; - for attr in tcx.get_attrs(def_id.to_def_id()).iter() { - if attr.has_name(SYMBOL_NAME) { - let def_id = def_id.to_def_id(); - let instance = Instance::new( - def_id, - tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def_id)), - ); - let mangled = tcx.symbol_name(instance); - tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled)); - if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) { - tcx.sess.span_err(attr.span, &format!("demangling({})", demangling)); - tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling)); - } - } else if attr.has_name(DEF_PATH) { - let path = with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id())); - tcx.sess.span_err(attr.span, &format!("def-path({})", path)); + // The formatting of `tag({})` is chosen so that tests can elect + // to test the entirety of the string, if they choose, or else just + // some subset. + for attr in tcx.get_attrs(def_id.to_def_id(), SYMBOL_NAME) { + let def_id = def_id.to_def_id(); + let instance = Instance::new( + def_id, + tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def_id)), + ); + let mangled = tcx.symbol_name(instance); + tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled)); + if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) { + tcx.sess.span_err(attr.span, &format!("demangling({})", demangling)); + tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling)); } + } - // (*) The formatting of `tag({})` is chosen so that tests can elect - // to test the entirety of the string, if they choose, or else just - // some subset. + for attr in tcx.get_attrs(def_id.to_def_id(), DEF_PATH) { + let path = with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id())); + tcx.sess.span_err(attr.span, &format!("def-path({})", path)); } } } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index c8fdf363f05..dc1946bcdc2 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -9,7 +9,9 @@ use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::print::{Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; -use rustc_middle::ty::{self, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy}; +use rustc_middle::ty::{ + self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy, +}; use rustc_span::symbol::kw; use rustc_target::abi::call::FnAbi; use rustc_target::abi::Integer; @@ -297,7 +299,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id); if !substs.is_empty() { - param_env = param_env.subst(self.tcx, substs); + param_env = EarlyBinder(param_env).subst(self.tcx, substs); } match &mut impl_trait_ref { @@ -788,7 +790,8 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { // These should never show up as `path_append` arguments. DefPathData::CrateRoot - | DefPathData::Misc + | DefPathData::Use + | DefPathData::GlobalAsm | DefPathData::Impl | DefPathData::MacroNs(_) | DefPathData::LifetimeNs(_) => { diff --git a/compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs new file mode 100644 index 00000000000..59c6a95c2c5 --- /dev/null +++ b/compiler/rustc_target/src/spec/aarch64_pc_windows_gnullvm.rs @@ -0,0 +1,16 @@ +use crate::spec::Target; + +pub fn target() -> Target { + let mut base = super::windows_gnullvm_base::opts(); + base.max_atomic_width = Some(64); + base.features = "+neon,+fp-armv8".into(); + base.linker = Some("aarch64-w64-mingw32-clang".into()); + + Target { + llvm_target: "aarch64-pc-windows-gnu".into(), + pointer_width: 64, + data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".into(), + arch: "aarch64".into(), + options: base, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 965a3c10983..832eeec3e8b 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -82,6 +82,7 @@ mod uefi_msvc_base; mod vxworks_base; mod wasm_base; mod windows_gnu_base; +mod windows_gnullvm_base; mod windows_msvc_base; mod windows_uwp_gnu_base; mod windows_uwp_msvc_base; @@ -939,6 +940,9 @@ supported_targets! { ("i686-uwp-windows-gnu", i686_uwp_windows_gnu), ("x86_64-uwp-windows-gnu", x86_64_uwp_windows_gnu), + ("aarch64-pc-windows-gnullvm", aarch64_pc_windows_gnullvm), + ("x86_64-pc-windows-gnullvm", x86_64_pc_windows_gnullvm), + ("aarch64-pc-windows-msvc", aarch64_pc_windows_msvc), ("aarch64-uwp-windows-msvc", aarch64_uwp_windows_msvc), ("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc), diff --git a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs new file mode 100644 index 00000000000..9f9f8be8718 --- /dev/null +++ b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs @@ -0,0 +1,52 @@ +use crate::spec::{cvs, LinkArgs, LinkerFlavor, TargetOptions}; + +pub fn opts() -> TargetOptions { + let pre_link_args = LinkArgs::from([( + LinkerFlavor::Gcc, + vec![ + // We cannot use `-nodefaultlibs` because compiler-rt has to be passed + // as a path since it's not added to linker search path by the default. + // There were attemts to make it behave like libgcc (so one can just use -l<name>) + // but LLVM maintainers rejected it: https://reviews.llvm.org/D51440 + "-nolibc".into(), + "--unwindlib=none".into(), + ], + )]); + let late_link_args = LinkArgs::from([( + LinkerFlavor::Gcc, + // Order of `late_link_args*` does not matter with LLD. + vec![ + "-lmingw32".into(), + "-lmingwex".into(), + "-lmsvcrt".into(), + "-lkernel32".into(), + "-luser32".into(), + ], + )]); + + TargetOptions { + os: "windows".into(), + env: "gnu".into(), + vendor: "pc".into(), + abi: "llvm".into(), + linker: Some("clang".into()), + dynamic_linking: true, + executables: true, + dll_prefix: "".into(), + dll_suffix: ".dll".into(), + exe_suffix: ".exe".into(), + families: cvs!["windows"], + is_like_windows: true, + allows_weak_linkage: false, + pre_link_args, + late_link_args, + abi_return_struct_as_int: true, + emit_debug_gdb_scripts: false, + requires_uwtable: true, + eh_frame_header: false, + no_default_libraries: false, + has_thread_local: true, + + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs new file mode 100644 index 00000000000..b5ff63e0532 --- /dev/null +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs @@ -0,0 +1,19 @@ +use crate::spec::{LinkerFlavor, Target}; + +pub fn target() -> Target { + let mut base = super::windows_gnullvm_base::opts(); + base.cpu = "x86-64".into(); + let gcc_pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); + gcc_pre_link_args.push("-m64".into()); + base.max_atomic_width = Some(64); + base.linker = Some("x86_64-w64-mingw32-clang".into()); + + Target { + llvm_target: "x86_64-pc-windows-gnu".into(), + pointer_width: 64, + data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + .into(), + arch: "x86_64".into(), + options: base, + } +} diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 74f5185d672..238c6d99990 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -82,6 +82,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { )); debug!(?definition_ty); + if !check_opaque_type_parameter_valid( + self.tcx, + opaque_type_key, + origin, + instantiated_ty.span, + ) { + return self.tcx.ty_error(); + } + // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs` // on stable and we'd break that. if let OpaqueTyOrigin::TyAlias = origin { @@ -148,6 +157,98 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } +fn check_opaque_type_parameter_valid( + tcx: TyCtxt<'_>, + opaque_type_key: OpaqueTypeKey<'_>, + origin: OpaqueTyOrigin, + span: Span, +) -> bool { + match origin { + // No need to check return position impl trait (RPIT) + // because for type and const parameters they are correct + // by construction: we convert + // + // fn foo<P0..Pn>() -> impl Trait + // + // into + // + // type Foo<P0...Pn> + // fn foo<P0..Pn>() -> Foo<P0...Pn>. + // + // For lifetime parameters we convert + // + // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> + // + // into + // + // type foo::<'p0..'pn>::Foo<'q0..'qm> + // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>. + // + // which would error here on all of the `'static` args. + OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true, + // Check these + OpaqueTyOrigin::TyAlias => {} + } + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); + for (i, arg) in opaque_type_key.substs.iter().enumerate() { + let arg_is_param = match arg.unpack() { + GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), + GenericArgKind::Lifetime(lt) if lt.is_static() => { + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_label( + tcx.def_span(opaque_generics.param_at(i, tcx).def_id), + "cannot use static lifetime; use a bound lifetime \ + instead or remove the lifetime parameter from the \ + opaque type", + ) + .emit(); + return false; + } + GenericArgKind::Lifetime(lt) => { + matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_)) + } + GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)), + }; + + if arg_is_param { + seen_params.entry(arg).or_default().push(i); + } else { + // Prevent `fn foo() -> Foo<u32>` from being defining. + let opaque_param = opaque_generics.param_at(i, tcx); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note( + tcx.def_span(opaque_param.def_id), + &format!( + "used non-generic {} `{}` for generic parameter", + opaque_param.kind.descr(), + arg, + ), + ) + .emit(); + return false; + } + } + + for (_, indices) in seen_params { + if indices.len() > 1 { + let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); + let spans: Vec<_> = indices + .into_iter() + .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) + .collect(); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note(spans, &format!("{} used multiple times", descr)) + .emit(); + return false; + } + } + true +} + struct ReverseMapper<'tcx> { tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 24110d30a84..d09cc4fb62f 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -135,8 +135,8 @@ fn with_fresh_ty_vars<'cx, 'tcx>( let header = ty::ImplHeader { impl_def_id, - self_ty: tcx.type_of(impl_def_id).subst(tcx, impl_substs), - trait_ref: tcx.impl_trait_ref(impl_def_id).subst(tcx, impl_substs), + self_ty: tcx.bound_type_of(impl_def_id).subst(tcx, impl_substs), + trait_ref: tcx.bound_impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)), predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates, }; diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 5daa9796d12..27ce08ea045 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -19,7 +19,7 @@ use rustc_middle::mir::interpret::{ use rustc_middle::thir; use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable}; use rustc_middle::ty::subst::{Subst, SubstsRef}; -use rustc_middle::ty::{self, DelaySpanBugEmitted, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, DelaySpanBugEmitted, EarlyBinder, TyCtxt, TypeFoldable}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::Span; @@ -263,8 +263,10 @@ impl<'tcx> AbstractConst<'tcx> { pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> { let node = self.inner.last().copied().unwrap(); match node { - Node::Leaf(leaf) => Node::Leaf(leaf.subst(tcx, self.substs)), - Node::Cast(kind, operand, ty) => Node::Cast(kind, operand, ty.subst(tcx, self.substs)), + Node::Leaf(leaf) => Node::Leaf(EarlyBinder(leaf).subst(tcx, self.substs)), + Node::Cast(kind, operand, ty) => { + Node::Cast(kind, operand, EarlyBinder(ty).subst(tcx, self.substs)) + } // Don't perform substitution on the following as they can't directly contain generic params Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node, } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 7a3579eb1cc..6082d7529c3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2,11 +2,10 @@ pub mod on_unimplemented; pub mod suggestions; use super::{ - DerivedObligationCause, EvaluationResult, FulfillmentContext, FulfillmentError, - FulfillmentErrorCode, ImplDerivedObligationCause, MismatchedProjectionTypes, Obligation, - ObligationCause, ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, - OutputTypeParameterMismatch, Overflow, PredicateObligation, SelectionContext, SelectionError, - TraitNotObjectSafe, + EvaluationResult, FulfillmentContext, FulfillmentError, FulfillmentErrorCode, + MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode, + OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, + PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe, }; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; @@ -684,42 +683,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut code = obligation.cause.code(); let mut trait_pred = trait_predicate; let mut peeled = false; - loop { - match &*code { - ObligationCauseCode::FunctionArgumentObligation { - parent_code, - .. - } => { - code = &parent_code; - } - ObligationCauseCode::ImplDerivedObligation( - box ImplDerivedObligationCause { - derived: - DerivedObligationCause { - parent_code, - parent_trait_pred, - }, - .. - }, - ) - | ObligationCauseCode::BuiltinDerivedObligation( - DerivedObligationCause { - parent_code, - parent_trait_pred, - }, - ) - | ObligationCauseCode::DerivedObligation( - DerivedObligationCause { - parent_code, - parent_trait_pred, - }, - ) => { - peeled = true; - code = &parent_code; - trait_pred = *parent_trait_pred; - } - _ => break, - }; + while let Some((parent_code, parent_trait_pred)) = code.parent() { + code = parent_code; + if let Some(parent_trait_pred) = parent_trait_pred { + trait_pred = parent_trait_pred; + peeled = true; + } } let def_id = trait_pred.def_id(); // Mention *all* the `impl`s for the *top most* obligation, the diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 9e9c230aebb..4263a6fdf18 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -45,7 +45,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| { let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id); - let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs); + let impl_trait_ref = tcx.bound_impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs); let impl_self_ty = impl_trait_ref.self_ty(); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index d20ba99ebc9..833e232e636 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1,6 +1,6 @@ use super::{ - DerivedObligationCause, EvaluationResult, ImplDerivedObligationCause, Obligation, - ObligationCause, ObligationCauseCode, PredicateObligation, SelectionContext, + EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, + SelectionContext, }; use crate::autoderef::Autoderef; @@ -623,28 +623,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let span = obligation.cause.span; let mut real_trait_pred = trait_pred; let mut code = obligation.cause.code(); - loop { - match &code { - ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => { - code = &parent_code; - } - ObligationCauseCode::ImplDerivedObligation(box ImplDerivedObligationCause { - derived: DerivedObligationCause { parent_code, parent_trait_pred }, - .. - }) - | ObligationCauseCode::BuiltinDerivedObligation(DerivedObligationCause { - parent_code, - parent_trait_pred, - }) - | ObligationCauseCode::DerivedObligation(DerivedObligationCause { - parent_code, - parent_trait_pred, - }) => { - code = &parent_code; - real_trait_pred = *parent_trait_pred; - } - _ => break, - }; + while let Some((parent_code, parent_trait_pred)) = code.parent() { + code = parent_code; + if let Some(parent_trait_pred) = parent_trait_pred { + real_trait_pred = parent_trait_pred; + } let Some(real_ty) = real_trait_pred.self_ty().no_bound_vars() else { continue; }; @@ -1669,7 +1652,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code); match code { ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => { - next_code = Some(parent_code.as_ref()); + next_code = Some(parent_code); } ObligationCauseCode::ImplDerivedObligation(cause) => { let ty = cause.derived.parent_trait_pred.skip_binder().self_ty(); @@ -1700,7 +1683,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => {} } - next_code = Some(cause.derived.parent_code.as_ref()); + next_code = Some(&cause.derived.parent_code); } ObligationCauseCode::DerivedObligation(derived_obligation) | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) => { @@ -1732,7 +1715,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => {} } - next_code = Some(derived_obligation.parent_code.as_ref()); + next_code = Some(&derived_obligation.parent_code); } _ => break, } @@ -2382,8 +2365,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) { false } else { - if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = - *data.parent_code + if let ObligationCauseCode::BuiltinDerivedObligation(data) = &*data.parent_code { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); @@ -2428,7 +2410,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err, &parent_predicate, param_env, - &cause_code.peel_derives(), + cause_code.peel_derives(), obligated_types, seen_requirements, ) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index e1b6ed92269..e3e384798d3 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -18,7 +18,7 @@ use rustc_errors::{FatalError, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor}; +use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_middle::ty::{Predicate, ToPredicate}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; @@ -531,7 +531,7 @@ fn receiver_for_self_ty<'tcx>( if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) } }); - let result = receiver_ty.subst(tcx, substs); + let result = EarlyBinder(receiver_ty).subst(tcx, substs); debug!( "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}", receiver_ty, self_ty, method_def_id, result diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index c266eec25aa..7d418198195 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -175,9 +175,7 @@ impl<'tcx> OnUnimplementedDirective { } pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> { - let attrs = tcx.get_attrs(item_def_id); - - let Some(attr) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else { + let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else { return Ok(None); }; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index be4d734b964..beaa56e1c1c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -31,7 +31,7 @@ use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder}; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; use std::collections::BTreeMap; @@ -515,7 +515,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } let substs = substs.super_fold_with(self); - let generic_ty = self.tcx().type_of(def_id); + let generic_ty = self.tcx().bound_type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.depth += 1; let folded_ty = self.fold_ty(concrete_ty); @@ -1276,8 +1276,8 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( // Check whether the self-type is itself a projection. // If so, extract what we know from the trait and try to come up with a good answer. let bounds = match *obligation.predicate.self_ty().kind() { - ty::Projection(ref data) => tcx.item_bounds(data.item_def_id).subst(tcx, data.substs), - ty::Opaque(def_id, substs) => tcx.item_bounds(def_id).subst(tcx, substs), + ty::Projection(ref data) => tcx.bound_item_bounds(data.item_def_id).subst(tcx, data.substs), + ty::Opaque(def_id, substs) => tcx.bound_item_bounds(def_id).subst(tcx, substs), ty::Infer(ty::TyVar(_)) => { // If the self-type is an inference variable, then it MAY wind up // being a projected type, so induce an ambiguity. @@ -2032,7 +2032,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( Progress { term: err.into(), obligations: nested } } else { assoc_ty_own_obligations(selcx, obligation, &mut nested); - Progress { term: term.subst(tcx, substs), obligations: nested } + Progress { term: EarlyBinder(term).subst(tcx, substs), obligations: nested } } } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index ed0ad5601aa..6a81a7764af 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -217,7 +217,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { self.infcx.report_overflow_error(&obligation, true); } - let generic_ty = self.tcx().type_of(def_id); + let generic_ty = self.tcx().bound_type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.anon_depth += 1; if concrete_ty == ty { diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 771a3072af5..d607f4e7642 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -12,22 +12,20 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, GenericParamDefKind, Ty}; +use rustc_middle::ty::{self, EarlyBinder, GenericParamDefKind, Ty}; use rustc_middle::ty::{ToPolyTraitRef, ToPredicate}; use rustc_span::def_id::DefId; use crate::traits::project::{normalize_with_depth, normalize_with_depth_to}; -use crate::traits::select::TraitObligationExt; use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def}; use crate::traits::{ - BuiltinDerivedObligation, DerivedObligationCause, ImplDerivedObligation, - ImplDerivedObligationCause, ImplSource, ImplSourceAutoImplData, ImplSourceBuiltinData, - ImplSourceClosureData, ImplSourceConstDestructData, ImplSourceDiscriminantKindData, - ImplSourceFnPointerData, ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, - ImplSourceTraitAliasData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, - ObjectCastObligation, Obligation, ObligationCause, OutputTypeParameterMismatch, - PredicateObligation, Selection, SelectionError, TraitNotObjectSafe, TraitObligation, - Unimplemented, VtblSegment, + BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource, + ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, + ImplSourceConstDestructData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, + ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData, + ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation, + Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, + SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented, VtblSegment, }; use super::BuiltinImplConditions; @@ -174,7 +172,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty), }; - let candidate_predicate = tcx.item_bounds(def_id)[idx].subst(tcx, substs); + let candidate_predicate = + tcx.bound_item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs); let candidate = candidate_predicate .to_opt_poly_trait_pred() .expect("projection candidate is not a trait predicate") @@ -500,7 +499,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This maybe belongs in wf, but that can't (doesn't) handle // higher-ranked things. // Prevent, e.g., `dyn Iterator<Item = str>`. - for bound in self.tcx().item_bounds(assoc_type) { + for bound in self.tcx().bound_item_bounds(assoc_type).transpose_iter() { let subst_bound = if defs.count() == 0 { bound.subst(tcx, trait_predicate.trait_ref.substs) @@ -509,9 +508,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { substs.extend(trait_predicate.trait_ref.substs.iter()); let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = smallvec::SmallVec::with_capacity( - bound.kind().bound_vars().len() + defs.count(), + bound.0.kind().bound_vars().len() + defs.count(), ); - bound_vars.extend(bound.kind().bound_vars().into_iter()); + bound_vars.extend(bound.0.kind().bound_vars().into_iter()); InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param .kind { @@ -558,7 +557,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let assoc_ty_substs = tcx.intern_substs(&substs); let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter()); - let bound = bound.kind().skip_binder().subst(tcx, assoc_ty_substs); + let bound = + EarlyBinder(bound.0.kind().skip_binder()).subst(tcx, assoc_ty_substs); tcx.mk_predicate(ty::Binder::bind_with_vars(bound, bound_vars)) }; let normalized_bound = normalize_with_depth_to( @@ -1005,10 +1005,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // The last field of the structure has to exist and contain type/const parameters. let (tail_field, prefix_fields) = def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?; - let tail_field_ty = tcx.type_of(tail_field.did); + let tail_field_ty = tcx.bound_type_of(tail_field.did); let mut unsizing_params = GrowableBitSet::new_empty(); - for arg in tail_field_ty.walk() { + for arg in tail_field_ty.0.walk() { if let Some(i) = maybe_unsizing_param_idx(arg) { unsizing_params.insert(i); } @@ -1126,21 +1126,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let substs = self.rematch_impl(impl_def_id, &new_obligation); debug!(?substs, "impl substs"); - let derived = DerivedObligationCause { - parent_trait_pred: obligation.predicate, - parent_code: obligation.cause.clone_code(), - }; - let derived_code = ImplDerivedObligation(Box::new(ImplDerivedObligationCause { - derived, - impl_def_id, - span: obligation.cause.span, - })); - - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - derived_code, - ); + let cause = obligation.derived_cause(|derived| { + ImplDerivedObligation(Box::new(ImplDerivedObligationCause { + derived, + impl_def_id, + span: obligation.cause.span, + })) + }); ensure_sufficient_stack(|| { self.vtable_impl( impl_def_id, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 6584d33032a..a1577a30c91 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -14,9 +14,9 @@ use super::util; use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; use super::wf; use super::{ - DerivedObligationCause, ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, - Normalized, Obligation, ObligationCause, ObligationCauseCode, Overflow, PredicateObligation, - Selection, SelectionError, SelectionResult, TraitObligation, TraitQueryMode, + ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation, + ObligationCause, ObligationCauseCode, Overflow, PredicateObligation, Selection, SelectionError, + SelectionResult, TraitObligation, TraitQueryMode, }; use crate::infer::{InferCtxt, InferOk, TypeFreshener}; @@ -38,7 +38,7 @@ use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef}; -use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; +use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable}; use rustc_span::symbol::sym; @@ -1156,9 +1156,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let ImplCandidate(def_id) = candidate { if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) { if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes { - let attrs = tcx.get_attrs(def_id); - let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl); - let value = attr.and_then(|a| a.value_str()); + let value = tcx + .get_attr(def_id, sym::rustc_reservation_impl) + .and_then(|a| a.value_str()); if let Some(value) = value { debug!( "filter_reservation_impls: \ @@ -1341,7 +1341,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } }; - let bounds = tcx.item_bounds(def_id).subst(tcx, substs); + let bounds = tcx.bound_item_bounds(def_id).subst(tcx, substs); // The bounds returned by `item_bounds` may contain duplicates after // normalization, so try to deduplicate when possible to avoid @@ -1795,11 +1795,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Adt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here - Where( - obligation.predicate.rebind({ - sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect() - }), - ) + Where(obligation.predicate.rebind({ + sized_crit.iter().map(|ty| EarlyBinder(*ty).subst(self.tcx(), substs)).collect() + })) } ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None, @@ -1962,7 +1960,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - t.rebind(vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)]) + t.rebind(vec![self.tcx().bound_type_of(def_id).subst(self.tcx(), substs)]) } } } @@ -2068,12 +2066,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id: DefId, obligation: &TraitObligation<'tcx>, ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> { - let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); + let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap(); // Before we create the substitutions and everything, first // consider a "quick reject". This avoids creating more types // and so forth that we need to. - if self.fast_reject_trait_refs(obligation, &impl_trait_ref) { + if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) { return Err(()); } @@ -2316,23 +2314,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?predicates); assert_eq!(predicates.parent, None); let mut obligations = Vec::with_capacity(predicates.predicates.len()); - let parent_code = cause.clone_code(); for (predicate, span) in predicates.predicates { let span = *span; - let derived = - DerivedObligationCause { parent_trait_pred, parent_code: parent_code.clone() }; - let code = ImplDerivedObligation(Box::new(ImplDerivedObligationCause { - derived, - impl_def_id: def_id, - span, - })); - let cause = ObligationCause::new(cause.span, cause.body_id, code); + let cause = cause.clone().derived_cause(parent_trait_pred, |derived| { + ImplDerivedObligation(Box::new(ImplDerivedObligationCause { + derived, + impl_def_id: def_id, + span, + })) + }); let predicate = normalize_with_depth_to( self, param_env, cause.clone(), recursion_depth, - predicate.subst(tcx, substs), + EarlyBinder(*predicate).subst(tcx, substs), &mut obligations, ); obligations.push(Obligation { cause, recursion_depth, param_env, predicate }); @@ -2342,42 +2338,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } -trait TraitObligationExt<'tcx> { - fn derived_cause( - &self, - variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, - ) -> ObligationCause<'tcx>; -} - -impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> { - fn derived_cause( - &self, - variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, - ) -> ObligationCause<'tcx> { - /*! - * Creates a cause for obligations that are derived from - * `obligation` by a recursive search (e.g., for a builtin - * bound, or eventually a `auto trait Foo`). If `obligation` - * is itself a derived obligation, this is just a clone, but - * otherwise we create a "derived obligation" cause so as to - * keep track of the original root obligation for error - * reporting. - */ - - let obligation = self; - - // NOTE(flaper87): As of now, it keeps track of the whole error - // chain. Ideally, we should have a way to configure this either - // by using -Z verbose or just a CLI argument. - let derived_cause = DerivedObligationCause { - parent_trait_pred: obligation.predicate, - parent_code: obligation.cause.clone_code(), - }; - let derived_code = variant(derived_cause); - ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) - } -} - impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> { TraitObligationStackList::with(self) diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 49c8c56083f..bca1d15ada9 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -85,7 +85,7 @@ pub fn translate_substs<'a, 'tcx>( param_env, source_impl, source_substs, target_node ); let source_trait_ref = - infcx.tcx.impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs); + infcx.tcx.bound_impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs); // translate the Self and Param parts of the substitution, since those // vary across impls diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index d101f69096f..f2e31c068a0 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -6,7 +6,7 @@ use smallvec::SmallVec; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef}; -use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, EarlyBinder, ImplSubject, ToPredicate, Ty, TyCtxt, TypeFoldable}; use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; pub use rustc_infer::traits::{self, util::*}; @@ -201,7 +201,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( impl_substs: SubstsRef<'tcx>, ) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) { let subject = selcx.tcx().impl_subject(impl_def_id); - let subject = subject.subst(selcx.tcx(), impl_substs); + let subject = EarlyBinder(subject).subst(selcx.tcx(), impl_substs); let Normalized { value: subject, obligations: normalization_obligations1 } = super::normalize(selcx, param_env, ObligationCause::dummy(), subject); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index de0ade64247..0379b16334c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -294,30 +294,22 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); debug!("compute_trait_ref obligations {:?}", obligations); - let cause = self.cause(traits::MiscObligation); let param_env = self.param_env; let depth = self.recursion_depth; let item = self.item; - let extend = |obligation: traits::PredicateObligation<'tcx>| { - let mut cause = cause.clone(); - if let Some(parent_trait_pred) = obligation.predicate.to_opt_poly_trait_pred() { - let derived_cause = traits::DerivedObligationCause { + let extend = |traits::PredicateObligation { predicate, mut cause, .. }| { + if let Some(parent_trait_pred) = predicate.to_opt_poly_trait_pred() { + cause = cause.derived_cause( parent_trait_pred, - parent_code: obligation.cause.clone_code(), - }; - *cause.make_mut_code() = - traits::ObligationCauseCode::DerivedObligation(derived_cause); + traits::ObligationCauseCode::DerivedObligation, + ); } extend_cause_with_original_assoc_item_obligation( - tcx, - trait_ref, - item, - &mut cause, - obligation.predicate, + tcx, trait_ref, item, &mut cause, predicate, ); - traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate) + traits::Obligation::with_depth(cause, depth, param_env, predicate) }; if let Elaborate::All = elaborate { @@ -339,17 +331,17 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { }) .filter(|(_, arg)| !arg.has_escaping_bound_vars()) .map(|(i, arg)| { - let mut new_cause = cause.clone(); + let mut cause = traits::ObligationCause::misc(self.span, self.body_id); // The first subst is the self ty - use the correct span for it. if i == 0 { if let Some(hir::ItemKind::Impl(hir::Impl { self_ty, .. })) = item.map(|i| &i.kind) { - new_cause.span = self_ty.span; + cause.span = self_ty.span; } } traits::Obligation::with_depth( - new_cause, + cause, depth, param_env, ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx), @@ -575,7 +567,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // generators don't take arguments. } - ty::Closure(_, substs) => { + ty::Closure(did, substs) => { // Only check the upvar types for WF, not the rest // of the types within. This is needed because we // capture the signature and it may not be WF @@ -596,18 +588,26 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // probably always be WF, because it should be // shorthand for something like `where(T: 'a) { // fn(&'a T) }`, as discussed in #25860. - // - // Note that we are also skipping the generic - // types. This is consistent with the `outlives` - // code, but anyway doesn't matter: within the fn + walker.skip_current_subtree(); // subtree handled below + // FIXME(eddyb) add the type to `walker` instead of recursing. + self.compute(substs.as_closure().tupled_upvars_ty().into()); + // Note that we cannot skip the generic types + // types. Normally, within the fn // body where they are created, the generics will // always be WF, and outside of that fn body we // are not directly inspecting closure types // anyway, except via auto trait matching (which // only inspects the upvar types). - walker.skip_current_subtree(); // subtree handled below - // FIXME(eddyb) add the type to `walker` instead of recursing. - self.compute(substs.as_closure().tupled_upvars_ty().into()); + // But when a closure is part of a type-alias-impl-trait + // then the function that created the defining site may + // have had more bounds available than the type alias + // specifies. This may cause us to have a closure in the + // hidden type that is not actually well formed and + // can cause compiler crashes when the user abuses unsafe + // code to procure such a closure. + // See src/test/ui/type-alias-impl-trait/wf_check_closures.rs + let obligations = self.nominal_obligations(did, substs); + self.out.extend(obligations); } ty::FnPtr(_) => { diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 6424b907478..5b5b8499191 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -8,7 +8,9 @@ use rustc_middle::traits::ChalkRustInterner as RustInterner; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, AssocItemContainer, AssocKind, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ + self, AssocItemContainer, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, +}; use rustc_ast::ast; use rustc_attr as attr; @@ -41,7 +43,7 @@ impl<'tcx> RustIrDatabase<'tcx> { let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates; predicates .iter() - .map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars)) + .map(|(wc, _)| EarlyBinder(*wc).subst(self.interner.tcx, bound_vars)) .filter_map(|wc| LowerInto::< Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> >::lower_into(wc, self.interner)).collect() @@ -55,7 +57,7 @@ impl<'tcx> RustIrDatabase<'tcx> { .tcx .explicit_item_bounds(def_id) .iter() - .map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars)) + .map(|(bound, _)| EarlyBinder(*bound).subst(self.interner.tcx, &bound_vars)) .filter_map(|bound| LowerInto::<Option<_>>::lower_into(bound, self.interner)) .collect() } @@ -272,15 +274,17 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars( self.interner, self.interner.tcx, - sig.inputs_and_output().subst(self.interner.tcx, bound_vars), + EarlyBinder(sig.inputs_and_output()).subst(self.interner.tcx, bound_vars), ); let argument_types = inputs_and_output[..inputs_and_output.len() - 1] .iter() - .map(|t| t.subst(self.interner.tcx, &bound_vars).lower_into(self.interner)) + .map(|t| { + EarlyBinder(*t).subst(self.interner.tcx, &bound_vars).lower_into(self.interner) + }) .collect(); - let return_type = inputs_and_output[inputs_and_output.len() - 1] + let return_type = EarlyBinder(inputs_and_output[inputs_and_output.len() - 1]) .subst(self.interner.tcx, &bound_vars) .lower_into(self.interner); @@ -306,7 +310,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(self.interner, bound_vars); - let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl"); + let trait_ref = self.interner.tcx.bound_impl_trait_ref(def_id).expect("not an impl"); let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars); let where_clauses = self.where_clauses_for(def_id, bound_vars); @@ -348,10 +352,10 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t let all_impls = self.interner.tcx.all_impls(def_id); let matched_impls = all_impls.filter(|impl_def_id| { use chalk_ir::could_match::CouldMatch; - let trait_ref = self.interner.tcx.impl_trait_ref(*impl_def_id).unwrap(); + let trait_ref = self.interner.tcx.bound_impl_trait_ref(*impl_def_id).unwrap(); let bound_vars = bound_vars_for_item(self.interner.tcx, *impl_def_id); - let self_ty = trait_ref.self_ty(); + let self_ty = trait_ref.map_bound(|t| t.self_ty()); let self_ty = self_ty.subst(self.interner.tcx, bound_vars); let lowered_ty = self_ty.lower_into(self.interner); @@ -463,7 +467,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t let ty = self .interner .tcx - .type_of(def_id) + .bound_type_of(def_id) .subst(self.interner.tcx, bound_vars) .lower_into(self.interner); @@ -506,7 +510,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t .tcx .explicit_item_bounds(opaque_ty_id.0) .iter() - .map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars)) + .map(|(bound, _)| EarlyBinder(*bound).subst(self.interner.tcx, &bound_vars)) .map(|bound| { bound.fold_with(&mut ReplaceOpaqueTyFolder { tcx: self.interner.tcx, diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index e4c22a35423..3fd0bb1814a 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -5,7 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives; use rustc_trait_selection::traits::query::dropck_outlives::{ @@ -271,9 +271,15 @@ fn dtorck_constraint_for_ty<'tcx>( tcx.at(span).adt_dtorck_constraint(def.did())?; // FIXME: we can try to recursively `dtorck_constraint_on_ty` // there, but that needs some way to handle cycles. - constraints.dtorck_types.extend(dtorck_types.iter().map(|t| t.subst(tcx, substs))); - constraints.outlives.extend(outlives.iter().map(|t| t.subst(tcx, substs))); - constraints.overflows.extend(overflows.iter().map(|t| t.subst(tcx, substs))); + constraints + .dtorck_types + .extend(dtorck_types.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); + constraints + .outlives + .extend(outlives.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); + constraints + .overflows + .extend(overflows.iter().map(|t| EarlyBinder(*t).subst(tcx, substs))); } // Objects must be alive in order for their destructor diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 6fcac9fcdc6..861d3bc564f 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -6,7 +6,9 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts}; -use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance}; +use rustc_middle::ty::{ + self, EarlyBinder, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance, +}; use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtBuilderExt; @@ -115,7 +117,7 @@ impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { where T: TypeFoldable<'tcx>, { - value.subst(self.tcx(), substs) + EarlyBinder(value).subst(self.tcx(), substs) } fn relate_mir_and_user_ty( diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index c5fc4e4c661..9ad44d14d61 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; use rustc_session::Limit; use rustc_span::{sym, DUMMY_SP}; @@ -204,7 +204,7 @@ fn drop_tys_helper<'tcx>( match subty.kind() { ty::Adt(adt_id, subst) => { for subty in tcx.adt_drop_tys(adt_id.did())? { - vec.push(subty.subst(tcx, subst)); + vec.push(EarlyBinder(subty).subst(tcx, subst)); } } _ => vec.push(subty), @@ -237,7 +237,7 @@ fn drop_tys_helper<'tcx>( Ok(Vec::new()) } else { let field_tys = adt_def.all_fields().map(|field| { - let r = tcx.type_of(field.did).subst(tcx, substs); + let r = tcx.bound_type_of(field.did).subst(tcx, substs); debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r); r }); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 6ad71bdb481..23700e653e3 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -2,7 +2,9 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{ + self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, +}; use rustc_span::{sym, Span}; use rustc_trait_selection::traits; @@ -33,7 +35,7 @@ fn sized_constraint_for_ty<'tcx>( debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys); adt_tys .iter() - .map(|ty| ty.subst(tcx, substs)) + .map(|ty| EarlyBinder(*ty).subst(tcx, substs)) .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty)) .collect() } @@ -442,7 +444,7 @@ pub fn conservative_is_privately_uninhabited_raw<'tcx>( // one uninhabited field. def.variants().iter().all(|var| { var.fields.iter().any(|field| { - let ty = tcx.type_of(field.did).subst(tcx, substs); + let ty = tcx.bound_type_of(field.did).subst(tcx, substs); tcx.conservative_is_privately_uninhabited(param_env.and(ty)) }) }) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index e940d065a99..2ff32bdf978 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -26,7 +26,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{GenericArg, GenericArgs}; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, Const, DefIdTree, EarlyBinder, Ty, TyCtxt, TypeFoldable}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS}; use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; @@ -523,7 +523,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.astconv .normalize_ty( self.span, - tcx.at(self.span).type_of(param.def_id).subst(tcx, substs), + EarlyBinder(tcx.at(self.span).type_of(param.def_id)) + .subst(tcx, substs), ) .into() } @@ -543,7 +544,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericParamDefKind::Const { has_default } => { let ty = tcx.at(self.span).type_of(param.def_id); if !infer_args && has_default { - tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into() + EarlyBinder(tcx.const_param_default(param.def_id)) + .subst(tcx, substs.unwrap()) + .into() } else { if infer_args { self.astconv.ct_infer(ty, Some(param), self.span).into() @@ -1292,7 +1295,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { item_segment: &hir::PathSegment<'_>, ) -> Ty<'tcx> { let substs = self.ast_path_substs_for_ty(span, did, item_segment); - self.normalize_ty(span, self.tcx().at(span).type_of(did).subst(self.tcx(), substs)) + self.normalize_ty( + span, + EarlyBinder(self.tcx().at(span).type_of(did)).subst(self.tcx(), substs), + ) } fn conv_object_ty_poly_trait_ref( @@ -2441,7 +2447,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { true, None, ); - self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs)) + EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id))) + .subst(tcx, substs) } hir::TyKind::Array(ref ty, ref length) => { let length = match length { @@ -2684,7 +2691,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_ref.def_id, )?; - let fn_sig = tcx.fn_sig(assoc.def_id).subst( + let fn_sig = tcx.bound_fn_sig(assoc.def_id).subst( tcx, trait_ref.substs.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)), ); diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 90b59df472c..0a84d41b4f3 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -339,7 +339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let (fn_sig, def_id) = match *callee_ty.kind() { ty::FnDef(def_id, subst) => { - let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, subst); + let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, subst); // Unit testing: function items annotated with // `#[rustc_evaluate_where_clauses]` trigger special output diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 4627b58c9bc..3e76738cc5d 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -171,7 +171,7 @@ pub(super) fn check_fn<'a, 'tcx>( let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); - Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()])) + Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()])) } else { None }; @@ -655,7 +655,7 @@ fn check_opaque_meets_bounds<'tcx>( span: Span, origin: &hir::OpaqueTyOrigin, ) { - let hidden_type = tcx.type_of(def_id).subst(tcx, substs); + let hidden_type = tcx.bound_type_of(def_id.to_def_id()).subst(tcx, substs); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let defining_use_anchor = match *origin { @@ -1056,9 +1056,7 @@ fn check_impl_items_against_trait<'tcx>( if let Some(missing_items) = must_implement_one_of { let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); let attr_span = tcx - .get_attrs(impl_trait_ref.def_id) - .iter() - .find(|attr| attr.has_name(sym::rustc_must_implement_one_of)) + .get_attr(impl_trait_ref.def_id, sym::rustc_must_implement_one_of) .map(|attr| attr.span); missing_items_must_implement_one_of_err(tcx, impl_span, missing_items, attr_span); @@ -1158,20 +1156,20 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { let repr = def.repr(); if repr.packed() { - for attr in tcx.get_attrs(def.did()).iter() { - for r in attr::find_repr_attrs(&tcx.sess, attr) { + for attr in tcx.get_attrs(def.did(), sym::repr) { + for r in attr::parse_repr_attr(&tcx.sess, attr) { if let attr::ReprPacked(pack) = r - && let Some(repr_pack) = repr.pack - && pack as u64 != repr_pack.bytes() - { - struct_span_err!( - tcx.sess, - sp, - E0634, - "type has conflicting packed representation hints" - ) - .emit(); - } + && let Some(repr_pack) = repr.pack + && pack as u64 != repr_pack.bytes() + { + struct_span_err!( + tcx.sess, + sp, + E0634, + "type has conflicting packed representation hints" + ) + .emit(); + } } } if repr.align.is_some() { @@ -1321,8 +1319,7 @@ fn check_enum<'tcx>( def.destructor(tcx); // force the destructor to be evaluated if vs.is_empty() { - let attributes = tcx.get_attrs(def_id.to_def_id()); - if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) { + if let Some(attr) = tcx.get_attr(def_id.to_def_id(), sym::repr) { struct_span_err!( tcx.sess, attr.span, diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 50e55bdc4af..c8fe0468736 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -175,19 +175,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) { match *expected_ty.kind() { ty::Opaque(def_id, substs) => { - let bounds = self.tcx.explicit_item_bounds(def_id); - let sig = bounds.iter().find_map(|(pred, span)| match pred.kind().skip_binder() { - ty::PredicateKind::Projection(proj_predicate) => self - .deduce_sig_from_projection( - Some(*span), - pred.kind().rebind(proj_predicate.subst(self.tcx, substs)), - ), - _ => None, - }); + let bounds = self.tcx.bound_explicit_item_bounds(def_id); + let sig = bounds + .transpose_iter() + .map(|e| e.map_bound(|e| *e).transpose_tuple2()) + .find_map(|(pred, span)| match pred.0.kind().skip_binder() { + ty::PredicateKind::Projection(proj_predicate) => self + .deduce_sig_from_projection( + Some(span.0), + pred.0.kind().rebind( + pred.map_bound(|_| proj_predicate).subst(self.tcx, substs), + ), + ), + _ => None, + }); let kind = bounds - .iter() - .filter_map(|(pred, _)| match pred.kind().skip_binder() { + .transpose_iter() + .map(|e| e.map_bound(|e| *e).transpose_tuple2()) + .filter_map(|(pred, _)| match pred.0.kind().skip_binder() { ty::PredicateKind::Trait(tp) => { self.tcx.fn_trait_kind_from_lang_item(tp.def_id()) } @@ -668,7 +674,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), }; - let item_bounds = self.tcx.explicit_item_bounds(def_id); + let item_bounds = self.tcx.bound_explicit_item_bounds(def_id); // Search for a pending obligation like // @@ -676,17 +682,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // where R is the return type we are expecting. This type `T` // will be our output. - let output_ty = item_bounds.iter().find_map(|&(predicate, span)| { - let bound_predicate = predicate.subst(self.tcx, substs).kind(); - if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() { - self.deduce_future_output_from_projection( - span, - bound_predicate.rebind(proj_predicate), - ) - } else { - None - } - }); + let output_ty = item_bounds + .transpose_iter() + .map(|e| e.map_bound(|e| *e).transpose_tuple2()) + .find_map(|(predicate, span)| { + let bound_predicate = predicate.subst(self.tcx, substs).kind(); + if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() + { + self.deduce_future_output_from_projection( + span.0, + bound_predicate.rebind(proj_predicate), + ) + } else { + None + } + }); debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty); output_ty diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index a83924d4636..b857679520b 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -265,9 +265,8 @@ fn compare_predicate_entailment<'tcx>( let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)); debug!("compare_impl_method: impl_fty={:?}", impl_fty); - // First liberate late bound regions and subst placeholders - let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id)); - let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs); + let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs); + let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig); let trait_sig = inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig); // Add the resulting inputs and output as well-formed. @@ -1066,7 +1065,7 @@ crate fn compare_const_impl<'tcx>( // Compute placeholder form of impl and trait const tys. let impl_ty = tcx.type_of(impl_c.def_id); - let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs); + let trait_ty = tcx.bound_type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs); let mut cause = ObligationCause::new( impl_c_span, impl_c_hir_id, @@ -1452,14 +1451,15 @@ pub fn check_type_bounds<'tcx>( }; let obligations = tcx - .explicit_item_bounds(trait_ty.def_id) - .iter() - .map(|&(bound, span)| { + .bound_explicit_item_bounds(trait_ty.def_id) + .transpose_iter() + .map(|e| e.map_bound(|e| *e).transpose_tuple2()) + .map(|(bound, span)| { debug!(?bound); let concrete_ty_bound = bound.subst(tcx, rebased_substs); debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); - traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound) + traits::Obligation::new(mk_cause(span.0), param_env, concrete_ty_bound) }) .collect(); debug!("check_type_bounds: item_bounds={:?}", obligations); diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index bfd2c32fd7e..ae4cebe866b 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -407,8 +407,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.has_only_self_parameter(m) && self .tcx - .get_attrs(m.def_id) - .iter() // This special internal attribute is used to permit // "identity-like" conversion methods to be suggested here. // @@ -419,7 +417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // FIXME? Other potential candidate methods: `as_ref` and // `as_mut`? - .any(|a| a.has_name(sym::rustc_conversion_suggestion)) + .has_attr(m.def_id, sym::rustc_conversion_suggestion) }); methods diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs index 3bc92166543..9caa4a40df7 100644 --- a/compiler/rustc_typeck/src/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -8,7 +8,7 @@ use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::{Subst, SubstsRef}; -use rustc_middle::ty::{self, Predicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, Predicate, Ty, TyCtxt}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::query::dropck_outlives::AtExt; @@ -84,7 +84,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( let drop_impl_span = tcx.def_span(drop_impl_did); let fresh_impl_substs = infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did.to_def_id()); - let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs); + let fresh_impl_self_ty = EarlyBinder(drop_impl_ty).subst(tcx, fresh_impl_substs); let cause = &ObligationCause::misc(drop_impl_span, drop_impl_hir_id); match infcx.at(cause, impl_param_env).eq(named_type, fresh_impl_self_ty) { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index d824c1d7cf2..501ce31557d 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -23,8 +23,8 @@ use rustc_middle::ty::subst::{ self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts, }; use rustc_middle::ty::{ - self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, ToPolyTraitRef, ToPredicate, - Ty, UserType, + self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPolyTraitRef, + ToPredicate, Ty, UserType, }; use rustc_session::lint; use rustc_span::hygiene::DesugaringKind; @@ -347,7 +347,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { T: TypeFoldable<'tcx>, { debug!("instantiate_type_scheme(value={:?}, substs={:?})", value, substs); - let value = value.subst(self.tcx, substs); + let value = EarlyBinder(value).subst(self.tcx, substs); let result = self.normalize_associated_types_in(span, value); debug!("instantiate_type_scheme = {:?}", result); result @@ -838,9 +838,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let def_kind = self.tcx.def_kind(def_id); let item_ty = if let DefKind::Variant = def_kind { - self.tcx.type_of(self.tcx.parent(def_id)) + self.tcx.bound_type_of(self.tcx.parent(def_id)) } else { - self.tcx.type_of(def_id) + self.tcx.bound_type_of(def_id) }; let substs = self.infcx.fresh_substs_for_item(span, def_id); let ty = item_ty.subst(self.tcx, substs); @@ -1044,8 +1044,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let (sig, did, substs) = match (&expected.kind(), &found.kind()) { (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { - let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); - let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); + let sig1 = self.tcx.bound_fn_sig(*did1).subst(self.tcx, substs1); + let sig2 = self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2); if sig1 != sig2 { return; } @@ -1056,7 +1056,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (sig1, *did1, substs1) } (ty::FnDef(did, substs), ty::FnPtr(sig2)) => { - let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs); + let sig1 = self.tcx.bound_fn_sig(*did).subst(self.tcx, substs); if sig1 != *sig2 { return; } @@ -1401,7 +1401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If we have a default, then we it doesn't matter that we're not // inferring the type arguments: we provide the default where any // is missing. - let default = tcx.type_of(param.def_id); + let default = tcx.bound_type_of(param.def_id); self.fcx .normalize_ty(self.span, default.subst(tcx, substs.unwrap())) .into() @@ -1415,7 +1415,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } GenericParamDefKind::Const { has_default } => { if !infer_args && has_default { - tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into() + EarlyBinder(tcx.const_param_default(param.def_id)) + .subst(tcx, substs.unwrap()) + .into() } else { self.fcx.var_for_def(self.span, param) } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 847c2c32dba..54003654db0 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -12,7 +12,6 @@ use crate::check::{ use crate::structured_errors::StructuredDiagnostic; use rustc_ast as ast; -use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic, DiagnosticId, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -1596,24 +1595,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Peel derived obligation, because it's the type that originally // started this inference chain that matters, not the one we wound // up with at the end. - fn unpeel_to_top( - mut code: Lrc<ObligationCauseCode<'_>>, - ) -> Lrc<ObligationCauseCode<'_>> { - let mut result_code = code.clone(); + fn unpeel_to_top<'a, 'tcx>( + mut code: &'a ObligationCauseCode<'tcx>, + ) -> &'a ObligationCauseCode<'tcx> { + let mut result_code = code; loop { - let parent = match &*code { - ObligationCauseCode::ImplDerivedObligation(c) => { - c.derived.parent_code.clone() - } + let parent = match code { + ObligationCauseCode::ImplDerivedObligation(c) => &c.derived.parent_code, ObligationCauseCode::BuiltinDerivedObligation(c) - | ObligationCauseCode::DerivedObligation(c) => c.parent_code.clone(), - _ => break, + | ObligationCauseCode::DerivedObligation(c) => &c.parent_code, + _ => break result_code, }; - result_code = std::mem::replace(&mut code, parent); + (result_code, code) = (code, parent); } - result_code } - let self_: ty::subst::GenericArg<'_> = match &*unpeel_to_top(error.obligation.cause.clone_code()) { + let self_: ty::subst::GenericArg<'_> = match unpeel_to_top(error.obligation.cause.code()) { ObligationCauseCode::BuiltinDerivedObligation(code) | ObligationCauseCode::DerivedObligation(code) => { code.parent_trait_pred.self_ty().skip_binder().into() @@ -1663,13 +1659,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We make sure that only *one* argument matches the obligation failure // and we assign the obligation's span to its expression's. error.obligation.cause.span = args[ref_in].span; - let parent_code = error.obligation.cause.clone_code(); - *error.obligation.cause.make_mut_code() = + error.obligation.cause.map_code(|parent_code| { ObligationCauseCode::FunctionArgumentObligation { arg_hir_id: args[ref_in].hir_id, call_hir_id: expr.hir_id, parent_code, - }; + } + }); } else if error.obligation.cause.span == call_sp { // Make function calls point at the callee, not the whole thing. if let hir::ExprKind::Call(callee, _) = expr.kind { diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 15edc11a497..be389f0e3f5 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -609,44 +609,43 @@ fn check_must_not_suspend_def( hir_id: HirId, data: SuspendCheckData<'_, '_>, ) -> bool { - for attr in tcx.get_attrs(def_id).iter() { - if attr.has_name(sym::must_not_suspend) { - tcx.struct_span_lint_hir( - rustc_session::lint::builtin::MUST_NOT_SUSPEND, - hir_id, - data.source_span, - |lint| { - let msg = format!( - "{}`{}`{} held across a suspend point, but should not be", - data.descr_pre, - tcx.def_path_str(def_id), - data.descr_post, - ); - let mut err = lint.build(&msg); + if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) { + tcx.struct_span_lint_hir( + rustc_session::lint::builtin::MUST_NOT_SUSPEND, + hir_id, + data.source_span, + |lint| { + let msg = format!( + "{}`{}`{} held across a suspend point, but should not be", + data.descr_pre, + tcx.def_path_str(def_id), + data.descr_post, + ); + let mut err = lint.build(&msg); - // add span pointing to the offending yield/await - err.span_label(data.yield_span, "the value is held across this suspend point"); + // add span pointing to the offending yield/await + err.span_label(data.yield_span, "the value is held across this suspend point"); - // Add optional reason note - if let Some(note) = attr.value_str() { - // FIXME(guswynn): consider formatting this better - err.span_note(data.source_span, note.as_str()); - } + // Add optional reason note + if let Some(note) = attr.value_str() { + // FIXME(guswynn): consider formatting this better + err.span_note(data.source_span, note.as_str()); + } - // Add some quick suggestions on what to do - // FIXME: can `drop` work as a suggestion here as well? - err.span_help( - data.source_span, - "consider using a block (`{ ... }`) \ - to shrink the value's scope, ending before the suspend point", - ); + // Add some quick suggestions on what to do + // FIXME: can `drop` work as a suggestion here as well? + err.span_help( + data.source_span, + "consider using a block (`{ ... }`) \ + to shrink the value's scope, ending before the suspend point", + ); - err.emit(); - }, - ); + err.emit(); + }, + ); - return true; - } + true + } else { + false } - false } diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs index 928daba0a7b..e89a8961996 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs @@ -180,6 +180,15 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> { diag_expr_id: HirId, ) { debug!("mutate {assignee_place:?}; diag_expr_id={diag_expr_id:?}"); + + if assignee_place.place.base == PlaceBase::Rvalue + && assignee_place.place.projections.is_empty() + { + // Assigning to an Rvalue is illegal unless done through a dereference. We would have + // already gotten a type error, so we will just return here. + return; + } + // If the type being assigned needs dropped, then the mutation counts as a borrow // since it is essentially doing `Drop::drop(&mut x); x = new_value;`. if assignee_place.place.base_ty.needs_drop(self.tcx, self.param_env) { diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index b67185e5211..7fe710cf8f4 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -129,7 +129,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ty::INNERMOST, ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrEnv }, )); - let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]); + let va_list_ty = tcx.bound_type_of(did).subst(tcx, &[region.into()]); (tcx.mk_ref(env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty) }) }; diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index 1b619776b85..7992460f546 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -460,7 +460,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { debug!("method_predicates after subst = {:?}", method_predicates); - let sig = self.tcx.fn_sig(def_id); + let sig = self.tcx.bound_fn_sig(def_id); let sig = sig.subst(self.tcx, all_substs); debug!("type scheme substituted, sig={:?}", sig); diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 1dd5e45fdc1..cb359434fdb 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -460,7 +460,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // N.B., instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let fn_sig = tcx.fn_sig(def_id); + let fn_sig = tcx.bound_fn_sig(def_id); let fn_sig = fn_sig.subst(self.tcx, substs); let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0; diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index c28ab9fa1ee..0861d121a1f 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -21,7 +21,7 @@ use rustc_middle::middle::stability; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::lev_distance::{ @@ -711,7 +711,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); - let impl_ty = impl_ty.subst(self.tcx, impl_substs); + let impl_ty = EarlyBinder(impl_ty).subst(self.tcx, impl_substs); debug!("impl_ty: {:?}", impl_ty); @@ -901,7 +901,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ) -> bool { match method.kind { ty::AssocKind::Fn => { - let fty = self.tcx.fn_sig(method.def_id); + let fty = self.tcx.bound_fn_sig(method.def_id); self.probe(|_| { let substs = self.fresh_substs_for_item(self.span, method.def_id); let fty = fty.subst(self.tcx, substs); @@ -1771,7 +1771,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> { - let fn_sig = self.tcx.fn_sig(method); + let fn_sig = self.tcx.bound_fn_sig(method); debug!(?fn_sig); assert!(!substs.has_escaping_bound_vars()); diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 829485367e0..50966868ec7 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -21,7 +21,8 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ - self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor, + self, AdtKind, EarlyBinder, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, + TypeVisitor, }; use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -1388,7 +1389,7 @@ fn check_where_clauses<'tcx, 'fcx>( } let mut param_count = CountParams::default(); let has_region = pred.visit_with(&mut param_count).is_break(); - let substituted_pred = pred.subst(tcx, substs); + let substituted_pred = EarlyBinder(pred).subst(tcx, substs); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. if substituted_pred.has_param_types_or_consts() diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs index 1310467aeb9..00f0d1e6f02 100644 --- a/compiler/rustc_typeck/src/check_unused.rs +++ b/compiler/rustc_typeck/src/check_unused.rs @@ -128,7 +128,8 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { tcx.struct_span_lint_hir(lint, id, span, |lint| { // Removal suggestion span needs to include attributes (Issue #54400) let span_with_attrs = tcx - .get_attrs(extern_crate.def_id) + .hir() + .attrs(id) .iter() .map(|attr| attr.span) .fold(span, |acc, attr_span| acc.to(attr_span)); @@ -166,13 +167,13 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { continue; } + let id = tcx.hir().local_def_id_to_hir_id(def_id); // If the extern crate has any attributes, they may have funky // semantics we can't faithfully represent using `use` (most // notably `#[macro_use]`). Ignore it. - if !tcx.get_attrs(extern_crate.def_id).is_empty() { + if !tcx.hir().attrs(id).is_empty() { continue; } - let id = tcx.hir().local_def_id_to_hir_id(def_id); tcx.struct_span_lint_hir(lint, id, extern_crate.span, |lint| { // Otherwise, we can convert it into a `use` of some kind. let base_replacement = match extern_crate.orig_name { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 2e0e026631b..29134bd168c 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -59,10 +59,7 @@ struct OnlySelfBounds(bool); // Main entry point fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module( - module_def_id, - &mut CollectItemTypesVisitor { tcx }.as_deep_visitor(), - ); + tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx }); } pub fn provide(providers: &mut Providers) { @@ -1200,9 +1197,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { ty::trait_def::TraitSpecializationKind::None }; let must_implement_one_of = tcx - .get_attrs(def_id) - .iter() - .find(|attr| attr.has_name(sym::rustc_must_implement_one_of)) + .get_attr(def_id, sym::rustc_must_implement_one_of) // Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]` // and that they are all identifiers .and_then(|attr| match attr.meta_item_list() { diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index fe285820ba6..67c6e791bfe 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -298,17 +298,12 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { error = true; } - for attr in tcx.get_attrs(main_def_id) { - if attr.has_name(sym::track_caller) { - tcx.sess - .struct_span_err( - attr.span, - "`main` function is not allowed to be `#[track_caller]`", - ) - .span_label(main_span, "`main` function is not allowed to be `#[track_caller]`") - .emit(); - error = true; - } + for attr in tcx.get_attrs(main_def_id, sym::track_caller) { + tcx.sess + .struct_span_err(attr.span, "`main` function is not allowed to be `#[track_caller]`") + .span_label(main_span, "`main` function is not allowed to be `#[track_caller]`") + .emit(); + error = true; } if error { diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs index 13d22b13ed4..52f9e386441 100644 --- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs +++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; use rustc_span::Span; use super::explicit::ExplicitPredicatesMap; @@ -137,7 +137,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( // `unsubstituted_predicate` is `U: 'b` in the // example above. So apply the substitution to // get `T: 'a` (or `predicate`): - let predicate = unsubstituted_predicate.subst(tcx, substs); + let predicate = EarlyBinder(*unsubstituted_predicate).subst(tcx, substs); insert_outlives_predicate( tcx, predicate.0, @@ -287,7 +287,7 @@ pub fn check_explicit_predicates<'tcx>( continue; } - let predicate = outlives_predicate.subst(tcx, substs); + let predicate = EarlyBinder(*outlives_predicate).subst(tcx, substs); debug!("predicate = {:?}", &predicate); insert_outlives_predicate(tcx, predicate.0, predicate.1, span, required_predicates); } diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 39f8f1d5a0e..6162b5c6d4c 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -387,7 +387,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! { #[cfg(all(not(no_global_oom_handling), test))] pub use std::alloc::handle_alloc_error; -#[cfg(all(not(no_global_oom_handling), not(any(target_os = "hermit", test))))] +#[cfg(all(not(no_global_oom_handling), not(test)))] #[doc(hidden)] #[allow(unused_attributes)] #[unstable(feature = "alloc_internals", issue = "none")] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 9dbac3c36ff..4be5f6cf9ca 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -118,7 +118,6 @@ impl<T, A: Allocator> RawVec<T, A> { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. - #[rustc_allow_const_fn_unstable(const_fn)] pub const fn new_in(alloc: A) -> Self { // `cap: 0` means "unallocated". zero-sized types are ignored. Self { ptr: Unique::dangling(), cap: 0, alloc } diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 8839a69d119..887246c6001 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -208,11 +208,9 @@ pub unsafe trait GlobalAlloc { /// /// If this returns a non-null pointer, then ownership of the memory block /// referenced by `ptr` has been transferred to this allocator. - /// The memory may or may not have been deallocated, - /// and should be considered unusable (unless of course it was - /// transferred back to the caller again via the return value of - /// this method). The new memory block is allocated with `layout`, but - /// with the `size` updated to `new_size`. This new layout should be + /// The memory may or may not have been deallocated, and should be + /// considered unusable. The new memory block is allocated with `layout`, + /// but with the `size` updated to `new_size`. This new layout should be /// used when deallocating the new memory block with `dealloc`. The range /// `0..min(layout.size(), new_size)` of the new memory block is /// guaranteed to have the same values as the original block. diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index a034562d13a..6cc6e359e65 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -161,8 +161,7 @@ pub unsafe trait Allocator { /// /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// transferred to this allocator. The memory may or may not have been freed, and should be - /// considered unusable unless it was transferred back to the caller again via the return value - /// of this method. + /// considered unusable. /// /// If this method returns `Err`, then ownership of the memory block has not been transferred to /// this allocator, and the contents of the memory block are unaltered. @@ -288,8 +287,7 @@ pub unsafe trait Allocator { /// /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// transferred to this allocator. The memory may or may not have been freed, and should be - /// considered unusable unless it was transferred back to the caller again via the return value - /// of this method. + /// considered unusable. /// /// If this method returns `Err`, then ownership of the memory block has not been transferred to /// this allocator, and the contents of the memory block are unaltered. diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 5cecc4086d8..f4885ed9ffb 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -266,7 +266,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> { Fold: FnMut(Acc, Self::Item) -> Acc, { let data = &mut self.data; - self.alive.by_ref().fold(init, |acc, idx| { + iter::ByRefSized(&mut self.alive).fold(init, |acc, idx| { // SAFETY: idx is obtained by folding over the `alive` range, which implies the // value is currently considered alive but as the range is being consumed each value // we read here will only be read once and then considered dead. @@ -323,6 +323,20 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> { }) } + #[inline] + fn rfold<Acc, Fold>(mut self, init: Acc, mut rfold: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + let data = &mut self.data; + iter::ByRefSized(&mut self.alive).rfold(init, |acc, idx| { + // SAFETY: idx is obtained by folding over the `alive` range, which implies the + // value is currently considered alive but as the range is being consumed each value + // we read here will only be read once and then considered dead. + rfold(acc, unsafe { data.get_unchecked(idx).assume_init_read() }) + }) + } + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { let len = self.len(); diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 58ea109c735..7ae1bfd4f35 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -5,27 +5,78 @@ use crate::intrinsics; -/// Informs the compiler that this point in the code is not reachable, enabling -/// further optimizations. +/// Informs the compiler that the site which is calling this function is not +/// reachable, possibly enabling further optimizations. /// /// # Safety /// -/// Reaching this function is completely *undefined behavior* (UB). In -/// particular, the compiler assumes that all UB must never happen, and -/// therefore will eliminate all branches that reach to a call to -/// `unreachable_unchecked()`. +/// Reaching this function is *Undefined Behavior*. /// -/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the -/// `unreachable_unchecked()` call is actually reachable among all possible -/// control flow, the compiler will apply the wrong optimization strategy, and -/// may sometimes even corrupt seemingly unrelated code, causing -/// difficult-to-debug problems. +/// As the compiler assumes that all forms of Undefined Behavior can never +/// happen, it will eliminate all branches in the surrounding code that it can +/// determine will invariably lead to a call to `unreachable_unchecked()`. /// -/// Use this function only when you can prove that the code will never call it. -/// Otherwise, consider using the [`unreachable!`] macro, which does not allow -/// optimizations but will panic when executed. +/// If the assumptions embedded in using this function turn out to be wrong - +/// that is, if the site which is calling `unreachable_unchecked()` is actually +/// reachable at runtime - the compiler may have generated nonsensical machine +/// instructions for this situation, including in seemingly unrelated code, +/// causing difficult-to-debug problems. /// -/// # Example +/// Use this function sparingly. Consider using the [`unreachable!`] macro, +/// which may prevent some optimizations but will safely panic in case it is +/// actually reached at runtime. Benchmark your code to find out if using +/// `unreachable_unchecked()` comes with a performance benefit. +/// +/// # Examples +/// +/// `unreachable_unchecked()` can be used in situations where the compiler +/// can't prove invariants that were previously established. Such situations +/// have a higher chance of occuring if those invariants are upheld by +/// external code that the compiler can't analyze. +/// ``` +/// fn prepare_inputs(divisors: &mut Vec<u32>) { +/// // Note to future-self when making changes: The invariant established +/// // here is NOT checked in `do_computation()`; if this changes, you HAVE +/// // to change `do_computation()`. +/// divisors.retain(|divisor| *divisor != 0) +/// } +/// +/// /// # Safety +/// /// All elements of `divisor` must be non-zero. +/// unsafe fn do_computation(i: u32, divisors: &[u32]) -> u32 { +/// divisors.iter().fold(i, |acc, divisor| { +/// // Convince the compiler that a division by zero can't happen here +/// // and a check is not needed below. +/// if *divisor == 0 { +/// // Safety: `divisor` can't be zero because of `prepare_inputs`, +/// // but the compiler does not know about this. We *promise* +/// // that we always call `prepare_inputs`. +/// std::hint::unreachable_unchecked() +/// } +/// // The compiler would normally introduce a check here that prevents +/// // a division by zero. However, if `divisor` was zero, the branch +/// // above would reach what we explicitly marked as unreachable. +/// // The compiler concludes that `divisor` can't be zero at this point +/// // and removes the - now proven useless - check. +/// acc / divisor +/// }) +/// } +/// +/// let mut divisors = vec![2, 0, 4]; +/// prepare_inputs(&mut divisors); +/// let result = unsafe { +/// // Safety: prepare_inputs() guarantees that divisors is non-zero +/// do_computation(100, &divisors) +/// }; +/// assert_eq!(result, 12); +/// +/// ``` +/// +/// While using `unreachable_unchecked()` is perfectly sound in the following +/// example, the compiler is able to prove that a division by zero is not +/// possible. Benchmarking reveals that `unreachable_unchecked()` provides +/// no benefit over using [`unreachable!`], while the latter does not introduce +/// the possibility of Undefined Behavior. /// /// ``` /// fn div_1(a: u32, b: u32) -> u32 { diff --git a/library/core/src/iter/adapters/by_ref_sized.rs b/library/core/src/iter/adapters/by_ref_sized.rs index 0b5e2a89ef3..bf2e3e182e2 100644 --- a/library/core/src/iter/adapters/by_ref_sized.rs +++ b/library/core/src/iter/adapters/by_ref_sized.rs @@ -9,22 +9,27 @@ pub(crate) struct ByRefSized<'a, I>(pub &'a mut I); impl<I: Iterator> Iterator for ByRefSized<'_, I> { type Item = I::Item; + #[inline] fn next(&mut self) -> Option<Self::Item> { self.0.next() } + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() } + #[inline] fn advance_by(&mut self, n: usize) -> Result<(), usize> { self.0.advance_by(n) } + #[inline] fn nth(&mut self, n: usize) -> Option<Self::Item> { self.0.nth(n) } + #[inline] fn fold<B, F>(self, init: B, f: F) -> B where F: FnMut(B, Self::Item) -> B, @@ -32,6 +37,7 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> { self.0.fold(init, f) } + #[inline] fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R where F: FnMut(B, Self::Item) -> R, @@ -40,3 +46,37 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> { self.0.try_fold(init, f) } } + +impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> { + #[inline] + fn next_back(&mut self) -> Option<Self::Item> { + self.0.next_back() + } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.0.advance_back_by(n) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<Self::Item> { + self.0.nth_back(n) + } + + #[inline] + fn rfold<B, F>(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.0.rfold(init, f) + } + + #[inline] + fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + self.0.try_rfold(init, f) + } +} diff --git a/library/core/src/num/dec2flt/common.rs b/library/core/src/num/dec2flt/common.rs index 247123737df..17957d7e770 100644 --- a/library/core/src/num/dec2flt/common.rs +++ b/library/core/src/num/dec2flt/common.rs @@ -36,7 +36,7 @@ pub(crate) trait ByteSlice: AsRef<[u8]> { } /// Check if self starts with u with a case-insensitive comparison. - fn eq_ignore_case(&self, u: &[u8]) -> bool { + fn starts_with_ignore_case(&self, u: &[u8]) -> bool { debug_assert!(self.as_ref().len() >= u.len()); let iter = self.as_ref().iter().zip(u.iter()); let d = iter.fold(0, |i, (&x, &y)| i | (x ^ y)); diff --git a/library/core/src/num/dec2flt/parse.rs b/library/core/src/num/dec2flt/parse.rs index fa677bf5123..1a90e0d206f 100644 --- a/library/core/src/num/dec2flt/parse.rs +++ b/library/core/src/num/dec2flt/parse.rs @@ -207,12 +207,12 @@ pub fn parse_number(s: &[u8], negative: bool) -> Option<Number> { /// Parse a partial representation of a special, non-finite float. fn parse_partial_inf_nan<F: RawFloat>(s: &[u8]) -> Option<(F, usize)> { fn parse_inf_rest(s: &[u8]) -> usize { - if s.len() >= 8 && s[3..].as_ref().eq_ignore_case(b"inity") { 8 } else { 3 } + if s.len() >= 8 && s[3..].as_ref().starts_with_ignore_case(b"inity") { 8 } else { 3 } } if s.len() >= 3 { - if s.eq_ignore_case(b"nan") { + if s.starts_with_ignore_case(b"nan") { return Some((F::NAN, 3)); - } else if s.eq_ignore_case(b"inf") { + } else if s.starts_with_ignore_case(b"inf") { return Some((F::INFINITY, parse_inf_rest(s))); } } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index a98b5d787f1..70969edd6ea 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -52,7 +52,6 @@ macro_rules! nonzero_integers { #[$const_new_unchecked_stability] #[must_use] #[inline] - #[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)] // required by assert_unsafe_precondition pub const unsafe fn new_unchecked(n: $Int) -> Self { // SAFETY: this is guaranteed to be safe by the caller. unsafe { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index f339b076dd7..d0746698f40 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1486,7 +1486,6 @@ impl<T> Option<T> { where T: ~const Default, { - #[rustc_allow_const_fn_unstable(const_fn_trait_bound)] const fn default<T: ~const Default>() -> T { T::default() } diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 27af227a1f2..413fe7e6cc4 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -147,7 +147,6 @@ impl RawWakerVTable { #[rustc_promotable] #[stable(feature = "futures_api", since = "1.36.0")] #[rustc_const_stable(feature = "futures_api", since = "1.36.0")] - #[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)] pub const fn new( clone: unsafe fn(*const ()) -> RawWaker, wake: unsafe fn(*const ()), diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index a778779c0fd..ee7ff012ec1 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs @@ -668,3 +668,35 @@ fn array_mixed_equality_nans() { assert!(!(mut3 == array3)); assert!(mut3 != array3); } + +#[test] +fn array_into_iter_fold() { + // Strings to help MIRI catch if we double-free or something + let a = ["Aa".to_string(), "Bb".to_string(), "Cc".to_string()]; + let mut s = "s".to_string(); + a.into_iter().for_each(|b| s += &b); + assert_eq!(s, "sAaBbCc"); + + let a = [1, 2, 3, 4, 5, 6]; + let mut it = a.into_iter(); + it.advance_by(1).unwrap(); + it.advance_back_by(2).unwrap(); + let s = it.fold(10, |a, b| 10 * a + b); + assert_eq!(s, 10234); +} + +#[test] +fn array_into_iter_rfold() { + // Strings to help MIRI catch if we double-free or something + let a = ["Aa".to_string(), "Bb".to_string(), "Cc".to_string()]; + let mut s = "s".to_string(); + a.into_iter().rev().for_each(|b| s += &b); + assert_eq!(s, "sCcBbAa"); + + let a = [1, 2, 3, 4, 5, 6]; + let mut it = a.into_iter(); + it.advance_by(1).unwrap(); + it.advance_back_by(2).unwrap(); + let s = it.rfold(10, |a, b| 10 * a + b); + assert_eq!(s, 10432); +} diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index cf51d8da16d..cdb2bac2607 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -416,7 +416,6 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>( } impl Client<fn(crate::TokenStream) -> crate::TokenStream> { - #[rustc_allow_const_fn_unstable(const_fn)] pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self { extern "C" fn run( bridge: Bridge<'_>, @@ -429,7 +428,6 @@ impl Client<fn(crate::TokenStream) -> crate::TokenStream> { } impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> { - #[rustc_allow_const_fn_unstable(const_fn)] pub const fn expand2( f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, ) -> Self { @@ -474,7 +472,6 @@ impl ProcMacro { } } - #[rustc_allow_const_fn_unstable(const_fn)] pub const fn custom_derive( trait_name: &'static str, attributes: &'static [&'static str], @@ -483,7 +480,6 @@ impl ProcMacro { ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } } - #[rustc_allow_const_fn_unstable(const_fn)] pub const fn attr( name: &'static str, expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, @@ -491,7 +487,6 @@ impl ProcMacro { ProcMacro::Attr { name, client: Client::expand2(expand) } } - #[rustc_allow_const_fn_unstable(const_fn)] pub const fn bang( name: &'static str, expand: fn(crate::TokenStream) -> crate::TokenStream, diff --git a/library/proc_macro/src/bridge/scoped_cell.rs b/library/proc_macro/src/bridge/scoped_cell.rs index e1307856175..2cde1f65adf 100644 --- a/library/proc_macro/src/bridge/scoped_cell.rs +++ b/library/proc_macro/src/bridge/scoped_cell.rs @@ -35,7 +35,6 @@ impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { pub struct ScopedCell<T: LambdaL>(Cell<<T as ApplyL<'static>>::Out>); impl<T: LambdaL> ScopedCell<T> { - #[rustc_allow_const_fn_unstable(const_fn)] pub const fn new(value: <T as ApplyL<'static>>::Out) -> Self { ScopedCell(Cell::new(value)) } diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index bfc5ce01564..53433823fbd 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -32,6 +32,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; // 32-bit c_int. Below is -2, in two's complement, but that only works out // because c_int is 32 bits. #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +#[rustc_nonnull_optimization_guaranteed] #[unstable(feature = "io_safety", issue = "87074")] pub struct BorrowedFd<'fd> { fd: RawFd, @@ -52,6 +53,7 @@ pub struct BorrowedFd<'fd> { // 32-bit c_int. Below is -2, in two's complement, but that only works out // because c_int is 32 bits. #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +#[rustc_nonnull_optimization_guaranteed] #[unstable(feature = "io_safety", issue = "87074")] pub struct OwnedFd { fd: RawFd, diff --git a/library/std/src/os/fd/tests.rs b/library/std/src/os/fd/tests.rs index 26ef93e3d71..b39863644f1 100644 --- a/library/std/src/os/fd/tests.rs +++ b/library/std/src/os/fd/tests.rs @@ -32,3 +32,22 @@ fn test_fd() { assert_eq!(stdin_as_file.as_fd().as_raw_fd(), raw_fd); assert_eq!(Into::<OwnedFd>::into(stdin_as_file).into_raw_fd(), raw_fd); } + +#[cfg(any(unix, target_os = "wasi"))] +#[test] +fn test_niche_optimizations() { + use crate::mem::size_of; + #[cfg(unix)] + use crate::os::unix::io::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; + #[cfg(target_os = "wasi")] + use crate::os::wasi::io::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; + + assert_eq!(size_of::<Option<OwnedFd>>(), size_of::<RawFd>()); + assert_eq!(size_of::<Option<BorrowedFd<'static>>>(), size_of::<RawFd>()); + unsafe { + assert_eq!(OwnedFd::from_raw_fd(RawFd::MIN).into_raw_fd(), RawFd::MIN); + assert_eq!(OwnedFd::from_raw_fd(RawFd::MAX).into_raw_fd(), RawFd::MAX); + assert_eq!(Some(OwnedFd::from_raw_fd(RawFd::MIN)).unwrap().into_raw_fd(), RawFd::MIN); + assert_eq!(Some(OwnedFd::from_raw_fd(RawFd::MAX)).unwrap().into_raw_fd(), RawFd::MAX); + } +} diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 290b7f0d08a..0ecac6b4475 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -22,8 +22,10 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// so it can be used in FFI in places where a handle is passed as an argument, /// it is not captured or consumed. /// -/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is -/// sometimes a valid handle value. See [here] for the full story. +/// Note that it *may* have the value `-1`, which in `BorrowedHandle` always +/// represents a valid handle value, such as [the current process handle], and +/// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See +/// [here] for the full story. /// /// And, it *may* have the value `NULL` (0), which can occur when consoles are /// detached from processes, or when `windows_subsystem` is used. @@ -33,6 +35,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// handle, which is then borrowed under the same lifetime. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 +/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks #[derive(Copy, Clone)] #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] @@ -45,8 +48,10 @@ pub struct BorrowedHandle<'handle> { /// /// This closes the handle on drop. /// -/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is -/// sometimes a valid handle value. See [here] for the full story. +/// Note that it *may* have the value `-1`, which in `OwnedHandle` always +/// represents a valid handle value, such as [the current process handle], and +/// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See +/// [here] for the full story. /// /// And, it *may* have the value `NULL` (0), which can occur when consoles are /// detached from processes, or when `windows_subsystem` is used. @@ -59,6 +64,7 @@ pub struct BorrowedHandle<'handle> { /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 +/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] pub struct OwnedHandle { @@ -75,11 +81,13 @@ pub struct OwnedHandle { /// `NULL`. This ensures that such FFI calls cannot start using the handle without /// checking for `NULL` first. /// -/// This type considers any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`. -/// This is because APIs that use `NULL` as their sentry value don't treat `INVALID_HANDLE_VALUE` -/// as special. +/// This type may hold any handle value that [`OwnedHandle`] may hold. As with `OwnedHandle`, when +/// it holds `-1`, that value is interpreted as a valid handle value, such as +/// [the current process handle], and not `INVALID_HANDLE_VALUE`. /// -/// If this holds a valid handle, it will close the handle on drop. +/// If this holds a non-null handle, it will close the handle on drop. +/// +/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] #[derive(Debug)] @@ -95,11 +103,10 @@ pub struct HandleOrNull(OwnedHandle); /// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without /// checking for `INVALID_HANDLE_VALUE` first. /// -/// This type considers any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`. -/// This is because APIs that use `INVALID_HANDLE_VALUE` as their sentry value may return `NULL` -/// under `windows_subsystem = "windows"` or other situations where I/O devices are detached. +/// This type may hold any handle value that [`OwnedHandle`] may hold, except that when it holds +/// `-1`, that value is interpreted to mean `INVALID_HANDLE_VALUE`. /// -/// If this holds a valid handle, it will close the handle on drop. +/// If holds a handle other than `INVALID_HANDLE_VALUE`, it will close the handle on drop. #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] #[derive(Debug)] @@ -199,6 +206,7 @@ impl OwnedHandle { } /// Allow child processes to inherit the handle. + #[cfg(not(target_vendor = "uwp"))] pub(crate) fn set_inheritable(&self) -> io::Result<()> { cvt(unsafe { c::SetHandleInformation( diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs index 2f6f0769548..3325688e661 100644 --- a/library/std/src/os/windows/io/mod.rs +++ b/library/std/src/os/windows/io/mod.rs @@ -54,3 +54,6 @@ pub use handle::*; pub use raw::*; #[unstable(feature = "io_safety", issue = "87074")] pub use socket::*; + +#[cfg(test)] +mod tests; diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index 68fa8918a56..49e4f304f5d 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -32,8 +32,15 @@ pub trait AsRawHandle { /// raw handle to the caller, and the handle is only guaranteed /// to be valid while the original object has not yet been destroyed. /// + /// This function may return null, such as when called on [`Stdin`], + /// [`Stdout`], or [`Stderr`] when the console is detached. + /// /// However, borrowing is not strictly required. See [`AsHandle::as_handle`] /// for an API which strictly borrows a handle. + /// + /// [`Stdin`]: io::Stdin + /// [`Stdout`]: io::Stdout + /// [`Stderr`]: io::Stderr #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_handle(&self) -> RawHandle; } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index c14a1d6192f..e23e1cf8cee 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -10,6 +10,7 @@ use crate::mem; use crate::mem::forget; use crate::sys; use crate::sys::c; +#[cfg(not(target_vendor = "uwp"))] use crate::sys::cvt; /// A borrowed socket. @@ -34,6 +35,7 @@ use crate::sys::cvt; target_pointer_width = "64", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE) )] +#[rustc_nonnull_optimization_guaranteed] #[unstable(feature = "io_safety", issue = "87074")] pub struct BorrowedSocket<'socket> { socket: RawSocket, @@ -56,6 +58,7 @@ pub struct BorrowedSocket<'socket> { target_pointer_width = "64", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE) )] +#[rustc_nonnull_optimization_guaranteed] #[unstable(feature = "io_safety", issue = "87074")] pub struct OwnedSocket { socket: RawSocket, diff --git a/library/std/src/os/windows/io/tests.rs b/library/std/src/os/windows/io/tests.rs new file mode 100644 index 00000000000..41734e52e8c --- /dev/null +++ b/library/std/src/os/windows/io/tests.rs @@ -0,0 +1,21 @@ +#[test] +fn test_niche_optimizations_socket() { + use crate::mem::size_of; + use crate::os::windows::io::{ + BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, + }; + + assert_eq!(size_of::<Option<OwnedSocket>>(), size_of::<RawSocket>()); + assert_eq!(size_of::<Option<BorrowedSocket<'static>>>(), size_of::<RawSocket>(),); + unsafe { + #[cfg(target_pointer_width = "32")] + let (min, max) = (i32::MIN as u32, i32::MAX as u32); + #[cfg(target_pointer_width = "64")] + let (min, max) = (i64::MIN as u64, i64::MAX as u64); + + assert_eq!(OwnedSocket::from_raw_socket(min).into_raw_socket(), min); + assert_eq!(OwnedSocket::from_raw_socket(max).into_raw_socket(), max); + assert_eq!(Some(OwnedSocket::from_raw_socket(min)).unwrap().into_raw_socket(), min); + assert_eq!(Some(OwnedSocket::from_raw_socket(max)).unwrap().into_raw_socket(), max); + } +} diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 771461a5908..6c5c08d0bea 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1725,6 +1725,49 @@ impl ExitCode { /// return the same codes (but will also `eprintln!` the error). #[stable(feature = "process_exitcode", since = "1.61.0")] pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE); + + /// Exit the current process with the given `ExitCode`. + /// + /// Note that this has the same caveats as [`process::exit()`][exit], namely that this function + /// terminates the process immediately, so no destructors on the current stack or any other + /// thread's stack will be run. If a clean shutdown is needed, it is recommended to simply + /// return this ExitCode from the `main` function, as demonstrated in the [type + /// documentation](#examples). + /// + /// # Differences from `process::exit()` + /// + /// `process::exit()` accepts any `i32` value as the exit code for the process; however, there + /// are platforms that only use a subset of that value (see [`process::exit` platform-specific + /// behavior][exit#platform-specific-behavior]). `ExitCode` exists because of this; only + /// `ExitCode`s that are supported by a majority of our platforms can be created, so those + /// problems don't exist (as much) with this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(exitcode_exit_method)] + /// # use std::process::ExitCode; + /// # use std::fmt; + /// # enum UhOhError { GenericProblem, Specific, WithCode { exit_code: ExitCode, _x: () } } + /// # impl fmt::Display for UhOhError { + /// # fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } + /// # } + /// // there's no way to gracefully recover from an UhOhError, so we just + /// // print a message and exit + /// fn handle_unrecoverable_error(err: UhOhError) -> ! { + /// eprintln!("UH OH! {err}"); + /// let code = match err { + /// UhOhError::GenericProblem => ExitCode::FAILURE, + /// UhOhError::Specific => ExitCode::from(3), + /// UhOhError::WithCode { exit_code, .. } => exit_code, + /// }; + /// code.exit_process() + /// } + /// ``` + #[unstable(feature = "exitcode_exit_method", issue = "none")] + pub fn exit_process(self) -> ! { + exit(self.to_i32()) + } } impl ExitCode { @@ -1944,7 +1987,17 @@ impl Child { /// process, no destructors on the current stack or any other thread's stack /// will be run. If a clean shutdown is needed it is recommended to only call /// this function at a known point where there are no more destructors left -/// to run. +/// to run; or, preferably, simply return a type implementing [`Termination`] +/// (such as [`ExitCode`] or `Result`) from the `main` function and avoid this +/// function altogether: +/// +/// ``` +/// # use std::io::Error as MyError; +/// fn main() -> Result<(), MyError> { +/// // ... +/// Ok(()) +/// } +/// ``` /// /// ## Platform-specific behavior /// @@ -1952,39 +2005,14 @@ impl Child { /// will be visible to a parent process inspecting the exit code. On most /// Unix-like platforms, only the eight least-significant bits are considered. /// -/// # Examples -/// -/// Due to this function’s behavior regarding destructors, a conventional way -/// to use the function is to extract the actual computation to another -/// function and compute the exit code from its return value: -/// -/// ``` -/// fn run_app() -> Result<(), ()> { -/// // Application logic here -/// Ok(()) -/// } -/// -/// fn main() { -/// std::process::exit(match run_app() { -/// Ok(_) => 0, -/// Err(err) => { -/// eprintln!("error: {err:?}"); -/// 1 -/// } -/// }); -/// } -/// ``` -/// -/// Due to [platform-specific behavior], the exit code for this example will be -/// `0` on Linux, but `256` on Windows: +/// For example, the exit code for this example will be `0` on Linux, but `256` +/// on Windows: /// /// ```no_run /// use std::process; /// /// process::exit(0x0100); /// ``` -/// -/// [platform-specific behavior]: #platform-specific-behavior #[stable(feature = "rust1", since = "1.0.0")] pub fn exit(code: i32) -> ! { crate::rt::cleanup(); diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs index 8d5ad18997d..8d05cb44b94 100644 --- a/library/std/src/sys/unix/futex.rs +++ b/library/std/src/sys/unix/futex.rs @@ -25,7 +25,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) - // // Overflows are rounded up to an infinite timeout (None). let timespec = timeout - .and_then(|d| Some(Timespec::now(libc::CLOCK_MONOTONIC).checked_add_duration(&d)?)) + .and_then(|d| Timespec::now(libc::CLOCK_MONOTONIC).checked_add_duration(&d)) .and_then(|t| t.to_timespec()); loop { @@ -136,15 +136,13 @@ pub fn futex_wake_all(futex: &AtomicU32) { #[cfg(target_os = "openbsd")] pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool { + use super::time::Timespec; use crate::ptr::{null, null_mut}; - let timespec = timeout.and_then(|d| { - Some(libc::timespec { - // Sleep forever if the timeout is longer than fits in a timespec. - tv_sec: d.as_secs().try_into().ok()?, - // This conversion never truncates, as subsec_nanos is always <1e9. - tv_nsec: d.subsec_nanos() as _, - }) - }); + + // Overflows are rounded up to an infinite timeout (None). + let timespec = timeout + .and_then(|d| Timespec::zero().checked_add_duration(&d)) + .and_then(|t| t.to_timespec()); let r = unsafe { libc::futex( diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 333182bdad4..f99c453a3a8 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -51,7 +51,7 @@ impl fmt::Debug for SystemTime { } impl Timespec { - const fn zero() -> Timespec { + pub const fn zero() -> Timespec { Timespec { tv_sec: 0, tv_nsec: 0 } } @@ -125,6 +125,7 @@ impl Timespec { Some(Timespec::new(secs, nsec as i64)) } + #[allow(dead_code)] pub fn to_timespec(&self) -> Option<libc::timespec> { Some(libc::timespec { tv_sec: self.tv_sec.try_into().ok()?, diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index 3b609825a79..c319cb28630 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -221,6 +221,7 @@ impl Handle { Ok(Self(self.0.duplicate(access, inherit, options)?)) } + #[cfg(not(target_vendor = "uwp"))] pub(crate) fn set_inheritable(&self) -> io::Result<()> { self.0.set_inheritable() } diff --git a/library/std/src/sys/windows/pipe.rs b/library/std/src/sys/windows/pipe.rs index 928bf2439c3..2c586f1abe4 100644 --- a/library/std/src/sys/windows/pipe.rs +++ b/library/std/src/sys/windows/pipe.rs @@ -57,10 +57,21 @@ impl Pipes { } else { let (ours, theirs) = if ours_readable { (read, write) } else { (write, read) }; let ours = Handle::from_raw_handle(ours); + #[cfg(not(target_vendor = "uwp"))] let theirs = Handle::from_raw_handle(theirs); + #[cfg(target_vendor = "uwp")] + let mut theirs = Handle::from_raw_handle(theirs); if their_handle_inheritable { - theirs.set_inheritable()?; + #[cfg(not(target_vendor = "uwp"))] + { + theirs.set_inheritable()?; + } + + #[cfg(target_vendor = "uwp")] + { + theirs = theirs.duplicate(0, true, c::DUPLICATE_SAME_ACCESS)?; + } } Ok(Pipes { ours: AnonPipe::Sync(ours), theirs: AnonPipe::Sync(theirs) }) diff --git a/library/unwind/build.rs b/library/unwind/build.rs index 61d3f45ca65..f88e6a924b5 100644 --- a/library/unwind/build.rs +++ b/library/unwind/build.rs @@ -36,7 +36,7 @@ fn main() { println!("cargo:rustc-link-lib=gcc_s"); } else if target.contains("dragonfly") { println!("cargo:rustc-link-lib=gcc_pic"); - } else if target.contains("pc-windows-gnu") { + } else if target.ends_with("pc-windows-gnu") { // This is handled in the target spec with late_link_args_[static|dynamic] } else if target.contains("uwp-windows-gnu") { println!("cargo:rustc-link-lib=unwind"); diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index a01b56004c4..c92a7d310f3 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -5,6 +5,7 @@ #![feature(nll)] #![feature(staged_api)] #![feature(c_unwind)] +#![feature(cfg_target_abi)] #![cfg_attr(not(target_env = "msvc"), feature(libc))] cfg_if::cfg_if! { @@ -85,3 +86,7 @@ extern "C" {} #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] #[link(name = "unwind", kind = "static", modifiers = "-bundle")] extern "C" {} + +#[cfg(all(target_os = "windows", target_env = "gnu", target_abi = "llvm"))] +#[link(name = "unwind", kind = "static", modifiers = "-bundle")] +extern "C" {} diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index ab4338e1c85..d36344ece4e 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -110,29 +110,42 @@ def download(path, url, probably_big, verbose, help_on_error=None): def _download(path, url, probably_big, verbose, exception, help_on_error=None): + # Try to use curl (potentially available on win32 + # https://devblogs.microsoft.com/commandline/tar-and-curl-come-to-windows/) + # If an error occurs: + # - If we are on win32 fallback to powershell + # - Otherwise raise the error if appropriate if probably_big or verbose: print("downloading {}".format(url)) - # see https://serverfault.com/questions/301128/how-to-download - if sys.platform == 'win32': - run(["PowerShell.exe", "/nologo", "-Command", - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", - "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')".format(url, path)], - verbose=verbose, - exception=exception) - else: + + platform_is_win32 = sys.platform == 'win32' + try: if probably_big or verbose: option = "-#" else: option = "-s" - require(["curl", "--version"]) + # If curl is not present on Win32, we shoud not sys.exit + # but raise `CalledProcessError` or `OSError` instead + require(["curl", "--version"], exception=platform_is_win32) run(["curl", option, "-L", # Follow redirect. "-y", "30", "-Y", "10", # timeout if speed is < 10 bytes/sec for > 30 seconds "--connect-timeout", "30", # timeout if cannot connect within 30 seconds "--retry", "3", "-Sf", "-o", path, url], verbose=verbose, - exception=exception, + exception=True, # Will raise RuntimeError on failure help_on_error=help_on_error) + except (subprocess.CalledProcessError, OSError, RuntimeError): + # see http://serverfault.com/questions/301128/how-to-download + if platform_is_win32: + run(["PowerShell.exe", "/nologo", "-Command", + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", + "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')".format(url, path)], + verbose=verbose, + exception=exception) + # Check if the RuntimeError raised by run(curl) should be silenced + elif verbose or exception: + raise def verify(path, expected, verbose): @@ -198,19 +211,23 @@ def run(args, verbose=False, exception=False, is_bootstrap=False, help_on_error= sys.exit(err) -def require(cmd, exit=True): +def require(cmd, exit=True, exception=False): '''Run a command, returning its output. On error, - If `exit` is `True`, exit the process. - Otherwise, return None.''' + If `exception` is `True`, raise the error + Otherwise If `exit` is `True`, exit the process + Else return None.''' try: return subprocess.check_output(cmd).strip() except (subprocess.CalledProcessError, OSError) as exc: - if not exit: - return None - print("error: unable to run `{}`: {}".format(' '.join(cmd), exc)) - print("Please make sure it's installed and in the path.") - sys.exit(1) + if exception: + raise + elif exit: + print("error: unable to run `{}`: {}".format(' '.join(cmd), exc)) + print("Please make sure it's installed and in the path.") + sys.exit(1) + return None + def format_build_time(duration): diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 7d838c0a61d..894d74fb269 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1154,9 +1154,13 @@ impl<'a> Builder<'a> { // backtrace, core_simd, std_float, ...), those dependencies have their own features // but cargo isn't involved in the #[path] and so cannot pass the complete list of // features, so for that reason we don't enable checking of features for std. - if mode != Mode::Std { - cargo.arg("-Zcheck-cfg-features"); - } + // + // FIXME: Re-enable this after the beta bump as apperently rustc-perf doesn't use the + // beta cargo. See https://github.com/rust-lang/rust/pull/96984#issuecomment-1126678773 + // #[cfg(not(bootstrap))] + // if mode != Mode::Std { + // cargo.arg("-Zcheck-cfg-features"); // -Zcheck-cfg=features after bump + // } // Enable cfg checking of well known names/values rustflags diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index d3e91c75837..4ab502e9052 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -507,6 +507,7 @@ mod dist { config.stage = 0; config.cmd = Subcommand::Test { paths: vec!["library/std".into()], + skip: vec![], test_args: vec![], rustc_args: vec![], fail_fast: true, @@ -577,6 +578,7 @@ mod dist { let mut config = configure(&["A"], &["A"]); config.cmd = Subcommand::Test { paths: vec![], + skip: vec![], test_args: vec![], rustc_args: vec![], fail_fast: true, diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 53933e4cd7d..7a8c7fee5f5 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -175,6 +175,7 @@ fn copy_third_party_objects( } if target == "x86_64-fortanix-unknown-sgx" + || target.contains("pc-windows-gnullvm") || builder.config.llvm_libunwind == LlvmLibunwind::InTree && (target.contains("linux") || target.contains("fuchsia")) { @@ -246,7 +247,7 @@ fn copy_self_contained_objects( DependencyType::TargetSelfContained, ); } - } else if target.contains("windows-gnu") { + } else if target.ends_with("windows-gnu") { for obj in ["crt2.o", "dllcrt2.o"].iter() { let src = compiler_file(builder, builder.cc(target), target, CLang::C, obj); let target = libdir_self_contained.join(obj); @@ -477,7 +478,7 @@ impl Step for StartupObjects { fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> { let for_compiler = self.compiler; let target = self.target; - if !target.contains("windows-gnu") { + if !target.ends_with("windows-gnu") { return vec![]; } diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index d37a59426f8..6181a611ec3 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -285,7 +285,7 @@ impl Step for Mingw { /// without any extra installed software (e.g., we bundle gcc, libraries, etc). fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { let host = self.host; - if !host.contains("pc-windows-gnu") { + if !host.ends_with("pc-windows-gnu") { return None; } @@ -341,7 +341,7 @@ impl Step for Rustc { // anything requiring us to distribute a license, but it's likely the // install will *also* include the rust-mingw package, which also needs // licenses, so to be safe we just include it here in all MinGW packages. - if host.contains("pc-windows-gnu") { + if host.ends_with("pc-windows-gnu") { make_win_dist(tarball.image_dir(), &tmpdir(builder), host, builder); tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc"); } @@ -1352,7 +1352,7 @@ impl Step for Extended { tarballs.push(builder.ensure(Rustc { compiler: builder.compiler(stage, target) })); tarballs.push(builder.ensure(Std { compiler, target }).expect("missing std")); - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { tarballs.push(builder.ensure(Mingw { host: target }).expect("missing mingw")); } @@ -1522,7 +1522,7 @@ impl Step for Extended { prepare(tool); } } - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { prepare("rust-mingw"); } @@ -1711,7 +1711,7 @@ impl Step for Extended { .arg("-t") .arg(etc.join("msi/remove-duplicates.xsl")), ); - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { builder.run( Command::new(&heat) .current_dir(&exe) @@ -1760,7 +1760,7 @@ impl Step for Extended { if built_tools.contains("miri") { cmd.arg("-dMiriDir=miri"); } - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { cmd.arg("-dGccDir=rust-mingw"); } builder.run(&mut cmd); @@ -1787,7 +1787,7 @@ impl Step for Extended { } candle("AnalysisGroup.wxs".as_ref()); - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { candle("GccGroup.wxs".as_ref()); } @@ -1829,7 +1829,7 @@ impl Step for Extended { cmd.arg("MiriGroup.wixobj"); } - if target.contains("windows-gnu") { + if target.ends_with("windows-gnu") { cmd.arg("GccGroup.wixobj"); } // ICE57 wrongly complains about the shortcuts @@ -1859,7 +1859,9 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) { .env("CFG_BUILD", target.triple) .env("CFG_CHANNEL", &builder.config.channel); - if target.contains("windows-gnu") { + if target.contains("windows-gnullvm") { + cmd.env("CFG_MINGW", "1").env("CFG_ABI", "LLVM"); + } else if target.contains("windows-gnu") { cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU"); } else { cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC"); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 58571ea129c..4cd835ade64 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -111,6 +111,7 @@ pub enum Subcommand { compare_mode: Option<String>, pass: Option<String>, run: Option<String>, + skip: Vec<String>, test_args: Vec<String>, rustc_args: Vec<String>, fail_fast: bool, @@ -261,6 +262,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", match subcommand { Kind::Test => { opts.optflag("", "no-fail-fast", "Run all tests regardless of failure"); + opts.optmulti("", "skip", "skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times", "SUBSTRING"); opts.optmulti( "", "test-args", @@ -545,6 +547,7 @@ Arguments: compare_mode: matches.opt_str("compare-mode"), pass: matches.opt_str("pass"), run: matches.opt_str("run"), + skip: matches.opt_strs("skip"), test_args: matches.opt_strs("test-args"), rustc_args: matches.opt_strs("rustc-args"), fail_fast: !matches.opt_present("no-fail-fast"), @@ -689,12 +692,26 @@ impl Subcommand { } pub fn test_args(&self) -> Vec<&str> { + let mut args = vec![]; + + match *self { + Subcommand::Test { ref skip, .. } => { + for s in skip { + args.push("--skip"); + args.push(s.as_str()); + } + } + _ => (), + }; + match *self { Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => { - test_args.iter().flat_map(|s| s.split_whitespace()).collect() + args.extend(test_args.iter().flat_map(|s| s.split_whitespace())) } - _ => Vec::new(), + _ => (), } + + args } pub fn rustc_args(&self) -> Vec<&str> { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 5d32b4f801a..a4e35bf6d47 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -122,7 +122,8 @@ use once_cell::sync::OnceCell; use crate::builder::Kind; use crate::config::{LlvmLibunwind, TargetSelection}; use crate::util::{ - exe, libdir, mtime, output, run, run_suppressed, t, try_run, try_run_suppressed, CiEnv, + check_run, exe, libdir, mtime, output, run, run_suppressed, t, try_run, try_run_suppressed, + CiEnv, }; mod builder; @@ -961,6 +962,17 @@ impl Build { try_run_suppressed(cmd) } + /// Runs a command, printing out nice contextual information if it fails. + /// Returns false if do not execute at all, otherwise returns its + /// `status.success()`. + fn check_run(&self, cmd: &mut Command) -> bool { + if self.config.dry_run { + return true; + } + self.verbose(&format!("running: {:?}", cmd)); + check_run(cmd, self.is_verbose()) + } + pub fn is_verbose(&self) -> bool { self.verbosity > 0 } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 64e25f803b2..09b8cbe9014 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -156,7 +156,7 @@ pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) { let llvm_lib = llvm_root.join("lib"); for entry in t!(fs::read_dir(&llvm_lib)) { let lib = t!(entry).path(); - if lib.ends_with(".so") { + if lib.extension().map_or(false, |ext| ext == "so") { fix_bin_or_dylib(builder, &lib); } } @@ -284,7 +284,7 @@ fn fix_bin_or_dylib(builder: &Builder<'_>, fname: &Path) { entries }; patchelf.args(&[OsString::from("--set-rpath"), rpath_entries]); - if !fname.ends_with(".so") { + if !fname.extension().map_or(false, |ext| ext == "so") { // Finally, set the corret .interp for binaries let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker"); // FIXME: can we support utf8 here? `args` doesn't accept Vec<u8>, only OsString ... @@ -306,39 +306,40 @@ fn download_component(builder: &Builder<'_>, base: &str, url: &str, dest_path: & fn download_with_retries(builder: &Builder<'_>, tempfile: &str, url: &str) { println!("downloading {}", url); - - // FIXME: check if curl is installed instead of skipping straight to powershell - if builder.build.build.contains("windows-msvc") { - for _ in 0..3 { - if builder.try_run(Command::new("PowerShell.exe").args(&[ - "/nologo", - "-Command", - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", - &format!( - "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", - url, tempfile - ), - ])) { - return; + // Try curl. If that fails and we are on windows, fallback to PowerShell. + if !builder.check_run(Command::new("curl").args(&[ + "-#", + "-y", + "30", + "-Y", + "10", // timeout if speed is < 10 bytes/sec for > 30 seconds + "--connect-timeout", + "30", // timeout if cannot connect within 30 seconds + "--retry", + "3", + "-Sf", + "-o", + tempfile, + url, + ])) { + if builder.build.build.contains("windows-msvc") { + println!("Fallback to PowerShell"); + for _ in 0..3 { + if builder.try_run(Command::new("PowerShell.exe").args(&[ + "/nologo", + "-Command", + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", + &format!( + "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", + url, tempfile + ), + ])) { + return; + } + println!("\nspurious failure, trying again"); } - println!("\nspurious failure, trying again"); } - } else { - builder.run(Command::new("curl").args(&[ - "-#", - "-y", - "30", - "-Y", - "10", // timeout if speed is < 10 bytes/sec for > 30 seconds - "--connect-timeout", - "30", // timeout if cannot connect within 30 seconds - "--retry", - "3", - "-Sf", - "-o", - tempfile, - url, - ])); + std::process::exit(1); } } @@ -1372,6 +1373,10 @@ impl Step for Libunwind { cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None); cfg.define("NDEBUG", None); } + if self.target.contains("windows") { + cfg.define("_LIBUNWIND_HIDE_SYMBOLS", "1"); + cfg.define("_LIBUNWIND_IS_NATIVE_ONLY", "1"); + } } cc_cfg.compiler(builder.cc(self.target)); diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index b78ca3712bd..710b3588b84 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -346,6 +346,24 @@ pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { status.success() } +pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { + let status = match cmd.status() { + Ok(status) => status, + Err(e) => { + println!("failed to execute command: {:?}\nerror: {}", cmd, e); + return false; + } + }; + if !status.success() && print_cmd_on_fail { + println!( + "\n\ncommand did not execute successfully: {:?}\n\ + expected success, got: {}\n\n", + cmd, status + ); + } + status.success() +} + pub fn run_suppressed(cmd: &mut Command) { if !try_run_suppressed(cmd) { std::process::exit(1); diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh index 9bd56394eaf..36c94458da7 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh @@ -2,16 +2,21 @@ set -ex -# Originally from https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz -curl https://ci-mirrors.rust-lang.org/rustc/2021-01-14-clang%2Bllvm-11.0.1-x86_64-linux-gnu-ubuntu-16.04.tar.xz | \ +# Originally from https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.0/clang+llvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz +curl https://ci-mirrors.rust-lang.org/rustc/2022-05-10-clang%2Bllvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz | \ tar xJf - -export PATH=`pwd`/clang+llvm-11.0.1-x86_64-linux-gnu-ubuntu-16.04/bin:$PATH +bin="$PWD/clang+llvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04/bin" git clone https://github.com/WebAssembly/wasi-libc cd wasi-libc -git reset --hard ad5133410f66b93a2381db5b542aad5e0964db96 -make -j$(nproc) INSTALL_DIR=/wasm32-wasi install +git reset --hard 9886d3d6200fcc3726329966860fc058707406cd +make -j$(nproc) \ + CC="$bin/clang" \ + NM="$bin/llvm-nm" \ + AR="$bin/llvm-ar" \ + INSTALL_DIR=/wasm32-wasi \ + install cd .. rm -rf wasi-libc diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 899f24fc754..f514a2f0bd0 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.9.0 \ No newline at end of file +0.9.1 \ No newline at end of file diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 952d8ef48fe..c2d44ac0e4d 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -15,12 +15,13 @@ - [Platform Support](platform-support.md) - [Template for target-specific documentation](platform-support/TEMPLATE.md) - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md) - - [aarch64-unknown-none-hermitkernel](platform-support/aarch64-unknown-none-hermitkernel.md) - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) - [\*-kmc-solid_\*](platform-support/kmc-solid.md) - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md) - [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md) + - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md) + - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [*-unknown-openbsd](platform-support/openbsd.md) - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md) - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md) diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 0d02fa7bd6b..d80e4f20869 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -52,7 +52,8 @@ where `KIND` may be one of: If the kind is specified, then linking modifiers can be attached to it. Modifiers are specified as a comma-delimited string with each modifier prefixed with either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively. -The last boolean value specified for a given modifier wins. \ +Specifying multiple `modifiers` arguments in a single `link` attribute, +or multiple identical modifiers in the same `modifiers` argument is not currently supported. \ Example: `-l static:+whole-archive=mylib`. The kind of library and the modifiers can also be specified in a [`#[link]` diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 12ac575210a..ab98651a1ec 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -208,6 +208,7 @@ target | std | host | notes `aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64 `aarch64-apple-tvos` | * | | ARM64 tvOS [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 +[`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ✓ | | ARM64 HermitCore `aarch64-unknown-uefi` | * | | ARM64 UEFI @@ -288,6 +289,7 @@ target | std | host | notes [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 `x86_64-apple-tvos` | * | | x86 64-bit tvOS +[`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `x86_64-pc-windows-msvc` | * | | 64-bit Windows XP support `x86_64-sun-solaris` | ? | | Deprecated target for 64-bit Solaris 10/11, illumos `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD diff --git a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md new file mode 100644 index 00000000000..1af1410d4bb --- /dev/null +++ b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md @@ -0,0 +1,58 @@ +# `nvptx64-nvidia-cuda` + +**Tier: 2** + +This is the target meant for deploying code for Nvidia® accelerators based on their CUDA +platform. + +## Target maintainers + +- Riccardo D'Ambrosio, https://github.com/RDambrosio016 +- Kjetil Kjeka, https://github.com/kjetilkjeka + +<!-- FIXME: fill this out + +## Requirements + +Does the target support host tools, or only cross-compilation? Does the target +support std, or alloc (either with a default allocator, or if the user supplies +an allocator)? + +Document the expectations of binaries built for the target. Do they assume +specific minimum features beyond the baseline of the CPU/environment/etc? What +version of the OS or environment do they expect? + +Are there notable `#[target_feature(...)]` or `-C target-feature=` values that +programs may wish to use? + +What calling convention does `extern "C"` use on the target? + +What format do binaries use by default? ELF, PE, something else? + +## Building the target + +If Rust doesn't build the target by default, how can users build it? Can users +just add it to the `target` list in `config.toml`? + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will either need to build Rust with the target enabled (see +"Building the target" above), or build your own copy of `core` by using +`build-std` or similar. + +## Testing + +Does the target support running binaries, or do binaries have varying +expectations that prevent having a standard way to run them? If users can run +binaries, can they do so in some common emulator, or do they need native +hardware? Does the target support running the Rust testsuite? + +## Cross-compilation toolchains and C code + +Does the target support C code? If so, what toolchain target should users use +to build compatible C code? (This may match the target triple, or it may be a +toolchain for a different target triple, potentially with specific options or +caveats.) + +--> diff --git a/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md b/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md new file mode 100644 index 00000000000..96ae065b31b --- /dev/null +++ b/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md @@ -0,0 +1,48 @@ +# \*-pc-windows-gnullvm + +**Tier: 3** + +Windows targets similar to `*-pc-windows-gnu` but using UCRT as the runtime and various LLVM tools/libraries instead of GCC/Binutils. + +Target triples avaiable so far: +- `aarch64-pc-windows-gnullvm` +- `x86_64-pc-windows-gnullvm` + +## Target maintainers + +- [@mati865](https://github.com/mati865) + +## Requirements + +The easiest way to obtain these targets is cross-compilation but native build from `x86_64-pc-windows-gnu` is possible with few hacks which I don't recommend. +Std support is expected to be on pair with `*-pc-windows-gnu`. + +Binaries for this target should be at least on pair with `*-pc-windows-gnu` in terms of requirements and functionality. + +Those targets follow Windows calling convention for `extern "C"`. + +Like with any other Windows target created binaries are in PE format. + +## Building the target + +For cross-compilation I recommend using [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) toolchain, one change that seems necessary beside configuring corss compilers is disabling experimental `m86k` target. Otherwise LLVM build fails with `multiple definition ...` errors. +Native bootstrapping builds require rather fragile hacks until host artifacts are avaiable so I won't describe them here. + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will either need to build Rust with the target enabled (see +"Building the target" above), or build your own copy of `core` by using +`build-std` or similar. + +## Testing + +Created binaries work fine on Windows or Wine using native hardware. Testing AArch64 on x86_64 is problematic though and requires spending some time with QEMU. +Once these targets bootstrap themselves on native hardware they should pass Rust testsuite. + +## Cross-compilation toolchains and C code + +Compatible C code can be built with Clang's `aarch64-pc-windows-gnu` and `x86_64-pc-windows-gnu` targets as long as LLVM based C toolchains are used. +Those include: +- [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) +- [MSYS2 with CLANG* environment](https://www.msys2.org/docs/environments) diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md index 098bc1879b5..d666d54b315 100644 --- a/src/doc/rustdoc/src/how-to-read-rustdoc.md +++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md @@ -59,15 +59,8 @@ or the current item whose documentation is being displayed. ## The Theme Picker and Search Interface When viewing `rustdoc`'s output in a browser with JavaScript enabled, -a dynamic interface appears at the top of the page. -To the left is the theme picker, denoted with a paint-brush icon, -and the search interface, help screen, and options appear to the right of that. - -### The Theme Picker - -Clicking on the theme picker provides a list of themes - -by default `ayu`, `light`, and `dark` - -which are available for viewing. +a dynamic interface appears at the top of the page composed of the search +interface, help screen, and options. ### The Search Interface @@ -91,12 +84,16 @@ When typing in the search bar, you can prefix your search term with a type followed by a colon (such as `mod:`) to restrict the results to just that kind of item. (The available items are listed in the help popup.) +### Changing displayed theme + +You can change the displayed theme by opening the settings menu (the gear +icon in the upper right) and then pick a new one from there. + ### Shortcuts Pressing `S` while focused elsewhere on the page will move focus to the search bar, and pressing `?` shows the help screen, which includes all these shortcuts and more. -Pressing `T` focuses the theme picker. When the search results are focused, the left and right arrows move between tabs and the up and down arrows move diff --git a/src/doc/rustdoc/src/write-documentation/what-to-include.md b/src/doc/rustdoc/src/write-documentation/what-to-include.md index 35e6ccbc388..e1e09aa4a8a 100644 --- a/src/doc/rustdoc/src/write-documentation/what-to-include.md +++ b/src/doc/rustdoc/src/write-documentation/what-to-include.md @@ -109,8 +109,9 @@ rustdoc --extend-css custom.css src/lib.rs A good example of using this feature to create a dark theme is documented [on this blog]. Just remember, dark theme is already included in the rustdoc output -by clicking on the paintbrush. Adding additional options to the themes are -as easy as creating a custom theme `.css` file and using the following syntax: +by clicking on the gear icon in the upper right. Adding additional options to the +themes are as easy as creating a custom theme `.css` file and using the following +syntax: ```bash rustdoc --theme awesome.css src/lib.rs diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 3f60caffef5..e83c4d98cc7 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -22,7 +22,10 @@ This feature allows for use of one of following sanitizers: To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`, `-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`, -`-Zsanitizer=memtag`, or `-Zsanitizer=thread`. +`-Zsanitizer=memtag`, or `-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags. Example: +```shell +$ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu +``` # AddressSanitizer diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index f0d87f7ce4c..805cc5c71d8 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -15,14 +15,14 @@ crate struct BlanketImplFinder<'a, 'tcx> { impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { crate fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> { let param_env = self.cx.tcx.param_env(item_def_id); - let ty = self.cx.tcx.type_of(item_def_id); + let ty = self.cx.tcx.bound_type_of(item_def_id); trace!("get_blanket_impls({:?})", ty); let mut impls = Vec::new(); self.cx.with_all_traits(|cx, all_traits| { for &trait_def_id in all_traits { if !cx.cache.access_levels.is_public(trait_def_id) - || cx.generated_synthetics.get(&(ty, trait_def_id)).is_some() + || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some() { continue; } @@ -34,12 +34,12 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { trait_def_id, impl_def_id ); - let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap(); - let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_)); + let trait_ref = cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap(); + let is_param = matches!(trait_ref.0.self_ty().kind(), ty::Param(_)); let may_apply = is_param && cx.tcx.infer_ctxt().enter(|infcx| { let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id); let ty = ty.subst(infcx.tcx, substs); - let param_env = param_env.subst(infcx.tcx, substs); + let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs); let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id); let trait_ref = trait_ref.subst(infcx.tcx, impl_substs); @@ -99,7 +99,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { continue; } - cx.generated_synthetics.insert((ty, trait_def_id)); + cx.generated_synthetics.insert((ty.0, trait_def_id)); impls.push(Item { name: None, @@ -115,15 +115,15 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { ), // FIXME(eddyb) compute both `trait_` and `for_` from // the post-inference `trait_ref`, as it's more accurate. - trait_: Some(trait_ref.clean(cx)), - for_: ty.clean(cx), + trait_: Some(trait_ref.0.clean(cx)), + for_: ty.0.clean(cx), items: cx.tcx .associated_items(impl_def_id) .in_definition_order() .map(|x| x.clean(cx)) .collect::<Vec<_>>(), polarity: ty::ImplPolarity::Positive, - kind: ImplKind::Blanket(box trait_ref.self_ty().clean(cx)), + kind: ImplKind::Blanket(box trait_ref.0.self_ty().clean(cx)), }), cfg: None, }); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 261eb39bf72..9a579cb5311 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -22,7 +22,7 @@ use crate::clean::{ use crate::core::DocContext; use crate::formats::item_type::ItemType; -type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>; +type Attrs<'hir> = &'hir [ast::Attribute]; /// Attempt to inline a definition into this AST. /// @@ -155,7 +155,7 @@ crate fn try_inline_glob( } crate fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> { - cx.tcx.get_attrs(did) + cx.tcx.get_attrs_unchecked(did) } /// Record an external fully qualified name in the external_paths cache. @@ -691,7 +691,7 @@ crate fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) { let trait_ = clean::TraitWithExtraInfo { trait_, - is_notable: clean::utils::has_doc_flag(cx.tcx.get_attrs(did), sym::notable_trait), + is_notable: clean::utils::has_doc_flag(cx.tcx, did, sym::notable_trait), }; cx.external_traits.borrow_mut().insert(did, trait_); cx.active_extern_traits.remove(&did); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7cc96183d6d..6e18f381c59 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -21,7 +21,7 @@ use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; use rustc_middle::middle::resolve_lifetime as rl; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, AdtKind, DefIdTree, Lift, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtKind, DefIdTree, EarlyBinder, Lift, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -1634,7 +1634,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { .tcx .explicit_item_bounds(def_id) .iter() - .map(|(bound, _)| bound.subst(cx.tcx, substs)) + .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs)) .collect::<Vec<_>>(); let mut regions = vec![]; let mut has_sized = false; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2b65b8f910c..456d860f125 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -211,8 +211,8 @@ impl ExternalCrate { // Failing that, see if there's an attribute specifying where to find this // external crate let did = self.crate_num.as_def_id(); - tcx.get_attrs(did) - .lists(sym::doc) + tcx.get_attrs(did, sym::doc) + .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) .filter(|a| a.has_name(sym::html_root_url)) .filter_map(|a| a.value_str()) .map(to_remote) @@ -226,11 +226,13 @@ impl ExternalCrate { let as_keyword = |res: Res<!>| { if let Res::Def(DefKind::Mod, def_id) = res { - let attrs = tcx.get_attrs(def_id); let mut keyword = None; - for attr in attrs.lists(sym::doc) { - if attr.has_name(sym::keyword) { - if let Some(v) = attr.value_str() { + let meta_items = tcx + .get_attrs(def_id, sym::doc) + .flat_map(|attr| attr.meta_item_list().unwrap_or_default()); + for meta in meta_items { + if meta.has_name(sym::keyword) { + if let Some(v) = meta.value_str() { keyword = Some(v); break; } @@ -288,11 +290,13 @@ impl ExternalCrate { // rendering by delegating everything to a hash map. let as_primitive = |res: Res<!>| { if let Res::Def(DefKind::Mod, def_id) = res { - let attrs = tcx.get_attrs(def_id); let mut prim = None; - for attr in attrs.lists(sym::doc) { - if let Some(v) = attr.value_str() { - if attr.has_name(sym::primitive) { + let meta_items = tcx + .get_attrs(def_id, sym::doc) + .flat_map(|attr| attr.meta_item_list().unwrap_or_default()); + for meta in meta_items { + if let Some(v) = meta.value_str() { + if meta.has_name(sym::primitive) { prim = PrimitiveType::from_symbol(v); if prim.is_some() { break; @@ -413,7 +417,10 @@ impl Item { } crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool { - self.item_id.as_def_id().map(|did| tcx.get_attrs(did).inner_docs()).unwrap_or(false) + self.item_id + .as_def_id() + .map(|did| tcx.get_attrs_unchecked(did).inner_docs()) + .unwrap_or(false) } crate fn span(&self, tcx: TyCtxt<'_>) -> Span { @@ -464,7 +471,7 @@ impl Item { kind: ItemKind, cx: &mut DocContext<'_>, ) -> Item { - let ast_attrs = cx.tcx.get_attrs(def_id); + let ast_attrs = cx.tcx.get_attrs_unchecked(def_id); Self::from_def_id_and_attrs_and_parts( def_id, diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 3a2f24d719c..c67b92df643 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -474,10 +474,9 @@ crate fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Option<De /// /// This function exists because it runs on `hir::Attributes` whereas the other is a /// `clean::Attributes` method. -crate fn has_doc_flag(attrs: ty::Attributes<'_>, flag: Symbol) -> bool { - attrs.iter().any(|attr| { - attr.has_name(sym::doc) - && attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag)) +crate fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool { + tcx.get_attrs(did, sym::doc).any(|attr| { + attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag)) }) } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 56a085c2982..5ba3bdc12ed 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1448,8 +1448,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> { // used in tera template files). map.insert("mainThemeStyle".into(), 1); map.insert("themeStyle".into(), 1); - map.insert("theme-picker".into(), 1); - map.insert("theme-choices".into(), 1); map.insert("settings-menu".into(), 1); map.insert("help-button".into(), 1); map.insert("main-content".into(), 1); diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index a30c533aa48..528180288de 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -596,9 +596,11 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { |buf: &mut Buffer| { write!( buf, - "<script defer src=\"{}settings{}.js\"></script>", - page.static_root_path.unwrap_or(""), - page.resource_suffix + "<link rel=\"stylesheet\" type=\"text/css\" \ + href=\"{root_path}settings{suffix}.css\">\ + <script defer src=\"{root_path}settings{suffix}.js\"></script>", + root_path = page.static_root_path.unwrap_or(""), + suffix = page.resource_suffix, ) }, &self.shared.style_files, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index fbb3d3e4584..4951cd83af2 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -323,7 +323,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl clean::ImportItem(ref import) => { let (stab, stab_tags) = if let Some(import_def_id) = import.source.did { - let ast_attrs = cx.tcx().get_attrs(import_def_id); + let ast_attrs = cx.tcx().get_attrs_unchecked(import_def_id); let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs, None)); // Just need an item with the correct def_id and attrs diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index e8e5fa17993..702bccb45cf 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -238,7 +238,6 @@ pub(super) fn write_shared( write_toolchain("favicon-16x16.png", static_files::RUST_FAVICON_PNG_16)?; write_toolchain("favicon-32x32.png", static_files::RUST_FAVICON_PNG_32)?; } - write_toolchain("brush.svg", static_files::BRUSH_SVG)?; write_toolchain("wheel.svg", static_files::WHEEL_SVG)?; write_toolchain("clipboard.svg", static_files::CLIPBOARD_SVG)?; write_toolchain("down-arrow.svg", static_files::DOWN_ARROW_SVG)?; @@ -417,7 +416,7 @@ pub(super) fn write_shared( )); all_sources.sort(); Ok(format!( - "var N = null;var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();\n", + "var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();\n", all_sources.join("\n") ) .into_bytes()) diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js index 52577b228aa..7634a15b9bd 100644 --- a/src/librustdoc/html/static/.eslintrc.js +++ b/src/librustdoc/html/static/.eslintrc.js @@ -29,5 +29,10 @@ module.exports = { "no-var": ["error"], "prefer-const": ["error"], "prefer-arrow-callback": ["error"], + "brace-style": [ + "error", + "1tbs", + { "allowSingleLine": false } + ], } }; diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index e35358c5649..0a19a99abf0 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -18,7 +18,3 @@ rules. /* The search bar and related controls don't work without JS */ display: none; } - -#theme-picker { - display: none; -} diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 0f4d842f433..38e67c233d6 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1379,31 +1379,30 @@ pre.rust { margin-bottom: 6px; } -.theme-picker { - position: absolute; - left: -38px; - top: 4px; -} - -.theme-picker button { - outline: none; -} - #settings-menu, #help-button { margin-left: 4px; outline: none; } -#theme-picker, #copy-path { +#copy-path { height: 34px; } -#theme-picker, #settings-menu, #help-button, #copy-path { +#settings-menu > a, #help-button, #copy-path { padding: 5px; width: 33px; border: 1px solid; border-radius: 2px; cursor: pointer; } +#settings-menu { + padding: 0; +} +#settings-menu > a { + padding: 5px; + width: 100%; + height: 100%; + display: block; +} @keyframes rotating { from { @@ -1413,9 +1412,33 @@ pre.rust { transform: rotate(360deg); } } -#settings-menu.rotate img { +#settings-menu.rotate > a img { animation: rotating 2s linear infinite; } +#settings-menu #settings { + position: absolute; + right: 0; + z-index: 1; + display: block; + margin-top: 7px; + border-radius: 3px; + border: 1px solid; +} +#settings-menu #settings .setting-line { + margin: 0.6em; +} +/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */ +#settings-menu #settings::before { + content: ''; + position: absolute; + right: 11px; + border: solid; + border-width: 1px 1px 0 0; + display: inline-block; + padding: 4px; + transform: rotate(-45deg); + top: -5px; +} #help-button { font-family: "Fira Sans", Arial, sans-serif; @@ -1838,12 +1861,6 @@ details.rustdoc-toggle[open] > summary.hideme::after { margin-left: 32px; } - /* Space is at a premium on mobile, so remove the theme-picker icon. */ - #theme-picker { - display: none; - width: 0; - } - .content { margin-left: 0px; } diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 7b337c2bc7a..07588748ad6 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -56,38 +56,6 @@ position: absolute; } -.select-wrapper { - float: right; - position: relative; - height: 27px; - min-width: 25%; -} - -.select-wrapper select { - appearance: none; - -moz-appearance: none; - -webkit-appearance: none; - background: none; - border: 2px solid #ccc; - padding-right: 28px; - width: 100%; -} - -.select-wrapper img { - pointer-events: none; - position: absolute; - right: 0; - bottom: 0; - background: #ccc; - height: 100%; - width: 28px; - padding: 0px 4px; -} - -.select-wrapper select option { - color: initial; -} - .slider { position: absolute; cursor: pointer; @@ -96,7 +64,6 @@ right: 0; bottom: 0; background-color: #ccc; - -webkit-transition: .3s; transition: .3s; } @@ -108,7 +75,6 @@ left: 4px; bottom: 4px; background-color: white; - -webkit-transition: .3s; transition: .3s; } @@ -121,8 +87,6 @@ input:focus + .slider { } input:checked + .slider:before { - -webkit-transform: translateX(19px); - -ms-transform: translateX(19px); transform: translateX(19px); } diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index b1bf06c1865..ea0cb5e0726 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -5,7 +5,7 @@ Original by Dempfi (https://github.com/dempfi/ayu) /* General structure and fonts */ -body { +body, #settings-menu #settings, #settings-menu #settings::before { background-color: #0f1419; color: #c5c5c5; } @@ -531,16 +531,20 @@ kbd { box-shadow: inset 0 -1px 0 #5c6773; } -#theme-picker, #settings-menu, #help-button { +#settings-menu > a, #help-button { border-color: #5c6773; background-color: #0f1419; color: #fff; } -#theme-picker > img, #settings-menu > img { +#settings-menu > a img { filter: invert(100); } +#settings-menu #settings, #settings-menu #settings::before { + border-color: #5c6773; +} + #copy-path { color: #fff; } @@ -551,8 +555,7 @@ kbd { filter: invert(100%); } -#theme-picker:hover, #theme-picker:focus, -#settings-menu:hover, #settings-menu:focus, +#settings-menu > a:hover, #settings-menu > a:focus, #help-button:hover, #help-button:focus { border-color: #e0e0e0; } @@ -570,12 +573,6 @@ kbd { background-color: rgba(110, 110, 110, 0.33); } -@media (max-width: 700px) { - #theme-picker { - background: #0f1419; - } -} - .search-results .result-name span.alias { color: #c5c5c5; } diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 236304ccc9f..1525163f502 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -1,4 +1,4 @@ -body { +body, #settings-menu #settings, #settings-menu #settings::before { background-color: #353535; color: #ddd; } @@ -408,18 +408,21 @@ kbd { box-shadow: inset 0 -1px 0 #c6cbd1; } -#theme-picker, #settings-menu, #help-button { +#settings-menu > a, #help-button { border-color: #e0e0e0; background: #f0f0f0; color: #000; } -#theme-picker:hover, #theme-picker:focus, -#settings-menu:hover, #settings-menu:focus, +#settings-menu > a:hover, #settings-menu > a:focus, #help-button:hover, #help-button:focus { border-color: #ffb900; } +#settings-menu #settings, #settings-menu #settings::before { + border-color: #d2d2d2; +} + #copy-path { color: #999; } @@ -443,12 +446,6 @@ kbd { background-color: #4e4e4e; } -@media (max-width: 700px) { - #theme-picker { - background: #f0f0f0; - } -} - .search-results .result-name span.alias { color: #fff; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index c923902aba2..d36a088d38e 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -1,6 +1,6 @@ /* General structure and fonts */ -body { +body, #settings-menu #settings, #settings-menu #settings::before { background-color: white; color: black; } @@ -394,17 +394,20 @@ kbd { box-shadow: inset 0 -1px 0 #c6cbd1; } -#theme-picker, #settings-menu, #help-button { +#settings-menu > a, #help-button { border-color: #e0e0e0; background-color: #fff; } -#theme-picker:hover, #theme-picker:focus, -#settings-menu:hover, #settings-menu:focus, +#settings-menu > a:hover, #settings-menu > a:focus, #help-button:hover, #help-button:focus { border-color: #717171; } +#settings-menu #settings, #settings-menu #settings::before { + border-color: #DDDDDD; +} + #copy-path { color: #999; } @@ -428,12 +431,6 @@ kbd { background-color: #eee; } -@media (max-width: 700px) { - #theme-picker { - background: #fff; - } -} - .search-results .result-name span.alias { color: #000; } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 336223ad28f..454c7f557b9 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1,7 +1,6 @@ // Local js definitions: /* global addClass, getSettingValue, hasClass, searchState */ /* global onEach, onEachLazy, removeClass */ -/* global switchTheme, useSystemTheme */ "use strict"; @@ -109,21 +108,11 @@ function getVirtualKey(ev) { return String.fromCharCode(c); } -const THEME_PICKER_ELEMENT_ID = "theme-picker"; -const THEMES_ELEMENT_ID = "theme-choices"; const MAIN_ID = "main-content"; const SETTINGS_BUTTON_ID = "settings-menu"; const ALTERNATIVE_DISPLAY_ID = "alternative-display"; const NOT_DISPLAYED_ID = "not-displayed"; -function getThemesElement() { - return document.getElementById(THEMES_ELEMENT_ID); -} - -function getThemePickerElement() { - return document.getElementById(THEME_PICKER_ELEMENT_ID); -} - function getSettingsButton() { return document.getElementById(SETTINGS_BUTTON_ID); } @@ -133,74 +122,10 @@ function getNakedUrl() { return window.location.href.split("?")[0].split("#")[0]; } -function showThemeButtonState() { - const themePicker = getThemePickerElement(); - const themeChoices = getThemesElement(); - - themeChoices.style.display = "block"; - themePicker.style.borderBottomRightRadius = "0"; - themePicker.style.borderBottomLeftRadius = "0"; -} - -function hideThemeButtonState() { - const themePicker = getThemePickerElement(); - const themeChoices = getThemesElement(); - - themeChoices.style.display = "none"; - themePicker.style.borderBottomRightRadius = "3px"; - themePicker.style.borderBottomLeftRadius = "3px"; -} - window.hideSettings = () => { // Does nothing by default. }; -// Set up the theme picker list. -(function () { - if (!document.location.href.startsWith("file:///")) { - return; - } - const themeChoices = getThemesElement(); - const themePicker = getThemePickerElement(); - const availableThemes = getVar("themes").split(","); - - removeClass(themeChoices.parentElement, "hidden"); - - function switchThemeButtonState() { - if (themeChoices.style.display === "block") { - hideThemeButtonState(); - } else { - showThemeButtonState(); - } - } - - function handleThemeButtonsBlur(e) { - const active = document.activeElement; - const related = e.relatedTarget; - - if (active.id !== THEME_PICKER_ELEMENT_ID && - (!active.parentNode || active.parentNode.id !== THEMES_ELEMENT_ID) && - (!related || - (related.id !== THEME_PICKER_ELEMENT_ID && - (!related.parentNode || related.parentNode.id !== THEMES_ELEMENT_ID)))) { - hideThemeButtonState(); - } - } - - themePicker.onclick = switchThemeButtonState; - themePicker.onblur = handleThemeButtonsBlur; - availableThemes.forEach(item => { - const but = document.createElement("button"); - but.textContent = item; - but.onclick = () => { - switchTheme(window.currentTheme, window.mainTheme, item, true); - useSystemTheme(false); - }; - but.onblur = handleThemeButtonsBlur; - themeChoices.appendChild(but); - }); -}()); - /** * This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode` * doesn't have a parent node. @@ -512,7 +437,7 @@ function loadCss(cssFileName) { ev.preventDefault(); } searchState.defocus(); - hideThemeButtonState(); + window.hideSettings(); } const disableShortcuts = getSettingValue("disable-shortcuts") === "true"; @@ -522,8 +447,6 @@ function loadCss(cssFileName) { return; } - let themePicker; - if (document.activeElement.tagName === "INPUT") { switch (getVirtualKey(ev)) { case "Escape": @@ -553,64 +476,9 @@ function loadCss(cssFileName) { displayHelp(true, ev); break; - case "t": - case "T": - displayHelp(false, ev); - ev.preventDefault(); - themePicker = getThemePickerElement(); - themePicker.click(); - themePicker.focus(); - break; - default: - if (getThemePickerElement().parentNode.contains(ev.target)) { - handleThemeKeyDown(ev); - } - } - } - } - - function handleThemeKeyDown(ev) { - const active = document.activeElement; - const themes = getThemesElement(); - switch (getVirtualKey(ev)) { - case "ArrowUp": - ev.preventDefault(); - if (active.previousElementSibling && ev.target.id !== THEME_PICKER_ELEMENT_ID) { - active.previousElementSibling.focus(); - } else { - showThemeButtonState(); - themes.lastElementChild.focus(); - } - break; - case "ArrowDown": - ev.preventDefault(); - if (active.nextElementSibling && ev.target.id !== THEME_PICKER_ELEMENT_ID) { - active.nextElementSibling.focus(); - } else { - showThemeButtonState(); - themes.firstElementChild.focus(); - } - break; - case "Enter": - case "Return": - case "Space": - if (ev.target.id === THEME_PICKER_ELEMENT_ID && themes.style.display === "none") { - ev.preventDefault(); - showThemeButtonState(); - themes.firstElementChild.focus(); + break; } - break; - case "Home": - ev.preventDefault(); - themes.firstElementChild.focus(); - break; - case "End": - ev.preventDefault(); - themes.lastElementChild.focus(); - break; - // The escape key is handled in handleEscape, not here, - // so that pressing escape will close the menu even if it isn't focused } } @@ -841,8 +709,8 @@ function loadCss(cssFileName) { onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { if (e.parentNode.id !== "implementations-list" || (!hasClass(e, "implementors-toggle") && - !hasClass(e, "type-contents-toggle"))) - { + !hasClass(e, "type-contents-toggle")) + ) { e.open = false; } }); @@ -1006,7 +874,6 @@ function loadCss(cssFileName) { const shortcuts = [ ["?", "Show this help dialog"], ["S", "Focus the search field"], - ["T", "Focus the theme picker menu"], ["↑", "Move up in search results"], ["↓", "Move down in search results"], ["← / →", "Switch result tab (when results focused)"], diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js index 408b7e19fea..7b9d86a851b 100644 --- a/src/librustdoc/html/static/js/scrape-examples.js +++ b/src/librustdoc/html/static/js/scrape-examples.js @@ -98,7 +98,9 @@ // visible. This is necessary since updateScrapedExample calls scrollToLoc which // depends on offsetHeight, a property that requires an element to be visible to // compute correctly. - setTimeout(() => { onEachLazy(moreExamples, updateScrapedExample); }); + setTimeout(() => { + onEachLazy(moreExamples, updateScrapedExample); + }); }, {once: true}); }); })(); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 7754d626e20..0be70d77d06 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -119,7 +119,7 @@ window.initSearch = rawSearchIndex => { */ let searchIndex; let currentResults; - const ALIASES = {}; + const ALIASES = Object.create(null); const params = searchState.getQueryStringParams(); // Populate search bar with query string search term when provided, @@ -320,8 +320,8 @@ window.initSearch = rawSearchIndex => { if (foundExclamation) { throw new Error("Cannot have more than one `!` in an ident"); } else if (parserState.pos + 1 < parserState.length && - isIdentCharacter(parserState.userQuery[parserState.pos + 1])) - { + isIdentCharacter(parserState.userQuery[parserState.pos + 1]) + ) { throw new Error("`!` can only be at the end of an ident"); } foundExclamation = true; @@ -330,12 +330,10 @@ window.initSearch = rawSearchIndex => { } else if ( isStopCharacter(c) || isSpecialStartCharacter(c) || - isSeparatorCharacter(c)) - { + isSeparatorCharacter(c) + ) { break; - } - // If we allow paths ("str::string" for example). - else if (c === ":") { + } else if (c === ":") { // If we allow paths ("str::string" for example). if (!isPathStart(parserState)) { break; } @@ -372,8 +370,8 @@ window.initSearch = rawSearchIndex => { end = getIdentEndPosition(parserState); } if (parserState.pos < parserState.length && - parserState.userQuery[parserState.pos] === "<") - { + parserState.userQuery[parserState.pos] === "<" + ) { if (isInGenerics) { throw new Error("Unexpected `<` after `<`"); } else if (start >= end) { @@ -592,8 +590,8 @@ window.initSearch = rawSearchIndex => { if (elem && elem.value !== "All crates" && - hasOwnPropertyRustdoc(rawSearchIndex, elem.value)) - { + hasOwnPropertyRustdoc(rawSearchIndex, elem.value) + ) { return elem.value; } return null; @@ -786,37 +784,51 @@ window.initSearch = rawSearchIndex => { // sort by exact match with regard to the last word (mismatch goes later) a = (aaa.word !== userQuery); b = (bbb.word !== userQuery); - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // Sort by non levenshtein results and then levenshtein results by the distance // (less changes required to match means higher rankings) a = (aaa.lev); b = (bbb.lev); - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // sort by crate (non-current crate goes later) a = (aaa.item.crate !== window.currentCrate); b = (bbb.item.crate !== window.currentCrate); - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // sort by item name length (longer goes later) a = aaa.word.length; b = bbb.word.length; - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // sort by item name (lexicographically larger goes later) a = aaa.word; b = bbb.word; - if (a !== b) { return (a > b ? +1 : -1); } + if (a !== b) { + return (a > b ? +1 : -1); + } // sort by index of keyword in item name (no literal occurrence goes later) a = (aaa.index < 0); b = (bbb.index < 0); - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // (later literal occurrence, if any, goes later) a = aaa.index; b = bbb.index; - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // special precedence for primitive and keyword pages if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) || @@ -831,17 +843,23 @@ window.initSearch = rawSearchIndex => { // sort by description (no description goes later) a = (aaa.item.desc === ""); b = (bbb.item.desc === ""); - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // sort by type (later occurrence in `itemTypes` goes later) a = aaa.item.ty; b = bbb.item.ty; - if (a !== b) { return a - b; } + if (a !== b) { + return a - b; + } // sort by path (lexicographically larger goes later) a = aaa.item.path; b = bbb.item.path; - if (a !== b) { return (a > b ? +1 : -1); } + if (a !== b) { + return (a > b ? +1 : -1); + } // que sera, sera return 0; @@ -1315,16 +1333,15 @@ window.initSearch = rawSearchIndex => { } if (searchWord.indexOf(elem.pathLast) > -1 || - row.normalizedName.indexOf(elem.pathLast) > -1) - { + row.normalizedName.indexOf(elem.pathLast) > -1 + ) { // filter type: ... queries if (!results_others[fullId] !== undefined) { index = row.normalizedName.indexOf(elem.pathLast); } } lev = levenshtein(searchWord, elem.pathLast); - if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) - { + if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) { if (elem.pathLast.length < 6) { lev = 1; } else { @@ -1670,8 +1687,8 @@ window.initSearch = rawSearchIndex => { // By default, the search DOM element is "empty" (meaning it has no children not // text content). Once a search has been run, it won't be empty, even if you press // ESC or empty the search input (which also "cancels" the search). - && (!search.firstChild || search.firstChild.innerText !== searchState.loadingText))) - { + && (!search.firstChild || search.firstChild.innerText !== searchState.loadingText)) + ) { const elem = document.createElement("a"); elem.href = results.others[0].href; removeClass(elem, "active"); @@ -1766,7 +1783,7 @@ window.initSearch = rawSearchIndex => { let i = 0; for (const elem of elems) { const j = i; - elem.onclick = () => { printTab(j); }; + elem.onclick = () => printTab(j); searchState.focusedByTab.push(null); i += 1; } @@ -1953,7 +1970,7 @@ window.initSearch = rawSearchIndex => { } if (aliases) { - ALIASES[crate] = {}; + ALIASES[crate] = Object.create(null); for (const alias_name in aliases) { if (!hasOwnPropertyRustdoc(aliases, alias_name)) { continue; diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index ad32a193893..2e2305029cd 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -1,7 +1,7 @@ // Local js definitions: /* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */ -/* global addClass, removeClass, onEach, onEachLazy, NOT_DISPLAYED_ID */ -/* global MAIN_ID, getVar, getSettingsButton, switchDisplayedElement, getNotDisplayedElem */ +/* global addClass, removeClass, onEach, onEachLazy */ +/* global MAIN_ID, getVar, getSettingsButton */ "use strict"; @@ -206,38 +206,60 @@ ]; // Then we build the DOM. - const el = document.createElement("section"); - el.id = "settings"; - let innerHTML = ` - <div class="main-heading"> + let innerHTML = ""; + let elementKind = "div"; + + if (isSettingsPage) { + elementKind = "section"; + innerHTML = `<div class="main-heading"> <h1 class="fqn"> <span class="in-band">Rustdoc settings</span> </h1> - <span class="out-of-band">`; - - if (isSettingsPage) { - innerHTML += - "<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">Back</a>"; - } else { - innerHTML += "<a id=\"back\" href=\"javascript:void(0)\" " + - "onclick=\"switchDisplayedElement(null);\">Back</a>"; + <span class="out-of-band"> + <a id="back" href="javascript:void(0)" onclick="history.back();">Back</a> + </span> + </div>`; } - innerHTML += `</span> - </div> - <div class="settings">${buildSettingsPageSections(settings)}</div>`; + innerHTML += `<div class="settings">${buildSettingsPageSections(settings)}</div>`; + const el = document.createElement(elementKind); + el.id = "settings"; el.innerHTML = innerHTML; if (isSettingsPage) { document.getElementById(MAIN_ID).appendChild(el); } else { - getNotDisplayedElem().appendChild(el); + el.setAttribute("tabindex", "-1"); + getSettingsButton().appendChild(el); } return el; } const settingsMenu = buildSettingsPage(); + function displaySettings() { + settingsMenu.style.display = ""; + } + + function elemIsInParent(elem, parent) { + while (elem && elem !== document.body) { + if (elem === parent) { + return true; + } + elem = elem.parentElement; + } + return false; + } + + function blurHandler(event) { + const settingsButton = getSettingsButton(); + if (!elemIsInParent(document.activeElement, settingsButton) && + !elemIsInParent(event.relatedTarget, settingsButton) + ) { + window.hideSettings(); + } + } + if (isSettingsPage) { // We replace the existing "onclick" callback to do nothing if clicked. getSettingsButton().onclick = function(event) { @@ -246,17 +268,27 @@ } else { // We replace the existing "onclick" callback. const settingsButton = getSettingsButton(); + const settingsMenu = document.getElementById("settings"); + window.hideSettings = function() { + settingsMenu.style.display = "none"; + }; settingsButton.onclick = function(event) { + if (elemIsInParent(event.target, settingsMenu)) { + return; + } event.preventDefault(); - if (settingsMenu.parentElement.id === NOT_DISPLAYED_ID) { - switchDisplayedElement(settingsMenu); - } else { + if (settingsMenu.style.display !== "none") { window.hideSettings(); + } else { + displaySettings(); } }; - window.hideSettings = function() { - switchDisplayedElement(null); - }; + settingsButton.onblur = blurHandler; + settingsButton.querySelector("a").onblur = blurHandler; + onEachLazy(settingsMenu.querySelectorAll("input"), el => { + el.onblur = blurHandler; + }); + settingsMenu.onblur = blurHandler; } // We now wait a bit for the web browser to end re-computing the DOM... @@ -264,7 +296,7 @@ setEvents(settingsMenu); // The setting menu is already displayed if we're on the settings page. if (!isSettingsPage) { - switchDisplayedElement(settingsMenu); + displaySettings(); } removeClass(getSettingsButton(), "rotate"); }, 0); diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index bec5c083fed..85ca8431d90 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -41,9 +41,6 @@ crate static SCRAPE_EXAMPLES_JS: &str = include_str!("static/js/scrape-examples. crate static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/scrape-examples-help.md"); -/// The file contents of `brush.svg`, the icon used for the theme-switch button. -crate static BRUSH_SVG: &[u8] = include_bytes!("static/images/brush.svg"); - /// The file contents of `wheel.svg`, the icon used for the settings button. crate static WHEEL_SVG: &[u8] = include_bytes!("static/images/wheel.svg"); diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 470cce93a50..cd672aadd7e 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -108,13 +108,6 @@ {%- endif -%} </a> {#- -#} <nav class="sub"> {#- -#} - <div class="theme-picker hidden"> {#- -#} - <button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"> {#- -#} - <img width="22" height="22" alt="Pick another theme!" {# -#} - src="{{static_root_path|safe}}brush{{page.resource_suffix}}.svg"> {#- -#} - </button> {#- -#} - <div id="theme-choices" role="menu"></div> {#- -#} - </div> {#- -#} <form class="search-form"> {#- -#} <div class="search-container"> {#- -#} <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#} @@ -126,10 +119,12 @@ placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#} type="search"> {#- -#} <button type="button" id="help-button" title="help">?</button> {#- -#} - <a id="settings-menu" href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#} - <img width="22" height="22" alt="Change settings" {# -#} + <div id="settings-menu" tabindex="-1"> + <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#} + <img width="22" height="22" alt="Change settings" {# -#} src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#} - </a> {#- -#} + </a> {#- -#} + </div> </div> {#- -#} </form> {#- -#} </nav> {#- -#} diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 22b2f8c0c8e..95ba4ce5b06 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -11,12 +11,12 @@ use rustc_hir::def::{DefKind, Namespace, PerNS}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::Mutability; use rustc_middle::ty::{DefIdTree, Ty, TyCtxt}; -use rustc_middle::{bug, span_bug, ty}; +use rustc_middle::{bug, ty}; use rustc_resolve::ParentScope; use rustc_session::lint::Lint; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{BytePos, DUMMY_SP}; +use rustc_span::BytePos; use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; @@ -48,18 +48,6 @@ fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate { krate } -/// Top-level errors emitted by this pass. -enum ErrorKind<'a> { - Resolve(Box<ResolutionFailure<'a>>), - AnchorFailure(AnchorFailure), -} - -impl<'a> From<ResolutionFailure<'a>> for ErrorKind<'a> { - fn from(err: ResolutionFailure<'a>) -> Self { - ErrorKind::Resolve(box err) - } -} - #[derive(Copy, Clone, Debug, Hash)] enum Res { Def(DefKind, DefId), @@ -97,12 +85,8 @@ impl Res { } } - fn as_hir_res(self) -> Option<rustc_hir::def::Res> { - match self { - Res::Def(kind, id) => Some(rustc_hir::def::Res::Def(kind, id)), - // FIXME: maybe this should handle the subset of PrimitiveType that fits into hir::PrimTy? - Res::Primitive(_) => None, - } + fn from_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Res { + Res::Def(tcx.def_kind(def_id), def_id) } /// Used for error reporting. @@ -160,8 +144,25 @@ impl TryFrom<ResolveRes> for Res { } } -/// A link failed to resolve. -#[derive(Clone, Debug)] +/// The link failed to resolve. [`resolution_failure`] should look to see if there's +/// a more helpful error that can be given. +#[derive(Debug)] +struct UnresolvedPath<'a> { + /// Item on which the link is resolved, used for resolving `Self`. + item_id: ItemId, + /// The scope the link was resolved in. + module_id: DefId, + /// If part of the link resolved, this has the `Res`. + /// + /// In `[std::io::Error::x]`, `std::io::Error` would be a partial resolution. + partial_res: Option<Res>, + /// The remaining unresolved path segments. + /// + /// In `[std::io::Error::x]`, `x` would be unresolved. + unresolved: Cow<'a, str>, +} + +#[derive(Debug)] enum ResolutionFailure<'a> { /// This resolved, but with the wrong namespace. WrongNamespace { @@ -173,35 +174,10 @@ enum ResolutionFailure<'a> { /// even though `Result`'s actual namespace is [`Namespace::TypeNS`]. expected_ns: Namespace, }, - /// The link failed to resolve. [`resolution_failure`] should look to see if there's - /// a more helpful error that can be given. - NotResolved { - /// Item on which the link is resolved, used for resolving `Self`. - item_id: ItemId, - /// The scope the link was resolved in. - module_id: DefId, - /// If part of the link resolved, this has the `Res`. - /// - /// In `[std::io::Error::x]`, `std::io::Error` would be a partial resolution. - partial_res: Option<Res>, - /// The remaining unresolved path segments. - /// - /// In `[std::io::Error::x]`, `x` would be unresolved. - unresolved: Cow<'a, str>, - }, - /// This happens when rustdoc can't determine the parent scope for an item. - /// It is always a bug in rustdoc. - NoParentItem, - /// This link has malformed generic parameters; e.g., the angle brackets are unbalanced. - MalformedGenerics(MalformedGenerics), - /// Used to communicate that this should be ignored, but shouldn't be reported to the user. - /// - /// This happens when there is no disambiguator and one of the namespaces - /// failed to resolve. - Dummy, + NotResolved(UnresolvedPath<'a>), } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] enum MalformedGenerics { /// This link has unbalanced angle brackets. /// @@ -242,35 +218,6 @@ enum MalformedGenerics { EmptyAngleBrackets, } -impl ResolutionFailure<'_> { - /// This resolved fully (not just partially) but is erroneous for some other reason - /// - /// Returns the full resolution of the link, if present. - fn full_res(&self) -> Option<Res> { - match self { - Self::WrongNamespace { res, expected_ns: _ } => Some(*res), - _ => None, - } - } -} - -#[derive(Clone, Copy)] -enum AnchorFailure { - /// User error: `[std#x#y]` is not valid - MultipleAnchors, - /// The anchor provided by the user conflicts with Rustdoc's generated anchor. - /// - /// This is an unfortunate state of affairs. Not every item that can be - /// linked to has its own page; sometimes it is a subheading within a page, - /// like for associated items. In those cases, rustdoc uses an anchor to - /// link to the subheading. Since you can't have two anchors for the same - /// link, Rustdoc disallows having a user-specified anchor. - /// - /// Most of the time this is fine, because you can just link to the page of - /// the item if you want to provide your own anchor. - RustdocAnchorConflict(Res), -} - #[derive(Clone, Debug, Hash, PartialEq, Eq)] crate enum UrlFragment { Item(ItemFragment), @@ -302,24 +249,32 @@ crate enum FragmentKind { VariantField, } -impl ItemFragment { - /// Create a fragment for an associated item. - #[instrument(level = "debug")] - fn from_assoc_item(item: &ty::AssocItem) -> Self { - let def_id = item.def_id; - match item.kind { - ty::AssocKind::Fn => { - if item.defaultness.has_value() { - ItemFragment(FragmentKind::Method, def_id) +impl FragmentKind { + fn from_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> FragmentKind { + match tcx.def_kind(def_id) { + DefKind::AssocFn => { + if tcx.associated_item(def_id).defaultness.has_value() { + FragmentKind::Method + } else { + FragmentKind::TyMethod + } + } + DefKind::AssocConst => FragmentKind::AssociatedConstant, + DefKind::AssocTy => FragmentKind::AssociatedType, + DefKind::Variant => FragmentKind::Variant, + DefKind::Field => { + if tcx.def_kind(tcx.parent(def_id)) == DefKind::Variant { + FragmentKind::VariantField } else { - ItemFragment(FragmentKind::TyMethod, def_id) + FragmentKind::StructField } } - ty::AssocKind::Const => ItemFragment(FragmentKind::AssociatedConstant, def_id), - ty::AssocKind::Type => ItemFragment(FragmentKind::AssociatedType, def_id), + kind => bug!("unexpected associated item kind: {:?}", kind), } } +} +impl ItemFragment { /// Render the fragment, including the leading `#`. crate fn render(&self, s: &mut String, tcx: TyCtxt<'_>) -> std::fmt::Result { write!(s, "#")?; @@ -389,9 +344,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { path_str: &'path str, item_id: ItemId, module_id: DefId, - ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> { + ) -> Result<(Res, DefId), UnresolvedPath<'path>> { let tcx = self.cx.tcx; - let no_res = || ResolutionFailure::NotResolved { + let no_res = || UnresolvedPath { item_id, module_id, partial_res: None, @@ -418,42 +373,27 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let ty_res = self.resolve_path(&path, TypeNS, item_id, module_id).ok_or_else(no_res)?; match ty_res { - Res::Def(DefKind::Enum, did) => { - if tcx - .inherent_impls(did) - .iter() - .flat_map(|imp| tcx.associated_items(*imp).in_definition_order()) - .any(|item| item.name == variant_name) - { - // This is just to let `fold_item` know that this shouldn't be considered; - // it's a bug for the error to make it to the user - return Err(ResolutionFailure::Dummy.into()); - } - match tcx.type_of(did).kind() { - ty::Adt(def, _) if def.is_enum() => { - if let Some(field) = def.all_fields().find(|f| f.name == variant_field_name) - { - Ok((ty_res, Some(ItemFragment(FragmentKind::VariantField, field.did)))) - } else { - Err(ResolutionFailure::NotResolved { - item_id, - module_id, - partial_res: Some(Res::Def(DefKind::Enum, def.did())), - unresolved: variant_field_name.to_string().into(), - } - .into()) - } + Res::Def(DefKind::Enum, did) => match tcx.type_of(did).kind() { + ty::Adt(def, _) if def.is_enum() => { + if let Some(field) = def.all_fields().find(|f| f.name == variant_field_name) { + Ok((ty_res, field.did)) + } else { + Err(UnresolvedPath { + item_id, + module_id, + partial_res: Some(Res::Def(DefKind::Enum, def.did())), + unresolved: variant_field_name.to_string().into(), + }) } - _ => unreachable!(), } - } - _ => Err(ResolutionFailure::NotResolved { + _ => unreachable!(), + }, + _ => Err(UnresolvedPath { item_id, module_id, partial_res: Some(ty_res), unresolved: variant_name.to_string().into(), - } - .into()), + }), } } @@ -463,35 +403,13 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { prim_ty: PrimitiveType, ns: Namespace, item_name: Symbol, - ) -> Option<(Res, ItemFragment)> { + ) -> Option<(Res, DefId)> { let tcx = self.cx.tcx; prim_ty.impls(tcx).find_map(|impl_| { tcx.associated_items(impl_) .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_) - .map(|item| { - let fragment = ItemFragment::from_assoc_item(item); - (Res::Primitive(prim_ty), fragment) - }) - }) - } - - /// Resolves a string as a macro. - /// - /// FIXME(jynelson): Can this be unified with `resolve()`? - fn resolve_macro( - &self, - path_str: &'a str, - item_id: ItemId, - module_id: DefId, - ) -> Result<Res, ResolutionFailure<'a>> { - self.resolve_path(path_str, MacroNS, item_id, module_id).ok_or_else(|| { - ResolutionFailure::NotResolved { - item_id, - module_id, - partial_res: None, - unresolved: path_str.into(), - } + .map(|item| (Res::Primitive(prim_ty), item.def_id)) }) } @@ -525,21 +443,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) } - /// HACK: Try to search the macro name in the list of all `macro_rules` items in the crate. - /// Used when nothing else works, may often give an incorrect result. - fn resolve_macro_rules(&self, path_str: &str, ns: Namespace) -> Option<Res> { - if ns != MacroNS { - return None; - } - - self.cx - .resolver_caches - .all_macro_rules - .get(&Symbol::intern(path_str)) - .copied() - .and_then(|res| res.try_into().ok()) - } - /// Convenience wrapper around `resolve_rustdoc_path`. /// /// This also handles resolving `true` and `false` as booleans. @@ -571,8 +474,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) }) .and_then(|res| res.try_into().ok()) - .or_else(|| resolve_primitive(path_str, ns)) - .or_else(|| self.resolve_macro_rules(path_str, ns)); + .or_else(|| resolve_primitive(path_str, ns)); debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); result } @@ -585,43 +487,22 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ns: Namespace, item_id: ItemId, module_id: DefId, - user_fragment: &Option<String>, - ) -> Result<(Res, Option<UrlFragment>), ErrorKind<'path>> { - let (res, rustdoc_fragment) = self.resolve_inner(path_str, ns, item_id, module_id)?; - let chosen_fragment = match (user_fragment, rustdoc_fragment) { - (Some(_), Some(r_frag)) => { - let diag_res = match r_frag { - ItemFragment(_, did) => Res::Def(self.cx.tcx.def_kind(did), did), - }; - let failure = AnchorFailure::RustdocAnchorConflict(diag_res); - return Err(ErrorKind::AnchorFailure(failure)); - } - (Some(u_frag), None) => Some(UrlFragment::UserWritten(u_frag.clone())), - (None, Some(r_frag)) => Some(UrlFragment::Item(r_frag)), - (None, None) => None, - }; - Ok((res, chosen_fragment)) - } - - fn resolve_inner<'path>( - &mut self, - path_str: &'path str, - ns: Namespace, - item_id: ItemId, - module_id: DefId, - ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> { + ) -> Result<(Res, Option<DefId>), UnresolvedPath<'path>> { if let Some(res) = self.resolve_path(path_str, ns, item_id, module_id) { - match res { - // FIXME(#76467): make this fallthrough to lookup the associated - // item a separate function. - Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => assert_eq!(ns, ValueNS), - Res::Def(DefKind::AssocTy, _) => assert_eq!(ns, TypeNS), - Res::Def(DefKind::Variant, _) => { - return handle_variant(self.cx, res); - } - // Not a trait item; just return what we found. - _ => return Ok((res, None)), - } + return Ok(match res { + Res::Def( + DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Variant, + def_id, + ) => (Res::from_def_id(self.cx.tcx, self.cx.tcx.parent(def_id)), Some(def_id)), + _ => ((res, None)), + }); + } else if ns == MacroNS { + return Err(UnresolvedPath { + item_id, + module_id, + partial_res: None, + unresolved: path_str.into(), + }); } // Try looking for methods and associated items. @@ -637,7 +518,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. .ok_or_else(|| { debug!("found no `::`, assumming {} was correctly not in scope", item_name); - ResolutionFailure::NotResolved { + UnresolvedPath { item_id, module_id, partial_res: None, @@ -652,24 +533,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { resolve_primitive(&path_root, TypeNS) .or_else(|| self.resolve_path(&path_root, TypeNS, item_id, module_id)) .and_then(|ty_res| { - let (res, fragment) = - self.resolve_associated_item(ty_res, item_name, ns, module_id)?; - - Some(Ok((res, Some(fragment)))) + self.resolve_associated_item(ty_res, item_name, ns, module_id).map(Ok) }) .unwrap_or_else(|| { if ns == Namespace::ValueNS { self.variant_field(path_str, item_id, module_id) } else { - Err(ResolutionFailure::NotResolved { + Err(UnresolvedPath { item_id, module_id, partial_res: None, unresolved: path_root.into(), - } - .into()) + }) } }) + .map(|(res, def_id)| (res, Some(def_id))) } /// Convert a DefId to a Res, where possible. @@ -694,7 +572,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ty::FnPtr(_) => Res::Primitive(Fn), ty::Never => Res::Primitive(Never), ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did, .. }, _)), _) | ty::Foreign(did) => { - Res::Def(self.cx.tcx.def_kind(did), did) + Res::from_def_id(self.cx.tcx, did) } ty::Projection(_) | ty::Closure(..) @@ -751,23 +629,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { item_name: Symbol, ns: Namespace, module_id: DefId, - ) -> Option<(Res, ItemFragment)> { + ) -> Option<(Res, DefId)> { let tcx = self.cx.tcx; match root_res { Res::Primitive(prim) => { self.resolve_primitive_associated_item(prim, ns, item_name).or_else(|| { - let assoc_item = self - .primitive_type_to_ty(prim) + self.primitive_type_to_ty(prim) .map(|ty| { resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx) }) - .flatten(); - - assoc_item.map(|item| { - let fragment = ItemFragment::from_assoc_item(&item); - (root_res, fragment) - }) + .flatten() + .map(|item| (root_res, item.def_id)) }) } Res::Def(DefKind::TyAlias, did) => { @@ -788,10 +661,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ty::Adt(adt_def, _) => { for variant in adt_def.variants() { if variant.name == item_name { - return Some(( - root_res, - ItemFragment(FragmentKind::Variant, variant.def_id), - )); + return Some((root_res, variant.def_id)); } } } @@ -832,8 +702,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { debug!("got associated item {:?}", assoc_item); if let Some(item) = assoc_item { - let fragment = ItemFragment::from_assoc_item(&item); - return Some((root_res, fragment)); + return Some((root_res, item.def_id)); } if ns != Namespace::ValueNS { @@ -861,59 +730,22 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }; let field = def.non_enum_variant().fields.iter().find(|item| item.name == item_name)?; - Some((root_res, ItemFragment(FragmentKind::StructField, field.did))) + Some((root_res, field.did)) } Res::Def(DefKind::Trait, did) => tcx .associated_items(did) .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, did) .map(|item| { - let fragment = ItemFragment::from_assoc_item(item); let res = Res::Def(item.kind.as_def_kind(), item.def_id); - (res, fragment) + (res, item.def_id) }), _ => None, } } +} - /// Used for reporting better errors. - /// - /// Returns whether the link resolved 'fully' in another namespace. - /// 'fully' here means that all parts of the link resolved, not just some path segments. - /// This returns the `Res` even if it was erroneous for some reason - /// (such as having invalid URL fragments or being in the wrong namespace). - fn check_full_res( - &mut self, - ns: Namespace, - path_str: &str, - item_id: ItemId, - module_id: DefId, - extra_fragment: &Option<String>, - ) -> Option<Res> { - // resolve() can't be used for macro namespace - let result = match ns { - Namespace::MacroNS => self - .resolve_macro(path_str, item_id, module_id) - .map(|res| (res, None)) - .map_err(ErrorKind::from), - Namespace::TypeNS | Namespace::ValueNS => { - self.resolve(path_str, ns, item_id, module_id, extra_fragment) - } - }; - - let res = match result { - Ok((res, frag)) => { - if let Some(UrlFragment::Item(ItemFragment(_, id))) = frag { - Some(Res::Def(self.cx.tcx.def_kind(id), id)) - } else { - Some(res) - } - } - Err(ErrorKind::Resolve(box kind)) => kind.full_res(), - Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => Some(res), - Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None, - }; - res - } +fn full_res(tcx: TyCtxt<'_>, (base, assoc_item): (Res, Option<DefId>)) -> Res { + assoc_item.map_or(base, |def_id| Res::from_def_id(tcx, def_id)) } /// Look to see if a resolved item has an associated item named `item_name`. @@ -1093,14 +925,23 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { } enum PreprocessingError { - Anchor(AnchorFailure), + /// User error: `[std#x#y]` is not valid + MultipleAnchors, Disambiguator(Range<usize>, String), - Resolution(ResolutionFailure<'static>, String, Option<Disambiguator>), + MalformedGenerics(MalformedGenerics, String), } -impl From<AnchorFailure> for PreprocessingError { - fn from(err: AnchorFailure) -> Self { - Self::Anchor(err) +impl PreprocessingError { + fn report(&self, cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>) { + match self { + PreprocessingError::MultipleAnchors => report_multiple_anchors(cx, diag_info), + PreprocessingError::Disambiguator(range, msg) => { + disambiguator_error(cx, diag_info, range.clone(), msg) + } + PreprocessingError::MalformedGenerics(err, path_str) => { + report_malformed_generics(cx, diag_info, *err, path_str) + } + } } } @@ -1145,7 +986,7 @@ fn preprocess_link( let extra_fragment = parts.next(); if parts.next().is_some() { // A valid link can't have multiple #'s - return Some(Err(AnchorFailure::MultipleAnchors.into())); + return Some(Err(PreprocessingError::MultipleAnchors)); } // Parse and strip the disambiguator from the link, if present. @@ -1173,13 +1014,9 @@ fn preprocess_link( let path_str = if path_str.contains(['<', '>'].as_slice()) { match strip_generics_from_path(path_str) { Ok(path) => path, - Err(err_kind) => { + Err(err) => { debug!("link has malformed generics: {}", path_str); - return Some(Err(PreprocessingError::Resolution( - err_kind, - path_str.to_owned(), - disambiguator, - ))); + return Some(Err(PreprocessingError::MalformedGenerics(err, path_str.to_owned()))); } } } else { @@ -1229,32 +1066,10 @@ impl LinkCollector<'_, '_> { link_range: ori_link.range.clone(), }; - let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } = match pp_link - { - Ok(x) => x, - Err(err) => { - match err { - PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, *err), - PreprocessingError::Disambiguator(range, msg) => { - disambiguator_error(self.cx, diag_info, range.clone(), msg) - } - PreprocessingError::Resolution(err, path_str, disambiguator) => { - resolution_failure( - self, - diag_info, - path_str, - *disambiguator, - smallvec![err.clone()], - ); - } - } - return None; - } - }; + let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } = + pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?; let disambiguator = *disambiguator; - let inner_docs = item.inner_docs(self.cx.tcx); - // In order to correctly resolve intra-doc links we need to // pick a base AST node to work from. If the documentation for // this module came from an inner comment (//!) then we anchor @@ -1266,21 +1081,10 @@ impl LinkCollector<'_, '_> { // we've already pushed this node onto the resolution stack but // for outer comments we explicitly try and resolve against the // parent_node first. + let inner_docs = item.inner_docs(self.cx.tcx); let base_node = if item.is_mod() && inner_docs { self.mod_ids.last().copied() } else { parent_node }; - - let Some(module_id) = base_node else { - // This is a bug. - debug!("attempting to resolve item without parent module: {}", path_str); - resolution_failure( - self, - diag_info, - path_str, - disambiguator, - smallvec![ResolutionFailure::NoParentItem], - ); - return None; - }; + let module_id = base_node.expect("doc link without parent module"); let (mut res, fragment) = self.resolve_with_disambiguator_cached( ResolutionInfo { @@ -1504,7 +1308,21 @@ impl LinkCollector<'_, '_> { } } - let res = self.resolve_with_disambiguator(&key, diag); + let res = self.resolve_with_disambiguator(&key, diag.clone()).and_then(|(res, def_id)| { + let fragment = match (&key.extra_fragment, def_id) { + (Some(_), Some(def_id)) => { + report_anchor_conflict(self.cx, diag, Res::from_def_id(self.cx.tcx, def_id)); + return None; + } + (Some(u_frag), None) => Some(UrlFragment::UserWritten(u_frag.clone())), + (None, Some(def_id)) => Some(UrlFragment::Item(ItemFragment( + FragmentKind::from_def_id(self.cx.tcx, def_id), + def_id, + ))), + (None, None) => None, + }; + Some((res, fragment)) + }); // Cache only if resolved successfully - don't silence duplicate errors if let Some(res) = res { @@ -1529,103 +1347,55 @@ impl LinkCollector<'_, '_> { &mut self, key: &ResolutionInfo, diag: DiagnosticInfo<'_>, - ) -> Option<(Res, Option<UrlFragment>)> { + ) -> Option<(Res, Option<DefId>)> { let disambiguator = key.dis; let path_str = &key.path_str; let item_id = key.item_id; let base_node = key.module_id; - let extra_fragment = &key.extra_fragment; match disambiguator.map(Disambiguator::ns) { - Some(expected_ns @ (ValueNS | TypeNS)) => { - match self.resolve(path_str, expected_ns, item_id, base_node, extra_fragment) { + Some(expected_ns) => { + match self.resolve(path_str, expected_ns, item_id, base_node) { Ok(res) => Some(res), - Err(ErrorKind::Resolve(box mut kind)) => { + Err(err) => { // We only looked in one namespace. Try to give a better error if possible. - if kind.full_res().is_none() { - let other_ns = if expected_ns == ValueNS { TypeNS } else { ValueNS }; - // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator` - // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach - for new_ns in [other_ns, MacroNS] { - if let Some(res) = self.check_full_res( - new_ns, - path_str, - item_id, - base_node, - extra_fragment, - ) { - kind = ResolutionFailure::WrongNamespace { res, expected_ns }; + // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`. + // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach. + let mut err = ResolutionFailure::NotResolved(err); + for other_ns in [TypeNS, ValueNS, MacroNS] { + if other_ns != expected_ns { + if let Ok(res) = + self.resolve(path_str, other_ns, item_id, base_node) + { + err = ResolutionFailure::WrongNamespace { + res: full_res(self.cx.tcx, res), + expected_ns, + }; break; } } } - resolution_failure(self, diag, path_str, disambiguator, smallvec![kind]); - // This could just be a normal link or a broken link - // we could potentially check if something is - // "intra-doc-link-like" and warn in that case. - None - } - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(self.cx, diag, msg); - None + resolution_failure(self, diag, path_str, disambiguator, smallvec![err]) } } } None => { // Try everything! - let mut candidates = PerNS { - macro_ns: self - .resolve_macro(path_str, item_id, base_node) - .map(|res| (res, extra_fragment.clone().map(UrlFragment::UserWritten))), - type_ns: match self.resolve( - path_str, - TypeNS, - item_id, - base_node, - extra_fragment, - ) { - Ok(res) => { - debug!("got res in TypeNS: {:?}", res); - Ok(res) - } - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(self.cx, diag, msg); - return None; - } - Err(ErrorKind::Resolve(box kind)) => Err(kind), - }, - value_ns: match self.resolve( - path_str, - ValueNS, - item_id, - base_node, - extra_fragment, - ) { - Ok(res) => Ok(res), - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(self.cx, diag, msg); - return None; - } - Err(ErrorKind::Resolve(box kind)) => Err(kind), - } - .and_then(|(res, fragment)| { - // Constructors are picked up in the type namespace. + let mut candidate = |ns| { + self.resolve(path_str, ns, item_id, base_node) + .map_err(ResolutionFailure::NotResolved) + }; + + let candidates = PerNS { + macro_ns: candidate(MacroNS), + type_ns: candidate(TypeNS), + value_ns: candidate(ValueNS).and_then(|(res, def_id)| { match res { + // Constructors are picked up in the type namespace. Res::Def(DefKind::Ctor(..), _) => { Err(ResolutionFailure::WrongNamespace { res, expected_ns: TypeNS }) } - _ => { - match (fragment, extra_fragment.clone()) { - (Some(fragment), Some(_)) => { - // Shouldn't happen but who knows? - Ok((res, Some(fragment))) - } - (fragment, None) => Ok((res, fragment)), - (None, fragment) => { - Ok((res, fragment.map(UrlFragment::UserWritten))) - } - } - } + _ => Ok((res, def_id)), } }), }; @@ -1633,15 +1403,13 @@ impl LinkCollector<'_, '_> { let len = candidates.iter().filter(|res| res.is_ok()).count(); if len == 0 { - resolution_failure( + return resolution_failure( self, diag, path_str, disambiguator, candidates.into_iter().filter_map(|res| res.err()).collect(), ); - // this could just be a normal link - return None; } if len == 1 { @@ -1649,38 +1417,17 @@ impl LinkCollector<'_, '_> { } else if len == 2 && is_derive_trait_collision(&candidates) { Some(candidates.type_ns.unwrap()) } else { - if is_derive_trait_collision(&candidates) { - candidates.macro_ns = Err(ResolutionFailure::Dummy); - } + let ignore_macro = is_derive_trait_collision(&candidates); // If we're reporting an ambiguity, don't mention the namespaces that failed - let candidates = candidates.map(|candidate| candidate.ok().map(|(res, _)| res)); + let mut candidates = + candidates.map(|candidate| candidate.ok().map(|(res, _)| res)); + if ignore_macro { + candidates.macro_ns = None; + } ambiguity_error(self.cx, diag, path_str, candidates.present_items().collect()); None } } - Some(MacroNS) => { - match self.resolve_macro(path_str, item_id, base_node) { - Ok(res) => Some((res, extra_fragment.clone().map(UrlFragment::UserWritten))), - Err(mut kind) => { - // `resolve_macro` only looks in the macro namespace. Try to give a better error if possible. - for ns in [TypeNS, ValueNS] { - if let Some(res) = self.check_full_res( - ns, - path_str, - item_id, - base_node, - extra_fragment, - ) { - kind = - ResolutionFailure::WrongNamespace { res, expected_ns: MacroNS }; - break; - } - } - resolution_failure(self, diag, path_str, disambiguator, smallvec![kind]); - None - } - } - } } } } @@ -1968,8 +1715,9 @@ fn resolution_failure( path_str: &str, disambiguator: Option<Disambiguator>, kinds: SmallVec<[ResolutionFailure<'_>; 3]>, -) { +) -> Option<(Res, Option<DefId>)> { let tcx = collector.cx.tcx; + let mut recovered_res = None; report_diagnostic( tcx, BROKEN_INTRA_DOC_LINKS, @@ -1995,12 +1743,12 @@ fn resolution_failure( } variants_seen.push(variant); - if let ResolutionFailure::NotResolved { + if let ResolutionFailure::NotResolved(UnresolvedPath { item_id, module_id, partial_res, unresolved, - } = &mut failure + }) = &mut failure { use DefKind::*; @@ -2026,11 +1774,9 @@ fn resolution_failure( }; name = start; for ns in [TypeNS, ValueNS, MacroNS] { - if let Some(res) = - collector.check_full_res(ns, start, item_id, module_id, &None) - { + if let Ok(res) = collector.resolve(start, ns, item_id, module_id) { debug!("found partial_res={:?}", res); - *partial_res = Some(res); + *partial_res = Some(full_res(collector.cx.tcx, res)); *unresolved = end.into(); break 'outer; } @@ -2059,11 +1805,22 @@ fn resolution_failure( diag.note(¬e); } - // If the link has `::` in it, assume it was meant to be an intra-doc link. - // Otherwise, the `[]` might be unrelated. - // FIXME: don't show this for autolinks (`<>`), `()` style links, or reference links if !path_str.contains("::") { - diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); + if disambiguator.map_or(true, |d| d.ns() == MacroNS) + && let Some(&res) = collector.cx.resolver_caches.all_macro_rules + .get(&Symbol::intern(path_str)) + { + diag.note(format!( + "`macro_rules` named `{path_str}` exists in this crate, \ + but it is not in scope at this link's location" + )); + recovered_res = res.try_into().ok().map(|res| (res, None)); + } else { + // If the link has `::` in it, assume it was meant to be an + // intra-doc link. Otherwise, the `[]` might be unrelated. + diag.help("to escape `[` and `]` characters, \ + add '\\' before them like `\\[` or `\\]`"); + } } continue; @@ -2130,7 +1887,6 @@ fn resolution_failure( } let note = match failure { ResolutionFailure::NotResolved { .. } => unreachable!("handled above"), - ResolutionFailure::Dummy => continue, ResolutionFailure::WrongNamespace { res, expected_ns } => { suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp); @@ -2140,38 +1896,6 @@ fn resolution_failure( expected_ns.descr() ) } - ResolutionFailure::NoParentItem => { - // FIXME(eddyb) this doesn't belong here, whatever made - // the `ResolutionFailure::NoParentItem` should emit an - // immediate or delayed `span_bug` about the issue. - tcx.sess.delay_span_bug( - sp.unwrap_or(DUMMY_SP), - "intra-doc link missing parent item", - ); - - "BUG: all intra-doc links should have a parent item".to_owned() - } - ResolutionFailure::MalformedGenerics(variant) => match variant { - MalformedGenerics::UnbalancedAngleBrackets => { - String::from("unbalanced angle brackets") - } - MalformedGenerics::MissingType => { - String::from("missing type for generic parameters") - } - MalformedGenerics::HasFullyQualifiedSyntax => { - diag.note("see https://github.com/rust-lang/rust/issues/74563 for more information"); - String::from("fully-qualified syntax is unsupported") - } - MalformedGenerics::InvalidPathSeparator => { - String::from("has invalid path separator") - } - MalformedGenerics::TooManyAngleBrackets => { - String::from("too many angle brackets") - } - MalformedGenerics::EmptyAngleBrackets => { - String::from("empty angle brackets") - } - }, }; if let Some(span) = sp { diag.span_label(span, ¬e); @@ -2181,24 +1905,28 @@ fn resolution_failure( } }, ); + + recovered_res } -/// Report an anchor failure. -fn anchor_failure(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, failure: AnchorFailure) { - let (msg, anchor_idx) = match failure { - AnchorFailure::MultipleAnchors => { - (format!("`{}` contains multiple anchors", diag_info.ori_link), 1) - } - AnchorFailure::RustdocAnchorConflict(res) => ( - format!( - "`{}` contains an anchor, but links to {kind}s are already anchored", - diag_info.ori_link, - kind = res.descr(), - ), - 0, - ), - }; +fn report_multiple_anchors(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>) { + let msg = format!("`{}` contains multiple anchors", diag_info.ori_link); + anchor_failure(cx, diag_info, &msg, 1) +} +fn report_anchor_conflict(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, res: Res) { + let (link, kind) = (diag_info.ori_link, res.descr()); + let msg = format!("`{link}` contains an anchor, but links to {kind}s are already anchored"); + anchor_failure(cx, diag_info, &msg, 0) +} + +/// Report an anchor failure. +fn anchor_failure( + cx: &DocContext<'_>, + diag_info: DiagnosticInfo<'_>, + msg: &str, + anchor_idx: usize, +) { report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, |diag, sp| { if let Some(mut sp) = sp { if let Some((fragment_offset, _)) = @@ -2208,13 +1936,6 @@ fn anchor_failure(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, failure: A } diag.span_label(sp, "invalid anchor"); } - if let AnchorFailure::RustdocAnchorConflict(Res::Primitive(_)) = failure { - if let Some(sp) = sp { - span_bug!(sp, "anchors should be allowed now"); - } else { - bug!("anchors should be allowed now"); - } - } }); } @@ -2235,6 +1956,40 @@ fn disambiguator_error( }); } +fn report_malformed_generics( + cx: &DocContext<'_>, + diag_info: DiagnosticInfo<'_>, + err: MalformedGenerics, + path_str: &str, +) { + report_diagnostic( + cx.tcx, + BROKEN_INTRA_DOC_LINKS, + &format!("unresolved link to `{}`", path_str), + &diag_info, + |diag, sp| { + let note = match err { + MalformedGenerics::UnbalancedAngleBrackets => "unbalanced angle brackets", + MalformedGenerics::MissingType => "missing type for generic parameters", + MalformedGenerics::HasFullyQualifiedSyntax => { + diag.note( + "see https://github.com/rust-lang/rust/issues/74563 for more information", + ); + "fully-qualified syntax is unsupported" + } + MalformedGenerics::InvalidPathSeparator => "has invalid path separator", + MalformedGenerics::TooManyAngleBrackets => "too many angle brackets", + MalformedGenerics::EmptyAngleBrackets => "empty angle brackets", + }; + if let Some(span) = sp { + diag.span_label(span, note); + } else { + diag.note(note); + } + }, + ); +} + /// Report an ambiguity error, where there were multiple possible resolutions. fn ambiguity_error( cx: &DocContext<'_>, @@ -2331,17 +2086,6 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str: }); } -/// Given an enum variant's res, return the res of its enum and the associated fragment. -fn handle_variant( - cx: &DocContext<'_>, - res: Res, -) -> Result<(Res, Option<ItemFragment>), ErrorKind<'static>> { - let parent = cx.tcx.parent(res.def_id(cx.tcx)); - let parent_def = Res::Def(DefKind::Enum, parent); - let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap()); - Ok((parent_def, Some(ItemFragment(FragmentKind::Variant, variant.def_id)))) -} - /// Resolve a primitive type or value. fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> { if ns != TypeNS { @@ -2381,7 +2125,7 @@ fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> { Some(Res::Primitive(prim)) } -fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure<'static>> { +fn strip_generics_from_path(path_str: &str) -> Result<String, MalformedGenerics> { let mut stripped_segments = vec![]; let mut path = path_str.chars().peekable(); let mut segment = Vec::new(); @@ -2396,9 +2140,7 @@ fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure< stripped_segments.push(stripped_segment); } } else { - return Err(ResolutionFailure::MalformedGenerics( - MalformedGenerics::InvalidPathSeparator, - )); + return Err(MalformedGenerics::InvalidPathSeparator); } } '<' => { @@ -2406,14 +2148,10 @@ fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure< match path.next() { Some('<') => { - return Err(ResolutionFailure::MalformedGenerics( - MalformedGenerics::TooManyAngleBrackets, - )); + return Err(MalformedGenerics::TooManyAngleBrackets); } Some('>') => { - return Err(ResolutionFailure::MalformedGenerics( - MalformedGenerics::EmptyAngleBrackets, - )); + return Err(MalformedGenerics::EmptyAngleBrackets); } Some(chr) => { segment.push(chr); @@ -2441,16 +2179,10 @@ fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure< let stripped_path = stripped_segments.join("::"); - if !stripped_path.is_empty() { - Ok(stripped_path) - } else { - Err(ResolutionFailure::MalformedGenerics(MalformedGenerics::MissingType)) - } + if !stripped_path.is_empty() { Ok(stripped_path) } else { Err(MalformedGenerics::MissingType) } } -fn strip_generics_from_path_segment( - segment: Vec<char>, -) -> Result<String, ResolutionFailure<'static>> { +fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<String, MalformedGenerics> { let mut stripped_segment = String::new(); let mut param_depth = 0; @@ -2465,9 +2197,7 @@ fn strip_generics_from_path_segment( if latest_generics_chunk.contains(" as ") { // The segment tries to use fully-qualified syntax, which is currently unsupported. // Give a helpful error message instead of completely ignoring the angle brackets. - return Err(ResolutionFailure::MalformedGenerics( - MalformedGenerics::HasFullyQualifiedSyntax, - )); + return Err(MalformedGenerics::HasFullyQualifiedSyntax); } } else { if param_depth == 0 { @@ -2482,6 +2212,6 @@ fn strip_generics_from_path_segment( Ok(stripped_segment) } else { // The segment has unbalanced angle brackets, e.g. `Vec<T` or `Vec<T>>` - Err(ResolutionFailure::MalformedGenerics(MalformedGenerics::UnbalancedAngleBrackets)) + Err(MalformedGenerics::UnbalancedAngleBrackets) } } diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs index 07d05cab1d1..6f9912e71c5 100644 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -40,6 +40,7 @@ crate fn early_resolve_intra_doc_links( traits_in_scope: Default::default(), all_traits: Default::default(), all_trait_impls: Default::default(), + all_macro_rules: Default::default(), document_private_items, }; @@ -64,7 +65,7 @@ crate fn early_resolve_intra_doc_links( traits_in_scope: link_resolver.traits_in_scope, all_traits: Some(link_resolver.all_traits), all_trait_impls: Some(link_resolver.all_trait_impls), - all_macro_rules: link_resolver.resolver.take_all_macro_rules(), + all_macro_rules: link_resolver.all_macro_rules, } } @@ -82,6 +83,7 @@ struct EarlyDocLinkResolver<'r, 'ra> { traits_in_scope: DefIdMap<Vec<TraitCandidate>>, all_traits: Vec<DefId>, all_trait_impls: Vec<DefId>, + all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>, document_private_items: bool, } @@ -134,24 +136,21 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { // using privacy, private traits and impls from other crates are never documented in // the current crate, and links in their doc comments are not resolved. for &def_id in &all_traits { - if self.resolver.cstore().visibility_untracked(def_id) == Visibility::Public { + if self.resolver.cstore().visibility_untracked(def_id).is_public() { self.resolve_doc_links_extern_impl(def_id, false); } } for &(trait_def_id, impl_def_id, simplified_self_ty) in &all_trait_impls { - if self.resolver.cstore().visibility_untracked(trait_def_id) - == Visibility::Public + if self.resolver.cstore().visibility_untracked(trait_def_id).is_public() && simplified_self_ty.and_then(|ty| ty.def()).map_or(true, |ty_def_id| { - self.resolver.cstore().visibility_untracked(ty_def_id) - == Visibility::Public + self.resolver.cstore().visibility_untracked(ty_def_id).is_public() }) { self.resolve_doc_links_extern_impl(impl_def_id, false); } } for (ty_def_id, impl_def_id) in all_inherent_impls { - if self.resolver.cstore().visibility_untracked(ty_def_id) == Visibility::Public - { + if self.resolver.cstore().visibility_untracked(ty_def_id).is_public() { self.resolve_doc_links_extern_impl(impl_def_id, true); } } @@ -173,35 +172,50 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { } fn resolve_doc_links_extern_impl(&mut self, def_id: DefId, is_inherent: bool) { - self.resolve_doc_links_extern_outer(def_id, def_id); + self.resolve_doc_links_extern_outer_fixme(def_id, def_id); let assoc_item_def_ids = Vec::from_iter( self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.sess), ); for assoc_def_id in assoc_item_def_ids { - if !is_inherent - || self.resolver.cstore().visibility_untracked(assoc_def_id) == Visibility::Public + if !is_inherent || self.resolver.cstore().visibility_untracked(assoc_def_id).is_public() { - self.resolve_doc_links_extern_outer(assoc_def_id, def_id); + self.resolve_doc_links_extern_outer_fixme(assoc_def_id, def_id); } } } - fn resolve_doc_links_extern_outer(&mut self, def_id: DefId, scope_id: DefId) { + // FIXME: replace all uses with `resolve_doc_links_extern_outer` to actually resolve links, not + // just add traits in scope. This may be expensive and require benchmarking and optimization. + fn resolve_doc_links_extern_outer_fixme(&mut self, def_id: DefId, scope_id: DefId) { if !self.resolver.cstore().may_have_doc_links_untracked(def_id) { return; } - // FIXME: actually resolve links, not just add traits in scope. if let Some(parent_id) = self.resolver.opt_parent(scope_id) { self.add_traits_in_scope(parent_id); } } + fn resolve_doc_links_extern_outer(&mut self, def_id: DefId, scope_id: DefId) { + if !self.resolver.cstore().may_have_doc_links_untracked(def_id) { + return; + } + let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess)); + let parent_scope = ParentScope::module( + self.resolver.get_nearest_non_block_module( + self.resolver.opt_parent(scope_id).unwrap_or(scope_id), + ), + self.resolver, + ); + self.resolve_doc_links(doc_attrs(attrs.iter()), parent_scope); + } + fn resolve_doc_links_extern_inner(&mut self, def_id: DefId) { if !self.resolver.cstore().may_have_doc_links_untracked(def_id) { return; } - // FIXME: actually resolve links, not just add traits in scope. - self.add_traits_in_scope(def_id); + let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess)); + let parent_scope = ParentScope::module(self.resolver.expect_module(def_id), self.resolver); + self.resolve_doc_links(doc_attrs(attrs.iter()), parent_scope); } fn resolve_doc_links_local(&mut self, attrs: &[ast::Attribute]) { @@ -255,9 +269,16 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { } } - // FIXME: Resolve all prefixes for type-relative resolution or for diagnostics. - if (need_assoc || !any_resolved) && pinfo.path_str.contains("::") { - need_traits_in_scope = true; + // Resolve all prefixes for type-relative resolution or for diagnostics. + if need_assoc || !any_resolved { + let mut path = &pinfo.path_str[..]; + while let Some(idx) = path.rfind("::") { + path = &path[..idx]; + need_traits_in_scope = true; + for ns in [TypeNS, ValueNS, MacroNS] { + self.resolve_and_cache(path, ns, &parent_scope); + } + } } } } @@ -279,7 +300,7 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> { for child in self.resolver.module_children_or_reexports(module_id) { // This condition should give a superset of `denied` from `fn clean_use_statement`. - if child.vis == Visibility::Public + if child.vis.is_public() || self.document_private_items && child.vis != Visibility::Restricted(module_id) && module_id.is_local() @@ -343,8 +364,10 @@ impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> { self.all_trait_impls.push(self.resolver.local_def_id(item.id).to_def_id()); } ItemKind::MacroDef(macro_def) if macro_def.macro_rules => { - self.parent_scope.macro_rules = + let (macro_rules_scope, res) = self.resolver.macro_rules_scope(self.resolver.local_def_id(item.id)); + self.parent_scope.macro_rules = macro_rules_scope; + self.all_macro_rules.insert(item.ident.name, res); } _ => {} } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index d245c3750ec..3b7ca7dc3c5 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -53,9 +53,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate while let Some(did) = parent { attr_buf.extend( cx.tcx - .get_attrs(did) - .iter() - .filter(|attr| attr.has_name(sym::doc)) + .get_attrs(did, sym::doc) .filter(|attr| { if let Some([attr]) = attr.meta_item_list().as_deref() { attr.has_name(sym::cfg) diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 0da490f3cd6..e0aed1e1ed4 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -303,7 +303,7 @@ crate fn run( // Run call-finder on all items let mut calls = FxHashMap::default(); let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates }; - tcx.hir().visit_all_item_likes(&mut finder.as_deep_visitor()); + tcx.hir().deep_visit_all_item_likes(&mut finder); // Sort call locations within a given file in document order for fn_calls in calls.values_mut() { diff --git a/src/llvm-project b/src/llvm-project -Subproject 593484fc1596707406b0b0b45b97feb08d2a1bf +Subproject 47848665966fc7393cb6f898077994f6dec2b59 diff --git a/src/test/codegen/simd-wide-sum.rs b/src/test/codegen/simd-wide-sum.rs new file mode 100644 index 00000000000..fde9b0fcd8a --- /dev/null +++ b/src/test/codegen/simd-wide-sum.rs @@ -0,0 +1,54 @@ +// compile-flags: -C opt-level=3 --edition=2021 +// only-x86_64 +// ignore-debug: the debug assertions get in the way + +#![crate_type = "lib"] +#![feature(portable_simd)] + +use std::simd::Simd; +const N: usize = 8; + +#[no_mangle] +// CHECK-LABEL: @wider_reduce_simd +pub fn wider_reduce_simd(x: Simd<u8, N>) -> u16 { + // CHECK: zext <8 x i8> + // CHECK-SAME: to <8 x i16> + // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> + let x: Simd<u16, N> = x.cast(); + x.reduce_sum() +} + +#[no_mangle] +// CHECK-LABEL: @wider_reduce_loop +pub fn wider_reduce_loop(x: Simd<u8, N>) -> u16 { + // CHECK: zext <8 x i8> + // CHECK-SAME: to <8 x i16> + // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> + let mut sum = 0_u16; + for i in 0..N { + sum += u16::from(x[i]); + } + sum +} + +#[no_mangle] +// CHECK-LABEL: @wider_reduce_iter +pub fn wider_reduce_iter(x: Simd<u8, N>) -> u16 { + // CHECK: zext <8 x i8> + // CHECK-SAME: to <8 x i16> + // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> + x.as_array().iter().copied().map(u16::from).sum() +} + +// This iterator one is the most interesting, as it's the one +// which used to not auto-vectorize due to a suboptimality in the +// `<array::IntoIter as Iterator>::fold` implementation. + +#[no_mangle] +// CHECK-LABEL: @wider_reduce_into_iter +pub fn wider_reduce_into_iter(x: Simd<u8, N>) -> u16 { + // CHECK: zext <8 x i8> + // CHECK-SAME: to <8 x i16> + // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> + x.to_array().into_iter().map(u16::from).sum() +} diff --git a/src/test/mir-opt/inline/cycle.g.Inline.diff b/src/test/mir-opt/inline/cycle.g.Inline.diff index 46f5e5e2065..450157e6428 100644 --- a/src/test/mir-opt/inline/cycle.g.Inline.diff +++ b/src/test/mir-opt/inline/cycle.g.Inline.diff @@ -4,22 +4,55 @@ fn g() -> () { let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:11:8: 11:8 let _1: (); // in scope 0 at $DIR/cycle.rs:12:5: 12:12 ++ let mut _2: fn() {main}; // in scope 0 at $DIR/cycle.rs:12:5: 12:12 ++ let mut _5: (); // in scope 0 at $DIR/cycle.rs:6:5: 6:8 ++ scope 1 (inlined f::<fn() {main}>) { // at $DIR/cycle.rs:12:5: 12:12 ++ debug g => _2; // in scope 1 at $DIR/cycle.rs:5:6: 5:7 ++ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ let mut _4: &fn() {main}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8 ++ } ++ } bb0: { StorageLive(_1); // scope 0 at $DIR/cycle.rs:12:5: 12:12 - _1 = f::<fn() {main}>(main) -> bb1; // scope 0 at $DIR/cycle.rs:12:5: 12:12 - // mir::Constant - // + span: $DIR/cycle.rs:12:5: 12:6 - // + literal: Const { ty: fn(fn() {main}) {f::<fn() {main}>}, val: Value(Scalar(<ZST>)) } +- _1 = f::<fn() {main}>(main) -> bb1; // scope 0 at $DIR/cycle.rs:12:5: 12:12 ++ StorageLive(_2); // scope 0 at $DIR/cycle.rs:12:5: 12:12 ++ _2 = main; // scope 0 at $DIR/cycle.rs:12:5: 12:12 // mir::Constant +- // + span: $DIR/cycle.rs:12:5: 12:6 +- // + literal: Const { ty: fn(fn() {main}) {f::<fn() {main}>}, val: Value(Scalar(<ZST>)) } +- // mir::Constant // + span: $DIR/cycle.rs:12:7: 12:11 // + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) } ++ StorageLive(_3); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ _5 = const (); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb1: { ++ StorageDead(_2); // scope 0 at $DIR/cycle.rs:12:5: 12:12 StorageDead(_1); // scope 0 at $DIR/cycle.rs:12:12: 12:13 _0 = const (); // scope 0 at $DIR/cycle.rs:11:8: 13:2 return; // scope 0 at $DIR/cycle.rs:13:2: 13:2 ++ } ++ ++ bb2 (cleanup): { ++ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2 ++ } ++ ++ bb3 (cleanup): { ++ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2 ++ } ++ ++ bb4: { ++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9 ++ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 } } diff --git a/src/test/mir-opt/inline/cycle.main.Inline.diff b/src/test/mir-opt/inline/cycle.main.Inline.diff index c8d1448d949..5e2f70799e4 100644 --- a/src/test/mir-opt/inline/cycle.main.Inline.diff +++ b/src/test/mir-opt/inline/cycle.main.Inline.diff @@ -4,22 +4,72 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:16:11: 16:11 let _1: (); // in scope 0 at $DIR/cycle.rs:17:5: 17:9 ++ let mut _2: fn() {g}; // in scope 0 at $DIR/cycle.rs:17:5: 17:9 ++ let mut _5: (); // in scope 0 at $DIR/cycle.rs:6:5: 6:8 ++ scope 1 (inlined f::<fn() {g}>) { // at $DIR/cycle.rs:17:5: 17:9 ++ debug g => _2; // in scope 1 at $DIR/cycle.rs:5:6: 5:7 ++ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ let mut _4: &fn() {g}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8 ++ scope 3 (inlined g) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL ++ let mut _6: fn() {main}; // in scope 3 at $DIR/cycle.rs:12:5: 12:12 ++ scope 4 (inlined f::<fn() {main}>) { // at $DIR/cycle.rs:12:5: 12:12 ++ debug g => _6; // in scope 4 at $DIR/cycle.rs:5:6: 5:7 ++ let _7: (); // in scope 4 at $DIR/cycle.rs:6:5: 6:8 ++ let mut _8: &fn() {main}; // in scope 4 at $DIR/cycle.rs:6:5: 6:6 ++ scope 5 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8 ++ } ++ } ++ } ++ } ++ } bb0: { StorageLive(_1); // scope 0 at $DIR/cycle.rs:17:5: 17:9 - _1 = f::<fn() {g}>(g) -> bb1; // scope 0 at $DIR/cycle.rs:17:5: 17:9 - // mir::Constant - // + span: $DIR/cycle.rs:17:5: 17:6 - // + literal: Const { ty: fn(fn() {g}) {f::<fn() {g}>}, val: Value(Scalar(<ZST>)) } +- _1 = f::<fn() {g}>(g) -> bb1; // scope 0 at $DIR/cycle.rs:17:5: 17:9 ++ StorageLive(_2); // scope 0 at $DIR/cycle.rs:17:5: 17:9 ++ _2 = g; // scope 0 at $DIR/cycle.rs:17:5: 17:9 // mir::Constant +- // + span: $DIR/cycle.rs:17:5: 17:6 +- // + literal: Const { ty: fn(fn() {g}) {f::<fn() {g}>}, val: Value(Scalar(<ZST>)) } +- // mir::Constant // + span: $DIR/cycle.rs:17:7: 17:8 // + literal: Const { ty: fn() {g}, val: Value(Scalar(<ZST>)) } ++ StorageLive(_3); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6 ++ StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ _5 = const (); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ StorageLive(_6); // scope 3 at $DIR/cycle.rs:12:5: 12:12 ++ StorageLive(_7); // scope 4 at $DIR/cycle.rs:6:5: 6:8 ++ StorageLive(_8); // scope 4 at $DIR/cycle.rs:6:5: 6:6 ++ _8 = &_6; // scope 4 at $DIR/cycle.rs:6:5: 6:6 ++ _7 = move (*_8)() -> [return: bb4, unwind: bb2]; // scope 5 at $SRC_DIR/core/src/ops/function.rs:LL:COL } bb1: { ++ StorageDead(_2); // scope 0 at $DIR/cycle.rs:17:5: 17:9 StorageDead(_1); // scope 0 at $DIR/cycle.rs:17:9: 17:10 _0 = const (); // scope 0 at $DIR/cycle.rs:16:11: 18:2 return; // scope 0 at $DIR/cycle.rs:18:2: 18:2 ++ } ++ ++ bb2 (cleanup): { ++ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2 ++ } ++ ++ bb3 (cleanup): { ++ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2 ++ } ++ ++ bb4: { ++ StorageDead(_8); // scope 4 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_7); // scope 4 at $DIR/cycle.rs:6:8: 6:9 ++ StorageDead(_6); // scope 3 at $DIR/cycle.rs:12:5: 12:12 ++ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8 ++ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8 ++ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9 ++ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2 } } diff --git a/src/test/mir-opt/inline/dyn-trait.rs b/src/test/mir-opt/inline/dyn-trait.rs new file mode 100644 index 00000000000..6a46e1e07b1 --- /dev/null +++ b/src/test/mir-opt/inline/dyn-trait.rs @@ -0,0 +1,35 @@ +#![crate_type = "lib"] + +use std::fmt::Debug; + +pub trait Cache { + type V: Debug; + + fn store_nocache(&self); +} + +pub trait Query { + type V; + type C: Cache<V = Self::V>; + + fn cache<T>(s: &T) -> &Self::C; +} + +// EMIT_MIR dyn_trait.mk_cycle.Inline.diff +#[inline(always)] +pub fn mk_cycle<V: Debug>(c: &dyn Cache<V = V>) { + c.store_nocache() +} + +// EMIT_MIR dyn_trait.try_execute_query.Inline.diff +#[inline(always)] +pub fn try_execute_query<C: Cache>(c: &C) { + mk_cycle(c) +} + +// EMIT_MIR dyn_trait.get_query.Inline.diff +#[inline(always)] +pub fn get_query<Q: Query, T>(t: &T) { + let c = Q::cache(t); + try_execute_query(c) +} diff --git a/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff new file mode 100644 index 00000000000..953d7b85c5b --- /dev/null +++ b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff @@ -0,0 +1,62 @@ +- // MIR for `get_query` before Inline ++ // MIR for `get_query` after Inline + + fn get_query(_1: &T) -> () { + debug t => _1; // in scope 0 at $DIR/dyn-trait.rs:32:31: 32:32 + let mut _0: (); // return place in scope 0 at $DIR/dyn-trait.rs:32:38: 32:38 + let _2: &<Q as Query>::C; // in scope 0 at $DIR/dyn-trait.rs:33:9: 33:10 + let mut _3: &T; // in scope 0 at $DIR/dyn-trait.rs:33:22: 33:23 + let mut _4: &<Q as Query>::C; // in scope 0 at $DIR/dyn-trait.rs:34:23: 34:24 + scope 1 { + debug c => _2; // in scope 1 at $DIR/dyn-trait.rs:33:9: 33:10 ++ scope 2 (inlined try_execute_query::<<Q as Query>::C>) { // at $DIR/dyn-trait.rs:34:5: 34:25 ++ debug c => _4; // in scope 2 at $DIR/dyn-trait.rs:26:36: 26:37 ++ let mut _5: &dyn Cache<V = <Q as Query>::V>; // in scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ let mut _6: &<Q as Query>::C; // in scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ scope 3 (inlined mk_cycle::<<Q as Query>::V>) { // at $DIR/dyn-trait.rs:27:5: 27:16 ++ debug c => _5; // in scope 3 at $DIR/dyn-trait.rs:20:27: 20:28 ++ let mut _7: &dyn Cache<V = <Q as Query>::V>; // in scope 3 at $DIR/dyn-trait.rs:21:5: 21:22 ++ } ++ } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/dyn-trait.rs:33:9: 33:10 + StorageLive(_3); // scope 0 at $DIR/dyn-trait.rs:33:22: 33:23 + _3 = &(*_1); // scope 0 at $DIR/dyn-trait.rs:33:22: 33:23 + _2 = <Q as Query>::cache::<T>(move _3) -> bb1; // scope 0 at $DIR/dyn-trait.rs:33:13: 33:24 + // mir::Constant + // + span: $DIR/dyn-trait.rs:33:13: 33:21 + // + user_ty: UserType(0) + // + literal: Const { ty: for<'r> fn(&'r T) -> &'r <Q as Query>::C {<Q as Query>::cache::<T>}, val: Value(Scalar(<ZST>)) } + } + + bb1: { + StorageDead(_3); // scope 0 at $DIR/dyn-trait.rs:33:23: 33:24 + StorageLive(_4); // scope 1 at $DIR/dyn-trait.rs:34:23: 34:24 + _4 = &(*_2); // scope 1 at $DIR/dyn-trait.rs:34:23: 34:24 +- _0 = try_execute_query::<<Q as Query>::C>(move _4) -> bb2; // scope 1 at $DIR/dyn-trait.rs:34:5: 34:25 ++ StorageLive(_5); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ StorageLive(_6); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ _6 = _4; // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ _5 = move _6 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ StorageDead(_6); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15 ++ StorageLive(_7); // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22 ++ _7 = _5; // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22 ++ _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _7) -> bb2; // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22 + // mir::Constant +- // + span: $DIR/dyn-trait.rs:34:5: 34:22 +- // + literal: Const { ty: for<'r> fn(&'r <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(Scalar(<ZST>)) } ++ // + span: $DIR/dyn-trait.rs:21:7: 21:20 ++ // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <Q as Query>::V>) {<dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache}, val: Value(Scalar(<ZST>)) } + } + + bb2: { ++ StorageDead(_7); // scope 3 at $DIR/dyn-trait.rs:21:21: 21:22 ++ StorageDead(_5); // scope 2 at $DIR/dyn-trait.rs:27:15: 27:16 + StorageDead(_4); // scope 1 at $DIR/dyn-trait.rs:34:24: 34:25 + StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:35:1: 35:2 + return; // scope 0 at $DIR/dyn-trait.rs:35:2: 35:2 + } + } + diff --git a/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff b/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff new file mode 100644 index 00000000000..27309328052 --- /dev/null +++ b/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff @@ -0,0 +1,23 @@ +- // MIR for `mk_cycle` before Inline ++ // MIR for `mk_cycle` after Inline + + fn mk_cycle(_1: &dyn Cache<V = V>) -> () { + debug c => _1; // in scope 0 at $DIR/dyn-trait.rs:20:27: 20:28 + let mut _0: (); // return place in scope 0 at $DIR/dyn-trait.rs:20:49: 20:49 + let mut _2: &dyn Cache<V = V>; // in scope 0 at $DIR/dyn-trait.rs:21:5: 21:22 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/dyn-trait.rs:21:5: 21:22 + _2 = &(*_1); // scope 0 at $DIR/dyn-trait.rs:21:5: 21:22 + _0 = <dyn Cache<V = V> as Cache>::store_nocache(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:21:5: 21:22 + // mir::Constant + // + span: $DIR/dyn-trait.rs:21:7: 21:20 + // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = V>) {<dyn Cache<V = V> as Cache>::store_nocache}, val: Value(Scalar(<ZST>)) } + } + + bb1: { + StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:21:21: 21:22 + return; // scope 0 at $DIR/dyn-trait.rs:22:2: 22:2 + } + } + diff --git a/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff new file mode 100644 index 00000000000..93bba58825d --- /dev/null +++ b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff @@ -0,0 +1,37 @@ +- // MIR for `try_execute_query` before Inline ++ // MIR for `try_execute_query` after Inline + + fn try_execute_query(_1: &C) -> () { + debug c => _1; // in scope 0 at $DIR/dyn-trait.rs:26:36: 26:37 + let mut _0: (); // return place in scope 0 at $DIR/dyn-trait.rs:26:43: 26:43 + let mut _2: &dyn Cache<V = <C as Cache>::V>; // in scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 + let mut _3: &C; // in scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 ++ scope 1 (inlined mk_cycle::<<C as Cache>::V>) { // at $DIR/dyn-trait.rs:27:5: 27:16 ++ debug c => _2; // in scope 1 at $DIR/dyn-trait.rs:20:27: 20:28 ++ let mut _4: &dyn Cache<V = <C as Cache>::V>; // in scope 1 at $DIR/dyn-trait.rs:21:5: 21:22 ++ } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 + StorageLive(_3); // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 + _3 = &(*_1); // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 + _2 = move _3 as &dyn Cache<V = <C as Cache>::V> (Pointer(Unsize)); // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 + StorageDead(_3); // scope 0 at $DIR/dyn-trait.rs:27:14: 27:15 +- _0 = mk_cycle::<<C as Cache>::V>(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:27:5: 27:16 ++ StorageLive(_4); // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22 ++ _4 = _2; // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22 ++ _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _4) -> bb1; // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22 + // mir::Constant +- // + span: $DIR/dyn-trait.rs:27:5: 27:13 +- // + literal: Const { ty: for<'r> fn(&'r (dyn Cache<V = <C as Cache>::V> + 'r)) {mk_cycle::<<C as Cache>::V>}, val: Value(Scalar(<ZST>)) } ++ // + span: $DIR/dyn-trait.rs:21:7: 21:20 ++ // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <C as Cache>::V>) {<dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache}, val: Value(Scalar(<ZST>)) } + } + + bb1: { ++ StorageDead(_4); // scope 1 at $DIR/dyn-trait.rs:21:21: 21:22 + StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:27:15: 27:16 + return; // scope 0 at $DIR/dyn-trait.rs:28:2: 28:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff index fddf7e6e1f0..267f53a8dfe 100644 --- a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff @@ -4,20 +4,13 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-cycle-generic.rs:8:11: 8:11 let _1: (); // in scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 -+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline-cycle-generic.rs:9:5: 9:24 -+ scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline-cycle-generic.rs:38:9: 38:31 -+ } -+ } bb0: { StorageLive(_1); // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 -- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 -+ _1 = <A as Call>::call() -> bb1; // scope 2 at $DIR/inline-cycle-generic.rs:31:9: 31:28 + _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24 // mir::Constant -- // + span: $DIR/inline-cycle-generic.rs:9:5: 9:22 -- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(Scalar(<ZST>)) } -+ // + span: $DIR/inline-cycle-generic.rs:31:9: 31:26 -+ // + literal: Const { ty: fn() {<A as Call>::call}, val: Value(Scalar(<ZST>)) } + // + span: $DIR/inline-cycle-generic.rs:9:5: 9:22 + // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(Scalar(<ZST>)) } } bb1: { diff --git a/src/test/run-make-fulldeps/obtain-borrowck/driver.rs b/src/test/run-make-fulldeps/obtain-borrowck/driver.rs index 86e6d9e756c..c3b82aa853c 100644 --- a/src/test/run-make-fulldeps/obtain-borrowck/driver.rs +++ b/src/test/run-make-fulldeps/obtain-borrowck/driver.rs @@ -21,7 +21,7 @@ extern crate rustc_session; use rustc_borrowck::consumers::BodyWithBorrowckFacts; use rustc_driver::Compilation; use rustc_hir::def_id::LocalDefId; -use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_hir::def::DefKind; use rustc_interface::interface::Compiler; use rustc_interface::{Config, Queries}; use rustc_middle::ty::query::query_values::mir_borrowck; @@ -65,11 +65,34 @@ impl rustc_driver::Callbacks for CompilerCalls { queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { // Collect definition ids of MIR bodies. let hir = tcx.hir(); - let mut visitor = HirVisitor { bodies: Vec::new() }; - hir.visit_all_item_likes(&mut visitor); + let mut bodies = Vec::new(); + + let crate_items = tcx.hir_crate_items(()); + for id in crate_items.items() { + if matches!(tcx.def_kind(id.def_id), DefKind::Fn) { + bodies.push(id.def_id); + } + } + + for id in crate_items.trait_items() { + if matches!(tcx.def_kind(id.def_id), DefKind::AssocFn) { + let trait_item = hir.trait_item(id); + if let rustc_hir::TraitItemKind::Fn(_, trait_fn) = &trait_item.kind { + if let rustc_hir::TraitFn::Provided(_) = trait_fn { + bodies.push(trait_item.def_id); + } + } + } + } + + for id in crate_items.impl_items() { + if matches!(tcx.def_kind(id.def_id), DefKind::AssocFn) { + bodies.push(id.def_id); + } + } // Trigger borrow checking of all bodies. - for def_id in visitor.bodies { + for def_id in bodies { let _ = tcx.optimized_mir(def_id); } @@ -121,35 +144,6 @@ fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> mir_borrowck<'tc original_mir_borrowck(tcx, def_id) } -/// Visitor that collects all body definition ids mentioned in the program. -struct HirVisitor { - bodies: Vec<LocalDefId>, -} - -impl<'tcx> ItemLikeVisitor<'tcx> for HirVisitor { - fn visit_item(&mut self, item: &rustc_hir::Item) { - if let rustc_hir::ItemKind::Fn(..) = item.kind { - self.bodies.push(item.def_id); - } - } - - fn visit_trait_item(&mut self, trait_item: &rustc_hir::TraitItem) { - if let rustc_hir::TraitItemKind::Fn(_, trait_fn) = &trait_item.kind { - if let rustc_hir::TraitFn::Provided(_) = trait_fn { - self.bodies.push(trait_item.def_id); - } - } - } - - fn visit_impl_item(&mut self, impl_item: &rustc_hir::ImplItem) { - if let rustc_hir::ImplItemKind::Fn(..) = impl_item.kind { - self.bodies.push(impl_item.def_id); - } - } - - fn visit_foreign_item(&mut self, _foreign_item: &rustc_hir::ForeignItem) {} -} - /// Pull MIR bodies stored in the thread-local. fn get_bodies<'tcx>(tcx: TyCtxt<'tcx>) -> Vec<(String, BodyWithBorrowckFacts<'tcx>)> { MIR_BODIES.with(|state| { diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml index 6c4611b1cb2..9a9c45a9b7f 100644 --- a/src/test/rustdoc-gui/settings.goml +++ b/src/test/rustdoc-gui/settings.goml @@ -5,36 +5,25 @@ assert-false: "#settings" // We now click on the settings button. click: "#settings-menu" wait-for: "#settings" -assert: "#main-content.hidden" assert-css: ("#settings", {"display": "block"}) // Let's close it by clicking on the same button. click: "#settings-menu" -assert-false: "#alternative-display #settings" -assert: "#not-displayed #settings" -assert: "#main-content:not(.hidden)" - -// Let's open and then close it again with the "close settings" button. -click: "#settings-menu" -wait-for: "#alternative-display #settings" -assert: "#main-content.hidden" -click: "#back" -wait-for: "#not-displayed #settings" -assert: "#main-content:not(.hidden)" +wait-for-css: ("#settings", {"display": "none"}) // Let's check that pressing "ESCAPE" is closing it. click: "#settings-menu" -wait-for: "#alternative-display #settings" +wait-for-css: ("#settings", {"display": "block"}) press-key: "Escape" -wait-for: "#not-displayed #settings" -assert: "#main-content:not(.hidden)" +wait-for-css: ("#settings", {"display": "none"}) // Let's click on it when the search results are displayed. focus: ".search-input" write: "test" wait-for: "#alternative-display #search" click: "#settings-menu" -wait-for: "#alternative-display #settings" -assert: "#not-displayed #search" +wait-for-css: ("#settings", {"display": "block"}) +// Ensure that the search is still displayed. +wait-for: "#alternative-display #search" assert: "#main-content.hidden" // Now let's check the content of the settings menu. @@ -65,3 +54,8 @@ assert: ".setting-line.hidden #theme" // We check their text as well. assert-text: ("#preferred-dark-theme .setting-name", "Preferred dark theme") assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme") + +// Now we go to the settings page to check that the CSS is loaded as expected. +goto: file://|DOC_PATH|/settings.html +wait-for: "#settings" +assert-css: (".setting-line .toggle", {"width": "45px", "margin-right": "20px"}) diff --git a/src/test/rustdoc-gui/shortcuts.goml b/src/test/rustdoc-gui/shortcuts.goml index 42d945d0eb8..37a7c166294 100644 --- a/src/test/rustdoc-gui/shortcuts.goml +++ b/src/test/rustdoc-gui/shortcuts.goml @@ -12,15 +12,3 @@ assert-css: ("#help", {"display": "flex"}) assert-false: "#help.hidden" press-key: "Escape" assert-css: ("#help.hidden", {"display": "none"}) -// Check for the themes list. -assert-css: ("#theme-choices", {"display": "none"}) -press-key: "t" -assert-css: ("#theme-choices", {"display": "block"}) -press-key: "t" -// We ensure that 't' hides back the menu. -assert-css: ("#theme-choices", {"display": "none"}) -press-key: "t" -assert-css: ("#theme-choices", {"display": "block"}) -press-key: "Escape" -// We ensure that 'Escape' hides the menu too. -assert-css: ("#theme-choices", {"display": "none"}) diff --git a/src/test/rustdoc-gui/theme-change.goml b/src/test/rustdoc-gui/theme-change.goml index 9706511ea19..fb1c37ae68e 100644 --- a/src/test/rustdoc-gui/theme-change.goml +++ b/src/test/rustdoc-gui/theme-change.goml @@ -1,12 +1,21 @@ // Ensures that the theme change is working as expected. goto: file://|DOC_PATH|/test_docs/index.html -click: "#theme-picker" -click: "#theme-choices > button:first-child" -// should be the ayu theme so let's check the color +local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} +reload: +click: "#settings-menu" +wait-for: "#theme-ayu" +click: "#theme-ayu" +// should be the ayu theme so let's check the color. wait-for-css: ("body", { "background-color": "rgb(15, 20, 25)" }) -click: "#theme-choices > button:last-child" -// should be the light theme so let's check the color +assert-local-storage: { "rustdoc-theme": "ayu" } +click: "#theme-light" +// should be the light theme so let's check the color. wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" }) +assert-local-storage: { "rustdoc-theme": "light" } +click: "#theme-dark" +// Should be the dark theme so let's check the color. +wait-for-css: ("body", { "background-color": "rgb(53, 53, 53)" }) +assert-local-storage: { "rustdoc-theme": "dark" } goto: file://|DOC_PATH|/settings.html wait-for: "#settings" diff --git a/src/test/rustdoc-js/prototype.js b/src/test/rustdoc-js/prototype.js new file mode 100644 index 00000000000..2f1d841c3be --- /dev/null +++ b/src/test/rustdoc-js/prototype.js @@ -0,0 +1,16 @@ +// exact-check + +const QUERY = ['constructor', '__proto__']; + +const EXPECTED = [ + { + 'others': [], + 'returned': [], + 'in_args': [], + }, + { + 'others': [], + 'returned': [], + 'in_args': [], + }, +]; diff --git a/src/test/rustdoc-js/prototype.rs b/src/test/rustdoc-js/prototype.rs new file mode 100644 index 00000000000..5f6d73cc196 --- /dev/null +++ b/src/test/rustdoc-js/prototype.rs @@ -0,0 +1,4 @@ +// The alias needed to be there to reproduce the bug +// that used to be here. +#[doc(alias="other_alias")] +pub fn something_else() {} diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs b/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs index 84d63c20aa8..8490584c1b4 100644 --- a/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs +++ b/src/test/rustdoc-ui/intra-doc/macro-rules-error.rs @@ -10,12 +10,11 @@ mod no_escape { } } -/// [before_but_limited_to_module] FIXME: This error should be reported -// ERROR unresolved link to `before_but_limited_to_module` -/// [after] FIXME: This error should be reported -// ERROR unresolved link to `after` -/// [str] FIXME: This error shouldn not be reported -//~^ ERROR `str` is both a builtin type and a macro +/// [before_but_limited_to_module] +//~^ ERROR unresolved link to `before_but_limited_to_module` +/// [after] +//~^ ERROR unresolved link to `after` +/// [str] fn check() {} macro_rules! after { diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr b/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr index 4b984f4f6c0..8e17323fdde 100644 --- a/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr +++ b/src/test/rustdoc-ui/intra-doc/macro-rules-error.stderr @@ -1,22 +1,23 @@ -error: `str` is both a builtin type and a macro - --> $DIR/macro-rules-error.rs:17:6 +error: unresolved link to `before_but_limited_to_module` + --> $DIR/macro-rules-error.rs:13:6 | -LL | /// [str] FIXME: This error shouldn not be reported - | ^^^ ambiguous link +LL | /// [before_but_limited_to_module] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `before_but_limited_to_module` in scope | note: the lint level is defined here --> $DIR/macro-rules-error.rs:5:9 | LL | #![deny(rustdoc::broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: to link to the builtin type, prefix with `prim@` + = note: `macro_rules` named `before_but_limited_to_module` exists in this crate, but it is not in scope at this link's location + +error: unresolved link to `after` + --> $DIR/macro-rules-error.rs:15:6 | -LL | /// [prim@str] FIXME: This error shouldn not be reported - | +++++ -help: to link to the macro, add an exclamation mark +LL | /// [after] + | ^^^^^ no item named `after` in scope | -LL | /// [str!] FIXME: This error shouldn not be reported - | + + = note: `macro_rules` named `after` exists in this crate, but it is not in scope at this link's location -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-consts/issue-88599-ref-self.rs b/src/test/ui/associated-consts/issue-88599-ref-self.rs new file mode 100644 index 00000000000..f1144db44ca --- /dev/null +++ b/src/test/ui/associated-consts/issue-88599-ref-self.rs @@ -0,0 +1,24 @@ +// check-pass +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +pub trait First { + const CONST: usize; +} +pub trait Second {} + +impl<'a> First for dyn Second +where + &'a Self: First, +{ + const CONST: usize = <&Self>::CONST; +} + +trait Third: First +where + [u8; Self::CONST]: +{ + const VAL: [u8; Self::CONST] = [0; Self::CONST]; +} + +fn main() {} diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.stderr b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr index 9c29e969de8..a65f84ae58e 100644 --- a/src/test/ui/associated-types/hr-associated-type-projection-1.stderr +++ b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr @@ -2,10 +2,18 @@ error[E0271]: type mismatch resolving `<T as Deref>::Target == T` --> $DIR/hr-associated-type-projection-1.rs:13:33 | LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T { - | - this type parameter ^^^^^^^^^^^^^^^^^ expected associated type, found type parameter `T` + | - this type parameter ^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type | - = note: expected associated type `<T as Deref>::Target` - found type parameter `T` + = note: expected type parameter `T` + found associated type `<T as Deref>::Target` +note: required by a bound in `UnsafeCopy` + --> $DIR/hr-associated-type-projection-1.rs:3:64 + | +LL | trait UnsafeCopy<'a, T: Copy> + | ---------- required by a bound in this +LL | where +LL | for<'b> <Self as UnsafeCopy<'b, T>>::Item: std::ops::Deref<Target = T>, + | ^^^^^^^^^^ required by this bound in `UnsafeCopy` help: consider further restricting this bound | LL | impl<T: Copy + std::ops::Deref + Deref<Target = T>> UnsafeCopy<'_, T> for T { diff --git a/src/test/ui/async-await/issue-73741-type-err-drop-tracking.rs b/src/test/ui/async-await/issue-73741-type-err-drop-tracking.rs new file mode 100644 index 00000000000..c3423ad629f --- /dev/null +++ b/src/test/ui/async-await/issue-73741-type-err-drop-tracking.rs @@ -0,0 +1,14 @@ +// edition:2018 +// compile-flags: -Zdrop-tracking +// Regression test for issue #73741 +// Ensures that we don't emit spurious errors when +// a type error ocurrs in an `async fn` + +async fn weird() { + 1 = 2; //~ ERROR invalid left-hand side + + let mut loop_count = 0; + async {}.await +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-73741-type-err-drop-tracking.stderr b/src/test/ui/async-await/issue-73741-type-err-drop-tracking.stderr new file mode 100644 index 00000000000..d4e3b6c3bf4 --- /dev/null +++ b/src/test/ui/async-await/issue-73741-type-err-drop-tracking.stderr @@ -0,0 +1,11 @@ +error[E0070]: invalid left-hand side of assignment + --> $DIR/issue-73741-type-err-drop-tracking.rs:8:7 + | +LL | 1 = 2; + | - ^ + | | + | cannot assign to this expression + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0070`. diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr index b1e59e9d5de..e2b177b951c 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr @@ -2,8 +2,13 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/builtin-superkinds-self-type.rs:10:16 | LL | impl <T: Sync> Foo for T { } - | ^^^ ...so that the type `T` will meet its required lifetime bounds + | ^^^ ...so that the type `T` will meet its required lifetime bounds... | +note: ...that is required by this bound + --> $DIR/builtin-superkinds-self-type.rs:6:24 + | +LL | trait Foo : Sized+Sync+'static { + | ^^^^^^^ help: consider adding an explicit lifetime bound... | LL | impl <T: Sync + 'static> Foo for T { } diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.rs b/src/test/ui/const-generics/generic_const_exprs/closures.rs index 847843fe1a6..1ea310d063b 100644 --- a/src/test/ui/const-generics/generic_const_exprs/closures.rs +++ b/src/test/ui/const-generics/generic_const_exprs/closures.rs @@ -1,6 +1,6 @@ #![feature(generic_const_exprs)] #![allow(incomplete_features)] fn test<const N: usize>() -> [u8; N + (|| 42)()] {} -//~^ ERROR overly complex generic constant +//~^ ERROR cycle detected when building an abstract representation fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.stderr b/src/test/ui/const-generics/generic_const_exprs/closures.stderr index 18010413b93..a15dd2016e9 100644 --- a/src/test/ui/const-generics/generic_const_exprs/closures.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/closures.stderr @@ -1,13 +1,26 @@ -error: overly complex generic constant +error[E0391]: cycle detected when building an abstract representation for test::{constant#0} --> $DIR/closures.rs:3:35 | LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {} - | ^^^^-------^^ - | | - | borrowing is not supported in generic constants + | ^^^^^^^^^^^^^ | - = help: consider moving this anonymous constant into a `const` function - = note: this operation may be supported in the future +note: ...which requires building THIR for `test::{constant#0}`... + --> $DIR/closures.rs:3:35 + | +LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {} + | ^^^^^^^^^^^^^ +note: ...which requires type-checking `test::{constant#0}`... + --> $DIR/closures.rs:3:35 + | +LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {} + | ^^^^^^^^^^^^^ + = note: ...which again requires building an abstract representation for test::{constant#0}, completing the cycle +note: cycle used when checking that `test` is well-formed + --> $DIR/closures.rs:3:1 + | +LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.rs b/src/test/ui/consts/miri_unleashed/ptr_arith.rs index 22314160c5e..2beb531cc68 100644 --- a/src/test/ui/consts/miri_unleashed/ptr_arith.rs +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.rs @@ -14,7 +14,7 @@ static CMP: () = { static PTR_INT_CAST: () = { let x = &0 as *const _ as usize; //~^ ERROR could not evaluate static initializer - //~| unable to turn pointer into raw bytes + //~| "exposing pointers" needs an rfc before being allowed inside constants let _v = x == x; }; diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr index 2764d10348a..61d34e2e35d 100644 --- a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr @@ -8,7 +8,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/ptr_arith.rs:15:13 | LL | let x = &0 as *const _ as usize; - | ^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^ "exposing pointers" needs an rfc before being allowed inside constants error[E0080]: could not evaluate static initializer --> $DIR/ptr_arith.rs:23:14 diff --git a/src/test/ui/empty/empty-linkname.rs b/src/test/ui/empty/empty-linkname.rs index b64123389c2..7113d913cd0 100644 --- a/src/test/ui/empty/empty-linkname.rs +++ b/src/test/ui/empty/empty-linkname.rs @@ -1,4 +1,4 @@ -#[link(name = "")] //~ ERROR: given with empty name +#[link(name = "")] //~ ERROR: link name must not be empty extern "C" {} fn main() {} diff --git a/src/test/ui/empty/empty-linkname.stderr b/src/test/ui/empty/empty-linkname.stderr index b9d1841f16c..adcf3670d1d 100644 --- a/src/test/ui/empty/empty-linkname.stderr +++ b/src/test/ui/empty/empty-linkname.stderr @@ -1,8 +1,8 @@ -error[E0454]: `#[link(name = "")]` given with empty name - --> $DIR/empty-linkname.rs:1:1 +error[E0454]: link name must not be empty + --> $DIR/empty-linkname.rs:1:15 | LL | #[link(name = "")] - | ^^^^^^^^^^^^^^^^^^ empty name given + | ^^ empty link name error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0138.stderr b/src/test/ui/error-codes/E0138.stderr index 2dc6976fe0e..fa8c3942732 100644 --- a/src/test/ui/error-codes/E0138.stderr +++ b/src/test/ui/error-codes/E0138.stderr @@ -2,10 +2,10 @@ error[E0138]: multiple `start` functions --> $DIR/E0138.rs:7:1 | LL | fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } - | ---------------------------------------------------------- previous `#[start]` function here + | ---------------------------------------------------- previous `#[start]` function here ... LL | fn f(argc: isize, argv: *const *const u8) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ multiple `start` functions + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ multiple `start` functions error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0454.stderr b/src/test/ui/error-codes/E0454.stderr index 6b62bef112f..b9a506fee83 100644 --- a/src/test/ui/error-codes/E0454.stderr +++ b/src/test/ui/error-codes/E0454.stderr @@ -1,8 +1,8 @@ -error[E0454]: `#[link(name = "")]` given with empty name - --> $DIR/E0454.rs:1:1 +error[E0454]: link name must not be empty + --> $DIR/E0454.rs:1:15 | LL | #[link(name = "")] extern "C" {} - | ^^^^^^^^^^^^^^^^^^ empty name given + | ^^ empty link name error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0458.stderr b/src/test/ui/error-codes/E0458.stderr index 0f2fec029e7..e641bba541e 100644 --- a/src/test/ui/error-codes/E0458.stderr +++ b/src/test/ui/error-codes/E0458.stderr @@ -1,12 +1,10 @@ -error[E0458]: unknown kind: `wonderful_unicorn` - --> $DIR/E0458.rs:1:8 +error[E0458]: unknown link kind `wonderful_unicorn`, expected one of: static, dylib, framework, raw-dylib + --> $DIR/E0458.rs:1:15 | LL | #[link(kind = "wonderful_unicorn")] extern "C" {} - | -------^^^^^^^^^^^^^^^^^^^^^^^^^^-- - | | - | unknown kind + | ^^^^^^^^^^^^^^^^^^^ unknown link kind -error[E0459]: `#[link(...)]` specified without `name = "foo"` +error[E0459]: `#[link]` attribute requires a `name = "string"` argument --> $DIR/E0458.rs:1:1 | LL | #[link(kind = "wonderful_unicorn")] extern "C" {} diff --git a/src/test/ui/error-codes/E0459.stderr b/src/test/ui/error-codes/E0459.stderr index 4e0d51e8753..8f0dd25e030 100644 --- a/src/test/ui/error-codes/E0459.stderr +++ b/src/test/ui/error-codes/E0459.stderr @@ -1,4 +1,4 @@ -error[E0459]: `#[link(...)]` specified without `name = "foo"` +error[E0459]: `#[link]` attribute requires a `name = "string"` argument --> $DIR/E0459.rs:1:1 | LL | #[link(kind = "dylib")] extern "C" {} diff --git a/src/test/ui/feature-gates/feature-gate-link_cfg.stderr b/src/test/ui/feature-gates/feature-gate-link_cfg.stderr index 41a7dfc3f37..8f47d596521 100644 --- a/src/test/ui/feature-gates/feature-gate-link_cfg.stderr +++ b/src/test/ui/feature-gates/feature-gate-link_cfg.stderr @@ -1,8 +1,8 @@ -error[E0658]: kind="link_cfg" is unstable - --> $DIR/feature-gate-link_cfg.rs:1:1 +error[E0658]: link cfg is unstable + --> $DIR/feature-gate-link_cfg.rs:1:22 | LL | #[link(name = "foo", cfg(foo))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = note: see issue #37406 <https://github.com/rust-lang/rust/issues/37406> for more information = help: add `#![feature(link_cfg)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs index fedee812398..132bc6ab04a 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs @@ -1,5 +1,5 @@ -#[link(name = "foo", modifiers = "+as-needed")] -//~^ ERROR: `#[link(modifiers="as-needed")]` is unstable +#[link(name = "foo", kind = "dylib", modifiers = "+as-needed")] +//~^ ERROR: linking modifier `as-needed` is unstable extern "C" {} fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr index 96750aa6e80..2ef6a1c0404 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr @@ -1,8 +1,8 @@ -error[E0658]: `#[link(modifiers="as-needed")]` is unstable - --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:1:34 +error[E0658]: linking modifier `as-needed` is unstable + --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:1:50 | -LL | #[link(name = "foo", modifiers = "+as-needed")] - | ^^^^^^^^^^^^ +LL | #[link(name = "foo", kind = "dylib", modifiers = "+as-needed")] + | ^^^^^^^^^^^^ | = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information = help: add `#![feature(native_link_modifiers_as_needed)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr index 900605c3b37..743bcc9a1b3 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle-3.stderr @@ -1,2 +1,2 @@ -error: bundle linking modifier is currently unstable and only accepted on the nightly compiler +error: linking modifier `bundle` is unstable and only accepted on the nightly compiler diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs index c3c3cff17c4..c1d5a31aaa4 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs @@ -1,5 +1,5 @@ -#[link(name = "foo", modifiers = "+bundle")] -//~^ ERROR: `#[link(modifiers="bundle")]` is unstable +#[link(name = "foo", kind = "static", modifiers = "+bundle")] +//~^ ERROR: linking modifier `bundle` is unstable extern "C" {} fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr index 984b90d9b6c..dcaa7fcc64f 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr @@ -1,8 +1,8 @@ -error[E0658]: `#[link(modifiers="bundle")]` is unstable - --> $DIR/feature-gate-native_link_modifiers_bundle.rs:1:34 +error[E0658]: linking modifier `bundle` is unstable + --> $DIR/feature-gate-native_link_modifiers_bundle.rs:1:51 | -LL | #[link(name = "foo", modifiers = "+bundle")] - | ^^^^^^^^^ +LL | #[link(name = "foo", kind = "static", modifiers = "+bundle")] + | ^^^^^^^^^ | = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information = help: add `#![feature(native_link_modifiers_bundle)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs index 57527be1112..7b09195dc3f 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs @@ -1,5 +1,5 @@ #[link(name = "foo", modifiers = "+verbatim")] -//~^ ERROR: `#[link(modifiers="verbatim")]` is unstable +//~^ ERROR: linking modifier `verbatim` is unstable extern "C" {} fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr index 5c64c0d21bd..3bfbeb8db35 100644 --- a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr @@ -1,4 +1,4 @@ -error[E0658]: `#[link(modifiers="verbatim")]` is unstable +error[E0658]: linking modifier `verbatim` is unstable --> $DIR/feature-gate-native_link_modifiers_verbatim.rs:1:34 | LL | #[link(name = "foo", modifiers = "+verbatim")] diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib.rs index 995d9ced480..f894f517b38 100644 --- a/src/test/ui/feature-gates/feature-gate-raw-dylib.rs +++ b/src/test/ui/feature-gates/feature-gate-raw-dylib.rs @@ -1,6 +1,6 @@ // only-windows #[link(name = "foo", kind = "raw-dylib")] -//~^ ERROR: kind="raw-dylib" is unstable +//~^ ERROR: link kind `raw-dylib` is unstable extern "C" {} fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib.stderr index bb64af38b2c..ca7a61f6413 100644 --- a/src/test/ui/feature-gates/feature-gate-raw-dylib.stderr +++ b/src/test/ui/feature-gates/feature-gate-raw-dylib.stderr @@ -1,8 +1,8 @@ -error[E0658]: kind="raw-dylib" is unstable - --> $DIR/feature-gate-raw-dylib.rs:2:1 +error[E0658]: link kind `raw-dylib` is unstable + --> $DIR/feature-gate-raw-dylib.rs:2:29 | LL | #[link(name = "foo", kind = "raw-dylib")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information = help: add `#![feature(raw_dylib)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr b/src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr index 76c317f7410..782d9e39456 100644 --- a/src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr +++ b/src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr @@ -1,2 +1,2 @@ -warning: library kind `static-nobundle` has been superseded by specifying `-bundle` on library kind `static`. Try `static:-bundle` +warning: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static`. Try `static:-bundle` diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle.rs b/src/test/ui/feature-gates/feature-gate-static-nobundle.rs index e4bfe8e8e05..50f1b7ff3fc 100644 --- a/src/test/ui/feature-gates/feature-gate-static-nobundle.rs +++ b/src/test/ui/feature-gates/feature-gate-static-nobundle.rs @@ -1,6 +1,6 @@ #[link(name = "foo", kind = "static-nobundle")] -//~^ WARNING: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static` -//~^^ ERROR: kind="static-nobundle" is unstable +//~^ WARNING: link kind `static-nobundle` has been superseded by specifying modifier `-bundle` with link kind `static` +//~^^ ERROR: link kind `static-nobundle` is unstable extern "C" {} fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr index eaf2e0db511..094661aeb57 100644 --- a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr +++ b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr @@ -1,14 +1,14 @@ -warning: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static` - --> $DIR/feature-gate-static-nobundle.rs:1:22 +warning: link kind `static-nobundle` has been superseded by specifying modifier `-bundle` with link kind `static` + --> $DIR/feature-gate-static-nobundle.rs:1:29 | LL | #[link(name = "foo", kind = "static-nobundle")] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ -error[E0658]: kind="static-nobundle" is unstable - --> $DIR/feature-gate-static-nobundle.rs:1:22 +error[E0658]: link kind `static-nobundle` is unstable + --> $DIR/feature-gate-static-nobundle.rs:1:29 | LL | #[link(name = "foo", kind = "static-nobundle")] - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = note: see issue #37403 <https://github.com/rust-lang/rust/issues/37403> for more information = help: add `#![feature(static_nobundle)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index b0e295178c8..d8d2eca570e 100644 --- a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -581,6 +581,10 @@ mod link { //~^ WARN attribute should be applied to an `extern` block //~| WARN this was previously accepted //~| NOTE not an `extern` block + + #[link()] extern "Rust" {} + //~^ WARN attribute should be applied to an `extern` block + //~| WARN this was previously accepted } struct StructForDeprecated; diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 2431957e539..cf9f89d8fde 100644 --- a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -310,7 +310,7 @@ LL | | } | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: attribute should be applied to an `extern` block +warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:554:1 | LL | #[link()] @@ -328,55 +328,55 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[must_use]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:601:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:605:1 | LL | #[must_use] | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:618:1 | LL | #[windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:658:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:1 | LL | #[no_main] | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:1 | LL | #[no_builtins] | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:735:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -407,7 +407,7 @@ LL | #![cold] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: attribute should be applied to an `extern` block +warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 | LL | #![link()] @@ -863,7 +863,7 @@ LL | #[link_section = "1800"] impl S { } | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: attribute should be applied to an `extern` block +warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:560:17 | LL | mod inner { #![link()] } @@ -871,7 +871,7 @@ LL | mod inner { #![link()] } | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: attribute should be applied to an `extern` block +warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:565:5 | LL | #[link()] fn f() { } @@ -879,7 +879,7 @@ LL | #[link()] fn f() { } | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: attribute should be applied to an `extern` block +warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:570:5 | LL | #[link()] struct S; @@ -887,7 +887,7 @@ LL | #[link()] struct S; | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: attribute should be applied to an `extern` block +warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:575:5 | LL | #[link()] type T = S; @@ -895,7 +895,7 @@ LL | #[link()] type T = S; | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: attribute should be applied to an `extern` block +warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:580:5 | LL | #[link()] impl S { } @@ -903,260 +903,268 @@ LL | #[link()] impl S { } | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +warning: attribute should be applied to an `extern` block with non-Rust ABI + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:585:5 + | +LL | #[link()] extern "Rust" {} + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: `#[must_use]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:607:17 | LL | mod inner { #![must_use] } | ^^^^^^^^^^^^ warning: `#[must_use]` has no effect when applied to a type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:609:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:613:5 | LL | #[must_use] type T = S; | ^^^^^^^^^^^ warning: `#[must_use]` has no effect when applied to an item - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:615:5 | LL | #[must_use] impl S { } | ^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:621:17 | LL | mod inner { #![windows_subsystem="windows"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:624:5 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:627:5 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:630:5 | LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:629:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:633:5 | LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:661:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:664:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:666:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:670:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:680:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:682:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:686:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:689:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:719:17 | LL | mod inner { #![no_builtins] } | ^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5 | LL | #[no_builtins] fn f() { } | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5 | LL | #[no_builtins] struct S; | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 | LL | #[no_builtins] type T = S; | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:5 | LL | #[no_builtins] impl S { } | ^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:740:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:769:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1169,5 +1177,5 @@ LL | #![feature(rust1)] | = note: `#[warn(stable_features)]` on by default -warning: 172 warnings emitted +warning: 173 warnings emitted diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr new file mode 100644 index 00000000000..15e83ab5a34 --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr @@ -0,0 +1,18 @@ +error: higher-ranked lifetime error + --> $DIR/issue-59311.rs:17:5 + | +LL | v.t(|| {}); + | ^^^^^^^^^^ + | + = note: could not prove [closure@$DIR/issue-59311.rs:17:9: 17:14] well-formed + +error: higher-ranked lifetime error + --> $DIR/issue-59311.rs:17:9 + | +LL | v.t(|| {}); + | ^^^^^ + | + = note: could not prove for<'a> &'a V: 'static + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.rs b/src/test/ui/higher-rank-trait-bounds/issue-59311.rs index d617571753c..69708577285 100644 --- a/src/test/ui/higher-rank-trait-bounds/issue-59311.rs +++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.rs @@ -14,7 +14,7 @@ pub fn crash<V>(v: &V) where for<'a> &'a V: T + 'static, { - v.t(|| {}); //~ ERROR: higher-ranked lifetime error + v.t(|| {}); //~ ERROR: `&'a V` does not fulfill the required lifetime } fn main() {} diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr index c16c8206153..3dd05bba5c0 100644 --- a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr +++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr @@ -1,10 +1,15 @@ -error: higher-ranked lifetime error - --> $DIR/issue-59311.rs:17:9 +error[E0477]: the type `&'a V` does not fulfill the required lifetime + --> $DIR/issue-59311.rs:17:5 | LL | v.t(|| {}); - | ^^^^^ + | ^^^^^^^^^^ | - = note: could not prove for<'a> &'a V: 'static +note: type must satisfy the static lifetime as required by this binding + --> $DIR/issue-59311.rs:15:24 + | +LL | for<'a> &'a V: T + 'static, + | ^^^^^^^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/impl-trait/issues/issue-54895.rs b/src/test/ui/impl-trait/issues/issue-54895.rs index a70166e03a7..8d7a1d56f83 100644 --- a/src/test/ui/impl-trait/issues/issue-54895.rs +++ b/src/test/ui/impl-trait/issues/issue-54895.rs @@ -1,5 +1,3 @@ -// check-pass - trait Trait<'a> { type Out; fn call(&'a self) -> Self::Out; @@ -15,6 +13,7 @@ impl<'a> Trait<'a> for X { } fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> { + //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet X(()) } diff --git a/src/test/ui/impl-trait/issues/issue-54895.stderr b/src/test/ui/impl-trait/issues/issue-54895.stderr new file mode 100644 index 00000000000..7d22f027a6d --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-54895.stderr @@ -0,0 +1,14 @@ +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/issue-54895.rs:15:53 + | +LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> { + | ^^ + | +note: lifetime declared here + --> $DIR/issue-54895.rs:15:20 + | +LL | fn f() -> impl for<'a> Trait<'a, Out = impl Sized + 'a> { + | ^^ + +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/issues/issue-67830.nll.stderr b/src/test/ui/impl-trait/issues/issue-67830.nll.stderr deleted file mode 100644 index 17fbe046e3a..00000000000 --- a/src/test/ui/impl-trait/issues/issue-67830.nll.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-67830.rs:23:5 - | -LL | Wrap(|a| Some(a).into_iter()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2` - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-67830.rs:23:5 - | -LL | Wrap(|a| Some(a).into_iter()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2` - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/impl-trait/issues/issue-67830.rs b/src/test/ui/impl-trait/issues/issue-67830.rs index a308d975b43..92f7e005dbf 100644 --- a/src/test/ui/impl-trait/issues/issue-67830.rs +++ b/src/test/ui/impl-trait/issues/issue-67830.rs @@ -19,7 +19,7 @@ where struct A; fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> { - //~^ ERROR implementation of `FnOnce` is not general enough + //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet Wrap(|a| Some(a).into_iter()) } diff --git a/src/test/ui/impl-trait/issues/issue-67830.stderr b/src/test/ui/impl-trait/issues/issue-67830.stderr index 4c0490c721b..d3ea8cb0377 100644 --- a/src/test/ui/impl-trait/issues/issue-67830.stderr +++ b/src/test/ui/impl-trait/issues/issue-67830.stderr @@ -1,11 +1,14 @@ -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-67830.rs:21:14 +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/issue-67830.rs:21:62 | LL | fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^ | - = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2` +note: lifetime declared here + --> $DIR/issue-67830.rs:21:23 + | +LL | fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> { + | ^^ error: aborting due to previous error diff --git a/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr b/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr deleted file mode 100644 index 66cffa9e36c..00000000000 --- a/src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr +++ /dev/null @@ -1,55 +0,0 @@ -error: implementation of `Hrtb` is not general enough - --> $DIR/issue-88236-2.rs:17:5 - | -LL | &() - | ^^^ implementation of `Hrtb` is not general enough - | - = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... - = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` - -error: implementation of `Hrtb` is not general enough - --> $DIR/issue-88236-2.rs:17:5 - | -LL | &() - | ^^^ implementation of `Hrtb` is not general enough - | - = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... - = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` - -error: lifetime may not live long enough - --> $DIR/issue-88236-2.rs:20:5 - | -LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { - | -- lifetime `'b` defined here -LL | x - | ^ returning this value requires that `'b` must outlive `'static` - | -help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'b` lifetime bound - | -LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b { - | ++++ -help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'b` lifetime bound - | -LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a + 'b> { - | ++++ - -error: implementation of `Hrtb` is not general enough - --> $DIR/issue-88236-2.rs:20:5 - | -LL | x - | ^ implementation of `Hrtb` is not general enough - | - = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... - = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` - -error: implementation of `Hrtb` is not general enough - --> $DIR/issue-88236-2.rs:20:5 - | -LL | x - | ^ implementation of `Hrtb` is not general enough - | - = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... - = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` - -error: aborting due to 5 previous errors - diff --git a/src/test/ui/impl-trait/issues/issue-88236-2.rs b/src/test/ui/impl-trait/issues/issue-88236-2.rs index af26a1f54c4..fde8a6704cc 100644 --- a/src/test/ui/impl-trait/issues/issue-88236-2.rs +++ b/src/test/ui/impl-trait/issues/issue-88236-2.rs @@ -13,11 +13,16 @@ impl<'a> Hrtb<'a> for &'a () { } fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { - &() //~^ ERROR implementation of `Hrtb` is not general enough + //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + &() } + fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { - x //~^ ERROR implementation of `Hrtb` is not general enough + //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + x } fn main() {} diff --git a/src/test/ui/impl-trait/issues/issue-88236-2.stderr b/src/test/ui/impl-trait/issues/issue-88236-2.stderr index 9574b880f7d..8605d07abe9 100644 --- a/src/test/ui/impl-trait/issues/issue-88236-2.stderr +++ b/src/test/ui/impl-trait/issues/issue-88236-2.stderr @@ -1,20 +1,38 @@ -error: implementation of `Hrtb` is not general enough - --> $DIR/issue-88236-2.rs:16:38 +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/issue-88236-2.rs:15:61 + | +LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} + | ^^ + | +note: lifetime declared here + --> $DIR/issue-88236-2.rs:15:28 + | +LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} + | ^^ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/issue-88236-2.rs:18:80 | LL | fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Hrtb` is not general enough + | ^^ | - = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... - = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` +note: lifetime declared here + --> $DIR/issue-88236-2.rs:18:47 + | +LL | fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { + | ^^ -error: implementation of `Hrtb` is not general enough - --> $DIR/issue-88236-2.rs:19:36 +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/issue-88236-2.rs:23:78 | LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Hrtb` is not general enough + | ^^ | - = note: `Hrtb<'1>` would have to be implemented for the type `&()`, for any lifetime `'1`... - = note: ...but `Hrtb<'_>` is actually implemented for the type `&()` +note: lifetime declared here + --> $DIR/issue-88236-2.rs:23:45 + | +LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { + | ^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/impl-trait/issues/issue-88236.rs b/src/test/ui/impl-trait/issues/issue-88236.rs index 2ea35270a7e..36d12417354 100644 --- a/src/test/ui/impl-trait/issues/issue-88236.rs +++ b/src/test/ui/impl-trait/issues/issue-88236.rs @@ -1,5 +1,3 @@ -// check-pass - // this used to cause stack overflows trait Hrtb<'a> { @@ -15,5 +13,6 @@ impl<'a> Hrtb<'a> for &'a () { } fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet fn main() {} diff --git a/src/test/ui/impl-trait/issues/issue-88236.stderr b/src/test/ui/impl-trait/issues/issue-88236.stderr new file mode 100644 index 00000000000..7a4cc57b088 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-88236.stderr @@ -0,0 +1,14 @@ +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/issue-88236.rs:15:61 + | +LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} + | ^^ + | +note: lifetime declared here + --> $DIR/issue-88236.rs:15:28 + | +LL | fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} + | ^^ + +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/nested-rpit-hrtb.rs b/src/test/ui/impl-trait/nested-rpit-hrtb.rs new file mode 100644 index 00000000000..abf6a7e956c --- /dev/null +++ b/src/test/ui/impl-trait/nested-rpit-hrtb.rs @@ -0,0 +1,64 @@ +// Test the interaction between rested RPIT and HRTB. + +trait Foo<'a> { + type Assoc; +} + +impl Foo<'_> for () { + type Assoc = (); +} + +// Alternative version of `Foo` whose impl uses `'a`. +trait Bar<'a> { + type Assoc; +} + +impl<'a> Bar<'a> for () { + type Assoc = &'a (); +} + +trait Qux<'a> {} + +impl Qux<'_> for () {} + +// This is not supported. +fn one_hrtb_outlives() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'a> {} +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + +// This is not supported. +fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {} +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + +fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + +fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} +//~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet + +// This should pass. +fn one_hrtb_mention_fn_trait_param<'b>() -> impl for<'a> Foo<'a, Assoc = impl Qux<'b>> {} + +// This should pass. +fn one_hrtb_mention_fn_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'b> {} + +// This should pass. +fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {} + +// This should pass. +fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {} + +// This should pass. +fn two_htrb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Qux<'b>> {} + +// `'b` is not in scope for the outlives bound. +fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {} +//~^ ERROR use of undeclared lifetime name `'b` [E0261] + +// This should pass. +fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Qux<'b>> {} + +// `'b` is not in scope for the outlives bound. +fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} +//~^ ERROR use of undeclared lifetime name `'b` [E0261] + +fn main() {} diff --git a/src/test/ui/impl-trait/nested-rpit-hrtb.stderr b/src/test/ui/impl-trait/nested-rpit-hrtb.stderr new file mode 100644 index 00000000000..3dbe6ebadfb --- /dev/null +++ b/src/test/ui/impl-trait/nested-rpit-hrtb.stderr @@ -0,0 +1,82 @@ +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/nested-rpit-hrtb.rs:54:77 + | +LL | fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {} + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | fn two_htrb_outlives() -> impl for<'b, 'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {} + | +++ +help: consider introducing lifetime `'b` here + | +LL | fn two_htrb_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {} + | ++++ + +error[E0261]: use of undeclared lifetime name `'b` + --> $DIR/nested-rpit-hrtb.rs:61:82 + | +LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} + | ^^ undeclared lifetime + | +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | fn two_htrb_outlives_uses() -> impl for<'b, 'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} + | +++ +help: consider introducing lifetime `'b` here + | +LL | fn two_htrb_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} + | ++++ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/nested-rpit-hrtb.rs:25:69 + | +LL | fn one_hrtb_outlives() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'a> {} + | ^^ + | +note: lifetime declared here + --> $DIR/nested-rpit-hrtb.rs:25:36 + | +LL | fn one_hrtb_outlives() -> impl for<'a> Foo<'a, Assoc = impl Sized + 'a> {} + | ^^ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/nested-rpit-hrtb.rs:29:68 + | +LL | fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {} + | ^^ + | +note: lifetime declared here + --> $DIR/nested-rpit-hrtb.rs:29:39 + | +LL | fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {} + | ^^ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/nested-rpit-hrtb.rs:32:74 + | +LL | fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} + | ^^ + | +note: lifetime declared here + --> $DIR/nested-rpit-hrtb.rs:32:41 + | +LL | fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} + | ^^ + +error: higher kinded lifetime bounds on nested opaque types are not supported yet + --> $DIR/nested-rpit-hrtb.rs:35:73 + | +LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} + | ^^ + | +note: lifetime declared here + --> $DIR/nested-rpit-hrtb.rs:35:44 + | +LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} + | ^^ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/inference/issue-28935.rs b/src/test/ui/inference/issue-28935.rs new file mode 100644 index 00000000000..872822dbd0f --- /dev/null +++ b/src/test/ui/inference/issue-28935.rs @@ -0,0 +1,9 @@ +// check-pass + +use std::cell::RefCell; + +pub fn f(v: Vec<RefCell<u8>>) { + let _t = &mut *v[0].borrow_mut(); +} + +fn main() {} diff --git a/src/test/ui/issues/issue-37725.rs b/src/test/ui/issues/issue-37725.rs index 965ecde6f3c..1c6df0da60c 100644 --- a/src/test/ui/issues/issue-37725.rs +++ b/src/test/ui/issues/issue-37725.rs @@ -1,4 +1,6 @@ // build-pass +// compiler-opts: -Zmir-opt-level=2 + #![allow(dead_code)] trait Foo { fn foo(&self); diff --git a/src/test/ui/issues/issue-43925.rs b/src/test/ui/issues/issue-43925.rs index 73d17928251..1a210887154 100644 --- a/src/test/ui/issues/issue-43925.rs +++ b/src/test/ui/issues/issue-43925.rs @@ -1,4 +1,4 @@ -#[link(name = "foo", cfg("rlib"))] //~ ERROR invalid argument for `cfg(..)` +#[link(name = "foo", cfg("rlib"))] //~ ERROR link cfg must have a single predicate argument extern "C" {} fn main() {} diff --git a/src/test/ui/issues/issue-43925.stderr b/src/test/ui/issues/issue-43925.stderr index 7bf64dc693c..b0ad25063de 100644 --- a/src/test/ui/issues/issue-43925.stderr +++ b/src/test/ui/issues/issue-43925.stderr @@ -1,8 +1,8 @@ -error: invalid argument for `cfg(..)` - --> $DIR/issue-43925.rs:1:26 +error: link cfg must have a single predicate argument + --> $DIR/issue-43925.rs:1:22 | LL | #[link(name = "foo", cfg("rlib"))] - | ^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43926.rs b/src/test/ui/issues/issue-43926.rs index 0171c12b1cc..6d3003552dc 100644 --- a/src/test/ui/issues/issue-43926.rs +++ b/src/test/ui/issues/issue-43926.rs @@ -1,4 +1,4 @@ -#[link(name = "foo", cfg())] //~ ERROR `cfg()` must have an argument +#[link(name = "foo", cfg())] //~ ERROR link cfg must have a single predicate argument extern "C" {} fn main() {} diff --git a/src/test/ui/issues/issue-43926.stderr b/src/test/ui/issues/issue-43926.stderr index d83e9bd7ed4..f67f91a6bd3 100644 --- a/src/test/ui/issues/issue-43926.stderr +++ b/src/test/ui/issues/issue-43926.stderr @@ -1,4 +1,4 @@ -error: `cfg()` must have an argument +error: link cfg must have a single predicate argument --> $DIR/issue-43926.rs:1:22 | LL | #[link(name = "foo", cfg())] diff --git a/src/test/ui/linkage-attr/bad-extern-link-attrs.rs b/src/test/ui/linkage-attr/bad-extern-link-attrs.rs deleted file mode 100644 index 43fe8c11d7c..00000000000 --- a/src/test/ui/linkage-attr/bad-extern-link-attrs.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[link()] //~ ERROR: specified without `name = -#[link(name = "")] //~ ERROR: with empty name -#[link(name = "foo")] -#[link(name = "foo", kind = "bar")] //~ ERROR: unknown kind -extern "C" {} - -fn main() {} diff --git a/src/test/ui/linkage-attr/bad-extern-link-attrs.stderr b/src/test/ui/linkage-attr/bad-extern-link-attrs.stderr deleted file mode 100644 index 525c605a9cf..00000000000 --- a/src/test/ui/linkage-attr/bad-extern-link-attrs.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0459]: `#[link(...)]` specified without `name = "foo"` - --> $DIR/bad-extern-link-attrs.rs:1:1 - | -LL | #[link()] - | ^^^^^^^^^ missing `name` argument - -error[E0454]: `#[link(name = "")]` given with empty name - --> $DIR/bad-extern-link-attrs.rs:2:1 - | -LL | #[link(name = "")] - | ^^^^^^^^^^^^^^^^^^ empty name given - -error[E0458]: unknown kind: `bar` - --> $DIR/bad-extern-link-attrs.rs:4:22 - | -LL | #[link(name = "foo", kind = "bar")] - | ---------------------^^^^^^^^^^^^-- - | | - | unknown kind - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0454, E0458, E0459. -For more information about an error, try `rustc --explain E0454`. diff --git a/src/test/ui/linkage-attr/link-attr-validation-early.rs b/src/test/ui/linkage-attr/link-attr-validation-early.rs new file mode 100644 index 00000000000..b9a835fb5e9 --- /dev/null +++ b/src/test/ui/linkage-attr/link-attr-validation-early.rs @@ -0,0 +1,8 @@ +// Top-level ill-formed +#[link] //~ ERROR attribute must be of the form + //~| WARN this was previously accepted +#[link = "foo"] //~ ERROR attribute must be of the form + //~| WARN this was previously accepted +extern "C" {} + +fn main() {} diff --git a/src/test/ui/linkage-attr/link-attr-validation-early.stderr b/src/test/ui/linkage-attr/link-attr-validation-early.stderr new file mode 100644 index 00000000000..d36601ed0b4 --- /dev/null +++ b/src/test/ui/linkage-attr/link-attr-validation-early.stderr @@ -0,0 +1,21 @@ +error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...")]` + --> $DIR/link-attr-validation-early.rs:2:1 + | +LL | #[link] + | ^^^^^^^ + | + = note: `#[deny(ill_formed_attribute_input)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571> + +error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...")]` + --> $DIR/link-attr-validation-early.rs:4:1 + | +LL | #[link = "foo"] + | ^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571> + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/linkage-attr/link-attr-validation-late.rs b/src/test/ui/linkage-attr/link-attr-validation-late.rs new file mode 100644 index 00000000000..b454fbd0ed1 --- /dev/null +++ b/src/test/ui/linkage-attr/link-attr-validation-late.rs @@ -0,0 +1,40 @@ +#![feature(native_link_modifiers_verbatim)] +#![feature(link_cfg)] + +// Top-level ill-formed +#[link(name = "...", "literal")] //~ ERROR unexpected `#[link]` argument +#[link(name = "...", unknown)] //~ ERROR unexpected `#[link]` argument +extern "C" {} + +// Duplicate arguments +#[link(name = "foo", name = "bar")] //~ ERROR multiple `name` arguments +#[link(name = "...", kind = "dylib", kind = "bar")] //~ ERROR multiple `kind` arguments +#[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] //~ ERROR multiple `modifiers` arguments +#[link(name = "...", cfg(FALSE), cfg(FALSE))] //~ ERROR multiple `cfg` arguments +#[link(wasm_import_module = "foo", wasm_import_module = "bar")] //~ ERROR multiple `wasm_import_module` arguments +extern "C" {} + +// Ill-formed arguments +#[link(name)] //~ ERROR link name must be of the form `name = "string"` + //~| ERROR `#[link]` attribute requires a `name = "string"` argument +#[link(name())] //~ ERROR link name must be of the form `name = "string"` + //~| ERROR `#[link]` attribute requires a `name = "string"` argument +#[link(name = "...", kind)] //~ ERROR link kind must be of the form `kind = "string"` +#[link(name = "...", kind())] //~ ERROR link kind must be of the form `kind = "string"` +#[link(name = "...", modifiers)] //~ ERROR link modifiers must be of the form `modifiers = "string"` +#[link(name = "...", modifiers())] //~ ERROR link modifiers must be of the form `modifiers = "string"` +#[link(name = "...", cfg)] //~ ERROR link cfg must be of the form `cfg(/* predicate */)` +#[link(name = "...", cfg = "literal")] //~ ERROR link cfg must be of the form `cfg(/* predicate */)` +#[link(name = "...", cfg("literal"))] //~ ERROR link cfg must have a single predicate argument +#[link(name = "...", wasm_import_module)] //~ ERROR wasm import module must be of the form `wasm_import_module = "string"` +#[link(name = "...", wasm_import_module())] //~ ERROR wasm import module must be of the form `wasm_import_module = "string"` +extern "C" {} + +// Basic modifier validation +#[link(name = "...", modifiers = "")] //~ ERROR invalid linking modifier syntax, expected '+' or '-' prefix +#[link(name = "...", modifiers = "no-plus-minus")] //~ ERROR invalid linking modifier syntax, expected '+' or '-' prefix +#[link(name = "...", modifiers = "+unknown")] //~ ERROR unknown linking modifier `unknown` +#[link(name = "...", modifiers = "+verbatim,+verbatim")] //~ ERROR multiple `verbatim` modifiers +extern "C" {} + +fn main() {} diff --git a/src/test/ui/linkage-attr/link-attr-validation-late.stderr b/src/test/ui/linkage-attr/link-attr-validation-late.stderr new file mode 100644 index 00000000000..bb08f9a4c02 --- /dev/null +++ b/src/test/ui/linkage-attr/link-attr-validation-late.stderr @@ -0,0 +1,147 @@ +error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module + --> $DIR/link-attr-validation-late.rs:5:22 + | +LL | #[link(name = "...", "literal")] + | ^^^^^^^^^ + +error: unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module + --> $DIR/link-attr-validation-late.rs:6:22 + | +LL | #[link(name = "...", unknown)] + | ^^^^^^^ + +error: multiple `name` arguments in a single `#[link]` attribute + --> $DIR/link-attr-validation-late.rs:10:22 + | +LL | #[link(name = "foo", name = "bar")] + | ^^^^^^^^^^^^ + +error: multiple `kind` arguments in a single `#[link]` attribute + --> $DIR/link-attr-validation-late.rs:11:38 + | +LL | #[link(name = "...", kind = "dylib", kind = "bar")] + | ^^^^^^^^^^^^ + +error: multiple `modifiers` arguments in a single `#[link]` attribute + --> $DIR/link-attr-validation-late.rs:12:47 + | +LL | #[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] + | ^^^^^^^^^^^^^^^^^ + +error: multiple `cfg` arguments in a single `#[link]` attribute + --> $DIR/link-attr-validation-late.rs:13:34 + | +LL | #[link(name = "...", cfg(FALSE), cfg(FALSE))] + | ^^^^^^^^^^ + +error: multiple `wasm_import_module` arguments in a single `#[link]` attribute + --> $DIR/link-attr-validation-late.rs:14:36 + | +LL | #[link(wasm_import_module = "foo", wasm_import_module = "bar")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: link name must be of the form `name = "string"` + --> $DIR/link-attr-validation-late.rs:18:8 + | +LL | #[link(name)] + | ^^^^ + +error[E0459]: `#[link]` attribute requires a `name = "string"` argument + --> $DIR/link-attr-validation-late.rs:18:1 + | +LL | #[link(name)] + | ^^^^^^^^^^^^^ missing `name` argument + +error: link name must be of the form `name = "string"` + --> $DIR/link-attr-validation-late.rs:20:8 + | +LL | #[link(name())] + | ^^^^^^ + +error[E0459]: `#[link]` attribute requires a `name = "string"` argument + --> $DIR/link-attr-validation-late.rs:20:1 + | +LL | #[link(name())] + | ^^^^^^^^^^^^^^^ missing `name` argument + +error: link kind must be of the form `kind = "string"` + --> $DIR/link-attr-validation-late.rs:22:22 + | +LL | #[link(name = "...", kind)] + | ^^^^ + +error: link kind must be of the form `kind = "string"` + --> $DIR/link-attr-validation-late.rs:23:22 + | +LL | #[link(name = "...", kind())] + | ^^^^^^ + +error: link modifiers must be of the form `modifiers = "string"` + --> $DIR/link-attr-validation-late.rs:24:22 + | +LL | #[link(name = "...", modifiers)] + | ^^^^^^^^^ + +error: link modifiers must be of the form `modifiers = "string"` + --> $DIR/link-attr-validation-late.rs:25:22 + | +LL | #[link(name = "...", modifiers())] + | ^^^^^^^^^^^ + +error: link cfg must be of the form `cfg(/* predicate */)` + --> $DIR/link-attr-validation-late.rs:26:22 + | +LL | #[link(name = "...", cfg)] + | ^^^ + +error: link cfg must be of the form `cfg(/* predicate */)` + --> $DIR/link-attr-validation-late.rs:27:22 + | +LL | #[link(name = "...", cfg = "literal")] + | ^^^^^^^^^^^^^^^ + +error: link cfg must have a single predicate argument + --> $DIR/link-attr-validation-late.rs:28:22 + | +LL | #[link(name = "...", cfg("literal"))] + | ^^^^^^^^^^^^^^ + +error: wasm import module must be of the form `wasm_import_module = "string"` + --> $DIR/link-attr-validation-late.rs:29:22 + | +LL | #[link(name = "...", wasm_import_module)] + | ^^^^^^^^^^^^^^^^^^ + +error: wasm import module must be of the form `wasm_import_module = "string"` + --> $DIR/link-attr-validation-late.rs:30:22 + | +LL | #[link(name = "...", wasm_import_module())] + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed + --> $DIR/link-attr-validation-late.rs:34:34 + | +LL | #[link(name = "...", modifiers = "")] + | ^^ + +error: invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed + --> $DIR/link-attr-validation-late.rs:35:34 + | +LL | #[link(name = "...", modifiers = "no-plus-minus")] + | ^^^^^^^^^^^^^^^ + +error: unknown linking modifier `unknown`, expected one of: bundle, verbatim, whole-archive, as-needed + --> $DIR/link-attr-validation-late.rs:36:34 + | +LL | #[link(name = "...", modifiers = "+unknown")] + | ^^^^^^^^^^ + +error: multiple `verbatim` modifiers in a single `modifiers` argument + --> $DIR/link-attr-validation-late.rs:37:34 + | +LL | #[link(name = "...", modifiers = "+verbatim,+verbatim")] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 24 previous errors + +For more information about this error, try `rustc --explain E0459`. diff --git a/src/test/ui/macros/macro-comma-support-rpass.rs b/src/test/ui/macros/macro-comma-support-rpass.rs index f6c4f896d67..25b8c3cc62e 100644 --- a/src/test/ui/macros/macro-comma-support-rpass.rs +++ b/src/test/ui/macros/macro-comma-support-rpass.rs @@ -193,6 +193,12 @@ fn line() { } #[test] +fn matches() { + let _ = matches!(1, x if x > 0); + let _ = matches!(1, x if x > 0,); +} + +#[test] fn module_path() { let _ = module_path!(); } diff --git a/src/test/ui/main-wrong-location.stderr b/src/test/ui/main-wrong-location.stderr index 0058af9b79e..3d64b0a67a1 100644 --- a/src/test/ui/main-wrong-location.stderr +++ b/src/test/ui/main-wrong-location.stderr @@ -8,7 +8,7 @@ note: here is a function named `main` --> $DIR/main-wrong-location.rs:4:5 | LL | fn main() { } - | ^^^^^^^^^^^^^ + | ^^^^^^^^^ = note: you have one or more functions named `main` not defined at the crate level = help: consider moving the `main` function definitions diff --git a/src/test/ui/manual/manual-link-bad-form.rs b/src/test/ui/manual/manual-link-bad-form.rs index 9d092ae6db4..bc9b6be0294 100644 --- a/src/test/ui/manual/manual-link-bad-form.rs +++ b/src/test/ui/manual/manual-link-bad-form.rs @@ -1,5 +1,5 @@ // compile-flags:-l static= -// error-pattern: empty library name given via `-l` +// error-pattern: library name must not be empty fn main() { } diff --git a/src/test/ui/manual/manual-link-bad-form.stderr b/src/test/ui/manual/manual-link-bad-form.stderr index ed3c4c4fc4d..7fd7a1066b4 100644 --- a/src/test/ui/manual/manual-link-bad-form.stderr +++ b/src/test/ui/manual/manual-link-bad-form.stderr @@ -1,4 +1,2 @@ -error: empty library name given via `-l` - -error: aborting due to previous error +error: library name must not be empty diff --git a/src/test/ui/manual/manual-link-bad-kind.rs b/src/test/ui/manual/manual-link-bad-kind.rs index 86830a599b5..d1609338db6 100644 --- a/src/test/ui/manual/manual-link-bad-kind.rs +++ b/src/test/ui/manual/manual-link-bad-kind.rs @@ -1,5 +1,5 @@ // compile-flags:-l bar=foo -// error-pattern: unknown library kind `bar`, expected one of dylib, framework, or static +// error-pattern: unknown library kind `bar`, expected one of: static, dylib, framework fn main() { } diff --git a/src/test/ui/manual/manual-link-bad-kind.stderr b/src/test/ui/manual/manual-link-bad-kind.stderr index 03c33a97512..86146956699 100644 --- a/src/test/ui/manual/manual-link-bad-kind.stderr +++ b/src/test/ui/manual/manual-link-bad-kind.stderr @@ -1,2 +1,2 @@ -error: unknown library kind `bar`, expected one of dylib, framework, or static +error: unknown library kind `bar`, expected one of: static, dylib, framework diff --git a/src/test/ui/manual/manual-link-framework.rs b/src/test/ui/manual/manual-link-framework.rs index 0474526fcc1..57c5966e960 100644 --- a/src/test/ui/manual/manual-link-framework.rs +++ b/src/test/ui/manual/manual-link-framework.rs @@ -1,7 +1,7 @@ // ignore-macos // ignore-ios // compile-flags:-l framework=foo -// error-pattern: native frameworks are only available on macOS targets +// error-pattern: library kind `framework` is only supported on Apple targets fn main() { } diff --git a/src/test/ui/manual/manual-link-framework.stderr b/src/test/ui/manual/manual-link-framework.stderr index 3e8da8b2f93..de045d56c9c 100644 --- a/src/test/ui/manual/manual-link-framework.stderr +++ b/src/test/ui/manual/manual-link-framework.stderr @@ -1,4 +1,4 @@ -error: native frameworks are only available on macOS targets +error: library kind `framework` is only supported on Apple targets error: aborting due to previous error diff --git a/src/test/ui/manual/manual-link-unsupported-kind.rs b/src/test/ui/manual/manual-link-unsupported-kind.rs index 34814db593f..7a40186d504 100644 --- a/src/test/ui/manual/manual-link-unsupported-kind.rs +++ b/src/test/ui/manual/manual-link-unsupported-kind.rs @@ -1,5 +1,5 @@ // compile-flags:-l raw-dylib=foo -// error-pattern: unknown library kind `raw-dylib`, expected one of dylib, framework, or static +// error-pattern: unknown library kind `raw-dylib`, expected one of: static, dylib, framework fn main() { } diff --git a/src/test/ui/manual/manual-link-unsupported-kind.stderr b/src/test/ui/manual/manual-link-unsupported-kind.stderr index acb4463cb04..4965c0af5f2 100644 --- a/src/test/ui/manual/manual-link-unsupported-kind.stderr +++ b/src/test/ui/manual/manual-link-unsupported-kind.stderr @@ -1,2 +1,2 @@ -error: unknown library kind `raw-dylib`, expected one of dylib, framework, or static +error: unknown library kind `raw-dylib`, expected one of: static, dylib, framework diff --git a/src/test/ui/native-library-link-flags/empty-kind-1.rs b/src/test/ui/native-library-link-flags/empty-kind-1.rs index 6f93d38ca93..086d8cff957 100644 --- a/src/test/ui/native-library-link-flags/empty-kind-1.rs +++ b/src/test/ui/native-library-link-flags/empty-kind-1.rs @@ -1,6 +1,6 @@ // Unspecified kind should fail with an error // compile-flags: -l =mylib -// error-pattern: unknown library kind ``, expected one of dylib, framework, or static +// error-pattern: unknown library kind ``, expected one of: static, dylib, framework fn main() {} diff --git a/src/test/ui/native-library-link-flags/empty-kind-1.stderr b/src/test/ui/native-library-link-flags/empty-kind-1.stderr index 2a4a82d538f..37846c0b06f 100644 --- a/src/test/ui/native-library-link-flags/empty-kind-1.stderr +++ b/src/test/ui/native-library-link-flags/empty-kind-1.stderr @@ -1,2 +1,2 @@ -error: unknown library kind ``, expected one of dylib, framework, or static +error: unknown library kind ``, expected one of: static, dylib, framework diff --git a/src/test/ui/native-library-link-flags/empty-kind-2.rs b/src/test/ui/native-library-link-flags/empty-kind-2.rs index c0c35577057..45ec8ec85e3 100644 --- a/src/test/ui/native-library-link-flags/empty-kind-2.rs +++ b/src/test/ui/native-library-link-flags/empty-kind-2.rs @@ -1,6 +1,6 @@ // Unspecified kind should fail with an error // compile-flags: -l :+bundle=mylib -// error-pattern: unknown library kind ``, expected one of dylib, framework, or static +// error-pattern: unknown library kind ``, expected one of: static, dylib, framework fn main() {} diff --git a/src/test/ui/native-library-link-flags/empty-kind-2.stderr b/src/test/ui/native-library-link-flags/empty-kind-2.stderr index 2a4a82d538f..37846c0b06f 100644 --- a/src/test/ui/native-library-link-flags/empty-kind-2.stderr +++ b/src/test/ui/native-library-link-flags/empty-kind-2.stderr @@ -1,2 +1,2 @@ -error: unknown library kind ``, expected one of dylib, framework, or static +error: unknown library kind ``, expected one of: static, dylib, framework diff --git a/src/test/ui/native-library-link-flags/modifiers-override-2.stderr b/src/test/ui/native-library-link-flags/modifiers-override-2.stderr index 9200d7bfb0c..aa5b59c5b6f 100644 --- a/src/test/ui/native-library-link-flags/modifiers-override-2.stderr +++ b/src/test/ui/native-library-link-flags/modifiers-override-2.stderr @@ -1,2 +1,2 @@ -error: duplicating linking modifier is currently unstable and only accepted on the nightly compiler +error: multiple `whole-archive` modifiers in a single `-l` option diff --git a/src/test/ui/native-library-link-flags/modifiers-override.rs b/src/test/ui/native-library-link-flags/modifiers-override.rs index f6d770559e6..3912ac9f13d 100644 --- a/src/test/ui/native-library-link-flags/modifiers-override.rs +++ b/src/test/ui/native-library-link-flags/modifiers-override.rs @@ -3,12 +3,13 @@ #![feature(native_link_modifiers_bundle)] #[link(name = "foo")] -#[link( //~ ERROR multiple `modifiers` arguments in a single `#[link]` attribute +#[link( name = "bar", kind = "static", modifiers = "+whole-archive,-whole-archive", - //~^ ERROR same modifier is used multiple times in a single `modifiers` argument + //~^ ERROR multiple `whole-archive` modifiers in a single `modifiers` argument modifiers = "+bundle" + //~^ ERROR multiple `modifiers` arguments in a single `#[link]` attribute )] extern "C" {} //~^ ERROR overriding linking modifiers from command line is not supported diff --git a/src/test/ui/native-library-link-flags/modifiers-override.stderr b/src/test/ui/native-library-link-flags/modifiers-override.stderr index 8644d2382d2..55362910e71 100644 --- a/src/test/ui/native-library-link-flags/modifiers-override.stderr +++ b/src/test/ui/native-library-link-flags/modifiers-override.stderr @@ -1,29 +1,23 @@ -error: same modifier is used multiple times in a single `modifiers` argument - --> $DIR/modifiers-override.rs:9:5 +error: multiple `modifiers` arguments in a single `#[link]` attribute + --> $DIR/modifiers-override.rs:11:5 | -LL | modifiers = "+whole-archive,-whole-archive", - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | modifiers = "+bundle" + | ^^^^^^^^^^^^^^^^^^^^^ -error: multiple `modifiers` arguments in a single `#[link]` attribute - --> $DIR/modifiers-override.rs:6:1 +error: multiple `whole-archive` modifiers in a single `modifiers` argument + --> $DIR/modifiers-override.rs:9:17 | -LL | / #[link( -LL | | name = "bar", -LL | | kind = "static", -LL | | modifiers = "+whole-archive,-whole-archive", -LL | | -LL | | modifiers = "+bundle" -LL | | )] - | |__^ +LL | modifiers = "+whole-archive,-whole-archive", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: overriding linking modifiers from command line is not supported - --> $DIR/modifiers-override.rs:13:1 + --> $DIR/modifiers-override.rs:14:1 | LL | extern "C" {} | ^^^^^^^^^^^^^ error: overriding linking modifiers from command line is not supported - --> $DIR/modifiers-override.rs:13:1 + --> $DIR/modifiers-override.rs:14:1 | LL | extern "C" {} | ^^^^^^^^^^^^^ diff --git a/src/test/ui/nll/issue-54779-anon-static-lifetime.rs b/src/test/ui/nll/issue-54779-anon-static-lifetime.rs new file mode 100644 index 00000000000..4bb983dd358 --- /dev/null +++ b/src/test/ui/nll/issue-54779-anon-static-lifetime.rs @@ -0,0 +1,51 @@ +// Regression test for #54779, checks if the diagnostics are confusing. + +#![feature(nll)] + +trait DebugWith<Cx: ?Sized> { + fn debug_with<'me>(&'me self, cx: &'me Cx) -> DebugCxPair<'me, Self, Cx> { + DebugCxPair { value: self, cx } + } + + fn fmt_with(&self, cx: &Cx, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result; +} + +struct DebugCxPair<'me, Value: ?Sized, Cx: ?Sized> +where + Value: DebugWith<Cx>, +{ + value: &'me Value, + cx: &'me Cx, +} + +trait DebugContext {} + +struct Foo { + bar: Bar, +} + +impl DebugWith<dyn DebugContext> for Foo { + fn fmt_with( + &self, + cx: &dyn DebugContext, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + let Foo { bar } = self; + bar.debug_with(cx); //~ ERROR: lifetime may not live long enough + Ok(()) + } +} + +struct Bar {} + +impl DebugWith<dyn DebugContext> for Bar { + fn fmt_with( + &self, + cx: &dyn DebugContext, + fmt: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + Ok(()) + } +} + +fn main() {} diff --git a/src/test/ui/nll/issue-54779-anon-static-lifetime.stderr b/src/test/ui/nll/issue-54779-anon-static-lifetime.stderr new file mode 100644 index 00000000000..9dc9bdbab8d --- /dev/null +++ b/src/test/ui/nll/issue-54779-anon-static-lifetime.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/issue-54779-anon-static-lifetime.rs:34:24 + | +LL | cx: &dyn DebugContext, + | - let's call the lifetime of this reference `'1` +... +LL | bar.debug_with(cx); + | ^^ cast requires that `'1` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/osx-frameworks.rs b/src/test/ui/osx-frameworks.rs index 31b853e24fe..958183ec0d7 100644 --- a/src/test/ui/osx-frameworks.rs +++ b/src/test/ui/osx-frameworks.rs @@ -2,6 +2,6 @@ #[link(name = "foo", kind = "framework")] extern "C" {} -//~^^ ERROR: native frameworks are only available on macOS +//~^^ ERROR: link kind `framework` is only supported on Apple targets fn main() {} diff --git a/src/test/ui/osx-frameworks.stderr b/src/test/ui/osx-frameworks.stderr index f3532913423..e4a5c98dc5c 100644 --- a/src/test/ui/osx-frameworks.stderr +++ b/src/test/ui/osx-frameworks.stderr @@ -1,8 +1,8 @@ -error[E0455]: native frameworks are only available on macOS targets - --> $DIR/osx-frameworks.rs:3:1 +error[E0455]: link kind `framework` is only supported on Apple targets + --> $DIR/osx-frameworks.rs:3:29 | LL | #[link(name = "foo", kind = "framework")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/rfc-1717-dllimport/rename-modifiers.rs b/src/test/ui/rfc-1717-dllimport/rename-modifiers.rs new file mode 100644 index 00000000000..30f4db7180e --- /dev/null +++ b/src/test/ui/rfc-1717-dllimport/rename-modifiers.rs @@ -0,0 +1,9 @@ +// compile-flags: -l dylib=foo:bar +// error-pattern: overriding linking modifiers from command line is not supported + +#![feature(native_link_modifiers_as_needed)] + +#![crate_type = "lib"] + +#[link(name = "foo", kind = "dylib", modifiers = "-as-needed")] +extern "C" {} diff --git a/src/test/ui/rfc-1717-dllimport/rename-modifiers.stderr b/src/test/ui/rfc-1717-dllimport/rename-modifiers.stderr new file mode 100644 index 00000000000..bee639bf26c --- /dev/null +++ b/src/test/ui/rfc-1717-dllimport/rename-modifiers.stderr @@ -0,0 +1,8 @@ +error: overriding linking modifiers from command line is not supported + --> $DIR/rename-modifiers.rs:9:1 + | +LL | extern "C" {} + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs index 7a5d7ac2934..5856b18aa16 100644 --- a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs +++ b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs @@ -3,5 +3,5 @@ #![feature(raw_dylib)] //~^ WARNING: the feature `raw_dylib` is incomplete #[link(name = "foo", kind = "raw-dylib")] -//~^ ERROR: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows +//~^ ERROR: link kind `raw-dylib` is only supported on Windows targets extern "C" {} diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr index f3879b63f91..600aac81a35 100644 --- a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr +++ b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr @@ -7,11 +7,12 @@ LL | #![feature(raw_dylib)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information -error: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows - --> $DIR/raw-dylib-windows-only.rs:5:1 +error[E0455]: link kind `raw-dylib` is only supported on Windows targets + --> $DIR/raw-dylib-windows-only.rs:5:29 | LL | #[link(name = "foo", kind = "raw-dylib")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ error: aborting due to previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0455`. diff --git a/src/test/ui/symbol-names/basic.legacy.stderr b/src/test/ui/symbol-names/basic.legacy.stderr index e4d58d3ccdb..3ad4ed24cf7 100644 --- a/src/test/ui/symbol-names/basic.legacy.stderr +++ b/src/test/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17h87acd86b3a6f1754E) +error: symbol-name(_ZN5basic4main17hcbad207c0eeb0b3bE) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::h87acd86b3a6f1754) +error: demangling(basic::main::hcbad207c0eeb0b3b) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr index c987ebc5343..21bf21ee71c 100644 --- a/src/test/ui/symbol-names/issue-60925.legacy.stderr +++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h8d22952c45e20d65E) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h2f2efcf580c9b1eeE) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h8d22952c45e20d65) +error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h2f2efcf580c9b1ee) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/traits/assoc-type-in-superbad.stderr b/src/test/ui/traits/assoc-type-in-superbad.stderr index cbdb6b96f46..f3694791417 100644 --- a/src/test/ui/traits/assoc-type-in-superbad.stderr +++ b/src/test/ui/traits/assoc-type-in-superbad.stderr @@ -2,7 +2,13 @@ error[E0271]: type mismatch resolving `<std::vec::IntoIter<i32> as Iterator>::It --> $DIR/assoc-type-in-superbad.rs:12:16 | LL | type Key = u32; - | ^^^ expected `i32`, found `u32` + | ^^^ expected `u32`, found `i32` + | +note: required by a bound in `Foo` + --> $DIR/assoc-type-in-superbad.rs:7:25 + | +LL | pub trait Foo: Iterator<Item=<Self as Foo>::Key> { + | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo` error: aborting due to previous error diff --git a/src/test/ui/traits/object/enforce-supertrait-projection.rs b/src/test/ui/traits/object/enforce-supertrait-projection.rs index 0ea944ec2df..2c9b41eea2a 100644 --- a/src/test/ui/traits/object/enforce-supertrait-projection.rs +++ b/src/test/ui/traits/object/enforce-supertrait-projection.rs @@ -7,7 +7,7 @@ trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {} fn transmute<A, B>(x: A) -> B { foo::<A, B, dyn Trait<A = A, B = B>>(x) - //~^ ERROR type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B` + //~^ ERROR type mismatch resolving `<dyn Trait<B = B, A = A> as SuperTrait>::A == B` } fn foo<A, B, T: ?Sized>(x: T::A) -> B diff --git a/src/test/ui/traits/object/enforce-supertrait-projection.stderr b/src/test/ui/traits/object/enforce-supertrait-projection.stderr index a3d17fabbe4..eab42ca568a 100644 --- a/src/test/ui/traits/object/enforce-supertrait-projection.stderr +++ b/src/test/ui/traits/object/enforce-supertrait-projection.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B` +error[E0271]: type mismatch resolving `<dyn Trait<B = B, A = A> as SuperTrait>::A == B` --> $DIR/enforce-supertrait-projection.rs:9:5 | LL | fn transmute<A, B>(x: A) -> B { diff --git a/src/test/ui/trivial-bounds/issue-73021-impossible-inline.inline.stderr b/src/test/ui/trivial-bounds/issue-73021-impossible-inline.inline.stderr new file mode 100644 index 00000000000..40829f53709 --- /dev/null +++ b/src/test/ui/trivial-bounds/issue-73021-impossible-inline.inline.stderr @@ -0,0 +1,46 @@ +warning: trait bound for<'any> &'any mut (): Clone does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:20:29 + | +LL | for<'any> &'any mut (): Clone, + | ^^^^^ + | + = note: `#[warn(trivial_bounds)]` on by default + +warning: trait bound i32: Foo does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:28:21 + | +LL | struct S where i32: Foo; + | ^^^ + +warning: trait bound i32: Foo does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:31:28 + | +LL | impl Foo for () where i32: Foo { + | ^^^ + +warning: trait bound i32: Foo does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:40:19 + | +LL | fn f() where i32: Foo { + | ^^^ + +warning: trait bound &'static str: Foo does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:48:28 + | +LL | fn g() where &'static str: Foo { + | ^^^ + +warning: trait bound String: Neg does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:57:13 + | +LL | String: ::std::ops::Neg<Output = String>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: trait bound i32: Iterator does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:65:10 + | +LL | i32: Iterator, + | ^^^^^^^^ + +warning: 7 warnings emitted + diff --git a/src/test/ui/trivial-bounds/issue-73021-impossible-inline.no-opt.stderr b/src/test/ui/trivial-bounds/issue-73021-impossible-inline.no-opt.stderr new file mode 100644 index 00000000000..40829f53709 --- /dev/null +++ b/src/test/ui/trivial-bounds/issue-73021-impossible-inline.no-opt.stderr @@ -0,0 +1,46 @@ +warning: trait bound for<'any> &'any mut (): Clone does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:20:29 + | +LL | for<'any> &'any mut (): Clone, + | ^^^^^ + | + = note: `#[warn(trivial_bounds)]` on by default + +warning: trait bound i32: Foo does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:28:21 + | +LL | struct S where i32: Foo; + | ^^^ + +warning: trait bound i32: Foo does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:31:28 + | +LL | impl Foo for () where i32: Foo { + | ^^^ + +warning: trait bound i32: Foo does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:40:19 + | +LL | fn f() where i32: Foo { + | ^^^ + +warning: trait bound &'static str: Foo does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:48:28 + | +LL | fn g() where &'static str: Foo { + | ^^^ + +warning: trait bound String: Neg does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:57:13 + | +LL | String: ::std::ops::Neg<Output = String>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: trait bound i32: Iterator does not depend on any type or lifetime parameters + --> $DIR/issue-73021-impossible-inline.rs:65:10 + | +LL | i32: Iterator, + | ^^^^^^^^ + +warning: 7 warnings emitted + diff --git a/src/test/ui/trivial-bounds/issue-73021-impossible-inline.rs b/src/test/ui/trivial-bounds/issue-73021-impossible-inline.rs new file mode 100644 index 00000000000..ab6677e911b --- /dev/null +++ b/src/test/ui/trivial-bounds/issue-73021-impossible-inline.rs @@ -0,0 +1,71 @@ +// build-pass +// revisions: no-opt inline +// [inline]compile-flags: -Zmir-opt-level=3 --emit=mir +#![feature(trivial_bounds)] +#![allow(unused)] + +trait Foo { + fn test(&self); +} + +fn foo<'a>(s: &'a mut ()) +where + &'a mut (): Foo, +{ + s.test(); +} + +fn clone(it: &mut ()) -> &mut () +where + for<'any> &'any mut (): Clone, + //~^ WARN trait bound for<'any> &'any mut (): Clone does not depend on any type or lifetime parameters +{ + it.clone() +} + +fn generic_function<X: Foo>(x: X) {} + +struct S where i32: Foo; +//~^ WARN trait bound i32: Foo does not depend on any type or lifetime parameters + +impl Foo for () where i32: Foo { +//~^ WARN trait bound i32: Foo does not depend on any type or lifetime parameters + fn test(&self) { + 3i32.test(); + Foo::test(&4i32); + generic_function(5i32); + } +} + +fn f() where i32: Foo { +//~^ WARN trait bound i32: Foo does not depend on any type or lifetime parameters + let s = S; + 3i32.test(); + Foo::test(&4i32); + generic_function(5i32); +} + +fn g() where &'static str: Foo { +//~^ WARN trait bound &'static str: Foo does not depend on any type or lifetime parameters + "Foo".test(); + Foo::test(&"Foo"); + generic_function("Foo"); +} + +fn use_op(s: String) -> String +where + String: ::std::ops::Neg<Output = String>, +//~^ WARN trait bound String: Neg does not depend on any type or lifetime parameters +{ + -s +} + +fn use_for() +where + i32: Iterator, +//~^ WARN trait bound i32: Iterator does not depend on any type or lifetime parameters +{ + for _ in 2i32 {} +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs index cf46add124c..093c1c23186 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs @@ -15,7 +15,6 @@ type TwoConsts<const X: usize, const Y: usize> = impl Debug; fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> { t //~^ ERROR non-defining opaque type use in defining scope - //~| ERROR `U` doesn't implement `Debug` } fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> { diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr index d661196e1bf..b2edcc5526a 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr @@ -1,14 +1,3 @@ -error[E0277]: `U` doesn't implement `Debug` - --> $DIR/generic_duplicate_param_use.rs:16:5 - | -LL | t - | ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` - | -help: consider restricting type parameter `U` - | -LL | type TwoTys<T, U: std::fmt::Debug> = impl Debug; - | +++++++++++++++++ - error: non-defining opaque type use in defining scope --> $DIR/generic_duplicate_param_use.rs:16:5 | @@ -22,7 +11,7 @@ LL | type TwoTys<T, U> = impl Debug; | ^ ^ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:22:5 + --> $DIR/generic_duplicate_param_use.rs:21:5 | LL | t | ^ @@ -34,7 +23,7 @@ LL | type TwoLifetimes<'a, 'b> = impl Debug; | ^^ ^^ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:27:5 + --> $DIR/generic_duplicate_param_use.rs:26:5 | LL | t | ^ @@ -45,6 +34,5 @@ note: constant used multiple times LL | type TwoConsts<const X: usize, const Y: usize> = impl Debug; | ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-53092.rs b/src/test/ui/type-alias-impl-trait/issue-53092.rs new file mode 100644 index 00000000000..45792ba97a7 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-53092.rs @@ -0,0 +1,14 @@ +#![feature(type_alias_impl_trait)] +#![allow(dead_code)] + +type Bug<T, U> = impl Fn(T) -> U + Copy; + +const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; + +fn make_bug<T, U: From<T>>() -> Bug<T, U> { + |x| x.into() //~ ERROR the trait bound `U: From<T>` is not satisfied +} + +fn main() { + CONST_BUG(0); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-53092.stderr b/src/test/ui/type-alias-impl-trait/issue-53092.stderr new file mode 100644 index 00000000000..2d423a0c0df --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-53092.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `U: From<T>` is not satisfied + --> $DIR/issue-53092.rs:9:5 + | +LL | |x| x.into() + | ^^^^^^^^^^^^ the trait `From<T>` is not implemented for `U` + | +note: required by a bound in `make_bug` + --> $DIR/issue-53092.rs:8:19 + | +LL | fn make_bug<T, U: From<T>>() -> Bug<T, U> { + | ^^^^^^^ required by this bound in `make_bug` +help: consider restricting type parameter `U` + | +LL | type Bug<T, U: std::convert::From<T>> = impl Fn(T) -> U + Copy; + | +++++++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-60564-working.rs b/src/test/ui/type-alias-impl-trait/issue-60564-working.rs new file mode 100644 index 00000000000..38accc8241c --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-60564-working.rs @@ -0,0 +1,24 @@ +#![feature(type_alias_impl_trait)] + +// check-pass + +trait IterBits { + type BitsIter: Iterator<Item = u8>; + fn iter_bits(self, n: u8) -> Self::BitsIter; +} + +impl<T: Copy, E> IterBits for T +where + T: std::ops::Shr<Output = T> + + std::ops::BitAnd<T, Output = T> + + std::convert::From<u8> + + std::convert::TryInto<u8, Error = E>, + E: std::fmt::Debug, +{ + type BitsIter = impl std::iter::Iterator<Item = u8>; + fn iter_bits(self, n: u8) -> Self::BitsIter { + (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.rs b/src/test/ui/type-alias-impl-trait/issue-60564.rs index 0aeebae639e..4fc7679311a 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60564.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60564.rs @@ -19,7 +19,6 @@ where fn iter_bits(self, n: u8) -> Self::BitsIter { (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) //~^ ERROR non-defining opaque type use in defining scope - //~| ERROR type mismatch resolving } } diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.stderr b/src/test/ui/type-alias-impl-trait/issue-60564.stderr index 9cb07cbbb44..bbc93657be3 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60564.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60564.stderr @@ -1,16 +1,3 @@ -error[E0271]: type mismatch resolving `<[closure@$DIR/issue-60564.rs:20:28: 20:100] as FnOnce<(u8,)>>::Output == I` - --> $DIR/issue-60564.rs:20:9 - | -LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>; - | - this type parameter -... -LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found type parameter `I` - | - = note: expected type `u8` - found type parameter `I` - = note: required because of the requirements on the impl of `Iterator` for `Map<Rev<std::ops::Range<u8>>, [closure@$DIR/issue-60564.rs:20:28: 20:100]>` - error: non-defining opaque type use in defining scope --> $DIR/issue-60564.rs:20:9 | @@ -23,6 +10,5 @@ note: used non-generic type `u8` for generic parameter LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>; | ^ -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs index bffff8787e4..b50462bf237 100644 --- a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs +++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs @@ -8,7 +8,6 @@ type Alias<'a, U> = impl Trait<U>; fn f<'a>() -> Alias<'a, ()> {} //~^ ERROR non-defining opaque type use in defining scope -//~| ERROR the trait bound `(): Trait<U>` is not satisfied fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr index b79d638ad99..8059621b61a 100644 --- a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr @@ -1,14 +1,3 @@ -error[E0277]: the trait bound `(): Trait<U>` is not satisfied - --> $DIR/issue-68368-non-defining-use.rs:9:29 - | -LL | fn f<'a>() -> Alias<'a, ()> {} - | ^^ the trait `Trait<U>` is not implemented for `()` - | -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement - | -LL | type Alias<'a, U> = impl Trait<U> where (): Trait<U>; - | ++++++++++++++++++ - error: non-defining opaque type use in defining scope --> $DIR/issue-68368-non-defining-use.rs:9:29 | @@ -21,6 +10,5 @@ note: used non-generic type `()` for generic parameter LL | type Alias<'a, U> = impl Trait<U>; | ^ -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs index b0de8bf6aa4..428454bc048 100644 --- a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs +++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs @@ -19,6 +19,5 @@ type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>; fn my_fun() -> Return<()> {} //~^ ERROR non-defining opaque type use in defining scope -//~| ERROR non-defining opaque type use in defining scope fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr index d038fbbe1b4..7b50c8af26e 100644 --- a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr @@ -26,18 +26,6 @@ note: used non-generic type `()` for generic parameter LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>; | ^ -error: non-defining opaque type use in defining scope - --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27 - | -LL | fn my_fun() -> Return<()> {} - | ^^ - | -note: used non-generic type `()` for generic parameter - --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13 - | -LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>; - | ^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs new file mode 100644 index 00000000000..449e9fbd0d8 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs @@ -0,0 +1,18 @@ +#![feature(type_alias_impl_trait)] + +trait Bar { + fn bar(&self); +} + +type FooFn<B> = impl FnOnce(B); + +fn foo<B: Bar>() -> FooFn<B> { + fn mop<B: Bar>(bar: B) { bar.bar() } + mop // NOTE: no function pointer, but function zst item + //~^ ERROR the trait bound `B: Bar` is not satisfied +} + +fn main() { + let boom: FooFn<u32> = unsafe { core::mem::zeroed() }; + boom(42); +} diff --git a/src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr new file mode 100644 index 00000000000..e0005489d1e --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `B: Bar` is not satisfied + --> $DIR/wf-check-fn-def.rs:11:5 + | +LL | mop // NOTE: no function pointer, but function zst item + | ^^^ the trait `Bar` is not implemented for `B` + | +note: required by a bound in `mop` + --> $DIR/wf-check-fn-def.rs:10:15 + | +LL | fn mop<B: Bar>(bar: B) { bar.bar() } + | ^^^ required by this bound in `mop` +help: consider restricting type parameter `B` + | +LL | type FooFn<B: Bar> = impl FnOnce(B); + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs b/src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs new file mode 100644 index 00000000000..3b8470e4ae6 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs @@ -0,0 +1,23 @@ +#![feature(type_alias_impl_trait)] + +// build-pass + +trait Bar { + fn bar(&self); +} + +type FooFn<B> = impl FnOnce(B); + +fn foo<B: Bar>() -> FooFn<B> { + fn mop<B: Bar>(bar: B) { bar.bar() } + mop as fn(B) + // function pointers don't have any obligations on them, + // thus the above compiles. It's obviously unsound to just + // procure a `FooFn` from the ether without making sure that + // the pointer is actually legal for all `B` +} + +fn main() { + let boom: FooFn<u32> = unsafe { core::mem::zeroed() }; + boom(42); +} diff --git a/src/test/ui/type-alias-impl-trait/wf_check_closures.rs b/src/test/ui/type-alias-impl-trait/wf_check_closures.rs new file mode 100644 index 00000000000..2c70696ffcf --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/wf_check_closures.rs @@ -0,0 +1,17 @@ +#![feature(type_alias_impl_trait)] + +trait Bar { + fn bar(&self); +} + +type FooFn<B> = impl FnOnce(); + +fn foo<B: Bar>(bar: B) -> FooFn<B> { + move || { bar.bar() } + //~^ ERROR the trait bound `B: Bar` is not satisfied +} + +fn main() { + let boom: FooFn<u32> = unsafe { core::mem::zeroed() }; + boom(); +} diff --git a/src/test/ui/type-alias-impl-trait/wf_check_closures.stderr b/src/test/ui/type-alias-impl-trait/wf_check_closures.stderr new file mode 100644 index 00000000000..58ae8617b9b --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/wf_check_closures.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `B: Bar` is not satisfied + --> $DIR/wf_check_closures.rs:10:5 + | +LL | move || { bar.bar() } + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `B` + | +note: required by a bound in `foo` + --> $DIR/wf_check_closures.rs:9:11 + | +LL | fn foo<B: Bar>(bar: B) -> FooFn<B> { + | ^^^ required by this bound in `foo` +help: consider restricting type parameter `B` + | +LL | type FooFn<B: Bar> = impl FnOnce(); + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/wasm/wasm-import-module.rs b/src/test/ui/wasm/wasm-import-module.rs index 4152a1065ca..bff08847d37 100644 --- a/src/test/ui/wasm/wasm-import-module.rs +++ b/src/test/ui/wasm/wasm-import-module.rs @@ -1,3 +1,5 @@ +#![feature(link_cfg)] + #[link(name = "...", wasm_import_module)] //~ ERROR: must be of the form extern "C" {} @@ -7,4 +9,13 @@ extern "C" {} #[link(name = "...", wasm_import_module())] //~ ERROR: must be of the form extern "C" {} +#[link(wasm_import_module = "foo", name = "bar")] //~ ERROR: `wasm_import_module` is incompatible with other arguments +extern "C" {} + +#[link(wasm_import_module = "foo", kind = "dylib")] //~ ERROR: `wasm_import_module` is incompatible with other arguments +extern "C" {} + +#[link(wasm_import_module = "foo", cfg(FALSE))] //~ ERROR: `wasm_import_module` is incompatible with other arguments +extern "C" {} + fn main() {} diff --git a/src/test/ui/wasm/wasm-import-module.stderr b/src/test/ui/wasm/wasm-import-module.stderr index 47d6cb68997..e792c33e91a 100644 --- a/src/test/ui/wasm/wasm-import-module.stderr +++ b/src/test/ui/wasm/wasm-import-module.stderr @@ -1,20 +1,38 @@ -error: must be of the form `#[link(wasm_import_module = "...")]` - --> $DIR/wasm-import-module.rs:1:22 +error: wasm import module must be of the form `wasm_import_module = "string"` + --> $DIR/wasm-import-module.rs:3:22 | LL | #[link(name = "...", wasm_import_module)] | ^^^^^^^^^^^^^^^^^^ -error: must be of the form `#[link(wasm_import_module = "...")]` - --> $DIR/wasm-import-module.rs:4:22 +error: wasm import module must be of the form `wasm_import_module = "string"` + --> $DIR/wasm-import-module.rs:6:22 | LL | #[link(name = "...", wasm_import_module(x))] | ^^^^^^^^^^^^^^^^^^^^^ -error: must be of the form `#[link(wasm_import_module = "...")]` - --> $DIR/wasm-import-module.rs:7:22 +error: wasm import module must be of the form `wasm_import_module = "string"` + --> $DIR/wasm-import-module.rs:9:22 | LL | #[link(name = "...", wasm_import_module())] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: `wasm_import_module` is incompatible with other arguments in `#[link]` attributes + --> $DIR/wasm-import-module.rs:12:8 + | +LL | #[link(wasm_import_module = "foo", name = "bar")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `wasm_import_module` is incompatible with other arguments in `#[link]` attributes + --> $DIR/wasm-import-module.rs:15:8 + | +LL | #[link(wasm_import_module = "foo", kind = "dylib")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `wasm_import_module` is incompatible with other arguments in `#[link]` attributes + --> $DIR/wasm-import-module.rs:18:8 + | +LL | #[link(wasm_import_module = "foo", cfg(FALSE))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/src/tools/cargo b/src/tools/cargo -Subproject a44758ac805600edbb6ba51e7e6fb81a6077c0c +Subproject 3f052d8eed98c6a24f8b332fb2e6e6249d12d8c diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index 14098340745..34a5f8444de 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{is_automatically_derived, is_default_equivalent, peel_blocks}; +use clippy_utils::{is_default_equivalent, peel_blocks}; use rustc_hir::{ def::{DefKind, Res}, Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, @@ -71,8 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { self_ty, .. }) = item.kind; - if let attrs = cx.tcx.hir().attrs(item.hir_id()); - if !is_automatically_derived(attrs); + if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived); if !item.span.from_expansion(); if let Some(def_id) = trait_ref.trait_def_id(); if cx.tcx.is_diagnostic_item(sym::Default, def_id); @@ -81,6 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { if let ImplItemKind::Fn(_, b) = &impl_item.kind; if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b); if let Some(adt_def) = cx.tcx.type_of(item.def_id).ty_adt_def(); + if let attrs = cx.tcx.hir().attrs(item.hir_id()); if !attrs.iter().any(|attr| attr.doc_str().is_some()); if let child_attrs = cx.tcx.hir().attrs(impl_item_hir); if !child_attrs.iter().any(|attr| attr.doc_str().is_some()); diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 557e101494e..545bc7d2103 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then}; use clippy_utils::paths; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{is_automatically_derived, is_lint_allowed, match_def_path}; +use clippy_utils::{is_lint_allowed, match_def_path}; use if_chain::if_chain; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; use rustc_hir::{ @@ -171,8 +171,8 @@ impl<'tcx> LateLintPass<'tcx> for Derive { }) = item.kind { let ty = cx.tcx.type_of(item.def_id); - let attrs = cx.tcx.hir().attrs(item.hir_id()); - let is_automatically_derived = is_automatically_derived(attrs); + let is_automatically_derived = + cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived); check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived); check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived); @@ -201,7 +201,7 @@ fn check_hash_peq<'tcx>( then { // Look for the PartialEq implementations for `ty` cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { - let peq_is_automatically_derived = is_automatically_derived(cx.tcx.get_attrs(impl_id)); + let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); if peq_is_automatically_derived == hash_is_automatically_derived { return; @@ -255,7 +255,7 @@ fn check_ord_partial_ord<'tcx>( then { // Look for the PartialOrd implementations for `ty` cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| { - let partial_ord_is_automatically_derived = is_automatically_derived(cx.tcx.get_attrs(impl_id)); + let partial_ord_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived); if partial_ord_is_automatically_derived == ord_is_automatically_derived { return; diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 1b19868e4c7..530d6d4de35 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -150,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if check_inputs(cx, body.params, args); let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(body.value.hir_id); - let call_ty = cx.tcx.type_of(method_def_id).subst(cx.tcx, substs); + let call_ty = cx.tcx.bound_type_of(method_def_id).subst(cx.tcx, substs); if check_sig(cx, closure_ty, call_ty); then { span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| { diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 38e943d2eb8..6672a6cb0b5 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -13,13 +13,13 @@ use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_must_use_ty; -use clippy_utils::{match_def_path, must_use_attr, return_ty, trait_ref_of_method}; +use clippy_utils::{match_def_path, return_ty, trait_ref_of_method}; use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); - let attr = must_use_attr(attrs); + let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use); if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind { let is_public = cx.access_levels.is_exported(item.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); @@ -44,7 +44,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let is_public = cx.access_levels.is_exported(item.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); - let attr = must_use_attr(attrs); + let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id).is_none() { @@ -67,7 +67,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); - let attr = must_use_attr(attrs); + let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); } else if let hir::TraitFn::Provided(eid) = *eid { diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 43911a313d5..5c46d6c7df7 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -5,7 +5,7 @@ use rustc_hir::{Body, FnDecl, HirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{Opaque, PredicateKind::Trait}; +use rustc_middle::ty::{EarlyBinder, Opaque, PredicateKind::Trait}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt; @@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let preds = cx.tcx.explicit_item_bounds(id); let mut is_future = false; for &(p, _span) in preds { - let p = p.subst(cx.tcx, subst); + let p = EarlyBinder(p).subst(cx.tcx, subst); if let Some(trait_pred) = p.to_opt_poly_trait_pred() { if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() { is_future = true; diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index b8d620d8171..09164690700 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -1,4 +1,3 @@ -use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::{is_lint_allowed, meets_msrv, msrvs}; @@ -161,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { let id = cx.tcx.hir().local_def_id(v.id); (matches!(v.data, hir::VariantData::Unit(_)) && v.ident.as_str().starts_with('_') - && is_doc_hidden(cx.tcx.get_attrs(id.to_def_id()))) + && cx.tcx.is_doc_hidden(id.to_def_id())) .then(|| (id, v.span)) }); if let Some((id, span)) = iter.next() diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs index 93bf0dc62e0..fc45ccee185 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs @@ -193,6 +193,5 @@ impl<'a> CommonPrefixSearcher<'a> { } fn is_hidden(cx: &LateContext<'_>, variant_def: &VariantDef) -> bool { - let attrs = cx.tcx.get_attrs(variant_def.def_id); - clippy_utils::attrs::is_doc_hidden(attrs) || clippy_utils::attrs::is_unstable(attrs) + cx.tcx.is_doc_hidden(variant_def.def_id) || cx.tcx.has_attr(variant_def.def_id, sym::unstable) } diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index 5c3e505c06c..9d8f8999ce4 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { ExprKind::MethodCall(path, arguments, _) => { let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(e.hir_id); - let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs); + let method_type = cx.tcx.bound_type_of(def_id).subst(cx.tcx, substs); check_arguments(cx, arguments, method_type, path.ident.as_str(), "method"); }, _ => (), diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index 2f733f221d5..2bdccb42507 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // can't be implemented for unsafe new return; } - if clippy_utils::is_doc_hidden(cx.tcx.hir().attrs(id)) { + if cx.tcx.is_doc_hidden(impl_item.def_id) { // shouldn't be implemented when it is hidden in docs return; } diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs index 1469cb434c0..09ac514d014 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_hir; -use clippy_utils::is_automatically_derived; use if_chain::if_chain; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -37,8 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if_chain! { if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind; - let attrs = cx.tcx.hir().attrs(item.hir_id()); - if !is_automatically_derived(attrs); + if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived); if let Some(eq_trait) = cx.tcx.lang_items().eq_trait(); if trait_ref.path.res.def_id() == eq_trait; then { diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/significant_drop_in_scrutinee.rs index 94ae0c8f5a6..f300acf0fb2 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_in_scrutinee.rs @@ -290,7 +290,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { fn has_sig_drop_attr(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { if let Some(adt) = ty.ty_adt_def() { - if get_attr(cx.sess(), cx.tcx.get_attrs(adt.did()), "has_significant_drop").count() > 0 { + if get_attr(cx.sess(), cx.tcx.get_attrs_unchecked(adt.did()), "has_significant_drop").count() > 0 { return true; } } diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs index f5e21267a89..be6277332db 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -307,7 +307,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> .non_enum_variant() .fields .iter() - .map(|f| cx.tcx.type_of(f.did).subst(cx.tcx, substs)); + .map(|f| cx.tcx.bound_type_of(f.did).subst(cx.tcx, substs)); let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else { return ReducedTy::TypeErasure; }; diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index 7f448175e32..904b1a05ccc 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -1,6 +1,7 @@ -use rustc_ast::{ast, attr}; +use rustc_ast::ast; use rustc_errors::Applicability; use rustc_session::Session; +use rustc_ast::attr; use rustc_span::sym; use std::str::FromStr; @@ -158,7 +159,3 @@ pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool { .any(|l| attr::list_contains_name(&l, sym::hidden)) } -/// Return true if the attributes contain `#[unstable]` -pub fn is_unstable(attrs: &[ast::Attribute]) -> bool { - attrs.iter().any(|attr| attr.has_name(sym::unstable)) -} diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index fdb822c3e5b..a80c7ee4929 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -9,7 +9,7 @@ use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, use rustc_lint::LateContext; use rustc_middle::mir::interpret::Scalar; use rustc_middle::ty::subst::{Subst, SubstsRef}; -use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; use std::cmp::Ordering::{self, Equal}; @@ -420,7 +420,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let substs = if self.substs.is_empty() { substs } else { - substs.subst(self.lcx.tcx, self.substs) + EarlyBinder(substs).subst(self.lcx.tcx, self.substs) }; let result = self diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 7d46952d971..6db7f247a99 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -66,7 +66,7 @@ use std::lazy::SyncOnceCell; use std::sync::{Mutex, MutexGuard}; use if_chain::if_chain; -use rustc_ast::ast::{self, Attribute, LitKind}; +use rustc_ast::ast::{self, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unhash::UnhashMap; use rustc_hir as hir; @@ -74,11 +74,10 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk}; use rustc_hir::{ def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl, - ForeignItem, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, + HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp, }; @@ -1472,12 +1471,6 @@ pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx> } } -/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d -/// implementations have. -pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool { - has_attr(attrs, sym::automatically_derived) -} - pub fn is_self(slf: &Param<'_>) -> bool { if let PatKind::Binding(.., name, _) = slf.pat.kind { name.name == kw::SelfLower @@ -1724,11 +1717,6 @@ pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'t None } -// Finds the `#[must_use]` attribute, if any -pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> { - attrs.iter().find(|a| a.has_name(sym::must_use)) -} - // check if expr is calling method or function with #[must_use] attribute pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let did = match expr.kind { @@ -1745,7 +1733,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { _ => None, }; - did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some()) + did.map_or(false, |did| cx.tcx.has_attr(did, sym::must_use)) } /// Checks if an expression represents the identity function @@ -2079,35 +2067,6 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { false } -struct TestItemNamesVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - names: Vec<Symbol>, -} - -impl<'hir> ItemLikeVisitor<'hir> for TestItemNamesVisitor<'hir> { - fn visit_item(&mut self, item: &Item<'_>) { - if let ItemKind::Const(ty, _body) = item.kind { - if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { - // We could also check for the type name `test::TestDescAndFn` - if let Res::Def(DefKind::Struct, _) = path.res { - let has_test_marker = self - .tcx - .hir() - .attrs(item.hir_id()) - .iter() - .any(|a| a.has_name(sym::rustc_test_marker)); - if has_test_marker { - self.names.push(item.ident.name); - } - } - } - } - } - fn visit_trait_item(&mut self, _: &TraitItem<'_>) {} - fn visit_impl_item(&mut self, _: &ImplItem<'_>) {} - fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {} -} - static TEST_ITEM_NAMES_CACHE: SyncOnceCell<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = SyncOnceCell::new(); fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool { @@ -2116,10 +2075,28 @@ fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn( match map.entry(module) { Entry::Occupied(entry) => f(entry.get()), Entry::Vacant(entry) => { - let mut visitor = TestItemNamesVisitor { tcx, names: Vec::new() }; - tcx.hir().visit_item_likes_in_module(module, &mut visitor); - visitor.names.sort_unstable(); - f(&*entry.insert(visitor.names)) + let mut names = Vec::new(); + for id in tcx.hir().module_items(module) { + if matches!(tcx.def_kind(id.def_id), DefKind::Const) + && let item = tcx.hir().item(id) + && let ItemKind::Const(ty, _body) = item.kind { + if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { + // We could also check for the type name `test::TestDescAndFn` + if let Res::Def(DefKind::Struct, _) = path.res { + let has_test_marker = tcx + .hir() + .attrs(item.hir_id()) + .iter() + .any(|a| a.has_name(sym::rustc_test_marker)); + if has_test_marker { + names.push(item.ident.name); + } + } + } + } + } + names.sort_unstable(); + f(&*entry.insert(names)) }, } } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 901e3e5390c..b09eb8c6cd1 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -22,7 +22,7 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::normalize::AtExt; use std::iter; -use crate::{match_def_path, must_use_attr, path_res, paths}; +use crate::{match_def_path, path_res, paths}; // Checks if the given type implements copy. pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { @@ -178,18 +178,18 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // Returns whether the type has #[must_use] attribute pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { - ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did())).is_some(), - ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(), + ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use), + ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use), ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays is_must_use_ty(cx, *ty) }, ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), - ty::Opaque(ref def_id, _) => { + ty::Opaque(def_id, _) => { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { if let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() { - if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() { + if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { return true; } } @@ -199,7 +199,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty::Dynamic(binder, _) => { for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { - if must_use_attr(cx.tcx.get_attrs(trait_ref.def_id)).is_some() { + if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) { return true; } } @@ -520,7 +520,7 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS let ty = cx.typeck_results().expr_ty_adjusted(expr).peel_refs(); match *ty.kind() { ty::Closure(_, subs) => Some(ExprFnSig::Closure(subs.as_closure().sig())), - ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst(cx.tcx, subs))), + ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs))), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig)), ty::Dynamic(bounds, _) => { let lang_items = cx.tcx.lang_items(); diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 2cb368c6881..ea13ae13208 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -246,6 +246,10 @@ pub struct Config { /// Only run tests that match these filters pub filters: Vec<String>, + /// Skip tests tests matching these substrings. Corresponds to + /// `test::TestOpts::skip`. `filter_exact` does not apply to these flags. + pub skip: Vec<String>, + /// Exactly match the filter, rather than a substring pub filter_exact: bool, diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 3d11ea21acf..e23cccf6cd1 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -91,6 +91,7 @@ pub fn parse_config(args: Vec<String>) -> Config { ) .optopt("", "run", "whether to execute run-* tests", "auto | always | never") .optflag("", "ignored", "run tests marked as ignored") + .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING") .optflag("", "exact", "filters match exactly") .optopt( "", @@ -236,6 +237,7 @@ pub fn parse_config(args: Vec<String>) -> Config { debugger: None, run_ignored, filters: matches.free.clone(), + skip: matches.opt_strs("skip"), filter_exact: matches.opt_present("exact"), force_pass_mode: matches.opt_str("pass").map(|mode| { mode.parse::<PassMode>() @@ -312,6 +314,7 @@ pub fn log_config(config: &Config) { logv(c, format!("mode: {}", config.mode)); logv(c, format!("run_ignored: {}", config.run_ignored)); logv(c, format!("filters: {:?}", config.filters)); + logv(c, format!("skip: {:?}", config.skip)); logv(c, format!("filter_exact: {}", config.filter_exact)); logv( c, @@ -506,7 +509,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts { shuffle: false, shuffle_seed: None, test_threads: None, - skip: vec![], + skip: config.skip.clone(), list: false, options: test::Options::new(), time_options: None, @@ -595,6 +598,7 @@ fn collect_tests_from_dir( debug!("found test file: {:?}", file_path.display()); let paths = TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() }; + tests.extend(make_test(config, &paths, inputs)) } else if file_path.is_dir() { let relative_file_path = relative_dir_path.join(file.file_name()); diff --git a/src/tools/miri b/src/tools/miri -Subproject 3b8b6aa8b689971d3b8776cefe3d809501e1b8f +Subproject 19ef76477c0ea1722f91ab6b1c2dcb365f06499 diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js index d75884567af..8532410a1bf 100644 --- a/src/tools/rustdoc-gui/tester.js +++ b/src/tools/rustdoc-gui/tester.js @@ -138,7 +138,7 @@ async function main(argv) { try { // This is more convenient that setting fields one by one. let args = [ - "--variable", "DOC_PATH", opts["doc_folder"], + "--variable", "DOC_PATH", opts["doc_folder"], "--enable-fail-on-js-error", ]; if (opts["debug"]) { debug = true; diff --git a/src/version b/src/version index 76d05362056..af92bdd9f58 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.62.0 +1.63.0 |
