diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 8c51225712093..3c95ebf9ffabc 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -474,17 +474,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let projected_ty = curr_projected_ty.projection_ty_core( tcx, proj, - |this, field, ()| { - let ty = this.field_ty(tcx, field); - self.structurally_resolve(ty, locations) - }, - |_, _| unreachable!(), + |ty| self.structurally_resolve(ty, locations), + |ty, variant_index, field, ()| PlaceTy::field_ty(tcx, ty, variant_index, field), + |_| unreachable!(), ); curr_projected_ty = projected_ty; } trace!(?curr_projected_ty); - let ty = curr_projected_ty.ty; + // Need to renormalize `a` as typecheck may have failed to normalize + // higher-ranked aliases if normalization was ambiguous due to inference. + let a = self.normalize(a, locations); + let ty = self.normalize(curr_projected_ty.ty, locations); self.relate_types(ty, v.xform(ty::Contravariant), a, locations, category)?; Ok(()) @@ -1852,7 +1853,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { | ProjectionElem::Downcast(..) => {} ProjectionElem::Field(field, fty) => { let fty = self.normalize(fty, location); - let ty = base_ty.field_ty(tcx, field); + let ty = PlaceTy::field_ty(tcx, base_ty.ty, base_ty.variant_index, field); let ty = self.normalize(ty, location); debug!(?fty, ?ty); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b802284eb3253..58fa3c392cae6 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -6,7 +6,7 @@ use std::fs::{File, OpenOptions, read}; use std::io::{BufWriter, Write}; use std::ops::{ControlFlow, Deref}; use std::path::{Path, PathBuf}; -use std::process::{ExitStatus, Output, Stdio}; +use std::process::{Output, Stdio}; use std::{env, fmt, fs, io, mem, str}; use cc::windows_registry; @@ -736,13 +736,10 @@ fn link_natively( // Invoke the system linker info!("{cmd:?}"); - let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok(); let unknown_arg_regex = Regex::new(r"(unknown|unrecognized) (command line )?(option|argument)").unwrap(); let mut prog; - let mut i = 0; loop { - i += 1; prog = sess.time("run_linker", || exec_linker(sess, &cmd, out_filename, flavor, tmpdir)); let Ok(ref output) = prog else { break; @@ -858,54 +855,7 @@ fn link_natively( continue; } - // Here's a terribly awful hack that really shouldn't be present in any - // compiler. Here an environment variable is supported to automatically - // retry the linker invocation if the linker looks like it segfaulted. - // - // Gee that seems odd, normally segfaults are things we want to know - // about! Unfortunately though in rust-lang/rust#38878 we're - // experiencing the linker segfaulting on Travis quite a bit which is - // causing quite a bit of pain to land PRs when they spuriously fail - // due to a segfault. - // - // The issue #38878 has some more debugging information on it as well, - // but this unfortunately looks like it's just a race condition in - // macOS's linker with some thread pool working in the background. It - // seems that no one currently knows a fix for this so in the meantime - // we're left with this... - if !retry_on_segfault || i > 3 { - break; - } - let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11"; - let msg_bus = "clang: error: unable to execute command: Bus error: 10"; - if out.contains(msg_segv) || out.contains(msg_bus) { - warn!( - ?cmd, %out, - "looks like the linker segfaulted when we tried to call it, \ - automatically retrying again", - ); - continue; - } - - if is_illegal_instruction(&output.status) { - warn!( - ?cmd, %out, status = %output.status, - "looks like the linker hit an illegal instruction when we \ - tried to call it, automatically retrying again.", - ); - continue; - } - - #[cfg(unix)] - fn is_illegal_instruction(status: &ExitStatus) -> bool { - use std::os::unix::prelude::*; - status.signal() == Some(libc::SIGILL) - } - - #[cfg(not(unix))] - fn is_illegal_instruction(_status: &ExitStatus) -> bool { - false - } + break; } match prog { diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index d59b6df44ed5d..06e41e64fdc7d 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -88,26 +88,31 @@ impl<'tcx> PlaceTy<'tcx> { /// /// Note that the resulting type has not been normalized. #[instrument(level = "debug", skip(tcx), ret)] - pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: FieldIdx) -> Ty<'tcx> { - if let Some(variant_index) = self.variant_index { - match *self.ty.kind() { + pub fn field_ty( + tcx: TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + variant_idx: Option, + f: FieldIdx, + ) -> Ty<'tcx> { + if let Some(variant_index) = variant_idx { + match *self_ty.kind() { ty::Adt(adt_def, args) if adt_def.is_enum() => { adt_def.variant(variant_index).fields[f].ty(tcx, args) } ty::Coroutine(def_id, args) => { let mut variants = args.as_coroutine().state_tys(def_id, tcx); let Some(mut variant) = variants.nth(variant_index.into()) else { - bug!("variant {variant_index:?} of coroutine out of range: {self:?}"); + bug!("variant {variant_index:?} of coroutine out of range: {self_ty:?}"); }; - variant - .nth(f.index()) - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")) + variant.nth(f.index()).unwrap_or_else(|| { + bug!("field {f:?} out of range of variant: {self_ty:?} {variant_idx:?}") + }) } - _ => bug!("can't downcast non-adt non-coroutine type: {self:?}"), + _ => bug!("can't downcast non-adt non-coroutine type: {self_ty:?}"), } } else { - match self.ty.kind() { + match self_ty.kind() { ty::Adt(adt_def, args) if !adt_def.is_enum() => { adt_def.non_enum_variant().fields[f].ty(tcx, args) } @@ -116,26 +121,25 @@ impl<'tcx> PlaceTy<'tcx> { .upvar_tys() .get(f.index()) .copied() - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), + .unwrap_or_else(|| bug!("field {f:?} out of range: {self_ty:?}")), ty::CoroutineClosure(_, args) => args .as_coroutine_closure() .upvar_tys() .get(f.index()) .copied() - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), + .unwrap_or_else(|| bug!("field {f:?} out of range: {self_ty:?}")), // Only prefix fields (upvars and current state) are // accessible without a variant index. - ty::Coroutine(_, args) => args - .as_coroutine() - .prefix_tys() - .get(f.index()) - .copied() - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), + ty::Coroutine(_, args) => { + args.as_coroutine().prefix_tys().get(f.index()).copied().unwrap_or_else(|| { + bug!("field {f:?} out of range of prefixes for {self_ty}") + }) + } ty::Tuple(tys) => tys .get(f.index()) .copied() - .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")), - _ => bug!("can't project out of {self:?}"), + .unwrap_or_else(|| bug!("field {f:?} out of range: {self_ty:?}")), + _ => bug!("can't project out of {self_ty:?}"), } } } @@ -148,11 +152,11 @@ impl<'tcx> PlaceTy<'tcx> { elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem)) } - /// Convenience wrapper around `projection_ty_core` for - /// `PlaceElem`, where we can just use the `Ty` that is already - /// stored inline on field projection elems. + /// Convenience wrapper around `projection_ty_core` for `PlaceElem`, + /// where we can just use the `Ty` that is already stored inline on + /// field projection elems. pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { - self.projection_ty_core(tcx, &elem, |_, _, ty| ty, |_, ty| ty) + self.projection_ty_core(tcx, &elem, |ty| ty, |_, _, _, ty| ty, |ty| ty) } /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` @@ -164,8 +168,9 @@ impl<'tcx> PlaceTy<'tcx> { self, tcx: TyCtxt<'tcx>, elem: &ProjectionElem, - mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>, - mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>, + mut structurally_normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>, + mut handle_field: impl FnMut(Ty<'tcx>, Option, FieldIdx, T) -> Ty<'tcx>, + mut handle_opaque_cast_and_subtype: impl FnMut(T) -> Ty<'tcx>, ) -> PlaceTy<'tcx> where V: ::std::fmt::Debug, @@ -176,16 +181,16 @@ impl<'tcx> PlaceTy<'tcx> { } let answer = match *elem { ProjectionElem::Deref => { - let ty = self.ty.builtin_deref(true).unwrap_or_else(|| { + let ty = structurally_normalize(self.ty).builtin_deref(true).unwrap_or_else(|| { bug!("deref projection of non-dereferenceable ty {:?}", self) }); PlaceTy::from_ty(ty) } ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { - PlaceTy::from_ty(self.ty.builtin_index().unwrap()) + PlaceTy::from_ty(structurally_normalize(self.ty).builtin_index().unwrap()) } ProjectionElem::Subslice { from, to, from_end } => { - PlaceTy::from_ty(match self.ty.kind() { + PlaceTy::from_ty(match structurally_normalize(self.ty).kind() { ty::Slice(..) => self.ty, ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from), ty::Array(inner, size) if from_end => { @@ -201,17 +206,18 @@ impl<'tcx> PlaceTy<'tcx> { ProjectionElem::Downcast(_name, index) => { PlaceTy { ty: self.ty, variant_index: Some(index) } } - ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), - ProjectionElem::OpaqueCast(ty) => { - PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) - } - ProjectionElem::Subtype(ty) => { - PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) - } + ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field( + structurally_normalize(self.ty), + self.variant_index, + f, + fty, + )), + ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)), + ProjectionElem::Subtype(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)), // FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general. ProjectionElem::UnwrapUnsafeBinder(ty) => { - PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) + PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)) } }; debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 494ee33fd8b9f..9825b947fe09a 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -323,9 +323,9 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> { let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place", @call(mir_field, args) => { - let (parent, ty) = self.parse_place_inner(args[0])?; + let (parent, place_ty) = self.parse_place_inner(args[0])?; let field = FieldIdx::from_u32(self.parse_integer_literal(args[1])? as u32); - let field_ty = ty.field_ty(self.tcx, field); + let field_ty = PlaceTy::field_ty(self.tcx, place_ty.ty, place_ty.variant_index, field); let proj = PlaceElem::Field(field, field_ty); let place = parent.project_deeper(&[proj], self.tcx); return Ok((place, PlaceTy::from_ty(field_ty))); diff --git a/compiler/rustc_target/src/spec/base/cygwin.rs b/compiler/rustc_target/src/spec/base/cygwin.rs index 819d1d68a71d9..d6ae0a905bf60 100644 --- a/compiler/rustc_target/src/spec/base/cygwin.rs +++ b/compiler/rustc_target/src/spec/base/cygwin.rs @@ -1,7 +1,8 @@ use std::borrow::Cow; use crate::spec::{ - BinaryFormat, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, cvs, + BinaryFormat, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, TlsModel, + cvs, }; pub(crate) fn opts() -> TargetOptions { @@ -44,6 +45,8 @@ pub(crate) fn opts() -> TargetOptions { eh_frame_header: false, debuginfo_kind: DebuginfoKind::Dwarf, supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), + tls_model: TlsModel::Emulated, + has_thread_local: true, ..Default::default() } } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 3b8c3655b8d1c..d4b5a80921508 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1832,7 +1832,9 @@ impl Config { .join(exe("rustc", config.build)) }; - config.initial_sysroot = config.initial_rustc.ancestors().nth(2).unwrap().into(); + config.initial_sysroot = t!(PathBuf::from_str( + output(Command::new(&config.initial_rustc).args(["--print", "sysroot"])).trim() + )); config.initial_cargo_clippy = cargo_clippy; diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index f9a4639663021..dc6a0e1ebad86 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -72,7 +72,6 @@ envs: env-x86_64-apple-tests: &env-x86_64-apple-tests SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is tested on our minimum supported macOS version. MACOSX_DEPLOYMENT_TARGET: 10.12 MACOSX_STD_DEPLOYMENT_TARGET: 10.12 @@ -402,7 +401,6 @@ auto: env: SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin --set rust.codegen-units=1 - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is built to support our minimum support macOS version. MACOSX_DEPLOYMENT_TARGET: 10.12 MACOSX_STD_DEPLOYMENT_TARGET: 10.12 @@ -420,7 +418,6 @@ auto: # Mac Catalyst cannot currently compile the sanitizer: # https://github.com/rust-lang/rust/issues/129069 RUST_CONFIGURE_ARGS: --enable-sanitizers --enable-profiler --set rust.jemalloc --set target.aarch64-apple-ios-macabi.sanitizers=false --set target.x86_64-apple-ios-macabi.sanitizers=false - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is built to support our minimum support macOS version. # FIXME(madsmtm): This might be redundant, as we're not building host tooling here (?) MACOSX_DEPLOYMENT_TARGET: 10.12 @@ -453,7 +450,6 @@ auto: --set llvm.ninja=false --set rust.lto=thin --set rust.codegen-units=1 - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 SELECT_XCODE: /Applications/Xcode_15.4.app USE_XCODE_CLANG: 1 # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else @@ -476,7 +472,6 @@ auto: --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 SELECT_XCODE: /Applications/Xcode_15.4.app USE_XCODE_CLANG: 1 # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f25cf60681297..55a116a018a8a 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -409,12 +409,12 @@ pub(crate) fn merge_attrs( } else { Attributes::from_hir(&both) }, - extract_cfg_from_attrs(both.iter(), cx.tcx, None, &cx.cache.hidden_cfg), + extract_cfg_from_attrs(both.iter(), cx.tcx, &cx.cache.hidden_cfg), ) } else { ( Attributes::from_hir(old_attrs), - extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, None, &cx.cache.hidden_cfg), + extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg), ) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b7a95384e3f92..0fbffc7808de0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -210,7 +210,6 @@ fn generate_item_with_correct_attrs( Cow::Owned(attr) => attr, }), cx.tcx, - def_id.as_local().map(|did| cx.tcx.local_def_id_to_hir_id(did)), &cx.cache.hidden_cfg, ); let attrs = Attributes::from_hir_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 0f92aab5abe5d..e85f1446be0fd 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -12,9 +12,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{BodyId, HirId, Mutability}; +use rustc_hir::{BodyId, Mutability}; use rustc_index::IndexVec; -use rustc_lint_defs::{BuiltinLintDiag, Lint}; use rustc_metadata::rendered_const; use rustc_middle::span_bug; use rustc_middle::ty::fast_reject::SimplifiedType; @@ -478,12 +477,7 @@ impl Item { name, kind, Attributes::from_hir(hir_attrs), - extract_cfg_from_attrs( - hir_attrs.iter(), - cx.tcx, - def_id.as_local().map(|did| cx.tcx.local_def_id_to_hir_id(did)), - &cx.cache.hidden_cfg, - ), + extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg), ) } @@ -1039,7 +1033,6 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator>( pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator + Clone>( attrs: I, tcx: TyCtxt<'_>, - hir_id: Option, hidden_cfg: &FxHashSet, ) -> Option> { let doc_cfg_active = tcx.features().doc_cfg(); @@ -1064,42 +1057,10 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator if doc_cfg.peek().is_some() && doc_cfg_active { let sess = tcx.sess; - struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, Option); - - impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> { - fn emit_span_lint( - &self, - sess: &Session, - lint: &'static Lint, - sp: rustc_span::Span, - builtin_diag: BuiltinLintDiag, - ) { - if let Some(hir_id) = self.1 { - self.0.node_span_lint(lint, hir_id, sp, |diag| { - rustc_lint::decorate_builtin_lint( - sess, - Some(self.0), - builtin_diag, - diag, - ) - }); - } else { - // No HIR id. Probably in another crate. Don't lint. - } - } - } - doc_cfg.fold(Cfg::True, |mut cfg, item| { if let Some(cfg_mi) = item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess)) { - // The result is unused here but we can gate unstable predicates - rustc_attr_parsing::cfg_matches( - cfg_mi, - tcx.sess, - RustdocCfgMatchesLintEmitter(tcx, hir_id), - Some(tcx.features()), - ); match Cfg::parse(cfg_mi) { Ok(new_cfg) => cfg &= new_cfg, Err(e) => { diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index a58ab3dd0fc94..f9d2aa3d3b4bd 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -116,12 +116,9 @@ impl HirCollector<'_> { nested: F, ) { let ast_attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); - if let Some(ref cfg) = extract_cfg_from_attrs( - ast_attrs.iter(), - self.tcx, - Some(self.tcx.local_def_id_to_hir_id(def_id)), - &FxHashSet::default(), - ) && !cfg.matches(&self.tcx.sess.psess) + if let Some(ref cfg) = + extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default()) + && !cfg.matches(&self.tcx.sess.psess) { return; } diff --git a/src/librustdoc/passes/check_doc_cfg.rs b/src/librustdoc/passes/check_doc_cfg.rs new file mode 100644 index 0000000000000..3284da77a0222 --- /dev/null +++ b/src/librustdoc/passes/check_doc_cfg.rs @@ -0,0 +1,76 @@ +use rustc_hir::HirId; +use rustc_hir::def_id::LocalDefId; +use rustc_middle::ty::TyCtxt; +use rustc_span::sym; + +use super::Pass; +use crate::clean::{Attributes, Crate, Item}; +use crate::core::DocContext; +use crate::visit::DocVisitor; + +pub(crate) const CHECK_DOC_CFG: Pass = Pass { + name: "check-doc-cfg", + run: Some(check_doc_cfg), + description: "checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs", +}; + +pub(crate) fn check_doc_cfg(krate: Crate, cx: &mut DocContext<'_>) -> Crate { + let mut checker = DocCfgChecker { cx }; + checker.visit_crate(&krate); + krate +} + +struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId); + +impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> { + fn emit_span_lint( + &self, + sess: &rustc_session::Session, + lint: &'static rustc_lint::Lint, + sp: rustc_span::Span, + builtin_diag: rustc_lint_defs::BuiltinLintDiag, + ) { + self.0.node_span_lint(lint, self.1, sp, |diag| { + rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag) + }); + } +} + +struct DocCfgChecker<'a, 'tcx> { + cx: &'a mut DocContext<'tcx>, +} + +impl DocCfgChecker<'_, '_> { + fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) { + let doc_cfgs = attrs + .other_attrs + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) + .filter(|attr| attr.has_name(sym::cfg)); + + for doc_cfg in doc_cfgs { + if let Some([cfg_mi]) = doc_cfg.meta_item_list() { + let _ = rustc_attr_parsing::cfg_matches( + cfg_mi, + &self.cx.tcx.sess, + RustdocCfgMatchesLintEmitter( + self.cx.tcx, + self.cx.tcx.local_def_id_to_hir_id(did), + ), + Some(self.cx.tcx.features()), + ); + } + } + } +} + +impl DocVisitor<'_> for DocCfgChecker<'_, '_> { + fn visit_item(&mut self, item: &'_ Item) { + if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) { + self.check_attrs(&item.attrs, local_did); + } + + self.visit_item_recur(item); + } +} diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 9ba63d34144ae..475d05b7d0e76 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -32,6 +32,9 @@ pub(crate) use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS; mod check_doc_test_visibility; pub(crate) use self::check_doc_test_visibility::CHECK_DOC_TEST_VISIBILITY; +mod check_doc_cfg; +pub(crate) use self::check_doc_cfg::CHECK_DOC_CFG; + mod collect_trait_impls; pub(crate) use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; @@ -72,6 +75,7 @@ pub(crate) enum Condition { /// The full list of passes. pub(crate) const PASSES: &[Pass] = &[ + CHECK_DOC_CFG, CHECK_DOC_TEST_VISIBILITY, STRIP_ALIASED_NON_LOCAL, STRIP_HIDDEN, @@ -89,6 +93,7 @@ pub(crate) const PASSES: &[Pass] = &[ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[ ConditionalPass::always(COLLECT_TRAIT_IMPLS), ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY), + ConditionalPass::always(CHECK_DOC_CFG), ConditionalPass::always(STRIP_ALIASED_NON_LOCAL), ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), diff --git a/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr b/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr index 7e6f8dec5ed06..0878f7edbf480 100644 --- a/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr +++ b/tests/rustdoc-ui/doc-cfg-check-cfg.cfg_empty.stderr @@ -1,12 +1,30 @@ warning: unexpected `cfg` condition name: `foo` - --> $DIR/doc-cfg-check-cfg.rs:13:11 + --> $DIR/doc-cfg-check-cfg.rs:12:12 + | +LL | #![doc(cfg(foo))] + | ^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(foo)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name: `foo` + --> $DIR/doc-cfg-check-cfg.rs:19:11 + | +LL | #[doc(cfg(foo))] + | ^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(foo)` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition name: `foo` + --> $DIR/doc-cfg-check-cfg.rs:15:11 | LL | #[doc(cfg(foo))] | ^^^ | = help: to expect this configuration use `--check-cfg=cfg(foo)` = note: see for more information about checking conditional configuration - = note: `#[warn(unexpected_cfgs)]` on by default -warning: 1 warning emitted +warning: 3 warnings emitted diff --git a/tests/rustdoc-ui/doc-cfg-check-cfg.rs b/tests/rustdoc-ui/doc-cfg-check-cfg.rs index 6bb520b0726d0..7d37077a32ddc 100644 --- a/tests/rustdoc-ui/doc-cfg-check-cfg.rs +++ b/tests/rustdoc-ui/doc-cfg-check-cfg.rs @@ -9,11 +9,15 @@ //@[cfg_foo] compile-flags: --check-cfg cfg(foo) #![feature(doc_cfg)] +#![doc(cfg(foo))] +//[cfg_empty]~^ WARN unexpected `cfg` condition name: `foo` #[doc(cfg(foo))] //[cfg_empty]~^ WARN unexpected `cfg` condition name: `foo` pub fn foo() {} +#[doc(cfg(foo))] +//[cfg_empty]~^ WARN unexpected `cfg` condition name: `foo` pub mod module { #[allow(unexpected_cfgs)] #[doc(cfg(bar))] diff --git a/tests/rustdoc-ui/doc-cfg.stderr b/tests/rustdoc-ui/doc-cfg.stderr index 48c8e79ce9625..1233ee010de21 100644 --- a/tests/rustdoc-ui/doc-cfg.stderr +++ b/tests/rustdoc-ui/doc-cfg.stderr @@ -10,6 +10,18 @@ error: multiple `cfg` predicates are specified LL | #[doc(cfg(), cfg(foo, bar))] | ^^^ +error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:9:7 + | +LL | #[doc(cfg())] + | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` + +error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:10:16 + | +LL | #[doc(cfg(foo, bar))] + | ^^^ + warning: unexpected `cfg` condition name: `foo` --> $DIR/doc-cfg.rs:6:11 | @@ -30,17 +42,5 @@ LL | #[doc(cfg(foo), cfg(bar))] = help: to expect this configuration use `--check-cfg=cfg(bar)` = note: see for more information about checking conditional configuration -error: `cfg` predicate is not specified - --> $DIR/doc-cfg.rs:9:7 - | -LL | #[doc(cfg())] - | ^^^^^ help: expected syntax is: `cfg(/* predicate */)` - -error: multiple `cfg` predicates are specified - --> $DIR/doc-cfg.rs:10:16 - | -LL | #[doc(cfg(foo, bar))] - | ^^^ - error: aborting due to 4 previous errors; 2 warnings emitted diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout index 790e58b0df9f9..30aadfe89f424 100644 --- a/tests/rustdoc-ui/issues/issue-91713.stdout +++ b/tests/rustdoc-ui/issues/issue-91713.stdout @@ -1,4 +1,5 @@ Available passes for running rustdoc: + check-doc-cfg - checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs check_doc_test_visibility - run various visibility-related lints on doctests strip-aliased-non-local - strips all non-local private aliased items from the output strip-hidden - strips all `#[doc(hidden)]` items from the output @@ -14,6 +15,7 @@ calculate-doc-coverage - counts the number of items with and without documentati Default passes for rustdoc: collect-trait-impls check_doc_test_visibility + check-doc-cfg strip-aliased-non-local strip-hidden (when not --document-hidden-items) strip-private (when not --document-private-items) diff --git a/tests/ui/nll/user-annotations/normalizing-user-annotation.rs b/tests/ui/nll/user-annotations/normalizing-user-annotation.rs new file mode 100644 index 0000000000000..fa8b3bfd577d5 --- /dev/null +++ b/tests/ui/nll/user-annotations/normalizing-user-annotation.rs @@ -0,0 +1,31 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for . + +// See description in there; this has to do with fundamental limitations +// to the old trait solver surrounding higher-ranked aliases with infer +// vars. This always worked in the new trait solver, but I added a revision +// just for good measure. + +trait Foo<'a> { + type Assoc; +} + +impl Foo<'_> for i32 { + type Assoc = u32; +} + +impl Foo<'_> for u32 { + type Assoc = u32; +} + +fn foo<'b: 'b, T: for<'a> Foo<'a>, F: for<'a> Fn(>::Assoc)>(_: F) -> (T, F) { + todo!() +} + +fn main() { + let (x, c): (i32, _) = foo::<'static, _, _>(|_| {}); +} diff --git a/tests/ui/traits/next-solver/normalize/normalize-place-elem.rs b/tests/ui/traits/next-solver/normalize/normalize-place-elem.rs new file mode 100644 index 0000000000000..9a600875bb9af --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/normalize-place-elem.rs @@ -0,0 +1,32 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +// Regression test for . +// Ensure that we normalize after applying projection elems in MIR typeck. + +use std::marker::PhantomData; + +#[derive(Copy, Clone)] +struct Span; + +trait AstKind { + type Inner; +} + +struct WithSpan; +impl AstKind for WithSpan { + type Inner + = (i32,); +} + +struct Expr<'a> { f: &'a ::Inner } + +impl Expr<'_> { + fn span(self) { + match self { + Self { f: (n,) } => {}, + } + } +} + +fn main() {}