Skip to content

Commit d9b9e50

Browse files
committed
Auto merge of #156374 - JonathanBrouwer:rollup-Orm2U9C, r=JonathanBrouwer
Rollup of 10 pull requests Successful merges: - #148214 (Consider `Result<T, Uninhabited>` and `ControlFlow<Uninhabited, T>` to be equivalent to `T` for must use lint) - #149362 (Add Command::get_resolved_envs) - #155705 (Add `str::word_to_titlecase()` to `alloc`) - #155970 (Add mention of sendfile(2) and splice(2) to fs::copy() documentation.) - #156006 (Update a bunch of bootstrap dependencies to remove windows-target) - #155188 (Add regression test for issue 144329) - #155515 (error on empty `export_name`) - #155817 (validate `#[link_name = "..."]` & `#[link(name = "...")]` parameters) - #156107 (remove turbofish notation + use None / Some instead of Option:: (in match documentation)) - #156133 (mark some panicking methods around Duration as track_caller)
2 parents 82bee96 + 390a757 commit d9b9e50

26 files changed

Lines changed: 621 additions & 277 deletions

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use rustc_span::edition::Edition::Edition2024;
55
use super::prelude::*;
66
use crate::attributes::AttributeSafety;
77
use crate::session_diagnostics::{
8-
NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector,
9-
ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
8+
EmptyExportName, NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass,
9+
NullOnObjcSelector, ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
1010
};
1111
use crate::target_checking::Policy::AllowSilent;
1212

@@ -129,6 +129,12 @@ impl SingleAttributeParser for ExportNameParser {
129129
cx.emit_err(NullOnExport { span: cx.attr_span });
130130
return None;
131131
}
132+
if name.is_empty() {
133+
// LLVM will make up a name if the empty string is given, but that name will be
134+
// inconsistent between compilation units, causing linker errors.
135+
cx.emit_err(EmptyExportName { span: cx.attr_span });
136+
return None;
137+
}
132138
Some(AttributeKind::ExportName { name, span: cx.attr_span })
133139
}
134140
}

compiler/rustc_attr_parsing/src/attributes/link_attrs.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::session_diagnostics::{
1717
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
1818
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
1919
InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple, LinkOrdinalOutOfRange,
20-
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
20+
LinkRequiresName, MultipleModifiers, NullOnLinkName, NullOnLinkSection, RawDylibOnlyWindows,
2121
WholeArchiveNeedsStatic,
2222
};
2323

@@ -42,6 +42,19 @@ impl SingleAttributeParser for LinkNameParser {
4242
return None;
4343
};
4444

45+
if name.as_str().contains('\0') {
46+
// `#[link_name = ...]` will be converted to a null-terminated string,
47+
// so it may not contain any null characters.
48+
cx.emit_err(NullOnLinkName { span: nv.value_span });
49+
return None;
50+
}
51+
if name.is_empty() {
52+
// Otherwise LLVM will just make up a name and the linker will fail
53+
// to find an empty symbol name.
54+
cx.emit_err(EmptyLinkName { span: nv.value_span });
55+
return None;
56+
}
57+
4558
Some(LinkName { name, span: cx.attr_span })
4659
}
4760
}
@@ -218,7 +231,7 @@ impl CombineAttributeParser for LinkParser {
218231
if wasm_import_module.is_some() {
219232
(name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
220233
}
221-
let Some((name, name_span)) = name else {
234+
let Some((name, _name_span)) = name else {
222235
cx.emit_err(LinkRequiresName { span: cx.attr_span });
223236
return None;
224237
};
@@ -230,12 +243,6 @@ impl CombineAttributeParser for LinkParser {
230243
}
231244
}
232245

233-
if let Some(NativeLibKind::RawDylib { .. }) = kind
234-
&& name.as_str().contains('\0')
235-
{
236-
cx.emit_err(RawDylibNoNul { span: name_span });
237-
}
238-
239246
Some(LinkEntry {
240247
span: cx.attr_span,
241248
kind: kind.unwrap_or(NativeLibKind::Unspecified),
@@ -265,9 +272,13 @@ impl LinkParser {
265272
return false;
266273
};
267274

275+
if link_name.as_str().contains('\0') {
276+
cx.emit_err(NullOnLinkName { span: nv.value_span });
277+
}
268278
if link_name.is_empty() {
269279
cx.emit_err(EmptyLinkName { span: nv.value_span });
270280
}
281+
271282
*name = Some((link_name, nv.value_span));
272283
true
273284
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,13 @@ pub(crate) struct UnusedMultiple {
396396
pub name: Symbol,
397397
}
398398

399+
#[derive(Diagnostic)]
400+
#[diag("`export_name` may not be empty")]
401+
pub(crate) struct EmptyExportName {
402+
#[primary_span]
403+
pub span: Span,
404+
}
405+
399406
#[derive(Diagnostic)]
400407
#[diag("`export_name` may not contain null characters", code = E0648)]
401408
pub(crate) struct NullOnExport {
@@ -410,6 +417,13 @@ pub(crate) struct NullOnLinkSection {
410417
pub span: Span,
411418
}
412419

420+
#[derive(Diagnostic)]
421+
#[diag("link name may not contain null characters", code = E0648)]
422+
pub(crate) struct NullOnLinkName {
423+
#[primary_span]
424+
pub span: Span,
425+
}
426+
413427
#[derive(Diagnostic)]
414428
#[diag("`objc::class!` may not contain null characters")]
415429
pub(crate) struct NullOnObjcClass {
@@ -984,13 +998,6 @@ pub(crate) struct LinkRequiresName {
984998
pub span: Span,
985999
}
9861000

987-
#[derive(Diagnostic)]
988-
#[diag("link name must not contain NUL characters if link kind is `raw-dylib`")]
989-
pub(crate) struct RawDylibNoNul {
990-
#[primary_span]
991-
pub span: Span,
992-
}
993-
9941001
#[derive(Diagnostic)]
9951002
#[diag("link kind `raw-dylib` is only supported on Windows targets", code = E0455)]
9961003
pub(crate) struct RawDylibOnlyWindows {

compiler/rustc_lint/src/unused/must_use.rs

Lines changed: 11 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -133,18 +133,11 @@ pub enum MustUsePath {
133133

134134
/// Returns `Some(path)` if `ty` should be considered as "`must_use`" in the context of `expr`
135135
/// (`expr` is used to get the parent module, which can affect which types are considered uninhabited).
136-
///
137-
/// If `simplify_uninhabited` is true, this function considers `Result<T, Uninhabited>` and
138-
/// `ControlFlow<Uninhabited, T>` the same as `T` (we don't set this *yet* in rustc, but expose this
139-
/// so clippy can use this).
140-
//
141-
// FIXME: remove `simplify_uninhabited` once clippy had a release with the new semantics.
142136
#[instrument(skip(cx, expr), level = "debug", ret)]
143137
pub fn is_ty_must_use<'tcx>(
144138
cx: &LateContext<'tcx>,
145139
ty: Ty<'tcx>,
146140
expr: &hir::Expr<'_>,
147-
simplify_uninhabited: bool,
148141
) -> IsTyMustUse {
149142
if ty.is_unit() {
150143
return IsTyMustUse::Trivial;
@@ -157,50 +150,29 @@ pub fn is_ty_must_use<'tcx>(
157150
match *ty.kind() {
158151
_ if is_uninhabited(ty) => IsTyMustUse::Trivial,
159152
ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => {
160-
is_ty_must_use(cx, boxed, expr, simplify_uninhabited)
161-
.map(|inner| MustUsePath::Boxed(Box::new(inner)))
153+
is_ty_must_use(cx, boxed, expr).map(|inner| MustUsePath::Boxed(Box::new(inner)))
162154
}
163155
ty::Adt(def, args) if cx.tcx.is_lang_item(def.did(), LangItem::Pin) => {
164156
let pinned_ty = args.type_at(0);
165-
is_ty_must_use(cx, pinned_ty, expr, simplify_uninhabited)
166-
.map(|inner| MustUsePath::Pinned(Box::new(inner)))
157+
is_ty_must_use(cx, pinned_ty, expr).map(|inner| MustUsePath::Pinned(Box::new(inner)))
167158
}
168159
// Consider `Result<T, Uninhabited>` (e.g. `Result<(), !>`) equivalent to `T`.
169160
ty::Adt(def, args)
170-
if simplify_uninhabited
171-
&& cx.tcx.is_diagnostic_item(sym::Result, def.did())
161+
if cx.tcx.is_diagnostic_item(sym::Result, def.did())
172162
&& is_uninhabited(args.type_at(1)) =>
173163
{
174164
let ok_ty = args.type_at(0);
175-
is_ty_must_use(cx, ok_ty, expr, simplify_uninhabited)
176-
.map(|path| MustUsePath::Result(Box::new(path)))
165+
is_ty_must_use(cx, ok_ty, expr).map(|path| MustUsePath::Result(Box::new(path)))
177166
}
178167
// Consider `ControlFlow<Uninhabited, T>` (e.g. `ControlFlow<!, ()>`) equivalent to `T`.
179168
ty::Adt(def, args)
180-
if simplify_uninhabited
181-
&& cx.tcx.is_diagnostic_item(sym::ControlFlow, def.did())
169+
if cx.tcx.is_diagnostic_item(sym::ControlFlow, def.did())
182170
&& is_uninhabited(args.type_at(0)) =>
183171
{
184172
let continue_ty = args.type_at(1);
185-
is_ty_must_use(cx, continue_ty, expr, simplify_uninhabited)
173+
is_ty_must_use(cx, continue_ty, expr)
186174
.map(|path| MustUsePath::ControlFlow(Box::new(path)))
187175
}
188-
// Suppress warnings on `Result<(), Uninhabited>` (e.g. `Result<(), !>`).
189-
ty::Adt(def, args)
190-
if cx.tcx.is_diagnostic_item(sym::Result, def.did())
191-
&& args.type_at(0).is_unit()
192-
&& is_uninhabited(args.type_at(1)) =>
193-
{
194-
IsTyMustUse::Trivial
195-
}
196-
// Suppress warnings on `ControlFlow<Uninhabited, ()>` (e.g. `ControlFlow<!, ()>`).
197-
ty::Adt(def, args)
198-
if cx.tcx.is_diagnostic_item(sym::ControlFlow, def.did())
199-
&& args.type_at(1).is_unit()
200-
&& is_uninhabited(args.type_at(0)) =>
201-
{
202-
IsTyMustUse::Trivial
203-
}
204176
ty::Adt(def, _) => {
205177
is_def_must_use(cx, def.did(), expr.span).map_or(IsTyMustUse::No, IsTyMustUse::Yes)
206178
}
@@ -258,7 +230,7 @@ pub fn is_ty_must_use<'tcx>(
258230
let mut nested_must_use = Vec::new();
259231

260232
tys.iter().zip(elem_exprs).enumerate().for_each(|(i, (ty, expr))| {
261-
let must_use = is_ty_must_use(cx, ty, expr, simplify_uninhabited);
233+
let must_use = is_ty_must_use(cx, ty, expr);
262234

263235
all_trivial &= matches!(must_use, IsTyMustUse::Trivial);
264236
if let IsTyMustUse::Yes(path) = must_use {
@@ -280,8 +252,9 @@ pub fn is_ty_must_use<'tcx>(
280252
// If the array is empty we don't lint, to avoid false positives
281253
Some(0) | None => IsTyMustUse::No,
282254
// If the array is definitely non-empty, we can do `#[must_use]` checking.
283-
Some(len) => is_ty_must_use(cx, ty, expr, simplify_uninhabited)
284-
.map(|inner| MustUsePath::Array(Box::new(inner), len)),
255+
Some(len) => {
256+
is_ty_must_use(cx, ty, expr).map(|inner| MustUsePath::Array(Box::new(inner), len))
257+
}
285258
},
286259
ty::Closure(..) | ty::CoroutineClosure(..) => {
287260
IsTyMustUse::Yes(MustUsePath::Closure(expr.span))
@@ -345,7 +318,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
345318

346319
let ty = cx.typeck_results().expr_ty(expr);
347320

348-
let must_use_result = is_ty_must_use(cx, ty, expr, false);
321+
let must_use_result = is_ty_must_use(cx, ty, expr);
349322
let type_lint_emitted_or_trivial = match must_use_result {
350323
IsTyMustUse::Yes(path) => {
351324
emit_must_use_untranslated(cx, &path, "", "", 1, false, expr_is_from_block);

0 commit comments

Comments
 (0)