Skip to content
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

Rollup of 9 pull requests #128248

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c90b6b8
stabilize `const_int_from_str`
Skgland May 9, 2024
eb799cf
mark `can_not_overflow` as `#[rustc_const_stable(...)]`
Skgland Jul 4, 2024
f99df29
fix tests after rebase
Skgland Jul 4, 2024
404519a
bless tests
Skgland Jul 4, 2024
ceec6dd
update text for E0736 and E0739
folkertdev Jul 16, 2024
4bd3632
improve error message when `#[naked]` is used with `#[inline]`
folkertdev Jul 16, 2024
7e6c083
improve error message when `#[naked]` is used with `#[track-caller] a…
folkertdev Jul 16, 2024
4d082b7
add error message when `#[naked]` is used with `#[test]`
folkertdev Jul 16, 2024
4596ce6
switch to an allowlist approach
folkertdev Jul 17, 2024
0ed639f
merge error codes
folkertdev Jul 17, 2024
6f2318c
allow `#[target_feature]` on `#[naked]` functions
folkertdev Jul 23, 2024
370fcce
rustdoc: change title of search results
lolbinarycat Jul 25, 2024
587b64e
use double quotes
lolbinarycat Jul 25, 2024
caee195
Invert early exit conditions in `collect_tokens_trailing_token`.
nnethercote Jul 25, 2024
4288edb
Inline and remove `AttrWrapper::is_complete`.
nnethercote Jul 25, 2024
3d363c3
Move `is_complete` to the module that uses it.
nnethercote Jul 25, 2024
e631b1e
Invert the sense of `is_complete` and rename it as `needs_tokens`.
nnethercote Jul 25, 2024
a560810
Don't include inner attribute ranges in `CaptureState`.
nnethercote Jul 26, 2024
6e87858
Fix a comment.
nnethercote Jul 26, 2024
6ea2da5
Tweak a loop.
nnethercote Jul 26, 2024
55d37ae
Remove an unnecessary block.
nnethercote Jul 26, 2024
33b98bf
Remove redundant option that was just encoding that a slice was empty
oli-obk Jul 26, 2024
114e0dc
CI: do not respect custom try jobs for unrolled perf builds
Kobzol Jul 26, 2024
33dd288
Add a test case for `extern "C" unsafe` to the ui tests
tdittr Jul 26, 2024
3fdc991
Improve error message for `extern "C" unsafe fn()`
tdittr Jul 26, 2024
130ce49
Fix docs
harryscholes Jul 26, 2024
45e943f
use attribute name that is incompatible in error message
folkertdev Jul 26, 2024
0e50d42
Rollup merge of #124941 - Skgland:stabilize-const-int-from-str, r=dto…
tgross35 Jul 26, 2024
3d85eac
Rollup merge of #127853 - folkertdev:naked-function-error-messages, r…
tgross35 Jul 26, 2024
d4ef544
Rollup merge of #128210 - lolbinarycat:rustdoc-search-title, r=notrid…
tgross35 Jul 26, 2024
d0de531
Rollup merge of #128223 - nnethercote:refactor-collect_tokens, r=petr…
tgross35 Jul 26, 2024
97f49e1
Rollup merge of #128224 - nnethercote:fewer-replace_ranges, r=petroch…
tgross35 Jul 26, 2024
436d6aa
Rollup merge of #128226 - oli-obk:option_vs_empty_slice, r=petrochenkov
tgross35 Jul 26, 2024
caa64a5
Rollup merge of #128227 - Kobzol:ci-unrolled-perf-build-matrix, r=tgr…
tgross35 Jul 26, 2024
6257615
Rollup merge of #128229 - tdittr:unsafe-extern-abi-error, r=compiler-…
tgross35 Jul 26, 2024
2157c39
Rollup merge of #128235 - harryscholes:fix-iterator-filter-docs, r=tg…
tgross35 Jul 26, 2024
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
6 changes: 3 additions & 3 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
id: NodeId,
hir_id: hir::HirId,
ident: &mut Ident,
attrs: Option<&'hir [Attribute]>,
attrs: &'hir [Attribute],
vis_span: Span,
i: &ItemKind,
) -> hir::ItemKind<'hir> {
Expand Down Expand Up @@ -488,7 +488,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
id: NodeId,
vis_span: Span,
ident: &mut Ident,
attrs: Option<&'hir [Attribute]>,
attrs: &'hir [Attribute],
) -> hir::ItemKind<'hir> {
let path = &tree.prefix;
let segments = prefix.segments.iter().chain(path.segments.iter()).cloned().collect();
Expand Down Expand Up @@ -566,7 +566,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `ItemLocalId` and the new owner. (See `lower_node_id`)
let kind =
this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs);
if let Some(attrs) = attrs {
if !attrs.is_empty() {
this.attrs.insert(hir::ItemLocalId::ZERO, attrs);
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -913,15 +913,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ret
}

fn lower_attrs(&mut self, id: HirId, attrs: &[Attribute]) -> Option<&'hir [Attribute]> {
fn lower_attrs(&mut self, id: HirId, attrs: &[Attribute]) -> &'hir [Attribute] {
if attrs.is_empty() {
None
&[]
} else {
debug_assert_eq!(id.owner, self.current_hir_id_owner);
let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)));
debug_assert!(!ret.is_empty());
self.attrs.insert(id.local_id, ret);
Some(ret)
ret
}
}

Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_builtin_macros/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,11 @@ builtin_macros_multiple_defaults = multiple declared defaults
.note = only one variant can be default
.suggestion = make `{$ident}` default
builtin_macros_naked_functions_testing_attribute =
cannot use `#[naked]` with testing attributes
.label = function marked with testing attribute here
.naked_attribute = `#[naked]` is incompatible with testing attributes
builtin_macros_no_default_variant = no default declared
.help = make a unit variant default by placing `#[default]` above it
.suggestion = make `{$ident}` default
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_builtin_macros/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -912,3 +912,13 @@ pub(crate) struct ExpectedItem<'a> {
pub span: Span,
pub token: &'a str,
}

#[derive(Diagnostic)]
#[diag(builtin_macros_naked_functions_testing_attribute, code = E0736)]
pub struct NakedFunctionTestingAttribute {
#[primary_span]
#[label(builtin_macros_naked_attribute)]
pub naked_span: Span,
#[label]
pub testing_span: Span,
}
8 changes: 8 additions & 0 deletions compiler/rustc_builtin_macros/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ pub(crate) fn expand_test_or_bench(
};
};

if let Some(attr) = attr::find_by_name(&item.attrs, sym::naked) {
cx.dcx().emit_err(errors::NakedFunctionTestingAttribute {
testing_span: attr_sp,
naked_span: attr.span,
});
return vec![Annotatable::Item(item)];
}

// check_*_signature will report any errors in the type so compilation
// will fail. We shouldn't try to expand in this case because the errors
// would be spurious.
Expand Down
18 changes: 12 additions & 6 deletions compiler/rustc_error_codes/src/error_codes/E0736.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
`#[track_caller]` and `#[naked]` cannot both be applied to the same function.
Functions marked with the `#[naked]` attribute are restricted in what other
attributes they may be marked with.

Notable attributes that are incompatible with `#[naked]` are:

* `#[inline]`
* `#[track_caller]`
* `#[test]`, `#[ignore]`, `#[should_panic]`

Erroneous code example:

```compile_fail,E0736
#[inline]
#[naked]
#[track_caller]
fn foo() {}
```

This is primarily due to ABI incompatibilities between the two attributes.
See [RFC 2091] for details on this and other limitations.

[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
These incompatibilities are due to the fact that naked functions deliberately
impose strict restrictions regarding the code that the compiler is
allowed to produce for this function.
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes/E0739.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
`#[track_caller]` can not be applied on struct.
`#[track_caller]` must be applied to a function

Erroneous code example:

Expand Down
11 changes: 0 additions & 11 deletions compiler/rustc_parse/src/parser/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,14 +457,3 @@ impl<'a> Parser<'a> {
Err(self.dcx().create_err(err))
}
}

/// The attributes are complete if all attributes are either a doc comment or a
/// builtin attribute other than `cfg_attr`.
pub fn is_complete(attrs: &[ast::Attribute]) -> bool {
attrs.iter().all(|attr| {
attr.is_doc_comment()
|| attr.ident().is_some_and(|ident| {
ident.name != sym::cfg_attr && rustc_feature::is_builtin_attr_name(ident.name)
})
})
}
123 changes: 64 additions & 59 deletions compiler/rustc_parse/src/parser/attr_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,6 @@ impl AttrWrapper {
pub fn is_empty(&self) -> bool {
self.attrs.is_empty()
}

pub fn is_complete(&self) -> bool {
crate::parser::attr::is_complete(&self.attrs)
}
}

/// Returns `true` if `attrs` contains a `cfg` or `cfg_attr` attribute
Expand Down Expand Up @@ -114,17 +110,15 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
replace_ranges.sort_by_key(|(range, _)| range.start);

#[cfg(debug_assertions)]
{
for [(range, tokens), (next_range, next_tokens)] in replace_ranges.array_windows() {
assert!(
range.end <= next_range.start || range.end >= next_range.end,
"Replace ranges should either be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})",
range,
tokens,
next_range,
next_tokens,
);
}
for [(range, tokens), (next_range, next_tokens)] in replace_ranges.array_windows() {
assert!(
range.end <= next_range.start || range.end >= next_range.end,
"Replace ranges should either be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})",
range,
tokens,
next_range,
next_tokens,
);
}

// Process the replace ranges, starting from the highest start
Expand All @@ -137,9 +131,9 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
// `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }`
//
// By starting processing from the replace range with the greatest
// start position, we ensure that any replace range which encloses
// another replace range will capture the *replaced* tokens for the inner
// range, not the original tokens.
// start position, we ensure that any (outer) replace range which
// encloses another (inner) replace range will fully overwrite the
// inner range's replacement.
for (range, target) in replace_ranges.into_iter().rev() {
assert!(!range.is_empty(), "Cannot replace an empty range: {range:?}");

Expand Down Expand Up @@ -199,20 +193,20 @@ impl<'a> Parser<'a> {
force_collect: ForceCollect,
f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, (R, bool)>,
) -> PResult<'a, R> {
// Skip collection when nothing could observe the collected tokens, i.e.
// all of the following conditions hold.
// - We are not force collecting tokens (because force collection
// requires tokens by definition).
if matches!(force_collect, ForceCollect::No)
// - None of our outer attributes require tokens.
&& attrs.is_complete()
// - Our target doesn't support custom inner attributes (custom
// We must collect if anything could observe the collected tokens, i.e.
// if any of the following conditions hold.
// - We are force collecting tokens (because force collection requires
// tokens by definition).
let needs_collection = matches!(force_collect, ForceCollect::Yes)
// - Any of our outer attributes require tokens.
|| needs_tokens(&attrs.attrs)
// - Our target supports custom inner attributes (custom
// inner attribute invocation might require token capturing).
&& !R::SUPPORTS_CUSTOM_INNER_ATTRS
// - We are not in `capture_cfg` mode (which requires tokens if
|| R::SUPPORTS_CUSTOM_INNER_ATTRS
// - We are in `capture_cfg` mode (which requires tokens if
// the parsed node has `#[cfg]` or `#[cfg_attr]` attributes).
&& !self.capture_cfg
{
|| self.capture_cfg;
if !needs_collection {
return Ok(f(self, attrs.attrs)?.0);
}

Expand Down Expand Up @@ -250,28 +244,28 @@ impl<'a> Parser<'a> {
return Ok(ret);
}

// This is similar to the "skip collection" check at the start of this
// function, but now that we've parsed an AST node we have more
// This is similar to the `needs_collection` check at the start of this
// function, but now that we've parsed an AST node we have complete
// information available. (If we return early here that means the
// setup, such as cloning the token cursor, was unnecessary. That's
// hard to avoid.)
//
// Skip collection when nothing could observe the collected tokens, i.e.
// all of the following conditions hold.
// - We are not force collecting tokens.
if matches!(force_collect, ForceCollect::No)
// - None of our outer *or* inner attributes require tokens.
// (`attrs` was just outer attributes, but `ret.attrs()` is outer
// and inner attributes. That makes this check more precise than
// `attrs.is_complete()` at the start of the function, and we can
// skip the subsequent check on `R::SUPPORTS_CUSTOM_INNER_ATTRS`.
&& crate::parser::attr::is_complete(ret.attrs())
// - We are not in `capture_cfg` mode, or we are but there are no
// `#[cfg]` or `#[cfg_attr]` attributes. (During normal
// non-`capture_cfg` parsing, we don't need any special capturing
// for those attributes, because they're builtin.)
&& (!self.capture_cfg || !has_cfg_or_cfg_attr(ret.attrs()))
{
// We must collect if anything could observe the collected tokens, i.e.
// if any of the following conditions hold.
// - We are force collecting tokens.
let needs_collection = matches!(force_collect, ForceCollect::Yes)
// - Any of our outer *or* inner attributes require tokens.
// (`attr.attrs` was just outer attributes, but `ret.attrs()` is
// outer and inner attributes. So this check is more precise than
// the earlier `needs_tokens` check, and we don't need to
// check `R::SUPPORTS_CUSTOM_INNER_ATTRS`.)
|| needs_tokens(ret.attrs())
// - We are in `capture_cfg` mode and there are `#[cfg]` or
// `#[cfg_attr]` attributes. (During normal non-`capture_cfg`
// parsing, we don't need any special capturing for those
// attributes, because they're builtin.)
|| (self.capture_cfg && has_cfg_or_cfg_attr(ret.attrs()));
if !needs_collection {
return Ok(ret);
}

Expand All @@ -297,11 +291,13 @@ impl<'a> Parser<'a> {
// with `None`, which means the relevant tokens will be removed. (More
// details below.)
let mut inner_attr_replace_ranges = Vec::new();
for inner_attr in ret.attrs().iter().filter(|a| a.style == ast::AttrStyle::Inner) {
if let Some(attr_range) = self.capture_state.inner_attr_ranges.remove(&inner_attr.id) {
inner_attr_replace_ranges.push((attr_range, None));
} else {
self.dcx().span_delayed_bug(inner_attr.span, "Missing token range for attribute");
for attr in ret.attrs() {
if attr.style == ast::AttrStyle::Inner {
if let Some(attr_range) = self.capture_state.inner_attr_ranges.remove(&attr.id) {
inner_attr_replace_ranges.push((attr_range, None));
} else {
self.dcx().span_delayed_bug(attr.span, "Missing token range for attribute");
}
}
}

Expand Down Expand Up @@ -337,8 +333,7 @@ impl<'a> Parser<'a> {
// When parsing `m`:
// - `start_pos..end_pos` is `0..34` (`mod m`, excluding the `#[cfg_eval]` attribute).
// - `inner_attr_replace_ranges` is empty.
// - `replace_range_start..replace_ranges_end` has two entries.
// - One to delete the inner attribute (`17..27`), obtained when parsing `g` (see above).
// - `replace_range_start..replace_ranges_end` has one entry.
// - One `AttrsTarget` (added below when parsing `g`) to replace all of `g` (`3..33`,
// including its outer attribute), with:
// - `attrs`: includes the outer and the inner attr.
Expand Down Expand Up @@ -369,12 +364,10 @@ impl<'a> Parser<'a> {

// What is the status here when parsing the example code at the top of this method?
//
// When parsing `g`, we add two entries:
// When parsing `g`, we add one entry:
// - The `start_pos..end_pos` (`3..33`) entry has a new `AttrsTarget` with:
// - `attrs`: includes the outer and the inner attr.
// - `tokens`: lazy tokens for `g` (with its inner attr deleted).
// - `inner_attr_replace_ranges` contains the one entry to delete the inner attr's
// tokens (`17..27`).
//
// When parsing `m`, we do nothing here.

Expand All @@ -384,7 +377,6 @@ impl<'a> Parser<'a> {
let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos };
let target = AttrsTarget { attrs: ret.attrs().iter().cloned().collect(), tokens };
self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target)));
self.capture_state.replace_ranges.extend(inner_attr_replace_ranges);
} else if matches!(self.capture_state.capturing, Capturing::No) {
// Only clear the ranges once we've finished capturing entirely, i.e. we've finished
// the outermost call to this method.
Expand Down Expand Up @@ -461,6 +453,19 @@ fn make_attr_token_stream(
AttrTokenStream::new(stack_top.inner)
}

/// Tokens are needed if:
/// - any non-single-segment attributes (other than doc comments) are present; or
/// - any `cfg_attr` attributes are present;
/// - any single-segment, non-builtin attributes are present.
fn needs_tokens(attrs: &[ast::Attribute]) -> bool {
attrs.iter().any(|attr| match attr.ident() {
None => !attr.is_doc_comment(),
Some(ident) => {
ident.name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(ident.name)
}
})
}

// Some types are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(target_pointer_width = "64")]
mod size_asserts {
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2483,12 +2483,15 @@ impl<'a> Parser<'a> {
/// `check_pub` adds additional `pub` to the checks in case users place it
/// wrongly, can be used to ensure `pub` never comes after `default`.
pub(super) fn check_fn_front_matter(&mut self, check_pub: bool, case: Case) -> bool {
const ALL_QUALS: &[Symbol] =
&[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern];

// We use an over-approximation here.
// `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
// `pub` is added in case users got confused with the ordering like `async pub fn`,
// only if it wasn't preceded by `default` as `default pub` is invalid.
let quals: &[Symbol] = if check_pub {
&[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern]
ALL_QUALS
} else {
&[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern]
};
Expand Down Expand Up @@ -2518,9 +2521,9 @@ impl<'a> Parser<'a> {
|| self.check_keyword_case(kw::Extern, case)
&& self.look_ahead(1, |t| t.can_begin_string_literal())
&& (self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) ||
// this branch is only for better diagnostic in later, `pub` is not allowed here
// this branch is only for better diagnostics; `pub`, `unsafe`, etc. are not allowed here
(self.may_recover()
&& self.look_ahead(2, |t| t.is_keyword(kw::Pub))
&& self.look_ahead(2, |t| ALL_QUALS.iter().any(|&kw| t.is_keyword(kw)))
&& self.look_ahead(3, |t| t.is_keyword_case(kw::Fn, case))))
}

Expand Down
11 changes: 5 additions & 6 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ passes_break_non_loop =
.suggestion = use `break` on its own without a value inside this `{$kind}` loop
.break_expr_suggestion = alternatively, you might have meant to use the available loop label
passes_cannot_inline_naked_function =
naked functions cannot be inlined
passes_cannot_stabilize_deprecated =
an API can't be stabilized after it is deprecated
.label = invalid version
Expand Down Expand Up @@ -485,16 +482,18 @@ passes_naked_functions_asm_block =
passes_naked_functions_asm_options =
asm options unsupported in naked functions: {$unsupported_options}
passes_naked_functions_incompatible_attribute =
attribute incompatible with `#[naked]`
.label = the `{$attr}` attribute is incompatible with `#[naked]`
.naked_attribute = function marked with `#[naked]` here
passes_naked_functions_must_use_noreturn =
asm in naked functions must use `noreturn` option
.suggestion = consider specifying that the asm block is responsible for returning from the function
passes_naked_functions_operands =
only `const` and `sym` operands are supported in naked functions
passes_naked_tracked_caller =
cannot use `#[track_caller]` with `#[naked]`
passes_no_link =
attribute should be applied to an `extern crate` item
.label = not an `extern crate` item
Expand Down
Loading
Loading