diff options
79 files changed, 1209 insertions, 178 deletions
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 60aa12b0511..6160450d766 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -452,6 +452,7 @@ E0766: include_str!("./error_codes/E0766.md"), E0767: include_str!("./error_codes/E0767.md"), E0768: include_str!("./error_codes/E0768.md"), E0769: include_str!("./error_codes/E0769.md"), +E0770: include_str!("./error_codes/E0770.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/src/librustc_error_codes/error_codes/E0671.md b/src/librustc_error_codes/error_codes/E0671.md index 449fb8ffc89..a993ce826a7 100644 --- a/src/librustc_error_codes/error_codes/E0671.md +++ b/src/librustc_error_codes/error_codes/E0671.md @@ -3,7 +3,7 @@ Const parameters cannot depend on type parameters. The following is therefore invalid: -```compile_fail,E0741 +```compile_fail,E0770 #![feature(const_generics)] fn const_id<T, const N: T>() -> T { // error diff --git a/src/librustc_error_codes/error_codes/E0705.md b/src/librustc_error_codes/error_codes/E0705.md index 8fa09fe8e72..1edd47de4cb 100644 --- a/src/librustc_error_codes/error_codes/E0705.md +++ b/src/librustc_error_codes/error_codes/E0705.md @@ -1,5 +1,5 @@ -A `#![feature]` attribute was declared for a feature that is stable in -the current edition, but not in all editions. +A `#![feature]` attribute was declared for a feature that is stable in the +current edition, but not in all editions. Erroneous code example: diff --git a/src/librustc_error_codes/error_codes/E0710.md b/src/librustc_error_codes/error_codes/E0710.md index d9cefe2a6da..b7037ea611b 100644 --- a/src/librustc_error_codes/error_codes/E0710.md +++ b/src/librustc_error_codes/error_codes/E0710.md @@ -1,4 +1,4 @@ -An unknown tool name found in scoped lint +An unknown tool name was found in a scoped lint. Erroneous code examples: diff --git a/src/librustc_error_codes/error_codes/E0770.md b/src/librustc_error_codes/error_codes/E0770.md new file mode 100644 index 00000000000..278bf9b907b --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0770.md @@ -0,0 +1,15 @@ +The type of a const parameter references other generic parameters. + +Erroneous code example: + +```compile_fail,E0770 +#![feature(const_generics)] +fn foo<T, const N: T>() {} // error! +``` + +To fix this error, use a concrete type for the const parameter: + +``` +#![feature(const_generics)] +fn foo<T, const N: usize>() {} +``` diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 07b489a7562..9204f778a24 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2687,7 +2687,7 @@ pub enum Node<'hir> { Crate(&'hir CrateItem<'hir>), } -impl Node<'_> { +impl<'hir> Node<'hir> { pub fn ident(&self) -> Option<Ident> { match self { Node::TraitItem(TraitItem { ident, .. }) @@ -2698,7 +2698,7 @@ impl Node<'_> { } } - pub fn fn_decl(&self) -> Option<&FnDecl<'_>> { + pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> { match self { Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) @@ -2722,7 +2722,7 @@ impl Node<'_> { } } - pub fn generics(&self) -> Option<&Generics<'_>> { + pub fn generics(&self) -> Option<&'hir Generics<'hir>> { match self { Node::TraitItem(TraitItem { generics, .. }) | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index af4397075bb..f1b9fafc781 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -354,13 +354,7 @@ fn configure_and_expand_inner<'a>( ) }); - // If we're actually rustdoc then there's no need to actually compile - // anything, so switch everything to just looping - let mut should_loop = sess.opts.actually_rustdoc; if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty { - should_loop |= true; - } - if should_loop { log::debug!("replacing bodies with loop {{}}"); util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate); } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index fbe3377d875..237a5a64f8b 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -484,7 +484,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { lint: &'static lint::Lint, source_info: SourceInfo, message: &'static str, - panic: AssertKind<ConstInt>, + panic: AssertKind<impl std::fmt::Debug>, ) -> Option<()> { let lint_root = self.lint_root(source_info)?; self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| { @@ -1004,11 +1004,27 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected)); let value_const = self.ecx.read_scalar(value).unwrap(); if expected != value_const { + enum DbgVal<T> { + Val(T), + Underscore, + } + impl<T: std::fmt::Debug> std::fmt::Debug for DbgVal<T> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Val(val) => val.fmt(fmt), + Self::Underscore => fmt.write_str("_"), + } + } + } let mut eval_to_int = |op| { - let op = self - .eval_operand(op, source_info) - .expect("if we got here, it must be const"); - self.ecx.read_immediate(op).unwrap().to_const_int() + // This can be `None` if the lhs wasn't const propagated and we just + // triggered the assert on the value of the rhs. + match self.eval_operand(op, source_info) { + Some(op) => { + DbgVal::Val(self.ecx.read_immediate(op).unwrap().to_const_int()) + } + None => DbgVal::Underscore, + } }; let msg = match msg { AssertKind::DivisionByZero(op) => { diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs index 46aa5a4dcdf..3e63a63d9d0 100644 --- a/src/librustc_passes/check_attr.rs +++ b/src/librustc_passes/check_attr.rs @@ -70,6 +70,8 @@ impl CheckAttrVisitor<'tcx> { self.check_target_feature(attr, span, target) } else if attr.check_name(sym::track_caller) { self.check_track_caller(&attr.span, attrs, span, target) + } else if attr.check_name(sym::doc) { + self.check_doc_alias(attr) } else { true }; @@ -216,6 +218,34 @@ impl CheckAttrVisitor<'tcx> { } } + fn check_doc_alias(&self, attr: &Attribute) -> bool { + if let Some(mi) = attr.meta() { + if let Some(list) = mi.meta_item_list() { + for meta in list { + if meta.check_name(sym::alias) { + if !meta.is_value_str() + || meta + .value_str() + .map(|s| s.to_string()) + .unwrap_or_else(String::new) + .is_empty() + { + self.tcx + .sess + .struct_span_err( + meta.span(), + "doc alias attribute expects a string: #[doc(alias = \"0\")]", + ) + .emit(); + return false; + } + } + } + } + } + true + } + /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr( &self, diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 4f25b948eb6..575049c6bac 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -442,6 +442,19 @@ impl<'a> Resolver<'a> { ); err } + ResolutionError::ParamInTyOfConstArg(name) => { + let mut err = struct_span_err!( + self.session, + span, + E0770, + "the type of const parameters must not depend on other generic parameters" + ); + err.span_label( + span, + format!("the type must not depend on the parameter `{}`", name), + ); + err + } ResolutionError::SelfInTyParamDefault => { let mut err = struct_span_err!( self.session, diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index c165a601408..ed88e549692 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -123,6 +123,10 @@ crate enum RibKind<'a> { /// from the default of a type parameter because they're not declared /// before said type parameter. Also see the `visit_generics` override. ForwardTyParamBanRibKind, + + /// We are inside of the type of a const parameter. Can't refer to any + /// parameters. + ConstParamTyRibKind, } impl RibKind<'_> { @@ -135,7 +139,8 @@ impl RibKind<'_> { | FnItemRibKind | ConstantItemRibKind | ModuleRibKind(_) - | MacroDefinition(_) => false, + | MacroDefinition(_) + | ConstParamTyRibKind => false, AssocItemRibKind | ItemRibKind(_) | ForwardTyParamBanRibKind => true, } } @@ -394,13 +399,23 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// Fields used to add information to diagnostic errors. diagnostic_metadata: DiagnosticMetadata<'ast>, + + /// State used to know whether to ignore resolution errors for function bodies. + /// + /// In particular, rustdoc uses this to avoid giving errors for `cfg()` items. + /// In most cases this will be `None`, in which case errors will always be reported. + /// If it is `Some(_)`, then it will be updated when entering a nested function or trait body. + in_func_body: bool, } /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { fn visit_item(&mut self, item: &'ast Item) { let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item)); + // Always report errors in items we just entered. + let old_ignore = replace(&mut self.in_func_body, false); self.resolve_item(item); + self.in_func_body = old_ignore; self.diagnostic_metadata.current_item = prev; } fn visit_arm(&mut self, arm: &'ast Arm) { @@ -497,6 +512,9 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { visit::walk_fn_ret_ty(this, &declaration.output); + // Ignore errors in function bodies if this is rustdoc + // Be sure not to set this until the function signature has been resolved. + let previous_state = replace(&mut this.in_func_body, true); // Resolve the function body, potentially inside the body of an async closure match fn_kind { FnKind::Fn(.., body) => walk_list!(this, visit_block, body), @@ -504,6 +522,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { }; debug!("(resolving function) leaving function"); + this.in_func_body = previous_state; }) }); self.diagnostic_metadata.current_function = previous_value; @@ -562,7 +581,11 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { for bound in ¶m.bounds { self.visit_param_bound(bound); } + self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind)); + self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind)); self.visit_ty(ty); + self.ribs[TypeNS].pop().unwrap(); + self.ribs[ValueNS].pop().unwrap(); } } } @@ -644,6 +667,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { label_ribs: Vec::new(), current_trait_ref: None, diagnostic_metadata: DiagnosticMetadata::default(), + // errors at module scope should always be reported + in_func_body: false, } } @@ -757,7 +782,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { return if self.is_label_valid_from_rib(i) { Some(*id) } else { - self.r.report_error( + self.report_error( original_span, ResolutionError::UnreachableLabel { name: label.name, @@ -775,7 +800,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label)); } - self.r.report_error( + self.report_error( original_span, ResolutionError::UndeclaredLabel { name: label.name, suggestion }, ); @@ -798,7 +823,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { | ItemRibKind(..) | ConstantItemRibKind | ModuleRibKind(..) - | ForwardTyParamBanRibKind => { + | ForwardTyParamBanRibKind + | ConstParamTyRibKind => { return false; } } @@ -833,7 +859,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }; let report_error = |this: &Self, ns| { let what = if ns == TypeNS { "type parameters" } else { "local variables" }; - this.r.session.span_err(ident.span, &format!("imports cannot refer to {}", what)); + if this.should_report_errs() { + this.r + .session + .span_err(ident.span, &format!("imports cannot refer to {}", what)); + } }; for &ns in nss { @@ -1008,7 +1038,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if seen_bindings.contains_key(&ident) { let span = seen_bindings.get(&ident).unwrap(); let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, *span); - self.r.report_error(param.ident.span, err); + self.report_error(param.ident.span, err); } seen_bindings.entry(ident).or_insert(param.ident.span); @@ -1274,7 +1304,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .is_err() { let path = &self.current_trait_ref.as_ref().unwrap().1.path; - self.r.report_error(span, err(ident.name, &path_names_to_string(path))); + self.report_error(span, err(ident.name, &path_names_to_string(path))); } } } @@ -1289,6 +1319,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } fn resolve_local(&mut self, local: &'ast Local) { + debug!("resolving local ({:?})", local); // Resolve the type. walk_list!(self, visit_ty, &local.ty); @@ -1390,7 +1421,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if inconsistent_vars.contains_key(name) { v.could_be_path = false; } - self.r.report_error( + self.report_error( *v.origin.iter().next().unwrap(), ResolutionError::VariableNotBoundInPattern(v), ); @@ -1400,7 +1431,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>(); inconsistent_vars.sort(); for (name, v) in inconsistent_vars { - self.r.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1)); + self.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1)); } // 5) Finally bubble up all the binding maps. @@ -1550,7 +1581,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // `Variant(a, a)`: _ => IdentifierBoundMoreThanOnceInSamePattern, }; - self.r.report_error(ident.span, error(ident.name)); + self.report_error(ident.span, error(ident.name)); } // Record as bound if it's valid: @@ -1624,7 +1655,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // to something unusable as a pattern (e.g., constructor function), // but we still conservatively report an error, see // issues/33118#issuecomment-233962221 for one reason why. - self.r.report_error( + self.report_error( ident.span, ResolutionError::BindingShadowsSomethingUnacceptable( pat_src.descr(), @@ -1677,18 +1708,27 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { source: PathSource<'ast>, crate_lint: CrateLint, ) -> PartialRes { + log::debug!("smart_resolve_path_fragment(id={:?},qself={:?},path={:?}", id, qself, path); let ns = source.namespace(); let is_expected = &|res| source.is_expected(res); let report_errors = |this: &mut Self, res: Option<Res>| { - let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); - - let def_id = this.parent_scope.module.normal_ancestor_id; - let instead = res.is_some(); - let suggestion = - if res.is_none() { this.report_missing_type_error(path) } else { None }; - - this.r.use_injections.push(UseError { err, candidates, def_id, instead, suggestion }); + if this.should_report_errs() { + let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); + + let def_id = this.parent_scope.module.normal_ancestor_id; + let instead = res.is_some(); + let suggestion = + if res.is_none() { this.report_missing_type_error(path) } else { None }; + + this.r.use_injections.push(UseError { + err, + candidates, + def_id, + instead, + suggestion, + }); + } PartialRes::new(Res::Err) }; @@ -1746,13 +1786,17 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let def_id = this.parent_scope.module.normal_ancestor_id; - this.r.use_injections.push(UseError { - err, - candidates, - def_id, - instead: false, - suggestion: None, - }); + if this.should_report_errs() { + this.r.use_injections.push(UseError { + err, + candidates, + def_id, + instead: false, + suggestion: None, + }); + } else { + err.cancel(); + } // We don't return `Some(parent_err)` here, because the error will // be already printed as part of the `use` injections @@ -1809,7 +1853,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { Err(err) => { if let Some(err) = report_errors_for_call(self, err) { - self.r.report_error(err.span, err.node); + self.report_error(err.span, err.node); } PartialRes::new(Res::Err) @@ -1843,6 +1887,21 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } } + /// A wrapper around [`Resolver::report_error`]. + /// + /// This doesn't emit errors for function bodies if this is rustdoc. + fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) { + if self.should_report_errs() { + self.r.report_error(span, resolution_error); + } + } + + #[inline] + /// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items. + fn should_report_errs(&self) -> bool { + !(self.r.session.opts.actually_rustdoc && self.in_func_body) + } + // Resolve in alternative namespaces if resolution in the primary namespace fails. fn resolve_qpath_anywhere( &mut self, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a265c15c18b..c3686ca4899 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -214,6 +214,8 @@ enum ResolutionError<'a> { BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>), /// Error E0128: type parameters with a default cannot use forward-declared identifiers. ForwardDeclaredTyParam, // FIXME(const_generics:defaults) + /// ERROR E0770: the type of const parameters must not depend on other generic parameters. + ParamInTyOfConstArg(Symbol), /// Error E0735: type parameters with a default cannot use `Self` SelfInTyParamDefault, /// Error E0767: use of unreachable label @@ -2480,6 +2482,12 @@ impl<'a> Resolver<'a> { } return Res::Err; } + ConstParamTyRibKind => { + if record_used { + self.report_error(span, ParamInTyOfConstArg(rib_ident.name)); + } + return Res::Err; + } } } if let Some(res_err) = res_err { @@ -2503,6 +2511,15 @@ impl<'a> Resolver<'a> { // This was an attempt to use a type parameter outside its scope. ItemRibKind(has_generic_params) => has_generic_params, FnItemRibKind => HasGenericParams::Yes, + ConstParamTyRibKind => { + if record_used { + self.report_error( + span, + ResolutionError::ParamInTyOfConstArg(rib_ident.name), + ); + } + return Res::Err; + } }; if record_used { @@ -2527,9 +2544,24 @@ impl<'a> Resolver<'a> { } for rib in ribs { let has_generic_params = match rib.kind { + NormalRibKind + | ClosureOrAsyncRibKind + | AssocItemRibKind + | ModuleRibKind(..) + | MacroDefinition(..) + | ForwardTyParamBanRibKind + | ConstantItemRibKind => continue, ItemRibKind(has_generic_params) => has_generic_params, FnItemRibKind => HasGenericParams::Yes, - _ => continue, + ConstParamTyRibKind => { + if record_used { + self.report_error( + span, + ResolutionError::ParamInTyOfConstArg(rib_ident.name), + ); + } + return Res::Err; + } }; // This was an attempt to use a const parameter outside its scope. diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b8e26fc4871..f6ebf8b56bd 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -937,6 +937,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // legal to implement. let mut candidates = all_traits(self.tcx) .into_iter() + // Don't issue suggestions for unstable traits since they're + // unlikely to be implementable anyway + .filter(|info| match self.tcx.lookup_stability(info.def_id) { + Some(attr) => attr.level.is_stable(), + None => true, + }) .filter(|info| { // We approximate the coherence rules to only suggest // traits that are legal to implement by requiring that diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4354996614b..17212187e6a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -29,7 +29,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::weak_lang_items; -use rustc_hir::{GenericParamKind, Node}; +use rustc_hir::{GenericParamKind, HirId, Node}; use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::hir::map::Map; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -1155,6 +1155,35 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S } } +struct AnonConstInParamListDetector { + in_param_list: bool, + found_anon_const_in_list: bool, + ct: HirId, +} + +impl<'v> Visitor<'v> for AnonConstInParamListDetector { + type Map = intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None + } + + fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { + let prev = self.in_param_list; + self.in_param_list = true; + intravisit::walk_generic_param(self, p); + self.in_param_list = prev; + } + + fn visit_anon_const(&mut self, c: &'v hir::AnonConst) { + if self.in_param_list && self.ct == c.hir_id { + self.found_anon_const_in_list = true; + } else { + intravisit::walk_anon_const(self, c) + } + } +} + fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { use rustc_hir::*; @@ -1176,10 +1205,32 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { let parent_id = tcx.hir().get_parent_item(hir_id); let parent_def_id = tcx.hir().local_def_id(parent_id); - // HACK(eddyb) this provides the correct generics when - // `feature(const_generics)` is enabled, so that const expressions - // used with const generics, e.g. `Foo<{N+1}>`, can work at all. - if tcx.lazy_normalization() { + let mut in_param_list = false; + for (_parent, node) in tcx.hir().parent_iter(hir_id) { + if let Some(generics) = node.generics() { + let mut visitor = AnonConstInParamListDetector { + in_param_list: false, + found_anon_const_in_list: false, + ct: hir_id, + }; + + visitor.visit_generics(generics); + in_param_list = visitor.found_anon_const_in_list; + break; + } + } + + if in_param_list { + // We do not allow generic parameters in anon consts if we are inside + // of a param list. + // + // This affects both default type bindings, e.g. `struct<T, U = [u8; std::mem::size_of::<T>()]>(T, U)`, + // and the types of const parameters, e.g. `struct V<const N: usize, const M: [u8; N]>();`. + None + } else if tcx.lazy_normalization() { + // HACK(eddyb) this provides the correct generics when + // `feature(const_generics)` is enabled, so that const expressions + // used with const generics, e.g. `Foo<{N+1}>`, can work at all. Some(parent_def_id.to_def_id()) } else { let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs index 4e5ef4329c2..1be32729b1e 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/src/librustc_typeck/expr_use_visitor.rs @@ -11,8 +11,10 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::PatKind; +use rustc_index::vec::Idx; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, adjustment, TyCtxt}; +use rustc_target::abi::VariantIdx; use crate::mem_categorization as mc; use rustc_span::Span; @@ -396,6 +398,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { &*with_expr, with_place.clone(), with_field.ty(self.tcx(), substs), + mc::ProjectionKind::Field(f_index as u32, VariantIdx::new(0)), ); self.delegate_consume(&field_place); } diff --git a/src/librustc_typeck/mem_categorization.rs b/src/librustc_typeck/mem_categorization.rs index ac42ce80689..70fe2c2cda5 100644 --- a/src/librustc_typeck/mem_categorization.rs +++ b/src/librustc_typeck/mem_categorization.rs @@ -54,11 +54,14 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::LocalDefId; +use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::PatKind; +use rustc_index::vec::Idx; use rustc_infer::infer::InferCtxt; use rustc_span::Span; +use rustc_target::abi::VariantIdx; use rustc_trait_selection::infer::InferCtxtExt; #[derive(Clone, Debug)] @@ -77,8 +80,20 @@ pub enum PlaceBase { pub enum ProjectionKind { /// A dereference of a pointer, reference or `Box<T>` of the given type Deref, - /// An index or a field - Other, + + /// `B.F` where `B` is the base expression and `F` is + /// the field. The field is identified by which variant + /// it appears in along with a field index. The variant + /// is used for enums. + Field(u32, VariantIdx), + + /// Some index like `B[x]`, where `B` is the base + /// expression. We don't preserve the index `x` because + /// we won't need it. + Index, + + /// A subslice covering a range of values like `B[x..y]`. + Subslice, } #[derive(Clone, Debug)] @@ -406,7 +421,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { hir::ExprKind::Field(ref base, _) => { let base = self.cat_expr(&base)?; debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base); - Ok(self.cat_projection(expr, base, expr_ty)) + + let field_idx = self + .tables + .field_indices() + .get(expr.hir_id) + .cloned() + .expect("Field index not found"); + + Ok(self.cat_projection( + expr, + base, + expr_ty, + ProjectionKind::Field(field_idx as u32, VariantIdx::new(0)), + )) } hir::ExprKind::Index(ref base, _) => { @@ -419,7 +447,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.cat_overloaded_place(expr, base) } else { let base = self.cat_expr(&base)?; - Ok(self.cat_projection(expr, base, expr_ty)) + Ok(self.cat_projection(expr, base, expr_ty, ProjectionKind::Index)) } } @@ -533,9 +561,10 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { node: &N, base_place: PlaceWithHirId<'tcx>, ty: Ty<'tcx>, + kind: ProjectionKind, ) -> PlaceWithHirId<'tcx> { let mut projections = base_place.place.projections; - projections.push(Projection { kind: ProjectionKind::Other, ty: ty }); + projections.push(Projection { kind: kind, ty: ty }); let ret = PlaceWithHirId::new( node.hir_id(), base_place.place.base_ty, @@ -609,6 +638,75 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.cat_pattern_(place, pat, &mut op) } + /// Returns the variant index for an ADT used within a Struct or TupleStruct pattern + /// Here `pat_hir_id` is the HirId of the pattern itself. + fn variant_index_for_adt( + &self, + qpath: &hir::QPath<'_>, + pat_hir_id: hir::HirId, + span: Span, + ) -> McResult<VariantIdx> { + let res = self.tables.qpath_res(qpath, pat_hir_id); + let ty = self.tables.node_type(pat_hir_id); + let adt_def = match ty.kind { + ty::Adt(adt_def, _) => adt_def, + _ => { + self.tcx() + .sess + .delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT"); + return Err(()); + } + }; + + match res { + Res::Def(DefKind::Variant, variant_id) => Ok(adt_def.variant_index_with_id(variant_id)), + Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => { + Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id)) + } + Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _) + | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) + | Res::SelfCtor(..) + | Res::SelfTy(..) => { + // Structs and Unions have only have one variant. + Ok(VariantIdx::new(0)) + } + _ => bug!("expected ADT path, found={:?}", res), + } + } + + /// Returns the total number of fields in an ADT variant used within a pattern. + /// Here `pat_hir_id` is the HirId of the pattern itself. + fn total_fields_in_adt_variant( + &self, + pat_hir_id: hir::HirId, + variant_index: VariantIdx, + span: Span, + ) -> McResult<usize> { + let ty = self.tables.node_type(pat_hir_id); + match ty.kind { + ty::Adt(adt_def, _) => Ok(adt_def.variants[variant_index].fields.len()), + _ => { + self.tcx() + .sess + .delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT"); + return Err(()); + } + } + } + + /// Returns the total number of fields in a tuple used within a Tuple pattern. + /// Here `pat_hir_id` is the HirId of the pattern itself. + fn total_fields_in_tuple(&self, pat_hir_id: hir::HirId, span: Span) -> McResult<usize> { + let ty = self.tables.node_type(pat_hir_id); + match ty.kind { + ty::Tuple(substs) => Ok(substs.len()), + _ => { + self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple"); + return Err(()); + } + } + } + // FIXME(#19596) This is a workaround, but there should be a better way to do this fn cat_pattern_<F>( &self, @@ -679,20 +777,54 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { op(&place_with_id, pat); match pat.kind { - PatKind::TupleStruct(_, ref subpats, _) | PatKind::Tuple(ref subpats, _) => { - // S(p1, ..., pN) or (p1, ..., pN) - for subpat in subpats.iter() { + PatKind::Tuple(ref subpats, dots_pos) => { + // (p1, ..., pN) + let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?; + + for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) { let subpat_ty = self.pat_ty_adjusted(&subpat)?; - let sub_place = self.cat_projection(pat, place_with_id.clone(), subpat_ty); + let projection_kind = ProjectionKind::Field(i as u32, VariantIdx::new(0)); + let sub_place = + self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind); self.cat_pattern_(sub_place, &subpat, op)?; } } - PatKind::Struct(_, field_pats, _) => { + PatKind::TupleStruct(ref qpath, ref subpats, dots_pos) => { + // S(p1, ..., pN) + let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?; + let total_fields = + self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?; + + for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) { + let subpat_ty = self.pat_ty_adjusted(&subpat)?; + let projection_kind = ProjectionKind::Field(i as u32, variant_index); + let sub_place = + self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind); + self.cat_pattern_(sub_place, &subpat, op)?; + } + } + + PatKind::Struct(ref qpath, field_pats, _) => { // S { f1: p1, ..., fN: pN } + + let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?; + for fp in field_pats { let field_ty = self.pat_ty_adjusted(&fp.pat)?; - let field_place = self.cat_projection(pat, place_with_id.clone(), field_ty); + let field_index = self + .tables + .field_indices() + .get(fp.hir_id) + .cloned() + .expect("no index for a field"); + + let field_place = self.cat_projection( + pat, + place_with_id.clone(), + field_ty, + ProjectionKind::Field(field_index as u32, variant_index), + ); self.cat_pattern_(field_place, &fp.pat, op)?; } } @@ -723,13 +855,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { return Err(()); } }; - let elt_place = self.cat_projection(pat, place_with_id.clone(), element_ty); + let elt_place = self.cat_projection( + pat, + place_with_id.clone(), + element_ty, + ProjectionKind::Index, + ); for before_pat in before { self.cat_pattern_(elt_place.clone(), &before_pat, op)?; } if let Some(ref slice_pat) = *slice { let slice_pat_ty = self.pat_ty_adjusted(&slice_pat)?; - let slice_place = self.cat_projection(pat, place_with_id, slice_pat_ty); + let slice_place = self.cat_projection( + pat, + place_with_id, + slice_pat_ty, + ProjectionKind::Subslice, + ); self.cat_pattern_(slice_place, &slice_pat, op)?; } for after_pat in after { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 1387389981d..491daa80e5c 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -341,6 +341,16 @@ pub fn build_impl( return; } } + + // Skip foreign unstable traits from lists of trait implementations and + // such. This helps prevent dependencies of the standard library, for + // example, from getting documented as "traits `u32` implements" which + // isn't really too helpful. + if let Some(stab) = cx.tcx.lookup_stability(did) { + if stab.level.is_unstable() { + return; + } + } } let for_ = if let Some(did) = did.as_local() { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5f6d9ecc047..6a03722cd08 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -486,33 +486,6 @@ impl Attributes { }) } - /// Enforce the format of attributes inside `#[doc(...)]`. - pub fn check_doc_attributes( - diagnostic: &::rustc_errors::Handler, - mi: &ast::MetaItem, - ) -> Option<(String, String)> { - mi.meta_item_list().and_then(|list| { - for meta in list { - if meta.check_name(sym::alias) { - if !meta.is_value_str() - || meta - .value_str() - .map(|s| s.to_string()) - .unwrap_or_else(String::new) - .is_empty() - { - diagnostic.span_err( - meta.span(), - "doc alias attribute expects a string: #[doc(alias = \"0\")]", - ); - } - } - } - - None - }) - } - pub fn has_doc_flag(&self, flag: Symbol) -> bool { for attr in &self.other_attrs { if !attr.check_name(sym::doc) { @@ -556,7 +529,6 @@ impl Attributes { } else { if attr.check_name(sym::doc) { if let Some(mi) = attr.meta() { - Attributes::check_doc_attributes(&diagnostic, &mi); if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { // Extracted #[doc(cfg(...))] match Cfg::parse(cfg_mi) { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index a222920c7d2..00315675faf 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -5,10 +5,15 @@ use rustc_driver::abort_on_err; use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::json::JsonEmitter; use rustc_feature::UnstableFeatures; -use rustc_hir::def::Namespace::TypeNS; +use rustc_hir::def::{Namespace::TypeNS, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::HirId; +use rustc_hir::{ + intravisit::{self, NestedVisitorMap, Visitor}, + Path, +}; use rustc_interface::interface; +use rustc_middle::hir::map::Map; use rustc_middle::middle::cstore::CrateStore; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{Ty, TyCtxt}; @@ -372,7 +377,35 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt crate_name, lint_caps, register_lints: None, - override_queries: None, + override_queries: Some(|_sess, providers, _external_providers| { + // Most lints will require typechecking, so just don't run them. + providers.lint_mod = |_, _| {}; + // Prevent `rustc_typeck::check_crate` from calling `typeck_tables_of` on all bodies. + providers.typeck_item_bodies = |_, _| {}; + // hack so that `used_trait_imports` won't try to call typeck_tables_of + providers.used_trait_imports = |_, _| { + lazy_static! { + static ref EMPTY_SET: FxHashSet<LocalDefId> = FxHashSet::default(); + } + &EMPTY_SET + }; + // In case typeck does end up being called, don't ICE in case there were name resolution errors + providers.typeck_tables_of = move |tcx, def_id| { + // Closures' tables come from their outermost function, + // as they are part of the same "inference environment". + // This avoids emitting errors for the parent twice (see similar code in `typeck_tables_of_with_fallback`) + let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local(); + if outer_def_id != def_id { + return tcx.typeck_tables_of(outer_def_id); + } + + let hir = tcx.hir(); + let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id))); + debug!("visiting body for {:?}", def_id); + EmitIgnoredResolutionErrors::new(tcx).visit_body(body); + (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck_tables_of)(tcx, def_id) + }; + }), registry: rustc_driver::diagnostics_registry(), }; @@ -416,10 +449,17 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take(); global_ctxt.enter(|tcx| { - tcx.analysis(LOCAL_CRATE).ok(); - - // Abort if there were any errors so far - sess.abort_if_errors(); + // Certain queries assume that some checks were run elsewhere + // (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425), + // so type-check everything other than function bodies in this crate before running lints. + // NOTE: this does not call `tcx.analysis()` so that we won't + // typeck function bodies or run the default rustc lints. + // (see `override_queries` in the `config`) + let _ = rustc_typeck::check_crate(tcx); + tcx.sess.abort_if_errors(); + sess.time("missing_docs", || { + rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new); + }); let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); // Convert from a HirId set to a DefId set since we don't always have easy access @@ -570,6 +610,62 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }) } +/// Due to https://github.com/rust-lang/rust/pull/73566, +/// the name resolution pass may find errors that are never emitted. +/// If typeck is called after this happens, then we'll get an ICE: +/// 'Res::Error found but not reported'. To avoid this, emit the errors now. +struct EmitIgnoredResolutionErrors<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> EmitIgnoredResolutionErrors<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> Self { + Self { tcx } + } +} + +impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + // We need to recurse into nested closures, + // since those will fallback to the parent for type checking. + NestedVisitorMap::OnlyBodies(self.tcx.hir()) + } + + fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) { + debug!("visiting path {:?}", path); + if path.res == Res::Err { + // We have less context here than in rustc_resolve, + // so we can only emit the name and span. + // However we can give a hint that rustc_resolve will have more info. + let label = format!( + "could not resolve path `{}`", + path.segments + .iter() + .map(|segment| segment.ident.as_str().to_string()) + .collect::<Vec<_>>() + .join("::") + ); + let mut err = rustc_errors::struct_span_err!( + self.tcx.sess, + path.span, + E0433, + "failed to resolve: {}", + label + ); + err.span_label(path.span, label); + err.note("this error was originally ignored because you are running `rustdoc`"); + err.note("try running again with `rustc` or `cargo check` and you may get a more detailed error"); + err.emit(); + } + // We could have an outer resolution that succeeded, + // but with generic parameters that failed. + // Recurse into the segments so we catch those too. + intravisit::walk_path(self, path); + } +} + /// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter /// for `impl Trait` in argument position. #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 8b5a3a2ba61..c8121d39d0f 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -37,14 +37,14 @@ impl ExternalHtml { let bc = format!( "{}{}", bc, - Markdown(&m_bc, &[], id_map, codes, edition, playground).to_string() + Markdown(&m_bc, &[], id_map, codes, edition, playground).into_string() ); let ac = load_external_files(after_content, diag)?; let m_ac = load_external_files(md_after_content, diag)?; let ac = format!( "{}{}", ac, - Markdown(&m_ac, &[], id_map, codes, edition, playground).to_string() + Markdown(&m_ac, &[], id_map, codes, edition, playground).into_string() ); Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac }) } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index c4bc73770a7..d4302d0cb54 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -12,15 +12,17 @@ use std::io; use std::io::prelude::*; use rustc_ast::token::{self, Token}; +use rustc_data_structures::sync::Lrc; use rustc_parse::lexer; use rustc_session::parse::ParseSess; +use rustc_span::hygiene::SyntaxContext; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym}; -use rustc_span::{FileName, Span}; +use rustc_span::{BytePos, FileName, SourceFile, Span}; /// Highlights `src`, returning the HTML output. pub fn render_with_highlighting( - src: &str, + src: String, class: Option<&str>, playground_button: Option<&str>, tooltip: Option<(&str, &str)>, @@ -38,12 +40,13 @@ pub fn render_with_highlighting( } let sess = ParseSess::with_silent_emitter(); - let sf = sess + let source_file = sess .source_map() - .new_source_file(FileName::Custom(String::from("rustdoc-highlighting")), src.to_owned()); + .new_source_file(FileName::Custom(String::from("rustdoc-highlighting")), src); + + let classifier_source_file = Lrc::clone(&source_file); let highlight_result = rustc_driver::catch_fatal_errors(|| { - let lexer = lexer::StringReader::new(&sess, sf, None); - let mut classifier = Classifier::new(lexer, sess.source_map()); + let mut classifier = Classifier::new(&sess, classifier_source_file); let mut highlighted_source = vec![]; if classifier.write_source(&mut highlighted_source).is_err() { @@ -61,9 +64,17 @@ pub fn render_with_highlighting( write_footer(&mut out, playground_button).unwrap(); } Err(()) => { + // Get the source back out of the source map to avoid a copy in the happy path. + let span = + Span::new(BytePos(0), BytePos(source_file.byte_length()), SyntaxContext::root()); + let src = sess + .source_map() + .span_to_snippet(span) + .expect("could not retrieve snippet from artificial source file"); + // If errors are encountered while trying to highlight, just emit // the unhighlighted source. - write!(out, "<pre><code>{}</code></pre>", Escape(src)).unwrap(); + write!(out, "<pre><code>{}</code></pre>", Escape(&src)).unwrap(); } } @@ -73,10 +84,10 @@ pub fn render_with_highlighting( /// Processes a program (nested in the internal `lexer`), classifying strings of /// text by highlighting category (`Class`). Calls out to a `Writer` to write /// each span of text in sequence. -struct Classifier<'a> { - lexer: lexer::StringReader<'a>, +struct Classifier<'sess> { + lexer: lexer::StringReader<'sess>, peek_token: Option<Token>, - source_map: &'a SourceMap, + source_map: &'sess SourceMap, // State of the classifier. in_attribute: bool, @@ -154,6 +165,7 @@ impl<U: Write> Writer for U { } } +#[derive(Debug)] enum HighlightError { LexError, IoError(io::Error), @@ -165,12 +177,14 @@ impl From<io::Error> for HighlightError { } } -impl<'a> Classifier<'a> { - fn new(lexer: lexer::StringReader<'a>, source_map: &'a SourceMap) -> Classifier<'a> { +impl<'sess> Classifier<'sess> { + fn new(sess: &ParseSess, source_file: Lrc<SourceFile>) -> Classifier<'_> { + let lexer = lexer::StringReader::new(sess, source_file, None); + Classifier { lexer, peek_token: None, - source_map, + source_map: sess.source_map(), in_attribute: false, in_macro: false, in_macro_nonterminal: false, @@ -209,11 +223,17 @@ impl<'a> Classifier<'a> { /// source. fn write_source<W: Writer>(&mut self, out: &mut W) -> Result<(), HighlightError> { loop { - let next = self.try_next_token()?; + let mut next = self.try_next_token()?; if next == token::Eof { break; } + // Glue any tokens that need to be glued. + if let Some(joint) = next.glue(self.peek()?) { + next = joint; + let _ = self.try_next_token()?; + } + self.write_token(out, next)?; } @@ -429,3 +449,6 @@ fn write_header(class: Option<&str>, out: &mut dyn Write) -> io::Result<()> { fn write_footer(out: &mut dyn Write, playground_button: Option<&str>) -> io::Result<()> { write!(out, "</pre>{}</div>\n", if let Some(button) = playground_button { button } else { "" }) } + +#[cfg(test)] +mod tests; diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs new file mode 100644 index 00000000000..01b25fd6be4 --- /dev/null +++ b/src/librustdoc/html/highlight/tests.rs @@ -0,0 +1,82 @@ +use rustc_ast::attr::with_session_globals; +use rustc_session::parse::ParseSess; +use rustc_span::edition::Edition; +use rustc_span::FileName; + +use super::Classifier; + +fn highlight(src: &str) -> String { + let mut out = vec![]; + + with_session_globals(Edition::Edition2018, || { + let sess = ParseSess::with_silent_emitter(); + let source_file = sess.source_map().new_source_file( + FileName::Custom(String::from("rustdoc-highlighting")), + src.to_owned(), + ); + + let mut classifier = Classifier::new(&sess, source_file); + classifier.write_source(&mut out).unwrap(); + }); + + String::from_utf8(out).unwrap() +} + +#[test] +fn function() { + assert_eq!( + highlight("fn main() {}"), + r#"<span class="kw">fn</span> <span class="ident">main</span>() {}"#, + ); +} + +#[test] +fn statement() { + assert_eq!( + highlight("let foo = true;"), + concat!( + r#"<span class="kw">let</span> <span class="ident">foo</span> "#, + r#"<span class="op">=</span> <span class="bool-val">true</span>;"#, + ), + ); +} + +#[test] +fn inner_attr() { + assert_eq!( + highlight(r##"#![crate_type = "lib"]"##), + concat!( + r##"<span class="attribute">#![<span class="ident">crate_type</span> "##, + r##"<span class="op">=</span> <span class="string">"lib"</span>]</span>"##, + ), + ); +} + +#[test] +fn outer_attr() { + assert_eq!( + highlight(r##"#[cfg(target_os = "linux")]"##), + concat!( + r##"<span class="attribute">#[<span class="ident">cfg</span>("##, + r##"<span class="ident">target_os</span> <span class="op">=</span> "##, + r##"<span class="string">"linux"</span>)]</span>"##, + ), + ); +} + +#[test] +fn mac() { + assert_eq!( + highlight("mac!(foo bar)"), + concat!( + r#"<span class="macro">mac</span><span class="macro">!</span>("#, + r#"<span class="ident">foo</span> <span class="ident">bar</span>)"#, + ), + ); +} + +// Regression test for #72684 +#[test] +fn andand() { + assert_eq!(highlight("&&"), r#"<span class="op">&&</span>"#); +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a0f8eb04e2e..4cfd81ffbce 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -13,7 +13,7 @@ //! let s = "My *markdown* _text_"; //! let mut id_map = IdMap::new(); //! let md = Markdown(s, &[], &mut id_map, ErrorCodes::Yes, Edition::Edition2015, &None); -//! let html = md.to_string(); +//! let html = md.into_string(); //! // ... something using html //! ``` @@ -292,7 +292,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { if let Some((s1, s2)) = tooltip { s.push_str(&highlight::render_with_highlighting( - &text, + text, Some(&format!( "rust-example-rendered{}", if ignore != Ignore::None { @@ -313,7 +313,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { Some(Event::Html(s.into())) } else { s.push_str(&highlight::render_with_highlighting( - &text, + text, Some(&format!( "rust-example-rendered{}", if ignore != Ignore::None { @@ -848,7 +848,7 @@ impl LangString { } impl Markdown<'_> { - pub fn to_string(self) -> String { + pub fn into_string(self) -> String { let Markdown(md, links, mut ids, codes, edition, playground) = self; // This is actually common enough to special-case @@ -878,7 +878,7 @@ impl Markdown<'_> { } impl MarkdownWithToc<'_> { - pub fn to_string(self) -> String { + pub fn into_string(self) -> String { let MarkdownWithToc(md, mut ids, codes, edition, playground) = self; let p = Parser::new_ext(md, opts()); @@ -899,7 +899,7 @@ impl MarkdownWithToc<'_> { } impl MarkdownHtml<'_> { - pub fn to_string(self) -> String { + pub fn into_string(self) -> String { let MarkdownHtml(md, mut ids, codes, edition, playground) = self; // This is actually common enough to special-case @@ -926,7 +926,7 @@ impl MarkdownHtml<'_> { } impl MarkdownSummaryLine<'_> { - pub fn to_string(self) -> String { + pub fn into_string(self) -> String { let MarkdownSummaryLine(md, links) = self; // This is actually common enough to special-case if md.is_empty() { diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index bf0451a1d9d..783977d285d 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -134,7 +134,7 @@ fn test_header() { fn t(input: &str, expect: &str) { let mut map = IdMap::new(); let output = - Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string(); + Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string(); assert_eq!(output, expect, "original: {}", input); } @@ -166,7 +166,8 @@ fn test_header() { fn test_header_ids_multiple_blocks() { let mut map = IdMap::new(); fn t(map: &mut IdMap, input: &str, expect: &str) { - let output = Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string(); + let output = + Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string(); assert_eq!(output, expect, "original: {}", input); } @@ -228,7 +229,7 @@ fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { let mut idmap = IdMap::new(); let output = - MarkdownHtml(input, &mut idmap, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string(); + MarkdownHtml(input, &mut idmap, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string(); assert_eq!(output, expect, "original: {}", input); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 3f49420492e..31e35125dac 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1895,7 +1895,7 @@ fn render_markdown( cx.shared.edition, &cx.shared.playground ) - .to_string() + .into_string() ) } @@ -2185,7 +2185,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: </tr>", name = *myitem.name.as_ref().unwrap(), stab_tags = stability_tags(myitem), - docs = MarkdownSummaryLine(doc_value, &myitem.links()).to_string(), + docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(), class = myitem.type_(), add = add, stab = stab.unwrap_or_else(String::new), @@ -2278,7 +2278,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> { cx.shared.edition, &cx.shared.playground, ); - message.push_str(&format!(": {}", html.to_string())); + message.push_str(&format!(": {}", html.into_string())); } stability.push(format!( "<div class='stab deprecated'><span class='emoji'>👎</span> {}</div>", @@ -2332,7 +2332,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> { cx.shared.edition, &cx.shared.playground, ) - .to_string() + .into_string() ); } @@ -3690,7 +3690,7 @@ fn render_impl( cx.shared.edition, &cx.shared.playground ) - .to_string() + .into_string() ); } } @@ -4585,7 +4585,12 @@ fn sidebar_foreign_type(buf: &mut Buffer, it: &clean::Item) { fn item_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Macro) { wrap_into_docblock(w, |w| { - w.write_str(&highlight::render_with_highlighting(&t.source, Some("macro"), None, None)) + w.write_str(&highlight::render_with_highlighting( + t.source.clone(), + Some("macro"), + None, + None, + )) }); document(w, cx, it) } diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 03f79b93186..e3215921f12 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -75,7 +75,7 @@ impl<'a> SourceCollector<'a> { return Ok(()); } - let contents = match fs::read_to_string(&p) { + let mut contents = match fs::read_to_string(&p) { Ok(contents) => contents, Err(e) => { return Err(Error::new(e, &p)); @@ -83,8 +83,9 @@ impl<'a> SourceCollector<'a> { }; // Remove the utf-8 BOM if any - let contents = - if contents.starts_with("\u{feff}") { &contents[3..] } else { &contents[..] }; + if contents.starts_with("\u{feff}") { + contents.drain(..3); + } // Create the intermediate directories let mut cur = self.dst.clone(); @@ -122,7 +123,7 @@ impl<'a> SourceCollector<'a> { &self.scx.layout, &page, "", - |buf: &mut _| print_src(buf, &contents), + |buf: &mut _| print_src(buf, contents), &self.scx.style_files, ); self.scx.fs.write(&cur, v.as_bytes())?; @@ -160,7 +161,7 @@ where /// Wrapper struct to render the source code of a file. This will do things like /// adding line numbers to the left-hand side. -fn print_src(buf: &mut Buffer, s: &str) { +fn print_src(buf: &mut Buffer, s: String) { let lines = s.lines().count(); let mut cols = 0; let mut tmp = lines; diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js index cfbfe6675f5..6805f2a266f 100644 --- a/src/librustdoc/html/static/source-script.js +++ b/src/librustdoc/html/static/source-script.js @@ -140,4 +140,9 @@ function createSourceSidebar() { }); main.insertBefore(sidebar, main.firstChild); + // Focus on the current file in the source files sidebar. + var selected_elem = sidebar.getElementsByClassName("selected")[0]; + if (typeof selected_elem !== "undefined") { + selected_elem.focus(); + } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 57151e2b200..cbf53d52ef0 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -15,6 +15,8 @@ #![recursion_limit = "256"] extern crate env_logger; +#[macro_use] +extern crate lazy_static; extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; @@ -94,6 +96,7 @@ pub fn main() { 32_000_000 // 32MB on other platforms }; rustc_driver::set_sigpipe_handler(); + rustc_driver::install_ice_hook(); env_logger::init_from_env("RUSTDOC_LOG"); let res = std::thread::Builder::new() .stack_size(thread_stack_size) diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index e0753bcd70f..89d184e35cb 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -68,9 +68,9 @@ pub fn render<P: AsRef<Path>>( let mut ids = IdMap::new(); let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); let text = if !options.markdown_no_toc { - MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).to_string() + MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string() } else { - Markdown(text, &[], &mut ids, error_codes, edition, &playground).to_string() + Markdown(text, &[], &mut ids, error_codes, edition, &playground).into_string() }; let err = write!( diff --git a/src/test/codegen/issue-44056-macos-tls-align.rs b/src/test/codegen/issue-44056-macos-tls-align.rs index eee59be629b..2270eca5014 100644 --- a/src/test/codegen/issue-44056-macos-tls-align.rs +++ b/src/test/codegen/issue-44056-macos-tls-align.rs @@ -6,12 +6,13 @@ #![crate_type = "rlib"] #![feature(thread_local)] -// CHECK: @STATIC_VAR_1 = thread_local local_unnamed_addr global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4 +// local_unnamed_addr does not appear when std is built with debug assertions. +// CHECK: @STATIC_VAR_1 = thread_local {{(local_unnamed_addr )?}}global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4 #[no_mangle] #[thread_local] static mut STATIC_VAR_1: [u32; 8] = [0; 8]; -// CHECK: @STATIC_VAR_2 = thread_local local_unnamed_addr global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4 +// CHECK: @STATIC_VAR_2 = thread_local {{(local_unnamed_addr )?}}global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4 #[no_mangle] #[thread_local] static mut STATIC_VAR_2: [u32; 8] = [4; 8]; diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index c23c57c8c59..59f29e756fc 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -3,6 +3,7 @@ // min-system-llvm-version: 9.0 // ignore-arm +// ignore-aarch64 // ignore-mips // ignore-mips64 // ignore-powerpc diff --git a/src/test/compile-fail/asm-src-loc-codegen-units.rs b/src/test/compile-fail/asm-src-loc-codegen-units.rs index c9415aed930..5b8690c3b98 100644 --- a/src/test/compile-fail/asm-src-loc-codegen-units.rs +++ b/src/test/compile-fail/asm-src-loc-codegen-units.rs @@ -1,5 +1,3 @@ -// WONTFIX(#20184) Needs landing pads (not present in stage1) or the compiler hangs. -// ignore-stage1 // compile-flags: -C codegen-units=2 // ignore-emscripten diff --git a/src/test/run-make-fulldeps/issue-37839/Makefile b/src/test/run-make-fulldeps/issue-37839/Makefile index c405d5c74d7..f17ce537fb8 100644 --- a/src/test/run-make-fulldeps/issue-37839/Makefile +++ b/src/test/run-make-fulldeps/issue-37839/Makefile @@ -1,7 +1,5 @@ -include ../tools.mk -# ignore-stage1 - all: $(RUSTC) a.rs && $(RUSTC) b.rs $(BARE_RUSTC) c.rs -L dependency=$(TMPDIR) --extern b=$(TMPDIR)/libb.rlib \ diff --git a/src/test/run-make-fulldeps/issue-37893/Makefile b/src/test/run-make-fulldeps/issue-37893/Makefile index df58d4f5d94..27b69baf977 100644 --- a/src/test/run-make-fulldeps/issue-37893/Makefile +++ b/src/test/run-make-fulldeps/issue-37893/Makefile @@ -1,6 +1,4 @@ -include ../tools.mk -# ignore-stage1 - all: $(RUSTC) a.rs && $(RUSTC) b.rs && $(RUSTC) c.rs diff --git a/src/test/run-make-fulldeps/rustdoc-determinism/Makefile b/src/test/run-make-fulldeps/rustdoc-determinism/Makefile new file mode 100644 index 00000000000..0534c2c3831 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-determinism/Makefile @@ -0,0 +1,16 @@ +-include ../tools.mk + +# Assert that the search index is generated deterministically, regardless of the +# order that crates are documented in. + +# ignore-windows +# Uses `diff`. + +all: + $(RUSTDOC) foo.rs -o $(TMPDIR)/foo_first + $(RUSTDOC) bar.rs -o $(TMPDIR)/foo_first + + $(RUSTDOC) bar.rs -o $(TMPDIR)/bar_first + $(RUSTDOC) foo.rs -o $(TMPDIR)/bar_first + + diff $(TMPDIR)/foo_first/search-index.js $(TMPDIR)/bar_first/search-index.js diff --git a/src/test/run-make-fulldeps/rustdoc-determinism/bar.rs b/src/test/run-make-fulldeps/rustdoc-determinism/bar.rs new file mode 100644 index 00000000000..ca05a6a9076 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-determinism/bar.rs @@ -0,0 +1 @@ +pub struct Bar; diff --git a/src/test/run-make-fulldeps/rustdoc-determinism/foo.rs b/src/test/run-make-fulldeps/rustdoc-determinism/foo.rs new file mode 100644 index 00000000000..4a835673a59 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-determinism/foo.rs @@ -0,0 +1 @@ +pub struct Foo; diff --git a/src/test/rustdoc-ui/error-in-impl-trait/README.md b/src/test/rustdoc-ui/error-in-impl-trait/README.md new file mode 100644 index 00000000000..1176a4a8c4c --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/README.md @@ -0,0 +1,7 @@ +Each of these needs to be in a separate file, +because the `delay_span_bug` ICE in rustdoc won't be triggerred +if even a single other error was emitted. + +However, conceptually they are all testing basically the same thing. +See https://github.com/rust-lang/rust/pull/73566#issuecomment-653689128 +for more details. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.rs b/src/test/rustdoc-ui/error-in-impl-trait/async.rs new file mode 100644 index 00000000000..112a2c494a5 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/async.rs @@ -0,0 +1,10 @@ +// edition:2018 + +/// This used to work with ResolveBodyWithLoop. +/// However now that we ignore type checking instead of modifying the function body, +/// the return type is seen as `impl Future<Output = u32>`, not a `u32`. +/// So it no longer allows errors in the function body. +pub async fn a() -> u32 { + error::_in::async_fn() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.stderr b/src/test/rustdoc-ui/error-in-impl-trait/async.stderr new file mode 100644 index 00000000000..086db1be722 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/async.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::async_fn` + --> $DIR/async.rs:8:5 + | +LL | error::_in::async_fn() + | ^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::async_fn` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs new file mode 100644 index 00000000000..df40c121d57 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs @@ -0,0 +1,5 @@ +// manually desugared version of an `async fn` (but with a closure instead of a generator) +pub fn a() -> impl Fn() -> u32 { + || content::doesnt::matter() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr new file mode 100644 index 00000000000..4ee9c4d1f43 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `content::doesnt::matter` + --> $DIR/closure.rs:3:8 + | +LL | || content::doesnt::matter() + | ^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `content::doesnt::matter` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs new file mode 100644 index 00000000000..0ccf2e3866f --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs @@ -0,0 +1,7 @@ +trait ValidTrait {} + +/// This has docs +pub fn f() -> impl ValidTrait { + Vec::<DoesNotExist>::new() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr new file mode 100644 index 00000000000..72716c258dc --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `DoesNotExist` + --> $DIR/generic-argument.rs:5:11 + | +LL | Vec::<DoesNotExist>::new() + | ^^^^^^^^^^^^ could not resolve path `DoesNotExist` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs new file mode 100644 index 00000000000..399fb827517 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs @@ -0,0 +1,6 @@ +pub trait ValidTrait {} +/// This returns impl trait +pub fn g() -> impl ValidTrait { + (|| error::_in::impl_trait::alias::nested::closure())() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr new file mode 100644 index 00000000000..55f9b609a11 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure` + --> $DIR/impl-keyword-closure.rs:4:9 + | +LL | (|| error::_in::impl_trait::alias::nested::closure())() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs new file mode 100644 index 00000000000..24b5734dbd0 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs @@ -0,0 +1,6 @@ +pub trait ValidTrait {} +/// This returns impl trait +pub fn g() -> impl ValidTrait { + error::_in::impl_trait() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr new file mode 100644 index 00000000000..3257079f942 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait` + --> $DIR/impl-keyword.rs:4:5 + | +LL | error::_in::impl_trait() + | ^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs new file mode 100644 index 00000000000..1498fa4f890 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs @@ -0,0 +1,10 @@ +#![feature(type_alias_impl_trait)] + +pub trait ValidTrait {} +type ImplTrait = impl ValidTrait; + +/// This returns impl trait, but using a type alias +pub fn h() -> ImplTrait { + (|| error::_in::impl_trait::alias::nested::closure())() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr new file mode 100644 index 00000000000..84b28139dbc --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure` + --> $DIR/trait-alias-closure.rs:8:9 + | +LL | (|| error::_in::impl_trait::alias::nested::closure())() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs new file mode 100644 index 00000000000..cf9bc48c7f8 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs @@ -0,0 +1,10 @@ +#![feature(type_alias_impl_trait)] + +pub trait ValidTrait {} +type ImplTrait = impl ValidTrait; + +/// This returns impl trait, but using a type alias +pub fn h() -> ImplTrait { + error::_in::impl_trait::alias() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr new file mode 100644 index 00000000000..9be6a3d8d6b --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias` + --> $DIR/trait-alias.rs:8:5 + | +LL | error::_in::impl_trait::alias() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/impl-fn-nesting.rs b/src/test/rustdoc-ui/impl-fn-nesting.rs new file mode 100644 index 00000000000..a927f6bd799 --- /dev/null +++ b/src/test/rustdoc-ui/impl-fn-nesting.rs @@ -0,0 +1,49 @@ +// Ensure that rustdoc gives errors for trait impls inside function bodies that don't resolve. +// See https://github.com/rust-lang/rust/pull/73566 +pub struct ValidType; +pub trait ValidTrait {} +pub trait NeedsBody { + type Item; + fn f(); +} + +/// This function has docs +pub fn f<B: UnknownBound>(a: UnknownType, b: B) { +//~^ ERROR cannot find trait `UnknownBound` in this scope +//~| ERROR cannot find type `UnknownType` in this scope + impl UnknownTrait for ValidType {} //~ ERROR cannot find trait `UnknownTrait` + impl<T: UnknownBound> UnknownTrait for T {} + //~^ ERROR cannot find trait `UnknownBound` in this scope + //~| ERROR cannot find trait `UnknownTrait` in this scope + impl ValidTrait for UnknownType {} + //~^ ERROR cannot find type `UnknownType` in this scope + impl ValidTrait for ValidType where ValidTrait: UnknownBound {} + //~^ ERROR cannot find trait `UnknownBound` in this scope + + /// This impl has documentation + impl NeedsBody for ValidType { + type Item = UnknownType; + //~^ ERROR cannot find type `UnknownType` in this scope + + /// This function has documentation + fn f() { + <UnknownTypeShouldBeIgnored>::a(); + content::shouldnt::matter(); + unknown_macro!(); + //~^ ERROR cannot find macro `unknown_macro` in this scope + + /// This is documentation for a macro + macro_rules! can_define_macros_here_too { + () => { + this::content::should::also::be::ignored() + } + } + can_define_macros_here_too!(); + + /// This also is documented. + pub fn doubly_nested(c: UnknownType) { + //~^ ERROR cannot find type `UnknownType` in this scope + } + } + } +} diff --git a/src/test/rustdoc-ui/impl-fn-nesting.stderr b/src/test/rustdoc-ui/impl-fn-nesting.stderr new file mode 100644 index 00000000000..608749af895 --- /dev/null +++ b/src/test/rustdoc-ui/impl-fn-nesting.stderr @@ -0,0 +1,66 @@ +error: cannot find macro `unknown_macro` in this scope + --> $DIR/impl-fn-nesting.rs:32:13 + | +LL | unknown_macro!(); + | ^^^^^^^^^^^^^ + +error[E0405]: cannot find trait `UnknownBound` in this scope + --> $DIR/impl-fn-nesting.rs:11:13 + | +LL | pub fn f<B: UnknownBound>(a: UnknownType, b: B) { + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `UnknownType` in this scope + --> $DIR/impl-fn-nesting.rs:11:30 + | +LL | pub fn f<B: UnknownBound>(a: UnknownType, b: B) { + | ^^^^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `UnknownTrait` in this scope + --> $DIR/impl-fn-nesting.rs:14:10 + | +LL | impl UnknownTrait for ValidType {} + | ^^^^^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `UnknownTrait` in this scope + --> $DIR/impl-fn-nesting.rs:15:27 + | +LL | impl<T: UnknownBound> UnknownTrait for T {} + | ^^^^^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `UnknownBound` in this scope + --> $DIR/impl-fn-nesting.rs:15:13 + | +LL | impl<T: UnknownBound> UnknownTrait for T {} + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `UnknownType` in this scope + --> $DIR/impl-fn-nesting.rs:18:25 + | +LL | impl ValidTrait for UnknownType {} + | ^^^^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `UnknownBound` in this scope + --> $DIR/impl-fn-nesting.rs:20:53 + | +LL | impl ValidTrait for ValidType where ValidTrait: UnknownBound {} + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `UnknownType` in this scope + --> $DIR/impl-fn-nesting.rs:25:21 + | +LL | type Item = UnknownType; + | ^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `UnknownType` in this scope + --> $DIR/impl-fn-nesting.rs:44:37 + | +LL | pub fn doubly_nested(c: UnknownType) { + | ^^^^^^^^^^^ not found in this scope + +error: Compilation failed, aborting rustdoc + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0405, E0412. +For more information about an error, try `rustc --explain E0405`. diff --git a/src/test/rustdoc-ui/infinite-recursive-type.rs b/src/test/rustdoc-ui/infinite-recursive-type.rs new file mode 100644 index 00000000000..32793fc4f76 --- /dev/null +++ b/src/test/rustdoc-ui/infinite-recursive-type.rs @@ -0,0 +1,4 @@ +enum E { +//~^ ERROR recursive type `E` has infinite size + V(E), +} diff --git a/src/test/rustdoc-ui/infinite-recursive-type.stderr b/src/test/rustdoc-ui/infinite-recursive-type.stderr new file mode 100644 index 00000000000..897445f200c --- /dev/null +++ b/src/test/rustdoc-ui/infinite-recursive-type.stderr @@ -0,0 +1,17 @@ +error[E0072]: recursive type `E` has infinite size + --> $DIR/infinite-recursive-type.rs:1:1 + | +LL | enum E { + | ^^^^^^ recursive type has infinite size +LL | +LL | V(E), + | - recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `E` representable + | +LL | V(Box<E>), + | ^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/rustdoc/impl-trait-alias.rs b/src/test/rustdoc/impl-trait-alias.rs new file mode 100644 index 00000000000..54c3f856ddb --- /dev/null +++ b/src/test/rustdoc/impl-trait-alias.rs @@ -0,0 +1,14 @@ +#![feature(type_alias_impl_trait)] + +trait MyTrait {} +impl MyTrait for i32 {} + +// @has impl_trait_alias/type.Foo.html 'Foo' +/// debug type +pub type Foo = impl MyTrait; + +// @has impl_trait_alias/fn.foo.html 'foo' +/// debug function +pub fn foo() -> Foo { + 1 +} diff --git a/src/test/rustdoc/macro-in-async-block.rs b/src/test/rustdoc/macro-in-async-block.rs new file mode 100644 index 00000000000..b4aaacf7b3d --- /dev/null +++ b/src/test/rustdoc/macro-in-async-block.rs @@ -0,0 +1,9 @@ +// Regression issue for rustdoc ICE encountered in PR #72088. +// edition:2018 +#![feature(decl_macro)] + +fn main() { + async { + macro m() {} + }; +} diff --git a/src/test/rustdoc/macro-in-closure.rs b/src/test/rustdoc/macro-in-closure.rs index 298ff601de8..b4411d927e2 100644 --- a/src/test/rustdoc/macro-in-closure.rs +++ b/src/test/rustdoc/macro-in-closure.rs @@ -6,4 +6,11 @@ fn main() { || { macro m() {} }; + + let _ = || { + macro n() {} + }; + + let cond = true; + let _ = || if cond { macro n() {} } else { panic!() }; } diff --git a/src/test/rustdoc/return-impl-trait.rs b/src/test/rustdoc/return-impl-trait.rs new file mode 100644 index 00000000000..1ccf5ac4611 --- /dev/null +++ b/src/test/rustdoc/return-impl-trait.rs @@ -0,0 +1,15 @@ +#![feature(type_alias_impl_trait)] + +pub trait Backend {} + +impl Backend for () {} + +pub struct Module<T>(T); + +pub type BackendImpl = impl Backend; + +// @has return_impl_trait/fn.make_module.html +/// Documentation +pub fn make_module() -> Module<BackendImpl> { + Module(()) +} diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/ui/check-doc-alias-attr.rs index 2f01099107d..b02cc1a4545 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.rs +++ b/src/test/ui/check-doc-alias-attr.rs @@ -1,3 +1,4 @@ +#![crate_type = "lib"] #![feature(doc_alias)] #[doc(alias = "foo")] // ok! diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/ui/check-doc-alias-attr.stderr index 480acc821aa..268230ab44a 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr +++ b/src/test/ui/check-doc-alias-attr.stderr @@ -1,17 +1,17 @@ error: doc alias attribute expects a string: #[doc(alias = "0")] - --> $DIR/check-doc-alias-attr.rs:6:7 + --> $DIR/check-doc-alias-attr.rs:7:7 | LL | #[doc(alias)] | ^^^^^ error: doc alias attribute expects a string: #[doc(alias = "0")] - --> $DIR/check-doc-alias-attr.rs:7:7 + --> $DIR/check-doc-alias-attr.rs:8:7 | LL | #[doc(alias = 0)] | ^^^^^^^^^ error: doc alias attribute expects a string: #[doc(alias = "0")] - --> $DIR/check-doc-alias-attr.rs:8:7 + --> $DIR/check-doc-alias-attr.rs:9:7 | LL | #[doc(alias("bar"))] | ^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs new file mode 100644 index 00000000000..5aa3617d1d7 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs @@ -0,0 +1,15 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +// Currently, const parameters cannot depend on other generic parameters, +// as our current implementation can't really support this. +// +// We may want to lift this restriction in the future. + +pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]); +//~^ ERROR: the type of const parameters must not depend on other generic parameters + +pub struct SelfDependent<const N: [u8; N]>; +//~^ ERROR: the type of const parameters must not depend on other generic parameters + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr new file mode 100644 index 00000000000..f6606aea726 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr @@ -0,0 +1,24 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/const-param-type-depends-on-const-param.rs:9:52 + | +LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]); + | ^ the type must not depend on the parameter `N` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/const-param-type-depends-on-const-param.rs:12:40 + | +LL | pub struct SelfDependent<const N: [u8; N]>; + | ^ the type must not depend on the parameter `N` + +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-param-type-depends-on-const-param.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs index 86ab8075896..db15ececfa4 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; struct B<T, const N: T>(PhantomData<[T; N]>); //~ ERROR const generics are unstable -//~^ ERROR `T` is not guaranteed to `#[derive(PartialEq, Eq)]` +//~^ ERROR the type of const parameters must not depend on other generic parameters fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr index 92a7edf96bc..35996e83361 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr @@ -1,3 +1,9 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22 + | +LL | struct B<T, const N: T>(PhantomData<[T; N]>); + | ^ the type must not depend on the parameter `T` + error[E0658]: const generics are unstable --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19 | @@ -7,15 +13,7 @@ LL | struct B<T, const N: T>(PhantomData<[T; N]>); = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information = help: add `#![feature(const_generics)]` to the crate attributes to enable -error[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter - --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22 - | -LL | struct B<T, const N: T>(PhantomData<[T; N]>); - | ^ `T` may not derive both `PartialEq` and `Eq` - | - = note: it is not currently possible to use a type parameter as the type of a const parameter - error: aborting due to 2 previous errors -Some errors have detailed explanations: E0658, E0741. +Some errors have detailed explanations: E0658, E0770. For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs index 654e36df37e..7fe04a43412 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs @@ -1,12 +1,13 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete -// Currently, const parameters cannot depend on type parameters, because there is no way to -// enforce the structural-match property on an arbitrary type parameter. This restriction -// may be relaxed in the future. See https://github.com/rust-lang/rfcs/pull/2000 for more -// details. +// Currently, const parameters cannot depend on other generic parameters, +// as our current implementation can't really support this. +// +// We may want to lift this restriction in the future. pub struct Dependent<T, const X: T>([(); X]); -//~^ ERROR `T` is not guaranteed to `#[derive(PartialEq, Eq)]` +//~^ ERROR: the type of const parameters must not depend on other generic parameters +//~| ERROR: parameter `T` is never used fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr index ed05264161e..d081dcbbc7a 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr @@ -1,3 +1,9 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/const-param-type-depends-on-type-param.rs:9:34 + | +LL | pub struct Dependent<T, const X: T>([(); X]); + | ^ the type must not depend on the parameter `T` + warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/const-param-type-depends-on-type-param.rs:1:12 | @@ -7,14 +13,15 @@ LL | #![feature(const_generics)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information -error[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter - --> $DIR/const-param-type-depends-on-type-param.rs:9:34 +error[E0392]: parameter `T` is never used + --> $DIR/const-param-type-depends-on-type-param.rs:9:22 | LL | pub struct Dependent<T, const X: T>([(); X]); - | ^ `T` may not derive both `PartialEq` and `Eq` + | ^ unused parameter | - = note: it is not currently possible to use a type parameter as the type of a const parameter + = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` -error: aborting due to previous error; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0741`. +Some errors have detailed explanations: E0392, E0770. +For more information about an error, try `rustc --explain E0392`. diff --git a/src/test/ui/const-generics/issues/issue-71169.rs b/src/test/ui/const-generics/issues/issue-71169.rs new file mode 100644 index 00000000000..943a16cfcd6 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71169.rs @@ -0,0 +1,10 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn foo<const LEN: usize, const DATA: [u8; LEN]>() {} +//~^ ERROR the type of const parameters must not +fn main() { + const DATA: [u8; 4] = *b"ABCD"; + foo::<4, DATA>(); + //~^ ERROR constant expression depends on +} diff --git a/src/test/ui/const-generics/issues/issue-71169.stderr b/src/test/ui/const-generics/issues/issue-71169.stderr new file mode 100644 index 00000000000..6d4cf4027c1 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71169.stderr @@ -0,0 +1,17 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71169.rs:4:43 + | +LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {} + | ^^^ the type must not depend on the parameter `LEN` + +error: constant expression depends on a generic parameter + --> $DIR/issue-71169.rs:8:14 + | +LL | foo::<4, DATA>(); + | ^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71381.rs b/src/test/ui/const-generics/issues/issue-71381.rs index c32bd2847f8..08f94823942 100644 --- a/src/test/ui/const-generics/issues/issue-71381.rs +++ b/src/test/ui/const-generics/issues/issue-71381.rs @@ -12,6 +12,7 @@ unsafe extern "C" fn pass(args: PassArg) { impl Test { pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) { //~^ ERROR: using function pointers as const generic parameters is forbidden + //~| ERROR: the type of const parameters must not depend on other generic parameters self.0 = Self::trampiline::<Args, IDX, FN> as _ } @@ -20,6 +21,7 @@ impl Test { const IDX: usize, const FN: unsafe extern "C" fn(Args), //~^ ERROR: using function pointers as const generic parameters is forbidden + //~| ERROR: the type of const parameters must not depend on other generic parameters >( args: Args, ) { diff --git a/src/test/ui/const-generics/issues/issue-71381.stderr b/src/test/ui/const-generics/issues/issue-71381.stderr index 6bb776fcfc0..fd4ebe3dead 100644 --- a/src/test/ui/const-generics/issues/issue-71381.stderr +++ b/src/test/ui/const-generics/issues/issue-71381.stderr @@ -1,3 +1,15 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71381.rs:13:82 + | +LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) { + | ^^^^ the type must not depend on the parameter `Args` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71381.rs:22:40 + | +LL | const FN: unsafe extern "C" fn(Args), + | ^^^^ the type must not depend on the parameter `Args` + error: using function pointers as const generic parameters is forbidden --> $DIR/issue-71381.rs:13:61 | @@ -5,10 +17,11 @@ LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern " | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-71381.rs:21:19 + --> $DIR/issue-71381.rs:22:19 | LL | const FN: unsafe extern "C" fn(Args), | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71611.rs b/src/test/ui/const-generics/issues/issue-71611.rs index 64a049e743f..06ff38dec66 100644 --- a/src/test/ui/const-generics/issues/issue-71611.rs +++ b/src/test/ui/const-generics/issues/issue-71611.rs @@ -3,6 +3,7 @@ fn func<A, const F: fn(inner: A)>(outer: A) { //~^ ERROR: using function pointers as const generic parameters is forbidden + //~| ERROR: the type of const parameters must not depend on other generic parameters F(outer); } diff --git a/src/test/ui/const-generics/issues/issue-71611.stderr b/src/test/ui/const-generics/issues/issue-71611.stderr index 9a7bf1c0a88..e2c9f22361e 100644 --- a/src/test/ui/const-generics/issues/issue-71611.stderr +++ b/src/test/ui/const-generics/issues/issue-71611.stderr @@ -1,8 +1,15 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71611.rs:4:31 + | +LL | fn func<A, const F: fn(inner: A)>(outer: A) { + | ^ the type must not depend on the parameter `A` + error: using function pointers as const generic parameters is forbidden --> $DIR/issue-71611.rs:4:21 | LL | fn func<A, const F: fn(inner: A)>(outer: A) { | ^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-73491.rs b/src/test/ui/const-generics/issues/issue-73491.rs new file mode 100644 index 00000000000..05e1513bb75 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73491.rs @@ -0,0 +1,9 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +const LEN: usize = 1024; + +fn hoge<const IN: [u32; LEN]>() {} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-74101.rs b/src/test/ui/const-generics/issues/issue-74101.rs new file mode 100644 index 00000000000..2f427ef3a27 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74101.rs @@ -0,0 +1,9 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn test<const N: [u8; 1 + 2]>() {} + +struct Foo<const N: [u8; 1 + 2]>; + +fn main() {} diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs index 5f2d5e80243..d19cf00eb9c 100644 --- a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs +++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs @@ -1,9 +1,12 @@ // check-pass +// compile-flags: --crate-type lib + +#![warn(unconditional_panic)] + pub struct Fixed64(i64); -pub fn div(f: Fixed64) { - f.0 / 0; +// HACK: this test passes only because this is a const fn that is written to metadata +pub const fn div(f: Fixed64) { + f.0 / 0; //~ WARN will panic at runtime } - -fn main() {} diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr new file mode 100644 index 00000000000..e2a3e4db8ab --- /dev/null +++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr @@ -0,0 +1,14 @@ +warning: this operation will panic at runtime + --> $DIR/ice-assert-fail-div-by-zero.rs:11:5 + | +LL | f.0 / 0; + | ^^^^^^^ attempt to divide _ by zero + | +note: the lint level is defined here + --> $DIR/ice-assert-fail-div-by-zero.rs:5:9 + | +LL | #![warn(unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 9aea859999c..c4292d041d0 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -127,7 +127,7 @@ impl Formatter for HTMLFormatter { DEFAULT_EDITION, &Some(playground) ) - .to_string() + .into_string() )? } None => write!(output, "<p>No description.</p>\n")?, |
