Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 20 additions & 8 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use rustc_hir::attrs::{
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::{self as hir, Attribute, find_attr};
use rustc_macros::Diagnostic;
use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
};
Expand Down Expand Up @@ -385,6 +386,17 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code
}
}

#[derive(Diagnostic)]
#[diag("non-default `sanitize` will have no effect after inlining")]
struct SanitizeOnInline {
#[note("inlining requested here")]
inline_span: Span,
}

#[derive(Diagnostic)]
#[diag("the async executor can run blocking code, without realtime sanitizer catching it")]
struct AsyncBlocking;

fn check_result(
tcx: TyCtxt<'_>,
did: LocalDefId,
Expand Down Expand Up @@ -425,10 +437,12 @@ fn check_result(
(interesting_spans.sanitize, interesting_spans.inline)
{
let hir_id = tcx.local_def_id_to_hir_id(did);
tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, sanitize_span, |lint| {
lint.primary_message("non-default `sanitize` will have no effect after inlining");
lint.span_note(inline_span, "inlining requested here");
})
tcx.emit_node_span_lint(
lint::builtin::INLINE_NO_SANITIZE,
hir_id,
sanitize_span,
SanitizeOnInline { inline_span },
)
}

// warn for nonblocking async functions, blocks and closures.
Expand All @@ -445,13 +459,11 @@ fn check_result(
!= rustc_hir::ClosureKind::Closure))
{
let hir_id = tcx.local_def_id_to_hir_id(did);
tcx.node_span_lint(
tcx.emit_node_span_lint(
lint::builtin::RTSAN_NONBLOCKING_ASYNC,
hir_id,
sanitize_span,
|lint| {
lint.primary_message(r#"the async executor can run blocking code, without realtime sanitizer catching it"#);
}
AsyncBlocking,
);
}

Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_errors/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError {
pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> {
/// Write out as a diagnostic out of `DiagCtxt`.
#[must_use]
#[track_caller]
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G>;
}

Expand Down Expand Up @@ -139,15 +140,15 @@ where
}

#[derive(Clone, Debug, Encodable, Decodable)]
pub(crate) struct DiagLocation {
pub struct DiagLocation {
file: Cow<'static, str>,
line: u32,
col: u32,
}

impl DiagLocation {
#[track_caller]
fn caller() -> Self {
pub fn caller() -> Self {
let loc = panic::Location::caller();
DiagLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }
}
Expand Down Expand Up @@ -248,7 +249,7 @@ pub struct DiagInner {
pub long_ty_path: Option<PathBuf>,
/// With `-Ztrack_diagnostics` enabled,
/// we print where in rustc this error was emitted.
pub(crate) emitted_at: DiagLocation,
pub emitted_at: DiagLocation,
}

impl DiagInner {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ pub use anstyle::{
pub use codes::*;
pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
pub use diagnostic::{
BugAbort, Diag, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee, FatalAbort,
StringPart, Subdiag, Subdiagnostic,
BugAbort, Diag, DiagInner, DiagLocation, DiagStyledString, Diagnostic, EmissionGuarantee,
FatalAbort, StringPart, Subdiag, Subdiagnostic,
};
pub use diagnostic_impls::{
DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
Expand Down
99 changes: 66 additions & 33 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ use std::ops::ControlFlow;
use rustc_abi::{ExternAbi, FieldIdx, ScalableElt};
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::codes::*;
use rustc_errors::{EmissionGuarantee, MultiSpan};
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan};
use rustc_hir as hir;
use rustc_hir::attrs::ReprAttr::ReprPacked;
use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::{LangItem, Node, find_attr, intravisit};
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::{Obligation, ObligationCauseCode, WellFormedLoc};
use rustc_lint_defs::builtin::{REPR_TRANSPARENT_NON_ZST_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS};
use rustc_macros::Diagnostic;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
use rustc_middle::middle::stability::EvalResult;
Expand Down Expand Up @@ -53,6 +54,22 @@ fn add_abi_diag_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T
}

pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) {
struct UnsupportedCallingConventions {
abi: ExternAbi,
}

impl<'a> Diagnostic<'a, ()> for UnsupportedCallingConventions {
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
let Self { abi } = self;
let mut lint = Diag::new(
dcx,
level,
format!("{abi} is not a supported ABI for the current target"),
);
add_abi_diag_help(abi, &mut lint);
lint
}
}
// FIXME: This should be checked earlier, e.g. in `rustc_ast_lowering`, as this
// currently only guards function imports, function definitions, and function pointer types.
// Functions in trait declarations can still use "deprecated" ABIs without any warning.
Expand All @@ -64,12 +81,12 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi
tcx.dcx().span_delayed_bug(span, format!("{abi} should be rejected in ast_lowering"));
}
AbiMapping::Deprecated(..) => {
tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
lint.primary_message(format!(
"{abi} is not a supported ABI for the current target"
));
add_abi_diag_help(abi, lint);
});
tcx.emit_node_span_lint(
UNSUPPORTED_CALLING_CONVENTIONS,
hir_id,
span,
UnsupportedCallingConventions { abi },
);
}
}
}
Expand Down Expand Up @@ -174,6 +191,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b

/// Check that a `static` is inhabited.
fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
#[derive(Diagnostic)]
#[diag("static of uninhabited type")]
#[note("uninhabited statics cannot be initialized, and any access would be an immediate error")]
struct StaticOfUninhabitedType;

// Make sure statics are inhabited.
// Other parts of the compiler assume that there are no uninhabited places. In principle it
// would be enough to check this for `extern` statics, as statics with an initializer will
Expand Down Expand Up @@ -204,15 +226,11 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
}
};
if layout.is_uninhabited() {
tcx.node_span_lint(
tcx.emit_node_span_lint(
UNINHABITED_STATIC,
tcx.local_def_id_to_hir_id(def_id),
span,
|lint| {
lint.primary_message("static of uninhabited type");
lint
.note("uninhabited statics cannot be initialized, and any access would be an immediate error");
},
StaticOfUninhabitedType,
);
}
}
Expand Down Expand Up @@ -1637,6 +1655,39 @@ pub(super) fn check_packed_inner(
}

pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
struct ZeroSizedFieldReprTransparentIncompatibility<'tcx> {
unsuited: UnsuitedInfo<'tcx>,
}

impl<'a, 'tcx> Diagnostic<'a, ()> for ZeroSizedFieldReprTransparentIncompatibility<'tcx> {
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
let Self { unsuited } = self;
let (title, note) = match unsuited.reason {
UnsuitedReason::NonExhaustive => (
"external non-exhaustive types",
"is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.",
),
UnsuitedReason::PrivateField => (
"external types with private fields",
"contains private fields, so it could become non-zero-sized in the future.",
),
UnsuitedReason::ReprC => (
"`repr(C)` types",
"is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.",
),
};
Diag::new(
dcx,
level,
format!("zero-sized fields in `repr(transparent)` cannot contain {title}"),
)
.with_note(format!(
"this field contains `{field_ty}`, which {note}",
field_ty = unsuited.ty,
))
}
}

if !adt.repr().transparent() {
return;
}
Expand Down Expand Up @@ -1747,29 +1798,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
// If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
// Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
if non_trivial_count > 0 || prev_unsuited_1zst {
tcx.node_span_lint(
tcx.emit_node_span_lint(
REPR_TRANSPARENT_NON_ZST_FIELDS,
tcx.local_def_id_to_hir_id(adt.did().expect_local()),
field.span,
|lint| {
let title = match unsuited.reason {
UnsuitedReason::NonExhaustive => "external non-exhaustive types",
UnsuitedReason::PrivateField => "external types with private fields",
UnsuitedReason::ReprC => "`repr(C)` types",
};
lint.primary_message(
format!("zero-sized fields in `repr(transparent)` cannot contain {title}"),
);
let note = match unsuited.reason {
UnsuitedReason::NonExhaustive => "is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.",
UnsuitedReason::PrivateField => "contains private fields, so it could become non-zero-sized in the future.",
UnsuitedReason::ReprC => "is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.",
};
lint.note(format!(
"this field contains `{field_ty}`, which {note}",
field_ty = unsuited.ty,
));
},
ZeroSizedFieldReprTransparentIncompatibility { unsuited },
);
} else {
prev_unsuited_1zst = true;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ use std::num::NonZero;
pub use check::{check_abi, check_custom_abi};
use rustc_abi::VariantIdx;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
use rustc_errors::{ErrorGuaranteed, pluralize, struct_span_code_err};
use rustc_hir::LangItem;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
Expand Down
31 changes: 24 additions & 7 deletions compiler/rustc_hir_analysis/src/check_unused.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
use rustc_data_structures::unord::{ExtendUnord, UnordSet};
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint;
use rustc_span::Span;
use tracing::debug;

struct UnusedImport<'tcx> {
tcx: TyCtxt<'tcx>,
span: Span,
}

impl<'a, 'tcx> Diagnostic<'a, ()> for UnusedImport<'tcx> {
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
let Self { tcx, span } = self;
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
Diag::new(dcx, level, format!("unused import: `{snippet}`"))
} else {
Diag::new(dcx, level, "unused import")
}
}
}

pub(super) fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) {
let mut used_trait_imports = UnordSet::<LocalDefId>::default();

Expand All @@ -31,12 +49,11 @@ pub(super) fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) {
continue;
}
let (path, _) = item.expect_use();
tcx.node_span_lint(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| {
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
lint.primary_message(format!("unused import: `{snippet}`"));
} else {
lint.primary_message("unused import");
}
});
tcx.emit_node_span_lint(
lint::builtin::UNUSED_IMPORTS,
item.hir_id(),
path.span,
UnusedImport { tcx, span: path.span },
);
}
}
25 changes: 18 additions & 7 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ use rustc_abi::{ExternAbi, Size};
use rustc_ast::Recovered;
use rustc_data_structures::assert_matches;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey};
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, Diagnostic, E0228, ErrorGuaranteed, Level, StashKey,
};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
Expand Down Expand Up @@ -610,6 +612,19 @@ pub(super) fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
}

pub(super) fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: LocalDefId) {
struct ReprCIssue {
msg: &'static str,
}

impl<'a> Diagnostic<'a, ()> for ReprCIssue {
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
let Self { msg } = self;
Diag::new(dcx, level, msg)
.with_note("`repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C")
.with_help("use `repr($int_ty)` instead to explicitly set the size of this enum")
}
}

let def = tcx.adt_def(def_id);
let repr_type = def.repr().discr_type();
let initial = repr_type.initial_discriminant(tcx);
Expand Down Expand Up @@ -659,15 +674,11 @@ pub(super) fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: LocalDefId) {
} else {
"`repr(C)` enum discriminant does not fit into C `int`, and a previous discriminant does not fit into C `unsigned int`"
};
tcx.node_span_lint(
tcx.emit_node_span_lint(
rustc_session::lint::builtin::REPR_C_ENUMS_LARGER_THAN_INT,
tcx.local_def_id_to_hir_id(def_id),
span,
|d| {
d.primary_message(msg)
.note("`repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C")
.help("use `repr($int_ty)` instead to explicitly set the size of this enum");
}
ReprCIssue { msg },
);
}
}
Expand Down
Loading
Loading