Skip to content

Rollup of 8 pull requests #99159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
34e9e6d
Fix duplicated type annotation suggestion
danobi Jul 9, 2022
f0a99f9
Fixup diagnostic-derive test
danobi Jul 9, 2022
fc26ca1
check non_exhaustive attr and private fields for transparent types
fee1-dead Jul 7, 2022
5fb6784
add more tests
fee1-dead Jul 10, 2022
3ac69d7
Fix sized check ICE in intrisicck
compiler-errors Jul 10, 2022
6c44357
fix(doctest): treat fatal parse errors as incomplete attributes
notriddle Jul 11, 2022
033a025
Don't rerun the build script for the compiler each time on linux
jyn514 Jul 11, 2022
0c39762
Use fake substs to check for `Self: Sized` predicates on method recei…
compiler-errors Jul 11, 2022
88f2140
Do not suggest same trait over again
compiler-errors Jul 11, 2022
e3d84b2
clippy argument support
Milo123459 Jul 11, 2022
992346d
Fix rustdoc -Zhelp and -Chelp options
GuillaumeGomez Jul 8, 2022
b65d3a6
Add tests for -Chelp and -Zhelp
GuillaumeGomez Jul 8, 2022
f6f6187
Rollup merge of #97210 - Milo123459:clippy-args, r=jyn514
matthiaskrgr Jul 11, 2022
a19693d
Rollup merge of #99020 - fee1-dead-contrib:repr_transparent_non_exhau…
matthiaskrgr Jul 11, 2022
f240ca0
Rollup merge of #99055 - GuillaumeGomez:rustdoc-help-options, r=jyn514
matthiaskrgr Jul 11, 2022
4dddc7f
Rollup merge of #99075 - danobi:dup_type_hint_sugg, r=petrochenkov
matthiaskrgr Jul 11, 2022
0b6ed7b
Rollup merge of #99124 - compiler-errors:issue-99122, r=oli-obk
matthiaskrgr Jul 11, 2022
b16819d
Rollup merge of #99142 - notriddle:notriddle/doctest-multiline-crate-…
matthiaskrgr Jul 11, 2022
28428d5
Rollup merge of #99145 - jyn514:dont-rerun-build-script, r=wesleywiser
matthiaskrgr Jul 11, 2022
807a75a
Rollup merge of #99146 - compiler-errors:issue-61525, r=lcnr
matthiaskrgr Jul 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ fn main() {
let target_env = env::var("CARGO_CFG_TARGET_ENV");
if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() {
set_windows_exe_options();
} else {
// Avoid rerunning the build script every time.
println!("cargo:rerun-if-changed=build.rs");
}
}

Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_errors/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,14 @@ impl Diagnostic {
self
}

/// Clear any existing suggestions.
pub fn clear_suggestions(&mut self) -> &mut Self {
if let Ok(suggestions) = &mut self.suggestions {
suggestions.clear();
}
self
}

/// Helper for pushing to `self.suggestions`, if available (not disable).
fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
if let Ok(suggestions) = &mut self.suggestions {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_errors/src/diagnostic_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
forward!(pub fn set_is_lint(&mut self,) -> &mut Self);

forward!(pub fn disable_suggestions(&mut self,) -> &mut Self);
forward!(pub fn clear_suggestions(&mut self,) -> &mut Self);

forward!(pub fn multipart_suggestion(
&mut self,
Expand Down
51 changes: 51 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3132,6 +3132,56 @@ declare_lint! {
"detects unexpected names and values in `#[cfg]` conditions",
}

declare_lint! {
/// The `repr_transparent_external_private_fields` lint
/// detects types marked #[repr(trasparent)] that (transitively)
/// contain an external ZST type marked #[non_exhaustive]
///
/// ### Example
///
/// ```rust,ignore (needs external crate)
/// #![deny(repr_transparent_external_private_fields)]
/// use foo::NonExhaustiveZst;
///
/// #[repr(transparent)]
/// struct Bar(u32, ([u32; 0], NonExhaustiveZst));
/// ```
///
/// This will produce:
///
/// ```text
/// error: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead
/// --> src/main.rs:3:1
/// |
/// 3 | #[macro_use]
/// | ^^^^^^^^^^^^
/// |
/// note: the lint level is defined here
/// --> src/main.rs:1:9
/// |
/// 1 | #![deny(repr_transparent_external_private_fields)]
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// ```
///
/// ### Explanation
///
/// Previous, Rust accepted fields that contain external private zero-sized types,
/// even though it should not be a breaking change to add a non-zero-sized field to
/// that private type.
///
/// This is a [future-incompatible] lint to transition this
/// to a hard error in the future. See [issue #78586] for more details.
///
/// [issue #78586]: https://github.com/rust-lang/rust/issues/78586
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
Warn,
"tranparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #78586 <https://github.com/rust-lang/rust/issues/78586>",
};
}

declare_lint_pass! {
/// Does nothing as a lint pass, but registers some `Lint`s
/// that are used by other parts of the compiler.
Expand Down Expand Up @@ -3237,6 +3287,7 @@ declare_lint_pass! {
DEPRECATED_WHERE_CLAUSE_LOCATION,
TEST_UNSTABLE_LINT,
FFI_UNWIND_CALLS,
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2094,6 +2094,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
// |
// = note: cannot satisfy `_: Tt`

// Clear any more general suggestions in favor of our specific one
err.clear_suggestions();

err.span_suggestion_verbose(
span.shrink_to_hi(),
&format!(
Expand Down
71 changes: 66 additions & 5 deletions compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::subst::GenericArgKind;
Expand Down Expand Up @@ -1318,7 +1319,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
}
}

// For each field, figure out if it's known to be a ZST and align(1)
// For each field, figure out if it's known to be a ZST and align(1), with "known"
// respecting #[non_exhaustive] attributes.
let field_infos = adt.all_fields().map(|field| {
let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
let param_env = tcx.param_env(field.did);
Expand All @@ -1327,16 +1329,56 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
let span = tcx.hir().span_if_local(field.did).unwrap();
let zst = layout.map_or(false, |layout| layout.is_zst());
let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1);
(span, zst, align1)
if !zst {
return (span, zst, align1, None);
}

fn check_non_exhaustive<'tcx>(
tcx: TyCtxt<'tcx>,
t: Ty<'tcx>,
) -> ControlFlow<(&'static str, DefId, SubstsRef<'tcx>, bool)> {
match t.kind() {
ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)),
ty::Array(ty, _) => check_non_exhaustive(tcx, *ty),
ty::Adt(def, subst) => {
if !def.did().is_local() {
let non_exhaustive = def.is_variant_list_non_exhaustive()
|| def
.variants()
.iter()
.any(ty::VariantDef::is_field_list_non_exhaustive);
let has_priv = def.all_fields().any(|f| !f.vis.is_public());
if non_exhaustive || has_priv {
return ControlFlow::Break((
def.descr(),
def.did(),
subst,
non_exhaustive,
));
}
}
def.all_fields()
.map(|field| field.ty(tcx, subst))
.try_for_each(|t| check_non_exhaustive(tcx, t))
}
_ => ControlFlow::Continue(()),
}
}

(span, zst, align1, check_non_exhaustive(tcx, ty).break_value())
});

let non_zst_fields =
field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None });
let non_zst_fields = field_infos
.clone()
.filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None });
let non_zst_count = non_zst_fields.clone().count();
if non_zst_count >= 2 {
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
}
for (span, zst, align1) in field_infos {
let incompatible_zst_fields =
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
for (span, zst, align1, non_exhaustive) in field_infos {
if zst && !align1 {
struct_span_err!(
tcx.sess,
Expand All @@ -1348,6 +1390,25 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
.span_label(span, "has alignment larger than 1")
.emit();
}
if incompat && let Some((descr, def_id, substs, non_exhaustive)) = non_exhaustive {
tcx.struct_span_lint_hir(
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
span,
|lint| {
let note = if non_exhaustive {
"is marked with `#[non_exhaustive]`"
} else {
"contains private fields"
};
let field_ty = tcx.def_path_str_with_substs(def_id, substs);
lint.build("zero-sized fields in repr(transparent) cannot contain external non-exhaustive types")
.note(format!("this {descr} contains `{field_ty}`, which {note}, \
and makes it not a breaking change to become non-zero-sized in the future."))
.emit();
},
)
}
}
}

Expand Down
34 changes: 13 additions & 21 deletions compiler/rustc_typeck/src/check/intrinsicck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
use rustc_middle::ty::{self, Article, FloatTy, InferTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
use rustc_session::lint;
use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_target::abi::{Pointer, VariantIdx};
Expand Down Expand Up @@ -99,8 +99,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.emit();
}

// FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) {
// Type still may have region variables, but `Sized` does not depend
// on those, so just erase them before querying.
if self.tcx.erase_regions(ty).is_sized(self.tcx.at(DUMMY_SP), self.param_env) {
return true;
}
if let ty::Foreign(..) = ty.kind() {
Expand Down Expand Up @@ -128,30 +131,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
64 => InlineAsmType::I64,
_ => unreachable!(),
};

// Expect types to be fully resolved, no const or type variables.
if ty.has_infer_types_or_consts() {
assert!(self.is_tainted_by_errors());
return None;
}

let asm_ty = match *ty.kind() {
// `!` is allowed for input but not for output (issue #87802)
ty::Never if is_input => return None,
ty::Error(_) => return None,
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8),
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16),
// Somewhat of a hack: fallback in the presence of errors does not actually
// fall back to i32, but to ty::Error. For integer inference variables this
// means that they don't get any fallback and stay as `{integer}`.
// Since compilation can't succeed anyway, it's fine to use this to avoid printing
// "cannot use value of type `{integer}`", even though that would absolutely
// work due due i32 fallback if the current function had no other errors.
ty::Infer(InferTy::IntVar(_)) => {
assert!(self.is_tainted_by_errors());
Some(InlineAsmType::I32)
}
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32),
ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Some(InlineAsmType::I64),
ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Some(InlineAsmType::I128),
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(asm_ty_isize),
ty::Infer(InferTy::FloatVar(_)) => {
assert!(self.is_tainted_by_errors());
Some(InlineAsmType::F32)
}
ty::Float(FloatTy::F32) => Some(InlineAsmType::F32),
ty::Float(FloatTy::F64) => Some(InlineAsmType::F64),
ty::FnPtr(_) => Some(asm_ty_isize),
Expand Down Expand Up @@ -191,6 +187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => None,
}
}
ty::Infer(_) => unreachable!(),
_ => None,
};
let Some(asm_ty) = asm_ty else {
Expand All @@ -204,11 +201,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
};

if ty.has_infer_types_or_consts() {
assert!(self.is_tainted_by_errors());
return None;
}

// Check that the type implements Copy. The only case where this can
// possibly fail is for SIMD types which don't #[derive(Copy)].
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) {
Expand Down
26 changes: 15 additions & 11 deletions compiler/rustc_typeck/src/check/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,25 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick);
let all_substs = self.instantiate_method_substs(&pick, segment, rcvr_substs);

debug!("all_substs={:?}", all_substs);
debug!("rcvr_substs={rcvr_substs:?}, all_substs={all_substs:?}");

// Create the final signature for the method, replacing late-bound regions.
let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_substs);

// If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that
// something which derefs to `Self` actually implements the trait and the caller
// wanted to make a static dispatch on it but forgot to import the trait.
// See test `src/test/ui/issue-35976.rs`.
//
// In that case, we'll error anyway, but we'll also re-run the search with all traits
// in scope, and if we find another method which can be used, we'll output an
// appropriate hint suggesting to import the trait.
let filler_substs = rcvr_substs
.extend_to(self.tcx, pick.item.def_id, |def, _| self.tcx.mk_param_from_def(def));
let illegal_sized_bound = self.predicates_require_illegal_sized_bound(
&self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs),
);

// Unify the (adjusted) self type with what the method expects.
//
// SUBTLE: if we want good error messages, because of "guessing" while matching
Expand All @@ -106,16 +120,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// Make sure nobody calls `drop()` explicitly.
self.enforce_illegal_method_limitations(&pick);

// If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that
// something which derefs to `Self` actually implements the trait and the caller
// wanted to make a static dispatch on it but forgot to import the trait.
// See test `src/test/ui/issue-35976.rs`.
//
// In that case, we'll error anyway, but we'll also re-run the search with all traits
// in scope, and if we find another method which can be used, we'll output an
// appropriate hint suggesting to import the trait.
let illegal_sized_bound = self.predicates_require_illegal_sized_bound(&method_predicates);

// Add any trait/regions obligations specified on the method's type parameters.
// We won't add these if we encountered an illegal sized bound, so that we can use
// a custom error in that case.
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_typeck/src/check/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use rustc_hir::def_id::DefId;
use rustc_infer::infer::{self, InferOk};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable};
use rustc_middle::ty::{DefIdTree, GenericParamDefKind};
use rustc_span::symbol::Ident;
use rustc_span::Span;
use rustc_trait_selection::traits;
Expand Down Expand Up @@ -221,7 +221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

// We probe again, taking all traits into account (not only those in scope).
let candidates = match self.lookup_probe(
let mut candidates = match self.lookup_probe(
span,
segment.ident,
self_ty,
Expand All @@ -243,6 +243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.collect(),
_ => Vec::new(),
};
candidates.retain(|candidate| *candidate != self.tcx.parent(result.callee.def_id));

return Err(IllegalSizedBound(candidates, needs_mut, span));
}
Expand Down
Loading