From b0eb55a092506aa4cfe34969c56adfeca9616750 Mon Sep 17 00:00:00 2001 From: jumbatm <30644300+jumbatm@users.noreply.github.com> Date: Sat, 15 Aug 2020 13:18:54 +1000 Subject: Add test demonstrating the issue. --- src/test/ui/lint/clashing-extern-fn-recursion.rs | 117 +++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/test/ui/lint/clashing-extern-fn-recursion.rs (limited to 'src') diff --git a/src/test/ui/lint/clashing-extern-fn-recursion.rs b/src/test/ui/lint/clashing-extern-fn-recursion.rs new file mode 100644 index 00000000000..51bfd203283 --- /dev/null +++ b/src/test/ui/lint/clashing-extern-fn-recursion.rs @@ -0,0 +1,117 @@ +// check-pass +// +// This tests checks that clashing_extern_declarations handles types that are recursive through a +// pointer or ref argument. See #75512. + +#![crate_type = "lib"] + +mod raw_ptr_recursion { + mod a { + #[repr(C)] + struct Pointy { + pointy: *const Pointy, + } + + extern "C" { + fn run_pointy(pointy: Pointy); + } + } + mod b { + #[repr(C)] + struct Pointy { + pointy: *const Pointy, + } + + extern "C" { + fn run_pointy(pointy: Pointy); + } + } +} + +mod raw_ptr_recursion_once_removed { + mod a { + #[repr(C)] + struct Pointy1 { + pointy_two: *const Pointy2, + } + + #[repr(C)] + struct Pointy2 { + pointy_one: *const Pointy1, + } + + extern "C" { + fn run_pointy2(pointy: Pointy2); + } + } + + mod b { + #[repr(C)] + struct Pointy1 { + pointy_two: *const Pointy2, + } + + #[repr(C)] + struct Pointy2 { + pointy_one: *const Pointy1, + } + + extern "C" { + fn run_pointy2(pointy: Pointy2); + } + } +} + +mod ref_recursion { + mod a { + #[repr(C)] + struct Reffy<'a> { + reffy: &'a Reffy<'a>, + } + + extern "C" { + fn reffy_recursion(reffy: Reffy); + } + } + mod b { + #[repr(C)] + struct Reffy<'a> { + reffy: &'a Reffy<'a>, + } + + extern "C" { + fn reffy_recursion(reffy: Reffy); + } + } +} + +mod ref_recursion_once_removed { + mod a { + #[repr(C)] + struct Reffy1<'a> { + reffy: &'a Reffy1<'a>, + } + + struct Reffy2<'a> { + reffy: &'a Reffy2<'a>, + } + + extern "C" { + fn reffy_once_removed(reffy: Reffy1); + } + } + mod b { + #[repr(C)] + struct Reffy1<'a> { + reffy: &'a Reffy1<'a>, + } + + struct Reffy2<'a> { + reffy: &'a Reffy2<'a>, + } + + extern "C" { + fn reffy_once_removed(reffy: Reffy1); + } + } +} -- cgit 1.4.1-3-g733a5 From db753137a14b04886567a1f20768b96feba05594 Mon Sep 17 00:00:00 2001 From: jumbatm <30644300+jumbatm@users.noreply.github.com> Date: Sat, 15 Aug 2020 15:05:18 +1000 Subject: Fix stack overflow for recursive types. Adds a seen set to structurally_same_type to avoid recursing indefinitely when a reference or pointer member introduces a cycle in the visited types. --- src/librustc_lint/builtin.rs | 289 ++++++++++++++++++++++++++++--------------- 1 file changed, 187 insertions(+), 102 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 3859d0f163a..0e578ac5034 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2153,44 +2153,99 @@ impl ClashingExternDeclarations { b: Ty<'tcx>, ckind: CItemKind, ) -> bool { - debug!("structurally_same_type(cx, a = {:?}, b = {:?})", a, b); - let tcx = cx.tcx; - if a == b || rustc_middle::ty::TyS::same_type(a, b) { - // All nominally-same types are structurally same, too. - true - } else { - // Do a full, depth-first comparison between the two. - use rustc_middle::ty::TyKind::*; - let a_kind = &a.kind; - let b_kind = &b.kind; - - let compare_layouts = |a, b| -> bool { - let a_layout = &cx.layout_of(a).unwrap().layout.abi; - let b_layout = &cx.layout_of(b).unwrap().layout.abi; - debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout); - a_layout == b_layout - }; + // In order to avoid endlessly recursing on recursive types, we maintain a "seen" set. + // We'll need to store every combination of types we encounter anyway, so we also memoize + // the result. + struct SeenSet<'tcx>(FxHashMap<(Ty<'tcx>, Ty<'tcx>), Option>); + + enum SeenSetResult { + /// We've never seen this combination of types. + Unseen, + /// We've seen this combination of types, but are still computing the result. + Computing, + /// We've seen this combination of types, and have already computed the result. + Computed(bool), + } + + impl<'tcx> SeenSet<'tcx> { + fn new() -> Self { + SeenSet(FxHashMap::default()) + } + /// Mark (a, b) as `Computing`. + fn mark_computing(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { + self.0.insert((a, b), None); + } + /// Mark (a, b) as `Computed(result)`. + fn mark_computed(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, result: bool) { + *self.0.get_mut(&(a, b)).expect("Missing prior call to mark_computing") = + Some(result); + } + fn get(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> SeenSetResult { + match self.0.get(&(a, b)) { + None => SeenSetResult::Unseen, + Some(None) => SeenSetResult::Computing, + Some(Some(b)) => SeenSetResult::Computed(*b), + } + } + } + fn structurally_same_type_impl<'tcx>( + seen_types: &mut SeenSet<'tcx>, + cx: &LateContext<'tcx>, + a: Ty<'tcx>, + b: Ty<'tcx>, + ckind: CItemKind, + ) -> bool { + debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b); + match seen_types.get(a, b) { + // If we've already computed the result, just return the memoized result. + SeenSetResult::Computed(result) => result, + // We are already in the process of computing structural sameness for this type, + // meaning we've found a cycle. The types are structurally same, then. + SeenSetResult::Computing => true, + // We haven't seen this combination of types at all -- compute their sameness. + SeenSetResult::Unseen => { + seen_types.mark_computing(a, b); + let tcx = cx.tcx; + let result = if a == b || rustc_middle::ty::TyS::same_type(a, b) { + // All nominally-same types are structurally same, too. + true + } else { + // Do a full, depth-first comparison between the two. + use rustc_middle::ty::TyKind::*; + let a_kind = &a.kind; + let b_kind = &b.kind; + + let compare_layouts = |a, b| -> bool { + let a_layout = &cx.layout_of(a).unwrap().layout.abi; + let b_layout = &cx.layout_of(b).unwrap().layout.abi; + debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout); + a_layout == b_layout + }; + + #[allow(rustc::usage_of_ty_tykind)] + let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| { + kind.is_primitive() || matches!(kind, RawPtr(..)) + }; - #[allow(rustc::usage_of_ty_tykind)] - let is_primitive_or_pointer = - |kind: &ty::TyKind<'_>| kind.is_primitive() || matches!(kind, RawPtr(..)); - - match (a_kind, b_kind) { - (Adt(_, a_substs), Adt(_, b_substs)) => { - let a = a.subst(cx.tcx, a_substs); - let b = b.subst(cx.tcx, b_substs); - debug!("Comparing {:?} and {:?}", a, b); - - if let (Adt(a_def, ..), Adt(b_def, ..)) = (&a.kind, &b.kind) { - // Grab a flattened representation of all fields. - let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter()); - let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter()); - compare_layouts(a, b) + match (a_kind, b_kind) { + (Adt(_, a_substs), Adt(_, b_substs)) => { + let a = a.subst(cx.tcx, a_substs); + let b = b.subst(cx.tcx, b_substs); + debug!("Comparing {:?} and {:?}", a, b); + + if let (Adt(a_def, ..), Adt(b_def, ..)) = (&a.kind, &b.kind) { + // Grab a flattened representation of all fields. + let a_fields = + a_def.variants.iter().flat_map(|v| v.fields.iter()); + let b_fields = + b_def.variants.iter().flat_map(|v| v.fields.iter()); + compare_layouts(a, b) && a_fields.eq_by( b_fields, |&ty::FieldDef { did: a_did, .. }, &ty::FieldDef { did: b_did, .. }| { - Self::structurally_same_type( + structurally_same_type_impl( + seen_types, cx, tcx.type_of(a_did), tcx.type_of(b_did), @@ -2198,78 +2253,108 @@ impl ClashingExternDeclarations { ) }, ) - } else { - unreachable!() - } - } - (Array(a_ty, a_const), Array(b_ty, b_const)) => { - // For arrays, we also check the constness of the type. - a_const.val == b_const.val - && Self::structurally_same_type(cx, a_const.ty, b_const.ty, ckind) - && Self::structurally_same_type(cx, a_ty, b_ty, ckind) - } - (Slice(a_ty), Slice(b_ty)) => Self::structurally_same_type(cx, a_ty, b_ty, ckind), - (RawPtr(a_tymut), RawPtr(b_tymut)) => { - a_tymut.mutbl == b_tymut.mutbl - && Self::structurally_same_type(cx, &a_tymut.ty, &b_tymut.ty, ckind) - } - (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => { - // For structural sameness, we don't need the region to be same. - a_mut == b_mut && Self::structurally_same_type(cx, a_ty, b_ty, ckind) - } - (FnDef(..), FnDef(..)) => { - let a_poly_sig = a.fn_sig(tcx); - let b_poly_sig = b.fn_sig(tcx); - - // As we don't compare regions, skip_binder is fine. - let a_sig = a_poly_sig.skip_binder(); - let b_sig = b_poly_sig.skip_binder(); - - (a_sig.abi, a_sig.unsafety, a_sig.c_variadic) - == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic) - && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { - Self::structurally_same_type(cx, a, b, ckind) - }) - && Self::structurally_same_type(cx, a_sig.output(), b_sig.output(), ckind) - } - (Tuple(a_substs), Tuple(b_substs)) => { - a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| { - Self::structurally_same_type(cx, a_ty, b_ty, ckind) - }) - } - // For these, it's not quite as easy to define structural-sameness quite so easily. - // For the purposes of this lint, take the conservative approach and mark them as - // not structurally same. - (Dynamic(..), Dynamic(..)) - | (Error(..), Error(..)) - | (Closure(..), Closure(..)) - | (Generator(..), Generator(..)) - | (GeneratorWitness(..), GeneratorWitness(..)) - | (Projection(..), Projection(..)) - | (Opaque(..), Opaque(..)) => false, - - // These definitely should have been caught above. - (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(), - - // An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a - // non-null field. - (Adt(..), other_kind) | (other_kind, Adt(..)) - if is_primitive_or_pointer(other_kind) => - { - let (primitive, adt) = - if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) }; - if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) { - ty == primitive - } else { - compare_layouts(a, b) - } + } else { + unreachable!() + } + } + (Array(a_ty, a_const), Array(b_ty, b_const)) => { + // For arrays, we also check the constness of the type. + a_const.val == b_const.val + && structurally_same_type_impl( + seen_types, cx, a_const.ty, b_const.ty, ckind, + ) + && structurally_same_type_impl( + seen_types, cx, a_ty, b_ty, ckind, + ) + } + (Slice(a_ty), Slice(b_ty)) => { + structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) + } + (RawPtr(a_tymut), RawPtr(b_tymut)) => { + a_tymut.mutbl == b_tymut.mutbl + && structurally_same_type_impl( + seen_types, + cx, + &a_tymut.ty, + &b_tymut.ty, + ckind, + ) + } + (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => { + // For structural sameness, we don't need the region to be same. + a_mut == b_mut + && structurally_same_type_impl( + seen_types, cx, a_ty, b_ty, ckind, + ) + } + (FnDef(..), FnDef(..)) => { + let a_poly_sig = a.fn_sig(tcx); + let b_poly_sig = b.fn_sig(tcx); + + // As we don't compare regions, skip_binder is fine. + let a_sig = a_poly_sig.skip_binder(); + let b_sig = b_poly_sig.skip_binder(); + + (a_sig.abi, a_sig.unsafety, a_sig.c_variadic) + == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic) + && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { + structurally_same_type_impl(seen_types, cx, a, b, ckind) + }) + && structurally_same_type_impl( + seen_types, + cx, + a_sig.output(), + b_sig.output(), + ckind, + ) + } + (Tuple(a_substs), Tuple(b_substs)) => { + a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| { + structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) + }) + } + // For these, it's not quite as easy to define structural-sameness quite so easily. + // For the purposes of this lint, take the conservative approach and mark them as + // not structurally same. + (Dynamic(..), Dynamic(..)) + | (Error(..), Error(..)) + | (Closure(..), Closure(..)) + | (Generator(..), Generator(..)) + | (GeneratorWitness(..), GeneratorWitness(..)) + | (Projection(..), Projection(..)) + | (Opaque(..), Opaque(..)) => false, + + // These definitely should have been caught above. + (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => { + unreachable!() + } + + // An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a + // non-null field. + (Adt(..), other_kind) | (other_kind, Adt(..)) + if is_primitive_or_pointer(other_kind) => + { + let (primitive, adt) = + if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) }; + if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) { + ty == primitive + } else { + compare_layouts(a, b) + } + } + // Otherwise, just compare the layouts. This may fail to lint for some + // incompatible types, but at the very least, will stop reads into + // uninitialised memory. + _ => compare_layouts(a, b), + } + }; + seen_types.mark_computed(a, b, result); + result } - // Otherwise, just compare the layouts. This may fail to lint for some - // incompatible types, but at the very least, will stop reads into - // uninitialised memory. - _ => compare_layouts(a, b), } } + let mut seen_types = SeenSet::new(); + structurally_same_type_impl(&mut seen_types, cx, a, b, ckind) } } -- cgit 1.4.1-3-g733a5 From 154b74e8f959581d37d1a1ae860ee1bf7b682f34 Mon Sep 17 00:00:00 2001 From: jumbatm <30644300+jumbatm@users.noreply.github.com> Date: Sun, 16 Aug 2020 10:26:45 +1000 Subject: Actually introduce a cycle in Reffy test. --- src/test/ui/lint/clashing-extern-fn-recursion.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/test/ui/lint/clashing-extern-fn-recursion.rs b/src/test/ui/lint/clashing-extern-fn-recursion.rs index 51bfd203283..ab0fd0a2e70 100644 --- a/src/test/ui/lint/clashing-extern-fn-recursion.rs +++ b/src/test/ui/lint/clashing-extern-fn-recursion.rs @@ -89,28 +89,30 @@ mod ref_recursion_once_removed { mod a { #[repr(C)] struct Reffy1<'a> { - reffy: &'a Reffy1<'a>, + reffy: &'a Reffy2<'a>, } struct Reffy2<'a> { - reffy: &'a Reffy2<'a>, + reffy: &'a Reffy1<'a>, } extern "C" { + #[allow(improper_ctypes)] fn reffy_once_removed(reffy: Reffy1); } } mod b { #[repr(C)] struct Reffy1<'a> { - reffy: &'a Reffy1<'a>, + reffy: &'a Reffy2<'a>, } struct Reffy2<'a> { - reffy: &'a Reffy2<'a>, + reffy: &'a Reffy1<'a>, } extern "C" { + #[allow(improper_ctypes)] fn reffy_once_removed(reffy: Reffy1); } } -- cgit 1.4.1-3-g733a5 From a1fa4e05acb2cbda9a02cc34f8000c965328dbde Mon Sep 17 00:00:00 2001 From: jumbatm <30644300+jumbatm@users.noreply.github.com> Date: Sun, 16 Aug 2020 10:41:59 +1000 Subject: Remove unnecessary rebinding of def ids. --- src/librustc_lint/builtin.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 0e578ac5034..47f680932f1 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2228,18 +2228,15 @@ impl ClashingExternDeclarations { }; match (a_kind, b_kind) { - (Adt(_, a_substs), Adt(_, b_substs)) => { + (Adt(a_def, a_substs), Adt(b_def, b_substs)) => { let a = a.subst(cx.tcx, a_substs); let b = b.subst(cx.tcx, b_substs); debug!("Comparing {:?} and {:?}", a, b); - if let (Adt(a_def, ..), Adt(b_def, ..)) = (&a.kind, &b.kind) { - // Grab a flattened representation of all fields. - let a_fields = - a_def.variants.iter().flat_map(|v| v.fields.iter()); - let b_fields = - b_def.variants.iter().flat_map(|v| v.fields.iter()); - compare_layouts(a, b) + // Grab a flattened representation of all fields. + let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter()); + let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter()); + compare_layouts(a, b) && a_fields.eq_by( b_fields, |&ty::FieldDef { did: a_did, .. }, @@ -2253,9 +2250,6 @@ impl ClashingExternDeclarations { ) }, ) - } else { - unreachable!() - } } (Array(a_ty, a_const), Array(b_ty, b_const)) => { // For arrays, we also check the constness of the type. -- cgit 1.4.1-3-g733a5 From 80c2c80d52e2384ee6ce33a7b41c0c47c4f0ffd1 Mon Sep 17 00:00:00 2001 From: jumbatm <30644300+jumbatm@users.noreply.github.com> Date: Sun, 16 Aug 2020 10:47:35 +1000 Subject: Remove structural equiv check for Array const. --- src/librustc_lint/builtin.rs | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 47f680932f1..2cf0ed390f4 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2254,9 +2254,6 @@ impl ClashingExternDeclarations { (Array(a_ty, a_const), Array(b_ty, b_const)) => { // For arrays, we also check the constness of the type. a_const.val == b_const.val - && structurally_same_type_impl( - seen_types, cx, a_const.ty, b_const.ty, ckind, - ) && structurally_same_type_impl( seen_types, cx, a_ty, b_ty, ckind, ) -- cgit 1.4.1-3-g733a5 From bca48ad7acbc7b7462bce58f0513c02c4e5444b5 Mon Sep 17 00:00:00 2001 From: jumbatm <30644300+jumbatm@users.noreply.github.com> Date: Sun, 16 Aug 2020 10:50:20 +1000 Subject: Reduce indentation by replacing match arm w/ early return. --- src/librustc_lint/builtin.rs | 243 +++++++++++++++++++++---------------------- 1 file changed, 118 insertions(+), 125 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 2cf0ed390f4..c23b443645d 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2198,45 +2198,46 @@ impl ClashingExternDeclarations { debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b); match seen_types.get(a, b) { // If we've already computed the result, just return the memoized result. - SeenSetResult::Computed(result) => result, + SeenSetResult::Computed(result) => return result, // We are already in the process of computing structural sameness for this type, // meaning we've found a cycle. The types are structurally same, then. - SeenSetResult::Computing => true, - // We haven't seen this combination of types at all -- compute their sameness. - SeenSetResult::Unseen => { - seen_types.mark_computing(a, b); - let tcx = cx.tcx; - let result = if a == b || rustc_middle::ty::TyS::same_type(a, b) { - // All nominally-same types are structurally same, too. - true - } else { - // Do a full, depth-first comparison between the two. - use rustc_middle::ty::TyKind::*; - let a_kind = &a.kind; - let b_kind = &b.kind; - - let compare_layouts = |a, b| -> bool { - let a_layout = &cx.layout_of(a).unwrap().layout.abi; - let b_layout = &cx.layout_of(b).unwrap().layout.abi; - debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout); - a_layout == b_layout - }; + SeenSetResult::Computing => return true, + // We haven't seen this combination of types at all -- continue on to computing + // their sameness. + SeenSetResult::Unseen => (), + } + seen_types.mark_computing(a, b); + let tcx = cx.tcx; + let result = if a == b || rustc_middle::ty::TyS::same_type(a, b) { + // All nominally-same types are structurally same, too. + true + } else { + // Do a full, depth-first comparison between the two. + use rustc_middle::ty::TyKind::*; + let a_kind = &a.kind; + let b_kind = &b.kind; + + let compare_layouts = |a, b| -> bool { + let a_layout = &cx.layout_of(a).unwrap().layout.abi; + let b_layout = &cx.layout_of(b).unwrap().layout.abi; + debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout); + a_layout == b_layout + }; - #[allow(rustc::usage_of_ty_tykind)] - let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| { - kind.is_primitive() || matches!(kind, RawPtr(..)) - }; + #[allow(rustc::usage_of_ty_tykind)] + let is_primitive_or_pointer = + |kind: &ty::TyKind<'_>| kind.is_primitive() || matches!(kind, RawPtr(..)); - match (a_kind, b_kind) { - (Adt(a_def, a_substs), Adt(b_def, b_substs)) => { - let a = a.subst(cx.tcx, a_substs); - let b = b.subst(cx.tcx, b_substs); - debug!("Comparing {:?} and {:?}", a, b); + match (a_kind, b_kind) { + (Adt(a_def, a_substs), Adt(b_def, b_substs)) => { + let a = a.subst(cx.tcx, a_substs); + let b = b.subst(cx.tcx, b_substs); + debug!("Comparing {:?} and {:?}", a, b); - // Grab a flattened representation of all fields. - let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter()); - let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter()); - compare_layouts(a, b) + // Grab a flattened representation of all fields. + let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter()); + let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter()); + compare_layouts(a, b) && a_fields.eq_by( b_fields, |&ty::FieldDef { did: a_did, .. }, @@ -2250,99 +2251,91 @@ impl ClashingExternDeclarations { ) }, ) - } - (Array(a_ty, a_const), Array(b_ty, b_const)) => { - // For arrays, we also check the constness of the type. - a_const.val == b_const.val - && structurally_same_type_impl( - seen_types, cx, a_ty, b_ty, ckind, - ) - } - (Slice(a_ty), Slice(b_ty)) => { - structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) - } - (RawPtr(a_tymut), RawPtr(b_tymut)) => { - a_tymut.mutbl == b_tymut.mutbl - && structurally_same_type_impl( - seen_types, - cx, - &a_tymut.ty, - &b_tymut.ty, - ckind, - ) - } - (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => { - // For structural sameness, we don't need the region to be same. - a_mut == b_mut - && structurally_same_type_impl( - seen_types, cx, a_ty, b_ty, ckind, - ) - } - (FnDef(..), FnDef(..)) => { - let a_poly_sig = a.fn_sig(tcx); - let b_poly_sig = b.fn_sig(tcx); - - // As we don't compare regions, skip_binder is fine. - let a_sig = a_poly_sig.skip_binder(); - let b_sig = b_poly_sig.skip_binder(); - - (a_sig.abi, a_sig.unsafety, a_sig.c_variadic) - == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic) - && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { - structurally_same_type_impl(seen_types, cx, a, b, ckind) - }) - && structurally_same_type_impl( - seen_types, - cx, - a_sig.output(), - b_sig.output(), - ckind, - ) - } - (Tuple(a_substs), Tuple(b_substs)) => { - a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| { - structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) - }) - } - // For these, it's not quite as easy to define structural-sameness quite so easily. - // For the purposes of this lint, take the conservative approach and mark them as - // not structurally same. - (Dynamic(..), Dynamic(..)) - | (Error(..), Error(..)) - | (Closure(..), Closure(..)) - | (Generator(..), Generator(..)) - | (GeneratorWitness(..), GeneratorWitness(..)) - | (Projection(..), Projection(..)) - | (Opaque(..), Opaque(..)) => false, - - // These definitely should have been caught above. - (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => { - unreachable!() - } - - // An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a - // non-null field. - (Adt(..), other_kind) | (other_kind, Adt(..)) - if is_primitive_or_pointer(other_kind) => - { - let (primitive, adt) = - if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) }; - if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) { - ty == primitive - } else { - compare_layouts(a, b) - } - } - // Otherwise, just compare the layouts. This may fail to lint for some - // incompatible types, but at the very least, will stop reads into - // uninitialised memory. - _ => compare_layouts(a, b), + } + (Array(a_ty, a_const), Array(b_ty, b_const)) => { + // For arrays, we also check the constness of the type. + a_const.val == b_const.val + && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) + } + (Slice(a_ty), Slice(b_ty)) => { + structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) + } + (RawPtr(a_tymut), RawPtr(b_tymut)) => { + a_tymut.mutbl == b_tymut.mutbl + && structurally_same_type_impl( + seen_types, + cx, + &a_tymut.ty, + &b_tymut.ty, + ckind, + ) + } + (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => { + // For structural sameness, we don't need the region to be same. + a_mut == b_mut + && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) + } + (FnDef(..), FnDef(..)) => { + let a_poly_sig = a.fn_sig(tcx); + let b_poly_sig = b.fn_sig(tcx); + + // As we don't compare regions, skip_binder is fine. + let a_sig = a_poly_sig.skip_binder(); + let b_sig = b_poly_sig.skip_binder(); + + (a_sig.abi, a_sig.unsafety, a_sig.c_variadic) + == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic) + && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { + structurally_same_type_impl(seen_types, cx, a, b, ckind) + }) + && structurally_same_type_impl( + seen_types, + cx, + a_sig.output(), + b_sig.output(), + ckind, + ) + } + (Tuple(a_substs), Tuple(b_substs)) => { + a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| { + structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) + }) + } + // For these, it's not quite as easy to define structural-sameness quite so easily. + // For the purposes of this lint, take the conservative approach and mark them as + // not structurally same. + (Dynamic(..), Dynamic(..)) + | (Error(..), Error(..)) + | (Closure(..), Closure(..)) + | (Generator(..), Generator(..)) + | (GeneratorWitness(..), GeneratorWitness(..)) + | (Projection(..), Projection(..)) + | (Opaque(..), Opaque(..)) => false, + + // These definitely should have been caught above. + (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(), + + // An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a + // non-null field. + (Adt(..), other_kind) | (other_kind, Adt(..)) + if is_primitive_or_pointer(other_kind) => + { + let (primitive, adt) = + if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) }; + if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) { + ty == primitive + } else { + compare_layouts(a, b) } - }; - seen_types.mark_computed(a, b, result); - result + } + // Otherwise, just compare the layouts. This may fail to lint for some + // incompatible types, but at the very least, will stop reads into + // uninitialised memory. + _ => compare_layouts(a, b), } - } + }; + seen_types.mark_computed(a, b, result); + result } let mut seen_types = SeenSet::new(); structurally_same_type_impl(&mut seen_types, cx, a, b, ckind) -- cgit 1.4.1-3-g733a5 From 6c57de1166d36725a689cef17e0dab8b9abcd00b Mon Sep 17 00:00:00 2001 From: jumbatm <30644300+jumbatm@users.noreply.github.com> Date: Sun, 16 Aug 2020 11:01:14 +1000 Subject: Don't memoize seen types. That cache is unlikely to be particularly useful within a single invocation of structurally_same_type, especially compared to memoizing results across _all_ invocations of that function. --- src/librustc_lint/builtin.rs | 60 +++++++------------------------------------- 1 file changed, 9 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c23b443645d..781ebb67167 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2153,62 +2153,22 @@ impl ClashingExternDeclarations { b: Ty<'tcx>, ckind: CItemKind, ) -> bool { - // In order to avoid endlessly recursing on recursive types, we maintain a "seen" set. - // We'll need to store every combination of types we encounter anyway, so we also memoize - // the result. - struct SeenSet<'tcx>(FxHashMap<(Ty<'tcx>, Ty<'tcx>), Option>); - - enum SeenSetResult { - /// We've never seen this combination of types. - Unseen, - /// We've seen this combination of types, but are still computing the result. - Computing, - /// We've seen this combination of types, and have already computed the result. - Computed(bool), - } - - impl<'tcx> SeenSet<'tcx> { - fn new() -> Self { - SeenSet(FxHashMap::default()) - } - /// Mark (a, b) as `Computing`. - fn mark_computing(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { - self.0.insert((a, b), None); - } - /// Mark (a, b) as `Computed(result)`. - fn mark_computed(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, result: bool) { - *self.0.get_mut(&(a, b)).expect("Missing prior call to mark_computing") = - Some(result); - } - fn get(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> SeenSetResult { - match self.0.get(&(a, b)) { - None => SeenSetResult::Unseen, - Some(None) => SeenSetResult::Computing, - Some(Some(b)) => SeenSetResult::Computed(*b), - } - } - } fn structurally_same_type_impl<'tcx>( - seen_types: &mut SeenSet<'tcx>, + seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>, cx: &LateContext<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>, ckind: CItemKind, ) -> bool { debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b); - match seen_types.get(a, b) { - // If we've already computed the result, just return the memoized result. - SeenSetResult::Computed(result) => return result, - // We are already in the process of computing structural sameness for this type, - // meaning we've found a cycle. The types are structurally same, then. - SeenSetResult::Computing => return true, - // We haven't seen this combination of types at all -- continue on to computing - // their sameness. - SeenSetResult::Unseen => (), + if seen_types.contains(&(a, b)) { + // We've encountered a cycle. There's no point going any further -- the types are + // structurally the same. + return true; } - seen_types.mark_computing(a, b); + seen_types.insert((a, b)); let tcx = cx.tcx; - let result = if a == b || rustc_middle::ty::TyS::same_type(a, b) { + if a == b || rustc_middle::ty::TyS::same_type(a, b) { // All nominally-same types are structurally same, too. true } else { @@ -2333,11 +2293,9 @@ impl ClashingExternDeclarations { // uninitialised memory. _ => compare_layouts(a, b), } - }; - seen_types.mark_computed(a, b, result); - result + } } - let mut seen_types = SeenSet::new(); + let mut seen_types = FxHashSet::default(); structurally_same_type_impl(&mut seen_types, cx, a, b, ckind) } } -- cgit 1.4.1-3-g733a5 From 7708abbbef679d208041bff57aa9ad50e9419895 Mon Sep 17 00:00:00 2001 From: jumbatm Date: Sun, 16 Aug 2020 17:14:09 +1000 Subject: Avoid double hashset lookup. Co-authored-by: Bastian Kauschke --- src/librustc_lint/builtin.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 781ebb67167..8625dc096d5 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2161,12 +2161,11 @@ impl ClashingExternDeclarations { ckind: CItemKind, ) -> bool { debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b); - if seen_types.contains(&(a, b)) { + if !seen_types.insert((a, b)) { // We've encountered a cycle. There's no point going any further -- the types are // structurally the same. return true; } - seen_types.insert((a, b)); let tcx = cx.tcx; if a == b || rustc_middle::ty::TyS::same_type(a, b) { // All nominally-same types are structurally same, too. -- cgit 1.4.1-3-g733a5 From 1321a2dce32893588a0ec4ba586c3a04fb5e47cf Mon Sep 17 00:00:00 2001 From: jumbatm <30644300+jumbatm@users.noreply.github.com> Date: Sun, 16 Aug 2020 18:04:14 +1000 Subject: Also accept Refs for is_primitive_or_pointer --- src/librustc_lint/builtin.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 8625dc096d5..2439fc66606 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2184,8 +2184,9 @@ impl ClashingExternDeclarations { }; #[allow(rustc::usage_of_ty_tykind)] - let is_primitive_or_pointer = - |kind: &ty::TyKind<'_>| kind.is_primitive() || matches!(kind, RawPtr(..)); + let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| { + kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..)) + }; match (a_kind, b_kind) { (Adt(a_def, a_substs), Adt(b_def, b_substs)) => { @@ -2274,8 +2275,8 @@ impl ClashingExternDeclarations { // These definitely should have been caught above. (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(), - // An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a - // non-null field. + // An Adt and a primitive or pointer type. This can be FFI-safe if non-null + // enum layout optimisation is being applied. (Adt(..), other_kind) | (other_kind, Adt(..)) if is_primitive_or_pointer(other_kind) => { -- cgit 1.4.1-3-g733a5 From bc15dd6dde58aaed724cf692c0635060a77fc99c Mon Sep 17 00:00:00 2001 From: jumbatm <30644300+jumbatm@users.noreply.github.com> Date: Tue, 18 Aug 2020 02:00:35 +1000 Subject: Wrap recursion in `ensure_sufficient_stack`. --- src/librustc_lint/builtin.rs | 179 ++++++++++++++++++++++--------------------- 1 file changed, 91 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 2439fc66606..147eb8f06c8 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -29,6 +29,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType}; use rustc_feature::{GateIssue, Stability}; @@ -2188,16 +2189,17 @@ impl ClashingExternDeclarations { kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..)) }; - match (a_kind, b_kind) { - (Adt(a_def, a_substs), Adt(b_def, b_substs)) => { - let a = a.subst(cx.tcx, a_substs); - let b = b.subst(cx.tcx, b_substs); - debug!("Comparing {:?} and {:?}", a, b); + ensure_sufficient_stack(|| { + match (a_kind, b_kind) { + (Adt(a_def, a_substs), Adt(b_def, b_substs)) => { + let a = a.subst(cx.tcx, a_substs); + let b = b.subst(cx.tcx, b_substs); + debug!("Comparing {:?} and {:?}", a, b); - // Grab a flattened representation of all fields. - let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter()); - let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter()); - compare_layouts(a, b) + // Grab a flattened representation of all fields. + let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter()); + let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter()); + compare_layouts(a, b) && a_fields.eq_by( b_fields, |&ty::FieldDef { did: a_did, .. }, @@ -2211,88 +2213,89 @@ impl ClashingExternDeclarations { ) }, ) - } - (Array(a_ty, a_const), Array(b_ty, b_const)) => { - // For arrays, we also check the constness of the type. - a_const.val == b_const.val - && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) - } - (Slice(a_ty), Slice(b_ty)) => { - structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) - } - (RawPtr(a_tymut), RawPtr(b_tymut)) => { - a_tymut.mutbl == b_tymut.mutbl - && structurally_same_type_impl( - seen_types, - cx, - &a_tymut.ty, - &b_tymut.ty, - ckind, - ) - } - (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => { - // For structural sameness, we don't need the region to be same. - a_mut == b_mut - && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) - } - (FnDef(..), FnDef(..)) => { - let a_poly_sig = a.fn_sig(tcx); - let b_poly_sig = b.fn_sig(tcx); - - // As we don't compare regions, skip_binder is fine. - let a_sig = a_poly_sig.skip_binder(); - let b_sig = b_poly_sig.skip_binder(); - - (a_sig.abi, a_sig.unsafety, a_sig.c_variadic) - == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic) - && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { - structurally_same_type_impl(seen_types, cx, a, b, ckind) - }) - && structurally_same_type_impl( - seen_types, - cx, - a_sig.output(), - b_sig.output(), - ckind, - ) - } - (Tuple(a_substs), Tuple(b_substs)) => { - a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| { + } + (Array(a_ty, a_const), Array(b_ty, b_const)) => { + // For arrays, we also check the constness of the type. + a_const.val == b_const.val + && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) + } + (Slice(a_ty), Slice(b_ty)) => { structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) - }) - } - // For these, it's not quite as easy to define structural-sameness quite so easily. - // For the purposes of this lint, take the conservative approach and mark them as - // not structurally same. - (Dynamic(..), Dynamic(..)) - | (Error(..), Error(..)) - | (Closure(..), Closure(..)) - | (Generator(..), Generator(..)) - | (GeneratorWitness(..), GeneratorWitness(..)) - | (Projection(..), Projection(..)) - | (Opaque(..), Opaque(..)) => false, - - // These definitely should have been caught above. - (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(), - - // An Adt and a primitive or pointer type. This can be FFI-safe if non-null - // enum layout optimisation is being applied. - (Adt(..), other_kind) | (other_kind, Adt(..)) - if is_primitive_or_pointer(other_kind) => - { - let (primitive, adt) = - if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) }; - if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) { - ty == primitive - } else { - compare_layouts(a, b) } + (RawPtr(a_tymut), RawPtr(b_tymut)) => { + a_tymut.mutbl == b_tymut.mutbl + && structurally_same_type_impl( + seen_types, + cx, + &a_tymut.ty, + &b_tymut.ty, + ckind, + ) + } + (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => { + // For structural sameness, we don't need the region to be same. + a_mut == b_mut + && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) + } + (FnDef(..), FnDef(..)) => { + let a_poly_sig = a.fn_sig(tcx); + let b_poly_sig = b.fn_sig(tcx); + + // As we don't compare regions, skip_binder is fine. + let a_sig = a_poly_sig.skip_binder(); + let b_sig = b_poly_sig.skip_binder(); + + (a_sig.abi, a_sig.unsafety, a_sig.c_variadic) + == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic) + && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { + structurally_same_type_impl(seen_types, cx, a, b, ckind) + }) + && structurally_same_type_impl( + seen_types, + cx, + a_sig.output(), + b_sig.output(), + ckind, + ) + } + (Tuple(a_substs), Tuple(b_substs)) => { + a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| { + structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) + }) + } + // For these, it's not quite as easy to define structural-sameness quite so easily. + // For the purposes of this lint, take the conservative approach and mark them as + // not structurally same. + (Dynamic(..), Dynamic(..)) + | (Error(..), Error(..)) + | (Closure(..), Closure(..)) + | (Generator(..), Generator(..)) + | (GeneratorWitness(..), GeneratorWitness(..)) + | (Projection(..), Projection(..)) + | (Opaque(..), Opaque(..)) => false, + + // These definitely should have been caught above. + (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(), + + // An Adt and a primitive or pointer type. This can be FFI-safe if non-null + // enum layout optimisation is being applied. + (Adt(..), other_kind) | (other_kind, Adt(..)) + if is_primitive_or_pointer(other_kind) => + { + let (primitive, adt) = + if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) }; + if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) { + ty == primitive + } else { + compare_layouts(a, b) + } + } + // Otherwise, just compare the layouts. This may fail to lint for some + // incompatible types, but at the very least, will stop reads into + // uninitialised memory. + _ => compare_layouts(a, b), } - // Otherwise, just compare the layouts. This may fail to lint for some - // incompatible types, but at the very least, will stop reads into - // uninitialised memory. - _ => compare_layouts(a, b), - } + }) } } let mut seen_types = FxHashSet::default(); -- cgit 1.4.1-3-g733a5 From 4f9cd749261cf95f48a9473a2b44a5cfcd27e10f Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 17 Aug 2020 19:51:09 -0400 Subject: Resolve true and false as booleans --- src/librustdoc/passes/collect_intra_doc_links.rs | 25 +++++++++++++++++------- src/test/rustdoc/intra-doc-link-true-false.rs | 10 ++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 src/test/rustdoc/intra-doc-link-true-false.rs (limited to 'src') diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index f7fc3579d67..8df089b6d81 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -222,11 +222,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { disambiguator, None | Some(Disambiguator::Namespace(Namespace::TypeNS)) ) { - if let Some(prim) = is_primitive(path_str, ns) { + if let Some((path, prim)) = is_primitive(path_str, ns) { if extra_fragment.is_some() { return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); } - return Ok((prim, Some(path_str.to_owned()))); + return Ok((prim, Some(path.to_owned()))); } } return Ok((res, extra_fragment.clone())); @@ -239,11 +239,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { if value != (ns == ValueNS) { return Err(ErrorKind::ResolutionFailure); } - } else if let Some(prim) = is_primitive(path_str, ns) { + } else if let Some((path, prim)) = is_primitive(path_str, ns) { if extra_fragment.is_some() { return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); } - return Ok((prim, Some(path_str.to_owned()))); + return Ok((prim, Some(path.to_owned()))); } else { // If resolution failed, it may still be a method // because methods are not handled by the resolver @@ -269,7 +269,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) .ok_or(ErrorKind::ResolutionFailure)?; - if let Some(prim) = is_primitive(&path, TypeNS) { + if let Some((path, prim)) = is_primitive(&path, TypeNS) { let did = primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)?; return cx .tcx @@ -1220,11 +1220,22 @@ const PRIMITIVES: &[(&str, Res)] = &[ ("f64", Res::PrimTy(hir::PrimTy::Float(rustc_ast::ast::FloatTy::F64))), ("str", Res::PrimTy(hir::PrimTy::Str)), ("bool", Res::PrimTy(hir::PrimTy::Bool)), + ("true", Res::PrimTy(hir::PrimTy::Bool)), + ("false", Res::PrimTy(hir::PrimTy::Bool)), ("char", Res::PrimTy(hir::PrimTy::Char)), ]; -fn is_primitive(path_str: &str, ns: Namespace) -> Option { - if ns == TypeNS { PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1) } else { None } +fn is_primitive(path_str: &str, ns: Namespace) -> Option<(&'static str, Res)> { + if ns == TypeNS { + PRIMITIVES + .iter() + .filter(|x| x.0 == path_str) + .copied() + .map(|x| if x.0 == "true" || x.0 == "false" { ("bool", x.1) } else { x }) + .next() + } else { + None + } } fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option { diff --git a/src/test/rustdoc/intra-doc-link-true-false.rs b/src/test/rustdoc/intra-doc-link-true-false.rs new file mode 100644 index 00000000000..7b21e934147 --- /dev/null +++ b/src/test/rustdoc/intra-doc-link-true-false.rs @@ -0,0 +1,10 @@ +#![deny(broken_intra_doc_links)] +#![crate_name = "foo"] + +// ignore-tidy-linelength + +// @has foo/index.html +// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'true' +// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'false' + +//! A `bool` is either [`true`] or [`false`]. -- cgit 1.4.1-3-g733a5 From d9d84dca8eaf463a0d878bbd4916665500a071d1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 18 Aug 2020 13:31:23 +0200 Subject: Add doc examples count for --show-coverage --- src/librustdoc/html/render/cache.rs | 6 +- src/librustdoc/passes/calculate_doc_coverage.rs | 80 +++++++++++++++++++++---- src/librustdoc/passes/doc_test_lints.rs | 28 +++++---- 3 files changed, 88 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 5a9e9dda677..ccc07645620 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -200,10 +200,12 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option match *clean_type { clean::ResolvedPath { ref path, .. } => { let segments = &path.segments; - let path_segment = segments.iter().last().unwrap_or_else(|| panic!( + let path_segment = segments.iter().last().unwrap_or_else(|| { + panic!( "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path", clean_type, accept_generic - )); + ) + }); Some(path_segment.name.clone()) } clean::Generic(ref s) if accept_generic => Some(s.clone()), diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index b722cfc8f75..0a836f46c0e 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -2,8 +2,9 @@ use crate::clean; use crate::config::OutputFormat; use crate::core::DocContext; use crate::fold::{self, DocFolder}; +use crate::html::markdown::{find_testable_code, ErrorCodes}; +use crate::passes::doc_test_lints::Tests; use crate::passes::Pass; - use rustc_span::symbol::sym; use rustc_span::FileName; use serde::Serialize; @@ -30,15 +31,19 @@ fn calculate_doc_coverage(krate: clean::Crate, ctx: &DocContext<'_>) -> clean::C struct ItemCount { total: u64, with_docs: u64, + with_examples: u64, } impl ItemCount { - fn count_item(&mut self, has_docs: bool) { + fn count_item(&mut self, has_docs: bool, has_doc_example: bool) { self.total += 1; if has_docs { self.with_docs += 1; } + if has_doc_example { + self.with_examples += 1; + } } fn percentage(&self) -> Option { @@ -48,13 +53,25 @@ impl ItemCount { None } } + + fn examples_percentage(&self) -> Option { + if self.total > 0 { + Some((self.with_examples as f64 * 100.0) / self.total as f64) + } else { + None + } + } } impl ops::Sub for ItemCount { type Output = Self; fn sub(self, rhs: Self) -> Self { - ItemCount { total: self.total - rhs.total, with_docs: self.with_docs - rhs.with_docs } + ItemCount { + total: self.total - rhs.total, + with_docs: self.with_docs - rhs.with_docs, + with_examples: self.with_examples - rhs.with_examples, + } } } @@ -62,6 +79,7 @@ impl ops::AddAssign for ItemCount { fn add_assign(&mut self, rhs: Self) { self.total += rhs.total; self.with_docs += rhs.with_docs; + self.with_examples += rhs.with_examples; } } @@ -103,33 +121,55 @@ impl CoverageCalculator { let mut total = ItemCount::default(); fn print_table_line() { - println!("+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", ""); + println!("+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", ""); } - fn print_table_record(name: &str, count: ItemCount, percentage: f64) { + fn print_table_record( + name: &str, + count: ItemCount, + percentage: f64, + examples_percentage: f64, + ) { println!( - "| {:<35} | {:>10} | {:>10} | {:>9.1}% |", - name, count.with_docs, count.total, percentage + "| {:<35} | {:>10} | {:>10} | {:>9.1}% | {:>10} | {:>9.1}% |", + name, + count.with_docs, + count.total, + percentage, + count.with_examples, + examples_percentage, ); } print_table_line(); println!( - "| {:<35} | {:>10} | {:>10} | {:>10} |", - "File", "Documented", "Total", "Percentage" + "| {:<35} | {:>10} | {:>10} | {:>10} | {:>10} | {:>10} |", + "File", "Documented", "Total", "Percentage", "Examples", "Percentage", ); print_table_line(); for (file, &count) in &self.items { - if let Some(percentage) = count.percentage() { - print_table_record(&limit_filename_len(file.to_string()), count, percentage); + if let (Some(percentage), Some(examples_percentage)) = + (count.percentage(), count.examples_percentage()) + { + print_table_record( + &limit_filename_len(file.to_string()), + count, + percentage, + examples_percentage, + ); total += count; } } print_table_line(); - print_table_record("Total", total, total.percentage().unwrap_or(0.0)); + print_table_record( + "Total", + total, + total.percentage().unwrap_or(0.0), + total.examples_percentage().unwrap_or(0.0), + ); print_table_line(); } } @@ -137,6 +177,17 @@ impl CoverageCalculator { impl fold::DocFolder for CoverageCalculator { fn fold_item(&mut self, i: clean::Item) -> Option { let has_docs = !i.attrs.doc_strings.is_empty(); + let mut tests = Tests { found_tests: 0 }; + + find_testable_code( + &i.attrs.doc_strings.iter().map(|d| d.as_str()).collect::>().join("\n"), + &mut tests, + ErrorCodes::No, + false, + None, + ); + + let has_doc_example = tests.found_tests != 0; match i.inner { _ if !i.def_id.is_local() => { @@ -187,7 +238,10 @@ impl fold::DocFolder for CoverageCalculator { } _ => { debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename); - self.items.entry(i.source.filename.clone()).or_default().count_item(has_docs); + self.items + .entry(i.source.filename.clone()) + .or_default() + .count_item(has_docs, has_doc_example); } } diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index aced7d55281..1fdc4ee247a 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -43,6 +43,22 @@ impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> { } } +pub(crate) struct Tests { + pub(crate) found_tests: usize, +} + +impl Tests { + pub(crate) fn new() -> Tests { + Tests { found_tests: 0 } + } +} + +impl crate::test::Tester for Tests { + fn add_test(&mut self, _: String, _: LangString, _: usize) { + self.found_tests += 1; + } +} + pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { let hir_id = match cx.as_local_hir_id(item.def_id) { Some(hir_id) => hir_id, @@ -52,17 +68,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { } }; - struct Tests { - found_tests: usize, - } - - impl crate::test::Tester for Tests { - fn add_test(&mut self, _: String, _: LangString, _: usize) { - self.found_tests += 1; - } - } - - let mut tests = Tests { found_tests: 0 }; + let mut tests = Tests::new(); find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None); -- cgit 1.4.1-3-g733a5 From f957bae74eb4e8847b0c0af5cd2c01812b110fc0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 18 Aug 2020 13:31:40 +0200 Subject: Update rustdoc-ui tests --- src/test/rustdoc-ui/coverage/basic.stdout | 14 +++++------ src/test/rustdoc-ui/coverage/doc-examples.rs | 27 ++++++++++++++++++++++ src/test/rustdoc-ui/coverage/doc-examples.stdout | 7 ++++++ src/test/rustdoc-ui/coverage/empty.stdout | 14 +++++------ src/test/rustdoc-ui/coverage/enums.stdout | 14 +++++------ src/test/rustdoc-ui/coverage/exotic.stdout | 16 ++++++------- src/test/rustdoc-ui/coverage/json.stdout | 2 +- src/test/rustdoc-ui/coverage/private.stdout | 14 +++++------ src/test/rustdoc-ui/coverage/statics-consts.stdout | 14 +++++------ src/test/rustdoc-ui/coverage/traits.stdout | 14 +++++------ 10 files changed, 85 insertions(+), 51 deletions(-) create mode 100644 src/test/rustdoc-ui/coverage/doc-examples.rs create mode 100644 src/test/rustdoc-ui/coverage/doc-examples.stdout (limited to 'src') diff --git a/src/test/rustdoc-ui/coverage/basic.stdout b/src/test/rustdoc-ui/coverage/basic.stdout index 3e916606316..7e795acc575 100644 --- a/src/test/rustdoc-ui/coverage/basic.stdout +++ b/src/test/rustdoc-ui/coverage/basic.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+ -| File | Documented | Total | Percentage | -+-------------------------------------+------------+------------+------------+ -| ...est/rustdoc-ui/coverage/basic.rs | 7 | 14 | 50.0% | -+-------------------------------------+------------+------------+------------+ -| Total | 7 | 14 | 50.0% | -+-------------------------------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+------------+ +| File | Documented | Total | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+------------+ +| ...est/rustdoc-ui/coverage/basic.rs | 7 | 14 | 50.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ +| Total | 7 | 14 | 50.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/doc-examples.rs b/src/test/rustdoc-ui/coverage/doc-examples.rs new file mode 100644 index 00000000000..cd718f8a34d --- /dev/null +++ b/src/test/rustdoc-ui/coverage/doc-examples.rs @@ -0,0 +1,27 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +//! This test ensure that only rust code examples are counted. + +/// Doc +/// +/// ``` +/// let x = 2; +/// ``` +pub struct Foo; + +/// Doc +/// +/// ```text +/// yolo +/// ``` +pub trait Bar {} + +/// Doc +/// +/// ```ignore (just for the sake of this test) +/// let x = 2; +/// ``` +pub fn foo(a: Foo, b: u32, c: T, d: D) -> u32 { + 0 +} diff --git a/src/test/rustdoc-ui/coverage/doc-examples.stdout b/src/test/rustdoc-ui/coverage/doc-examples.stdout new file mode 100644 index 00000000000..f25cf79a3f3 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/doc-examples.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+------------+ +| File | Documented | Total | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+------------+ +| ...tdoc-ui/coverage/doc-examples.rs | 4 | 4 | 100.0% | 2 | 50.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ +| Total | 4 | 4 | 100.0% | 2 | 50.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/empty.stdout b/src/test/rustdoc-ui/coverage/empty.stdout index 11b514fbfea..2a6a2231e5b 100644 --- a/src/test/rustdoc-ui/coverage/empty.stdout +++ b/src/test/rustdoc-ui/coverage/empty.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+ -| File | Documented | Total | Percentage | -+-------------------------------------+------------+------------+------------+ -| ...est/rustdoc-ui/coverage/empty.rs | 0 | 1 | 0.0% | -+-------------------------------------+------------+------------+------------+ -| Total | 0 | 1 | 0.0% | -+-------------------------------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+------------+ +| File | Documented | Total | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+------------+ +| ...est/rustdoc-ui/coverage/empty.rs | 0 | 1 | 0.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ +| Total | 0 | 1 | 0.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/enums.stdout b/src/test/rustdoc-ui/coverage/enums.stdout index 87e2ad9f20d..dd86f61f8d5 100644 --- a/src/test/rustdoc-ui/coverage/enums.stdout +++ b/src/test/rustdoc-ui/coverage/enums.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+ -| File | Documented | Total | Percentage | -+-------------------------------------+------------+------------+------------+ -| ...est/rustdoc-ui/coverage/enums.rs | 6 | 8 | 75.0% | -+-------------------------------------+------------+------------+------------+ -| Total | 6 | 8 | 75.0% | -+-------------------------------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+------------+ +| File | Documented | Total | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+------------+ +| ...est/rustdoc-ui/coverage/enums.rs | 6 | 8 | 75.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ +| Total | 6 | 8 | 75.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/exotic.stdout b/src/test/rustdoc-ui/coverage/exotic.stdout index 2bacfcfceca..f920a3abd36 100644 --- a/src/test/rustdoc-ui/coverage/exotic.stdout +++ b/src/test/rustdoc-ui/coverage/exotic.stdout @@ -1,8 +1,8 @@ -+-------------------------------------+------------+------------+------------+ -| File | Documented | Total | Percentage | -+-------------------------------------+------------+------------+------------+ -| ...st/rustdoc-ui/coverage/exotic.rs | 1 | 1 | 100.0% | -| | 2 | 2 | 100.0% | -+-------------------------------------+------------+------------+------------+ -| Total | 3 | 3 | 100.0% | -+-------------------------------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+------------+ +| File | Documented | Total | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+------------+ +| ...st/rustdoc-ui/coverage/exotic.rs | 1 | 1 | 100.0% | 0 | 0.0% | +| | 2 | 2 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ +| Total | 3 | 3 | 100.0% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/json.stdout b/src/test/rustdoc-ui/coverage/json.stdout index 63b22a7d94b..7b5b083e158 100644 --- a/src/test/rustdoc-ui/coverage/json.stdout +++ b/src/test/rustdoc-ui/coverage/json.stdout @@ -1 +1 @@ -{"$DIR/json.rs":{"total":13,"with_docs":7}} +{"$DIR/json.rs":{"total":13,"with_docs":7,"with_examples":0}} diff --git a/src/test/rustdoc-ui/coverage/private.stdout b/src/test/rustdoc-ui/coverage/private.stdout index 0d4c7c68fd0..bca3d51da59 100644 --- a/src/test/rustdoc-ui/coverage/private.stdout +++ b/src/test/rustdoc-ui/coverage/private.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+ -| File | Documented | Total | Percentage | -+-------------------------------------+------------+------------+------------+ -| ...t/rustdoc-ui/coverage/private.rs | 4 | 7 | 57.1% | -+-------------------------------------+------------+------------+------------+ -| Total | 4 | 7 | 57.1% | -+-------------------------------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+------------+ +| File | Documented | Total | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+------------+ +| ...t/rustdoc-ui/coverage/private.rs | 4 | 7 | 57.1% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ +| Total | 4 | 7 | 57.1% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/statics-consts.stdout b/src/test/rustdoc-ui/coverage/statics-consts.stdout index 8459f90ae7b..31b48cc602a 100644 --- a/src/test/rustdoc-ui/coverage/statics-consts.stdout +++ b/src/test/rustdoc-ui/coverage/statics-consts.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+ -| File | Documented | Total | Percentage | -+-------------------------------------+------------+------------+------------+ -| ...oc-ui/coverage/statics-consts.rs | 6 | 7 | 85.7% | -+-------------------------------------+------------+------------+------------+ -| Total | 6 | 7 | 85.7% | -+-------------------------------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+------------+ +| File | Documented | Total | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+------------+ +| ...oc-ui/coverage/statics-consts.rs | 6 | 7 | 85.7% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ +| Total | 6 | 7 | 85.7% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/coverage/traits.stdout b/src/test/rustdoc-ui/coverage/traits.stdout index e347a4da0b9..ac63b65023d 100644 --- a/src/test/rustdoc-ui/coverage/traits.stdout +++ b/src/test/rustdoc-ui/coverage/traits.stdout @@ -1,7 +1,7 @@ -+-------------------------------------+------------+------------+------------+ -| File | Documented | Total | Percentage | -+-------------------------------------+------------+------------+------------+ -| ...st/rustdoc-ui/coverage/traits.rs | 6 | 7 | 85.7% | -+-------------------------------------+------------+------------+------------+ -| Total | 6 | 7 | 85.7% | -+-------------------------------------+------------+------------+------------+ ++-------------------------------------+------------+------------+------------+------------+------------+ +| File | Documented | Total | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+------------+ +| ...st/rustdoc-ui/coverage/traits.rs | 6 | 7 | 85.7% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ +| Total | 6 | 7 | 85.7% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+------------+ -- cgit 1.4.1-3-g733a5 From ff73a409957d704aba735fb29ab4be2d77efe958 Mon Sep 17 00:00:00 2001 From: Tyson Nottingham Date: Mon, 17 Aug 2020 19:15:51 -0700 Subject: Don't emit "is not a logical operator" error outside of associative expressions Avoid showing this error where it doesn't make sense by not assuming "and" and "or" were intended to mean "&&" and "||" until after we decide to continue parsing input as an associative expression. Note that the decision of whether or not to continue parsing input as an associative expression doesn't actually depend on this assumption. Fixes #75599 --- src/librustc_parse/parser/expr.rs | 2 +- .../issue-54109-and_instead_of_ampersands.rs | 8 --- .../issue-54109-and_instead_of_ampersands.stderr | 82 +++------------------- .../did_you_mean/issue-54109-without-witness.fixed | 8 --- .../ui/did_you_mean/issue-54109-without-witness.rs | 8 --- .../issue-54109-without-witness.stderr | 80 +++------------------ src/test/ui/issues/issue-75599.rs | 24 +++++++ 7 files changed, 42 insertions(+), 170 deletions(-) create mode 100644 src/test/ui/issues/issue-75599.rs (limited to 'src') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 0ceb588b3af..d16347954fa 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -308,7 +308,7 @@ impl<'a> Parser<'a> { } fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool { - match (self.expr_is_complete(lhs), self.check_assoc_op().map(|op| op.node)) { + match (self.expr_is_complete(lhs), AssocOp::from_token(&self.token)) { // Semi-statement forms are odd: // See https://github.com/rust-lang/rust/issues/29071 (true, None) => false, diff --git a/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs b/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs index 467daef63f6..44421b077fa 100644 --- a/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs +++ b/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs @@ -5,10 +5,8 @@ fn test_and() { let b = false; let _ = a and b; //~ ERROR `and` is not a logical operator - //~| ERROR `and` is not a logical operator if a and b { //~ ERROR `and` is not a logical operator - //~| ERROR `and` is not a logical operator println!("both"); } @@ -20,10 +18,8 @@ fn test_or() { let b = false; let _ = a or b; //~ ERROR `or` is not a logical operator - //~| ERROR `or` is not a logical operator if a or b { //~ ERROR `or` is not a logical operator - //~| ERROR `or` is not a logical operator println!("both"); } } @@ -32,7 +28,6 @@ fn test_and_par() { let a = true; let b = false; if (a and b) { //~ ERROR `and` is not a logical operator - //~| ERROR `and` is not a logical operator println!("both"); } } @@ -41,7 +36,6 @@ fn test_or_par() { let a = true; let b = false; if (a or b) { //~ ERROR `or` is not a logical operator - //~| ERROR `or` is not a logical operator println!("both"); } } @@ -50,7 +44,6 @@ fn test_while_and() { let a = true; let b = false; while a and b { //~ ERROR `and` is not a logical operator - //~| ERROR `and` is not a logical operator println!("both"); } } @@ -59,7 +52,6 @@ fn test_while_or() { let a = true; let b = false; while a or b { //~ ERROR `or` is not a logical operator - //~| ERROR `or` is not a logical operator println!("both"); } } diff --git a/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr b/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr index e8731cf238e..528c62f501e 100644 --- a/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr +++ b/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr @@ -7,23 +7,7 @@ LL | let _ = a and b; = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators error: `and` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:7:15 - | -LL | let _ = a and b; - | ^^^ help: use `&&` to perform logical conjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - -error: `and` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:10:10 - | -LL | if a and b { - | ^^^ help: use `&&` to perform logical conjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - -error: `and` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:10:10 + --> $DIR/issue-54109-and_instead_of_ampersands.rs:9:10 | LL | if a and b { | ^^^ help: use `&&` to perform logical conjunction @@ -31,7 +15,7 @@ LL | if a and b { = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators error: `or` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:15 + --> $DIR/issue-54109-and_instead_of_ampersands.rs:20:15 | LL | let _ = a or b; | ^^ help: use `||` to perform logical disjunction @@ -39,23 +23,7 @@ LL | let _ = a or b; = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators error: `or` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:15 - | -LL | let _ = a or b; - | ^^ help: use `||` to perform logical disjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - -error: `or` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:25:10 - | -LL | if a or b { - | ^^ help: use `||` to perform logical disjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - -error: `or` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:25:10 + --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:10 | LL | if a or b { | ^^ help: use `||` to perform logical disjunction @@ -63,31 +31,15 @@ LL | if a or b { = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators error: `and` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:34:11 + --> $DIR/issue-54109-and_instead_of_ampersands.rs:30:11 | LL | if (a and b) { | ^^^ help: use `&&` to perform logical conjunction | = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators -error: `and` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:34:11 - | -LL | if (a and b) { - | ^^^ help: use `&&` to perform logical conjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - -error: `or` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:43:11 - | -LL | if (a or b) { - | ^^ help: use `||` to perform logical disjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - error: `or` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:43:11 + --> $DIR/issue-54109-and_instead_of_ampersands.rs:38:11 | LL | if (a or b) { | ^^ help: use `||` to perform logical disjunction @@ -95,31 +47,15 @@ LL | if (a or b) { = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators error: `and` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:52:13 + --> $DIR/issue-54109-and_instead_of_ampersands.rs:46:13 | LL | while a and b { | ^^^ help: use `&&` to perform logical conjunction | = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators -error: `and` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:52:13 - | -LL | while a and b { - | ^^^ help: use `&&` to perform logical conjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - -error: `or` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:61:13 - | -LL | while a or b { - | ^^ help: use `||` to perform logical disjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - error: `or` is not a logical operator - --> $DIR/issue-54109-and_instead_of_ampersands.rs:61:13 + --> $DIR/issue-54109-and_instead_of_ampersands.rs:54:13 | LL | while a or b { | ^^ help: use `||` to perform logical disjunction @@ -127,13 +63,13 @@ LL | while a or b { = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators error[E0308]: mismatched types - --> $DIR/issue-54109-and_instead_of_ampersands.rs:15:33 + --> $DIR/issue-54109-and_instead_of_ampersands.rs:13:33 | LL | let _recovery_witness: () = 0; | -- ^ expected `()`, found integer | | | expected due to this -error: aborting due to 17 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/did_you_mean/issue-54109-without-witness.fixed b/src/test/ui/did_you_mean/issue-54109-without-witness.fixed index 21471d75c82..5079a37f4da 100644 --- a/src/test/ui/did_you_mean/issue-54109-without-witness.fixed +++ b/src/test/ui/did_you_mean/issue-54109-without-witness.fixed @@ -11,10 +11,8 @@ fn test_and() { let b = false; let _ = a && b; //~ ERROR `and` is not a logical operator - //~| ERROR `and` is not a logical operator if a && b { //~ ERROR `and` is not a logical operator - //~| ERROR `and` is not a logical operator println!("both"); } } @@ -24,10 +22,8 @@ fn test_or() { let b = false; let _ = a || b; //~ ERROR `or` is not a logical operator - //~| ERROR `or` is not a logical operator if a || b { //~ ERROR `or` is not a logical operator - //~| ERROR `or` is not a logical operator println!("both"); } } @@ -36,7 +32,6 @@ fn test_and_par() { let a = true; let b = false; if (a && b) { //~ ERROR `and` is not a logical operator - //~| ERROR `and` is not a logical operator println!("both"); } } @@ -45,7 +40,6 @@ fn test_or_par() { let a = true; let b = false; if (a || b) { //~ ERROR `or` is not a logical operator - //~| ERROR `or` is not a logical operator println!("both"); } } @@ -54,7 +48,6 @@ fn test_while_and() { let a = true; let b = false; while a && b { //~ ERROR `and` is not a logical operator - //~| ERROR `and` is not a logical operator println!("both"); } } @@ -63,7 +56,6 @@ fn test_while_or() { let a = true; let b = false; while a || b { //~ ERROR `or` is not a logical operator - //~| ERROR `or` is not a logical operator println!("both"); } } diff --git a/src/test/ui/did_you_mean/issue-54109-without-witness.rs b/src/test/ui/did_you_mean/issue-54109-without-witness.rs index bb9a3a19596..00660a938d5 100644 --- a/src/test/ui/did_you_mean/issue-54109-without-witness.rs +++ b/src/test/ui/did_you_mean/issue-54109-without-witness.rs @@ -11,10 +11,8 @@ fn test_and() { let b = false; let _ = a and b; //~ ERROR `and` is not a logical operator - //~| ERROR `and` is not a logical operator if a and b { //~ ERROR `and` is not a logical operator - //~| ERROR `and` is not a logical operator println!("both"); } } @@ -24,10 +22,8 @@ fn test_or() { let b = false; let _ = a or b; //~ ERROR `or` is not a logical operator - //~| ERROR `or` is not a logical operator if a or b { //~ ERROR `or` is not a logical operator - //~| ERROR `or` is not a logical operator println!("both"); } } @@ -36,7 +32,6 @@ fn test_and_par() { let a = true; let b = false; if (a and b) { //~ ERROR `and` is not a logical operator - //~| ERROR `and` is not a logical operator println!("both"); } } @@ -45,7 +40,6 @@ fn test_or_par() { let a = true; let b = false; if (a or b) { //~ ERROR `or` is not a logical operator - //~| ERROR `or` is not a logical operator println!("both"); } } @@ -54,7 +48,6 @@ fn test_while_and() { let a = true; let b = false; while a and b { //~ ERROR `and` is not a logical operator - //~| ERROR `and` is not a logical operator println!("both"); } } @@ -63,7 +56,6 @@ fn test_while_or() { let a = true; let b = false; while a or b { //~ ERROR `or` is not a logical operator - //~| ERROR `or` is not a logical operator println!("both"); } } diff --git a/src/test/ui/did_you_mean/issue-54109-without-witness.stderr b/src/test/ui/did_you_mean/issue-54109-without-witness.stderr index fe48af592db..0350890c1fd 100644 --- a/src/test/ui/did_you_mean/issue-54109-without-witness.stderr +++ b/src/test/ui/did_you_mean/issue-54109-without-witness.stderr @@ -7,23 +7,7 @@ LL | let _ = a and b; = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators error: `and` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:13:15 - | -LL | let _ = a and b; - | ^^^ help: use `&&` to perform logical conjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - -error: `and` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:16:10 - | -LL | if a and b { - | ^^^ help: use `&&` to perform logical conjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - -error: `and` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:16:10 + --> $DIR/issue-54109-without-witness.rs:15:10 | LL | if a and b { | ^^^ help: use `&&` to perform logical conjunction @@ -31,7 +15,7 @@ LL | if a and b { = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators error: `or` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:26:15 + --> $DIR/issue-54109-without-witness.rs:24:15 | LL | let _ = a or b; | ^^ help: use `||` to perform logical disjunction @@ -39,23 +23,7 @@ LL | let _ = a or b; = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators error: `or` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:26:15 - | -LL | let _ = a or b; - | ^^ help: use `||` to perform logical disjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - -error: `or` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:29:10 - | -LL | if a or b { - | ^^ help: use `||` to perform logical disjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - -error: `or` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:29:10 + --> $DIR/issue-54109-without-witness.rs:26:10 | LL | if a or b { | ^^ help: use `||` to perform logical disjunction @@ -63,31 +31,15 @@ LL | if a or b { = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators error: `and` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:38:11 + --> $DIR/issue-54109-without-witness.rs:34:11 | LL | if (a and b) { | ^^^ help: use `&&` to perform logical conjunction | = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators -error: `and` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:38:11 - | -LL | if (a and b) { - | ^^^ help: use `&&` to perform logical conjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - -error: `or` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:47:11 - | -LL | if (a or b) { - | ^^ help: use `||` to perform logical disjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - error: `or` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:47:11 + --> $DIR/issue-54109-without-witness.rs:42:11 | LL | if (a or b) { | ^^ help: use `||` to perform logical disjunction @@ -95,36 +47,20 @@ LL | if (a or b) { = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators error: `and` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:56:13 + --> $DIR/issue-54109-without-witness.rs:50:13 | LL | while a and b { | ^^^ help: use `&&` to perform logical conjunction | = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators -error: `and` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:56:13 - | -LL | while a and b { - | ^^^ help: use `&&` to perform logical conjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - -error: `or` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:65:13 - | -LL | while a or b { - | ^^ help: use `||` to perform logical disjunction - | - = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators - error: `or` is not a logical operator - --> $DIR/issue-54109-without-witness.rs:65:13 + --> $DIR/issue-54109-without-witness.rs:58:13 | LL | while a or b { | ^^ help: use `||` to perform logical disjunction | = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators -error: aborting due to 16 previous errors +error: aborting due to 8 previous errors diff --git a/src/test/ui/issues/issue-75599.rs b/src/test/ui/issues/issue-75599.rs new file mode 100644 index 00000000000..0857676e4ed --- /dev/null +++ b/src/test/ui/issues/issue-75599.rs @@ -0,0 +1,24 @@ +// check-pass +#![allow(non_upper_case_globals)] + +const or: usize = 1; +const and: usize = 2; + +mod or { + pub const X: usize = 3; +} + +mod and { + pub const X: usize = 4; +} + +fn main() { + match 0 { + 0 => {} + or => {} + and => {} + or::X => {} + and::X => {} + _ => {} + } +} -- cgit 1.4.1-3-g733a5