Skip to content

Commit 3522c34

Browse files
committed
Auto merge of #158487 - JonathanBrouwer:rollup-ln8LEcs, r=JonathanBrouwer
Rollup of 13 pull requests Successful merges: - #157871 ([rustdoc] Update `doc_cfg` hide/show syntax) - #158234 (Cross-referencing tuple_trait tracking issue, source and the Unstable Book) - #158480 (add smoketest for std::net::hostname) - #157625 (Use infer tys for synthetic params when lowering const paths point to fns) - #158290 (add crashtests [1/N]) - #158306 (tests: modify s390x vector test to be robust to instruction scheduling) - #158313 (Move `check_target_feature` into the attribute parser) - #158431 (More lint cleanups) - #158452 (Add missing links in integer docs) - #158467 (Add proc macro for unused assignments and corresponding test) - #158472 (Add regression test for unexpected pointer dereference issue) - #158475 (Fix doc comment on get_debug_as_hex.) - #158476 (Fix doc comment on FormattingOptions::new().)
2 parents cb41b6d + a85522c commit 3522c34

88 files changed

Lines changed: 1326 additions & 460 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::attributes::AttributeSafety;
1010
use crate::session_diagnostics::{
1111
EmptyExportName, NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass,
1212
NullOnObjcSelector, ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
13-
SanitizeInvalidStatic,
13+
SanitizeInvalidStatic, TargetFeatureOnLangItem,
1414
};
1515
use crate::target_checking::Policy::AllowSilent;
1616

@@ -524,15 +524,6 @@ impl CombineAttributeParser for TargetFeatureParser {
524524
was_forced: false,
525525
};
526526
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
527-
const STABILITY: AttributeStability = AttributeStability::Stable;
528-
529-
fn extend(
530-
cx: &mut AcceptContext<'_, '_>,
531-
args: &ArgParser,
532-
) -> impl IntoIterator<Item = Self::Item> {
533-
parse_tf_attribute(cx, args)
534-
}
535-
536527
const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
537528
Allow(Target::Fn),
538529
Allow(Target::Method(MethodKind::Inherent)),
@@ -544,6 +535,29 @@ impl CombineAttributeParser for TargetFeatureParser {
544535
Warn(Target::MacroDef),
545536
Warn(Target::MacroCall),
546537
]);
538+
const STABILITY: AttributeStability = AttributeStability::Stable;
539+
540+
fn extend(
541+
cx: &mut AcceptContext<'_, '_>,
542+
args: &ArgParser,
543+
) -> impl IntoIterator<Item = Self::Item> {
544+
parse_tf_attribute(cx, args)
545+
}
546+
547+
fn finalize_check(cx: &FinalizeContext<'_, '_>, attr_span: Span) {
548+
// `#[target_feature]` is incompatible with lang item functions,
549+
// except on WASM where calling target-feature functions is safe (see #84988).
550+
if !cx.sess().target.is_like_wasm && !cx.sess().opts.actually_rustdoc {
551+
// `#[panic_handler]` is checked first so it takes priority in the diagnostic.
552+
let lang_kind = cx
553+
.all_attrs
554+
.iter()
555+
.find_map(|a| [sym::panic_handler, sym::lang].into_iter().find(|&s| a.word_is(s)));
556+
if let Some(kind) = lang_kind {
557+
cx.emit_err(TargetFeatureOnLangItem { attr_span, kind, item_span: cx.target_span });
558+
}
559+
}
560+
}
547561
}
548562

549563
pub(crate) struct ForceTargetFeatureParser;

compiler/rustc_attr_parsing/src/attributes/doc.rs

Lines changed: 133 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
11
use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit};
2+
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, IndexEntry};
23
use rustc_errors::{Applicability, msg};
34
use rustc_feature::AttributeStability;
45
use rustc_hir::Target;
56
use rustc_hir::attrs::{
6-
AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow,
7+
AttributeKind, CfgEntry, CfgHideShow, DocAttribute, DocCfgHideShow, DocCfgHideShowValue,
8+
DocInline, HideOrShow,
79
};
810
use rustc_session::errors::feature_err;
911
use rustc_span::{Span, Symbol, edition, sym};
10-
use thin_vec::ThinVec;
1112

1213
use super::prelude::{ALL_TARGETS, AllowedTargets};
1314
use super::{AcceptMapping, AttributeParser, template};
1415
use crate::context::{AcceptContext, FinalizeContext};
1516
use crate::diagnostics::{
1617
AttrCrateLevelOnly, DocAliasDuplicated, DocAutoCfgExpectsHideOrShow,
17-
DocAutoCfgHideShowExpectsList, DocAutoCfgHideShowUnexpectedItem, DocAutoCfgWrongLiteral,
18-
DocTestLiteral, DocTestTakesList, DocTestUnknown, DocUnknownAny, DocUnknownInclude,
19-
DocUnknownPasses, DocUnknownPlugins, DocUnknownSpotlight, ExpectedNameValue, ExpectedNoArgs,
20-
IllFormedAttributeInput, MalformedDoc,
18+
DocAutoCfgHideShowExpectsList, DocAutoCfgHideShowNoIdentBeforeValues,
19+
DocAutoCfgHideShowUnexpectedItem, DocAutoCfgHideShowUnexpectedItemAfterValues,
20+
DocAutoCfgHideShowValuesMix, DocAutoCfgWrongLiteral, DocTestLiteral, DocTestTakesList,
21+
DocTestUnknown, DocUnknownAny, DocUnknownInclude, DocUnknownPasses, DocUnknownPlugins,
22+
DocUnknownSpotlight, ExpectedNameValue, ExpectedNoArgs, IllFormedAttributeInput, MalformedDoc,
23+
};
24+
use crate::parser::{
25+
ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser,
2126
};
22-
use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser};
2327
use crate::session_diagnostics::{
2428
DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttrNotCrateLevel,
2529
DocAttributeNotAttribute, DocKeywordNotKeyword, UnusedDuplicate,
@@ -304,6 +308,81 @@ impl DocParser {
304308
}
305309
}
306310

311+
// Parses the `doc(auto_cfg(hide/show(..., values())))` attribute.
312+
fn parse_auto_cfg_values(
313+
&self,
314+
cx: &mut AcceptContext<'_, '_>,
315+
list: &MetaItemListParser,
316+
values: &mut Option<DocCfgHideShow>,
317+
) {
318+
let mut cfg_values = DocCfgHideShow::new();
319+
320+
let mut values_set = FxHashSet::default();
321+
for item in list.mixed() {
322+
match item {
323+
// If it's a string literal, all good.
324+
MetaItemOrLitParser::Lit(MetaItemLit {
325+
kind: LitKind::Str(symbol, _),
326+
span,
327+
..
328+
}) => match &mut cfg_values {
329+
DocCfgHideShow::Any(any_span) => {
330+
cx.emit_lint(
331+
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
332+
DocAutoCfgHideShowValuesMix { value_span: *span },
333+
*any_span,
334+
);
335+
}
336+
DocCfgHideShow::List(symbols) => {
337+
if values_set.insert(symbol) {
338+
symbols.push(DocCfgHideShowValue::new(*symbol, *span));
339+
}
340+
}
341+
},
342+
// If it's any other kind of literal, then it's wrong and we emit a lint.
343+
MetaItemOrLitParser::Lit(lit) => cx.emit_lint(
344+
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
345+
DocAutoCfgHideShowUnexpectedItem { attr_name: lit.symbol },
346+
lit.span,
347+
),
348+
// If it's a list, then only `any()` and `none()` are allowed and they must not
349+
// contain any item.
350+
MetaItemOrLitParser::MetaItemParser(sub_item) => {
351+
if let Some(ident) = sub_item.ident()
352+
&& [sym::any, sym::none].contains(&ident.name)
353+
&& let ArgParser::List(list) = sub_item.args()
354+
&& list.mixed().count() == 0
355+
{
356+
if ident.name == sym::any {
357+
if let DocCfgHideShow::List(values) = &cfg_values
358+
&& let Some(value) = values.first()
359+
{
360+
cx.emit_lint(
361+
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
362+
DocAutoCfgHideShowValuesMix { value_span: value.span },
363+
sub_item.span(),
364+
);
365+
} else {
366+
cfg_values.merge_with(&DocCfgHideShow::Any(sub_item.span()));
367+
}
368+
} else {
369+
cfg_values.push_none(sub_item.span());
370+
}
371+
} else {
372+
cx.emit_lint(
373+
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
374+
DocAutoCfgHideShowUnexpectedItem {
375+
attr_name: sub_item.ident().unwrap().name,
376+
},
377+
sub_item.span(),
378+
);
379+
}
380+
}
381+
}
382+
}
383+
*values = Some(cfg_values);
384+
}
385+
307386
fn parse_auto_cfg(
308387
&mut self,
309388
cx: &mut AcceptContext<'_, '_>,
@@ -315,7 +394,7 @@ impl DocParser {
315394
self.attribute.auto_cfg_change.push((true, path.span()));
316395
}
317396
ArgParser::List(list) => {
318-
for meta in list.mixed() {
397+
'main: for meta in list.mixed() {
319398
let MetaItemOrLitParser::MetaItemParser(item) = meta else {
320399
cx.emit_lint(
321400
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
@@ -324,6 +403,8 @@ impl DocParser {
324403
);
325404
continue;
326405
};
406+
// Only `hide` and `show` are allowed in `auto_cfg` if it's a list, and both
407+
// must be a list.
327408
let (kind, attr_name) = match item.path().word_sym() {
328409
Some(sym::hide) => (HideOrShow::Hide, sym::hide),
329410
Some(sym::show) => (HideOrShow::Show, sym::show),
@@ -345,56 +426,71 @@ impl DocParser {
345426
continue;
346427
};
347428

348-
let mut cfg_hide_show = CfgHideShow { kind, values: ThinVec::new() };
429+
let mut cfg_hide_show = CfgHideShow { kind, values: FxIndexMap::default() };
349430

431+
let mut cfg_names = FxHashSet::default();
432+
let mut values = None;
350433
for item in list.mixed() {
351434
let MetaItemOrLitParser::MetaItemParser(sub_item) = item else {
352435
cx.emit_lint(
353436
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
354437
DocAutoCfgHideShowUnexpectedItem { attr_name },
355438
item.span(),
356439
);
357-
continue;
440+
continue 'main;
358441
};
359442
match sub_item.args() {
360-
a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => {
443+
ArgParser::NoArgs if values.is_none() => {
361444
let Some(name) = sub_item.path().word_sym() else {
362-
// FIXME: remove this method once merged and uncomment the line
363-
// below instead.
364-
// cx.expected_identifier(sub_item.path().span());
445+
cx.adcx().expected_identifier(sub_item.path().span());
446+
continue 'main;
447+
};
448+
cfg_names.insert(name);
449+
}
450+
// The only accepted list is `values()`.
451+
ArgParser::List(list) if values.is_none() => {
452+
let Some(sym::values) = sub_item.path().word_sym() else {
453+
cx.adcx().expected_identifier(sub_item.path().span());
454+
continue 'main;
455+
};
456+
if cfg_names.is_empty() {
365457
cx.emit_lint(
366458
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
367-
MalformedDoc,
368-
sub_item.path().span(),
369-
);
370-
continue;
371-
};
372-
if let Ok(CfgEntry::NameValue { name, value, .. }) =
373-
super::cfg::parse_name_value(
374-
name,
375-
sub_item.path().span(),
376-
a.as_name_value(),
459+
DocAutoCfgHideShowNoIdentBeforeValues,
377460
sub_item.span(),
378-
cx,
379-
)
380-
{
381-
cfg_hide_show.values.push(CfgInfo {
382-
name,
383-
name_span: sub_item.path().span(),
384-
// If `value` is `Some`, `a.name_value()` will always return
385-
// `Some` as well.
386-
value: value
387-
.map(|v| (v, a.as_name_value().unwrap().value_span)),
388-
})
461+
);
462+
continue 'main;
389463
}
464+
self.parse_auto_cfg_values(cx, list, &mut values);
390465
}
391-
_ => {
466+
// No `name = value` is allowed.
467+
ArgParser::NameValue(_) => {
392468
cx.emit_lint(
393469
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
394470
DocAutoCfgHideShowUnexpectedItem { attr_name },
395471
sub_item.span(),
396472
);
397-
continue;
473+
}
474+
// If `values()` was already used, no item should come after it.
475+
_ => {
476+
cx.emit_lint(
477+
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
478+
DocAutoCfgHideShowUnexpectedItemAfterValues,
479+
sub_item.span(),
480+
);
481+
}
482+
}
483+
}
484+
485+
let values = values.unwrap_or(DocCfgHideShow::new_with_only_key(item.span()));
486+
#[allow(rustc::potential_query_instability)]
487+
for cfg_name in &cfg_names {
488+
match cfg_hide_show.values.entry(*cfg_name) {
489+
IndexEntry::Vacant(v) => {
490+
v.insert(values.clone());
491+
}
492+
IndexEntry::Occupied(mut o) => {
493+
o.get_mut().merge_with(&values);
398494
}
399495
}
400496
}

compiler/rustc_attr_parsing/src/attributes/link_attrs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ impl NoArgsAttributeParser for FfiPureParser {
576576
const STABILITY: AttributeStability = unstable!(ffi_pure);
577577
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
578578

579-
fn finalize_check(attr_span: Span, cx: &FinalizeContext<'_, '_>) {
579+
fn finalize_check(cx: &FinalizeContext<'_, '_>, attr_span: Span) {
580580
// `#[ffi_const]` functions cannot be `#[ffi_pure]`.
581581
if cx.all_attrs.iter().any(|a| a.word_is(sym::ffi_const)) {
582582
cx.emit_err(BothFfiConstAndPure { attr_span });

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ pub(crate) trait SingleAttributeParser: 'static {
154154
/// reject incompatible combinations. `attr_span` is the span of this attribute.
155155
///
156156
/// Defaults to a no-op.
157-
fn finalize_check(_attr_span: Span, _cx: &FinalizeContext<'_, '_>) {}
157+
fn finalize_check(_cx: &FinalizeContext<'_, '_>, _attr_span: Span) {}
158158
}
159159

160160
/// Use in combination with [`SingleAttributeParser`].
@@ -187,7 +187,7 @@ impl<T: SingleAttributeParser> AttributeParser for Single<T> {
187187

188188
fn finalize(self, cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
189189
let (kind, span) = self.1?;
190-
T::finalize_check(span, cx);
190+
T::finalize_check(cx, span);
191191
Some(kind)
192192
}
193193
}
@@ -275,7 +275,7 @@ pub(crate) trait NoArgsAttributeParser: 'static {
275275
/// `attr_span` is the span of this attribute.
276276
///
277277
/// Defaults to a no-op.
278-
fn finalize_check(_attr_span: Span, _cx: &FinalizeContext<'_, '_>) {}
278+
fn finalize_check(_cx: &FinalizeContext<'_, '_>, _attr_span: Span) {}
279279
}
280280

281281
pub(crate) struct WithoutArgs<T: NoArgsAttributeParser>(PhantomData<T>);
@@ -299,8 +299,8 @@ impl<T: NoArgsAttributeParser> SingleAttributeParser for WithoutArgs<T> {
299299
Some(T::CREATE(cx.attr_span))
300300
}
301301

302-
fn finalize_check(attr_span: Span, cx: &FinalizeContext<'_, '_>) {
303-
T::finalize_check(attr_span, cx)
302+
fn finalize_check(cx: &FinalizeContext<'_, '_>, attr_span: Span) {
303+
T::finalize_check(cx, attr_span)
304304
}
305305
}
306306

@@ -335,6 +335,14 @@ pub(crate) trait CombineAttributeParser: 'static {
335335
cx: &mut AcceptContext<'_, '_>,
336336
args: &ArgParser,
337337
) -> impl IntoIterator<Item = Self::Item>;
338+
339+
/// Optional cross-attribute validation, run once during finalization after all
340+
/// attributes on the item have been parsed. Has access to the sibling attributes via
341+
/// [`FinalizeContext::all_attrs`], so it can reject incompatible combinations.
342+
/// `attr_span` is the span of the first attribute that was encountered.
343+
///
344+
/// Defaults to a no-op.
345+
fn finalize_check(_cx: &FinalizeContext<'_, '_>, _attr_span: Span) {}
338346
}
339347

340348
/// Use in combination with [`CombineAttributeParser`].
@@ -367,8 +375,9 @@ impl<T: CombineAttributeParser> AttributeParser for Combine<T> {
367375
const ALLOWED_TARGETS: AllowedTargets<'_> = T::ALLOWED_TARGETS;
368376
const SAFETY: AttributeSafety = T::SAFETY;
369377

370-
fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
378+
fn finalize(self, cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
371379
if let Some(first_span) = self.first_span {
380+
T::finalize_check(cx, first_span);
372381
Some(T::CONVERT(self.items, first_span))
373382
} else {
374383
None

0 commit comments

Comments
 (0)