Merge pull request #2021 from rust-lang/rustc-pull

Rustc pull update
This commit is contained in:
Folkert de Vries 2026-02-05 09:33:08 +00:00 committed by GitHub
commit b4e2a8400b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
1377 changed files with 32657 additions and 17022 deletions

View file

@ -165,9 +165,6 @@ jobs:
- name: install sccache
run: src/ci/scripts/install-sccache.sh
- name: select Xcode
run: src/ci/scripts/select-xcode.sh
- name: install clang
run: src/ci/scripts/install-clang.sh

2
.gitmodules vendored
View file

@ -25,7 +25,7 @@
[submodule "src/llvm-project"]
path = src/llvm-project
url = https://github.com/rust-lang/llvm-project.git
branch = rustc/21.1-2025-08-01
branch = rustc/22.1-2026-01-27
shallow = true
[submodule "src/doc/embedded-book"]
path = src/doc/embedded-book

View file

@ -184,9 +184,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "askama"
version = "0.15.1"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb7125972258312e79827b60c9eb93938334100245081cf701a2dee981b17427"
checksum = "08e1676b346cadfec169374f949d7490fd80a24193d37d2afce0c047cf695e57"
dependencies = [
"askama_macros",
"itoa",
@ -197,9 +197,9 @@ dependencies = [
[[package]]
name = "askama_derive"
version = "0.15.1"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ba5e7259a1580c61571e3116ebaaa01e3c001b2132b17c4cc5c70780ca3e994"
checksum = "7661ff56517787343f376f75db037426facd7c8d3049cef8911f1e75016f3a37"
dependencies = [
"askama_parser",
"basic-toml",
@ -214,18 +214,18 @@ dependencies = [
[[package]]
name = "askama_macros"
version = "0.15.1"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "236ce20b77cb13506eaf5024899f4af6e12e8825f390bd943c4c37fd8f322e46"
checksum = "713ee4dbfd1eb719c2dab859465b01fa1d21cb566684614a713a6b7a99a4e47b"
dependencies = [
"askama_derive",
]
[[package]]
name = "askama_parser"
version = "0.15.1"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3c63392767bb2df6aa65a6e1e3b80fd89bb7af6d58359b924c0695620f1512e"
checksum = "1d62d674238a526418b30c0def480d5beadb9d8964e7f38d635b03bf639c704c"
dependencies = [
"rustc-hash 2.1.1",
"serde",
@ -580,9 +580,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.51"
version = "4.5.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
dependencies = [
"clap_builder",
"clap_derive",
@ -600,9 +600,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.51"
version = "4.5.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
dependencies = [
"anstream",
"anstyle",
@ -857,7 +857,7 @@ dependencies = [
"tracing-subscriber",
"unified-diff",
"walkdir",
"windows",
"windows 0.61.3",
]
[[package]]
@ -2038,7 +2038,7 @@ dependencies = [
"serde",
"tempfile",
"uuid",
"windows",
"windows 0.61.3",
]
[[package]]
@ -3543,7 +3543,6 @@ dependencies = [
"rustc_ast_pretty",
"rustc_errors",
"rustc_feature",
"rustc_fluent_macro",
"rustc_hir",
"rustc_lexer",
"rustc_macros",
@ -3636,7 +3635,6 @@ dependencies = [
"rustc_codegen_ssa",
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
"rustc_fs_util",
"rustc_hashes",
"rustc_hir",
@ -3684,7 +3682,6 @@ dependencies = [
"rustc_macros",
"rustc_metadata",
"rustc_middle",
"rustc_query_system",
"rustc_serialize",
"rustc_session",
"rustc_span",
@ -3698,7 +3695,7 @@ dependencies = [
"thorin-dwp",
"tracing",
"wasm-encoder 0.219.2",
"windows",
"windows 0.61.3",
]
[[package]]
@ -3756,7 +3753,7 @@ dependencies = [
"tempfile",
"thin-vec",
"tracing",
"windows",
"windows 0.61.3",
]
[[package]]
@ -3780,7 +3777,6 @@ dependencies = [
"rustc_ast_lowering",
"rustc_ast_passes",
"rustc_ast_pretty",
"rustc_attr_parsing",
"rustc_borrowck",
"rustc_builtin_macros",
"rustc_codegen_ssa",
@ -3789,13 +3785,10 @@ dependencies = [
"rustc_errors",
"rustc_expand",
"rustc_feature",
"rustc_fluent_macro",
"rustc_hir_analysis",
"rustc_hir_pretty",
"rustc_hir_typeck",
"rustc_incremental",
"rustc_index",
"rustc_infer",
"rustc_interface",
"rustc_lexer",
"rustc_lint",
@ -3804,25 +3797,20 @@ dependencies = [
"rustc_metadata",
"rustc_middle",
"rustc_mir_build",
"rustc_mir_dataflow",
"rustc_mir_transform",
"rustc_monomorphize",
"rustc_parse",
"rustc_passes",
"rustc_pattern_analysis",
"rustc_privacy",
"rustc_public",
"rustc_query_system",
"rustc_resolve",
"rustc_session",
"rustc_span",
"rustc_target",
"rustc_trait_selection",
"rustc_ty_utils",
"serde_json",
"shlex",
"tracing",
"windows",
"windows 0.61.3",
]
[[package]]
@ -3873,7 +3861,7 @@ dependencies = [
"serde_json",
"termize",
"tracing",
"windows",
"windows 0.61.3",
]
[[package]]
@ -4054,7 +4042,6 @@ dependencies = [
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
"rustc_fs_util",
"rustc_graphviz",
"rustc_hashes",
@ -4093,7 +4080,6 @@ version = "0.0.0"
dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
"rustc_hir",
"rustc_index",
"rustc_macros",
@ -4124,7 +4110,6 @@ dependencies = [
"rustc_errors",
"rustc_expand",
"rustc_feature",
"rustc_fluent_macro",
"rustc_fs_util",
"rustc_hir",
"rustc_hir_analysis",
@ -4170,6 +4155,7 @@ version = "0.0.0"
dependencies = [
"bitflags",
"rustc_abi",
"rustc_apfloat",
"rustc_ast",
"rustc_ast_pretty",
"rustc_attr_parsing",
@ -4228,6 +4214,8 @@ dependencies = [
name = "rustc_macros"
version = "0.0.0"
dependencies = [
"fluent-bundle",
"fluent-syntax",
"proc-macro2",
"quote",
"syn 2.0.110",
@ -4335,11 +4323,10 @@ dependencies = [
"polonius-engine",
"regex",
"rustc_abi",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
"rustc_graphviz",
"rustc_hir",
"rustc_index",
"rustc_macros",
"rustc_middle",
@ -4353,7 +4340,6 @@ name = "rustc_mir_transform"
version = "0.0.0"
dependencies = [
"either",
"hashbrown 0.16.1",
"itertools",
"rustc_abi",
"rustc_arena",
@ -4383,7 +4369,6 @@ dependencies = [
"rustc_abi",
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
"rustc_hir",
"rustc_index",
"rustc_macros",
@ -4496,7 +4481,6 @@ dependencies = [
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
"rustc_hir",
"rustc_macros",
"rustc_middle",
@ -4564,14 +4548,12 @@ dependencies = [
name = "rustc_query_system"
version = "0.0.0"
dependencies = [
"hashbrown 0.16.1",
"parking_lot",
"rustc_abi",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
"rustc_fluent_macro",
"rustc_hashes",
"rustc_hir",
"rustc_index",
@ -4653,7 +4635,6 @@ dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
"rustc_fluent_macro",
"rustc_fs_util",
"rustc_hashes",
"rustc_hir",
@ -4664,7 +4645,7 @@ dependencies = [
"rustc_target",
"termize",
"tracing",
"windows",
"windows 0.61.3",
]
[[package]]
@ -4809,7 +4790,6 @@ dependencies = [
"rustc_abi",
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
"rustc_hashes",
"rustc_hir",
"rustc_index",
@ -5438,14 +5418,14 @@ dependencies = [
[[package]]
name = "sysinfo"
version = "0.37.2"
version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f"
checksum = "fe840c5b1afe259a5657392a4dbb74473a14c8db999c3ec2f4ae812e028a94da"
dependencies = [
"libc",
"objc2-core-foundation",
"objc2-io-kit",
"windows",
"windows 0.62.2",
]
[[package]]
@ -5622,6 +5602,7 @@ version = "0.1.0"
dependencies = [
"build_helper",
"cargo_metadata 0.21.0",
"clap",
"fluent-syntax",
"globset",
"ignore",
@ -6398,22 +6379,34 @@ version = "0.61.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
dependencies = [
"windows-collections",
"windows-collections 0.2.0",
"windows-core 0.61.2",
"windows-future",
"windows-future 0.2.1",
"windows-link 0.1.3",
"windows-numerics",
"windows-numerics 0.2.0",
]
[[package]]
name = "windows"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
dependencies = [
"windows-collections 0.3.2",
"windows-core 0.62.2",
"windows-future 0.3.2",
"windows-numerics 0.3.1",
]
[[package]]
name = "windows-bindgen"
version = "0.61.1"
version = "0.66.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4e97b01190d32f268a2dfbd3f006f77840633746707fbe40bcee588108a231"
checksum = "81b7ec123a4eadd44d1f44f76804316b477b2537abed9a2ab950b3c54afa1fcf"
dependencies = [
"serde",
"serde_json",
"windows-threading",
"windows-threading 0.2.1",
]
[[package]]
@ -6425,6 +6418,15 @@ dependencies = [
"windows-core 0.61.2",
]
[[package]]
name = "windows-collections"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
dependencies = [
"windows-core 0.62.2",
]
[[package]]
name = "windows-core"
version = "0.61.2"
@ -6459,7 +6461,18 @@ checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
dependencies = [
"windows-core 0.61.2",
"windows-link 0.1.3",
"windows-threading",
"windows-threading 0.1.0",
]
[[package]]
name = "windows-future"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
dependencies = [
"windows-core 0.62.2",
"windows-link 0.2.1",
"windows-threading 0.2.1",
]
[[package]]
@ -6506,6 +6519,16 @@ dependencies = [
"windows-link 0.1.3",
]
[[package]]
name = "windows-numerics"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
dependencies = [
"windows-core 0.62.2",
"windows-link 0.2.1",
]
[[package]]
name = "windows-result"
version = "0.3.4"
@ -6611,6 +6634,15 @@ dependencies = [
"windows-link 0.1.3",
]
[[package]]
name = "windows-threading"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
dependencies = [
"windows-link 0.2.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"

View file

@ -53,7 +53,7 @@ path = [
]
precedence = "override"
SPDX-FileCopyrightText = "The Rust Project Developers (see https://thanks.rust-lang.org)"
SPDX-License-Identifier = "MIT or Apache-2.0"
SPDX-License-Identifier = "MIT OR Apache-2.0"
[[annotations]]
path = "compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp"

View file

@ -172,8 +172,22 @@ impl<T> TypedArena<T> {
available_bytes >= additional_bytes
}
/// Allocates storage for `len >= 1` values in this arena, and returns a
/// raw pointer to the first value's storage.
///
/// # Safety
///
/// Caller must initialize each of the `len` slots to a droppable value
/// before the arena is dropped.
///
/// In practice, this typically means that the caller must be able to
/// raw-copy `len` already-initialized values into the slice without any
/// possibility of panicking.
///
/// FIXME(Zalathar): This is *very* fragile; perhaps we need a different
/// approach to arena-allocating slices of droppable values.
#[inline]
fn alloc_raw_slice(&self, len: usize) -> *mut T {
unsafe fn alloc_raw_slice(&self, len: usize) -> *mut T {
assert!(size_of::<T>() != 0);
assert!(len != 0);
@ -208,7 +222,7 @@ impl<T> TypedArena<T> {
&self,
iter: impl IntoIterator<Item = Result<T, E>>,
) -> Result<&mut [T], E> {
// Despite the similarlty with `DroplessArena`, we cannot reuse their fast case. The reason
// Despite the similarity with `DroplessArena`, we cannot reuse their fast case. The reason
// is subtle: these arenas are reentrant. In other words, `iter` may very well be holding a
// reference to `self` and adding elements to the arena during iteration.
//
@ -229,9 +243,15 @@ impl<T> TypedArena<T> {
}
// Move the content to the arena by copying and then forgetting it.
let len = vec.len();
let start_ptr = self.alloc_raw_slice(len);
// SAFETY: After allocating raw storage for exactly `len` values, we
// must fully initialize the storage without panicking, and we must
// also prevent the stale values in the vec from being dropped.
Ok(unsafe {
let start_ptr = self.alloc_raw_slice(len);
// Initialize the newly-allocated storage without panicking.
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
// Prevent the stale values in the vec from being dropped.
vec.set_len(0);
slice::from_raw_parts_mut(start_ptr, len)
})
@ -490,19 +510,6 @@ impl DroplessArena {
}
}
/// Used by `Lift` to check whether this slice is allocated
/// in this arena.
#[inline]
pub fn contains_slice<T>(&self, slice: &[T]) -> bool {
for chunk in self.chunks.borrow_mut().iter_mut() {
let ptr = slice.as_ptr().cast::<u8>().cast_mut();
if chunk.start() <= ptr && chunk.end() >= ptr {
return true;
}
}
false
}
/// Allocates a string slice that is copied into the `DroplessArena`, returning a
/// reference to it. Will panic if passed an empty string.
///
@ -584,7 +591,7 @@ impl DroplessArena {
&self,
iter: impl IntoIterator<Item = Result<T, E>>,
) -> Result<&mut [T], E> {
// Despite the similarlty with `alloc_from_iter`, we cannot reuse their fast case, as we
// Despite the similarity with `alloc_from_iter`, we cannot reuse their fast case, as we
// cannot know the minimum length of the iterator in this case.
assert!(size_of::<T>() != 0);

View file

@ -354,7 +354,13 @@ fn make_attr_token_stream(
FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] },
));
} else if let Some(delim) = kind.close_delim() {
let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap());
// If there's no matching opening delimiter, the token stream is malformed,
// likely due to a improper delimiter positions in the source code.
// It's not delimiter mismatch, and lexer can not detect it, so we just ignore it here.
let Some(frame) = stack_rest.pop() else {
return AttrTokenStream::new(stack_top.inner);
};
let frame_data = mem::replace(&mut stack_top, frame);
let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
assert!(
open_delim.eq_ignoring_invisible_origin(&delim),

View file

@ -51,6 +51,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
| asm::InlineAsmArch::LoongArch32
| asm::InlineAsmArch::LoongArch64
| asm::InlineAsmArch::S390x
| asm::InlineAsmArch::PowerPC
| asm::InlineAsmArch::PowerPC64
);
if !is_stable
&& !self.tcx.features().asm_experimental_arch()

View file

@ -1961,7 +1961,8 @@ impl<'a> State<'a> {
}
fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
self.print_name(lifetime.ident.name)
self.word(lifetime.ident.name.to_string());
self.ann_post(lifetime.ident)
}
fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {

View file

@ -10,7 +10,6 @@ rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir = { path = "../rustc_hir" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_macros = { path = "../rustc_macros" }

View file

@ -1,246 +0,0 @@
attr_parsing_as_needed_compatibility =
linking modifier `as-needed` is only compatible with `dylib`, `framework` and `raw-dylib` linking kinds
attr_parsing_bundle_needs_static =
linking modifier `bundle` is only compatible with `static` linking kind
attr_parsing_cfg_attr_bad_delim = wrong `cfg_attr` delimiters
attr_parsing_deprecated_item_suggestion =
suggestions on deprecated items are unstable
.help = add `#![feature(deprecated_suggestion)]` to the crate root
.note = see #94785 for more details
attr_parsing_doc_alias_bad_char =
{$char_} character isn't allowed in {$attr_str}
attr_parsing_doc_alias_empty =
{$attr_str} attribute cannot have empty value
attr_parsing_doc_alias_malformed =
doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
attr_parsing_doc_alias_start_end =
{$attr_str} cannot start or end with ' '
attr_parsing_doc_attr_not_crate_level =
`#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
attr_parsing_doc_attribute_not_attribute =
nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]`
.help = only existing builtin attributes are allowed in core/std
attr_parsing_doc_keyword_not_keyword =
nonexistent keyword `{$keyword}` used in `#[doc(keyword = "...")]`
.help = only existing keywords are allowed in core/std
attr_parsing_empty_confusables =
expected at least one confusable name
attr_parsing_empty_link_name =
link name must not be empty
.label = empty link name
attr_parsing_expected_single_version_literal =
expected single version literal
attr_parsing_expected_version_literal =
expected a version literal
attr_parsing_expects_feature_list =
`{$name}` expects a list of feature names
attr_parsing_expects_features =
`{$name}` expects feature names
attr_parsing_import_name_type_raw =
import name type can only be used with link kind `raw-dylib`
attr_parsing_import_name_type_x86 =
import name type is only supported on x86
attr_parsing_incompatible_wasm_link =
`wasm_import_module` is incompatible with other arguments in `#[link]` attributes
attr_parsing_incorrect_repr_format_align_one_arg =
incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
attr_parsing_incorrect_repr_format_expect_literal_integer =
incorrect `repr(align)` attribute format: `align` expects a literal integer as argument
attr_parsing_incorrect_repr_format_generic =
incorrect `repr({$repr_arg})` attribute format
.suggestion = use parentheses instead
attr_parsing_incorrect_repr_format_packed_expect_integer =
incorrect `repr(packed)` attribute format: `packed` expects a literal integer as argument
attr_parsing_incorrect_repr_format_packed_one_or_zero_arg =
incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
attr_parsing_invalid_alignment_value =
invalid alignment value: {$error_part}
attr_parsing_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
.label = this is not an unsafe attribute
.suggestion = remove the `unsafe(...)`
.note = extraneous unsafe is not allowed in attributes
attr_parsing_invalid_issue_string =
`issue` must be a non-zero numeric string or "none"
.must_not_be_zero = `issue` must not be "0", use "none" instead
.empty = cannot parse integer from empty string
.invalid_digit = invalid digit found in string
.pos_overflow = number too large to fit in target type
.neg_overflow = number too small to fit in target type
attr_parsing_invalid_link_modifier =
invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr}
.remove_neg_sugg = negative numbers are not literals, try removing the `-` sign
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
.label = {$descr}s are not allowed here
attr_parsing_invalid_predicate =
invalid predicate `{$predicate}`
attr_parsing_invalid_repr_align_need_arg =
invalid `repr(align)` attribute: `align` needs an argument
.suggestion = supply an argument here
attr_parsing_invalid_repr_generic =
invalid `repr({$repr_arg})` attribute: {$error_part}
attr_parsing_invalid_repr_hint_no_paren =
invalid representation hint: `{$name}` does not take a parenthesized argument list
attr_parsing_invalid_repr_hint_no_value =
invalid representation hint: `{$name}` does not take a value
attr_parsing_invalid_since =
'since' must be a Rust version number, such as "1.31.0"
attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target}
.help = `#[{$name}]` can {$only}be applied to {$applied}
.suggestion = remove the attribute
attr_parsing_limit_invalid =
`limit` must be a non-negative integer
.label = {$error_str}
attr_parsing_link_arg_unstable =
link kind `link-arg` is unstable
attr_parsing_link_cfg_unstable =
link cfg is unstable
attr_parsing_link_framework_apple =
link kind `framework` is only supported on Apple targets
attr_parsing_link_ordinal_out_of_range = ordinal value in `link_ordinal` is too large: `{$ordinal}`
.note = the value may not exceed `u16::MAX`
attr_parsing_link_requires_name =
`#[link]` attribute requires a `name = "string"` argument
.label = missing `name` argument
attr_parsing_meta_bad_delim = wrong meta list delimiters
attr_parsing_meta_bad_delim_suggestion = the delimiters should be `(` and `)`
attr_parsing_missing_feature =
missing 'feature'
attr_parsing_missing_issue =
missing 'issue'
attr_parsing_missing_note =
missing 'note'
attr_parsing_missing_since =
missing 'since'
attr_parsing_multiple_modifiers =
multiple `{$modifier}` modifiers in a single `modifiers` argument
attr_parsing_multiple_stability_levels =
multiple stability levels
attr_parsing_naked_functions_incompatible_attribute =
attribute incompatible with `#[unsafe(naked)]`
.label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`
.naked_attribute = function marked with `#[unsafe(naked)]` here
attr_parsing_non_ident_feature =
'feature' is not an identifier
attr_parsing_null_on_export = `export_name` may not contain null characters
attr_parsing_null_on_link_section = `link_section` may not contain null characters
attr_parsing_null_on_objc_class = `objc::class!` may not contain null characters
attr_parsing_null_on_objc_selector = `objc::selector!` may not contain null characters
attr_parsing_objc_class_expected_string_literal = `objc::class!` expected a string literal
attr_parsing_objc_selector_expected_string_literal = `objc::selector!` expected a string literal
attr_parsing_raw_dylib_elf_unstable =
link kind `raw-dylib` is unstable on ELF platforms
attr_parsing_raw_dylib_no_nul =
link name must not contain NUL characters if link kind is `raw-dylib`
attr_parsing_raw_dylib_only_windows =
link kind `raw-dylib` is only supported on Windows targets
attr_parsing_repr_ident =
meta item in `repr` must be an identifier
attr_parsing_rustc_allowed_unstable_pairing =
`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
attr_parsing_rustc_promotable_pairing =
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
attr_parsing_rustc_scalable_vector_count_out_of_range = element count in `rustc_scalable_vector` is too large: `{$n}`
.note = the value may not exceed `u16::MAX`
attr_parsing_soft_no_args =
`soft` should not have any arguments
attr_parsing_stability_outside_std = stability attributes may not be used outside of the standard library
attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
attr_parsing_unknown_version_literal =
unknown version literal format, assuming it refers to a future version
attr_parsing_unrecognized_repr_hint =
unrecognized representation hint
.help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
.note = for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
attr_parsing_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
.label = usage of unsafe attribute
attr_parsing_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
attr_parsing_unstable_cfg_target_compact =
compact `cfg(target(..))` is experimental and subject to change
attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable
.help = if this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
attr_parsing_unsupported_instruction_set = target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]`
attr_parsing_unsupported_literal_suggestion =
consider removing the prefix
attr_parsing_unused_multiple =
multiple `{$name}` attributes
.suggestion = remove this attribute
.note = attribute also specified here
attr_parsing_whole_archive_needs_static =
linking modifier `whole-archive` is only compatible with `static` linking kind

View file

@ -57,7 +57,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
type Item = Symbol;
const CONVERT: ConvertFn<Self::Item> =
|items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span);
|items, first_span| AttributeKind::RustcAllowConstFnUnstable(items, first_span);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),

View file

@ -3,14 +3,14 @@ use std::convert::identity;
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token};
use rustc_errors::{Applicability, PResult};
use rustc_errors::{Applicability, PResult, inline_fluent};
use rustc_feature::{
AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template,
};
use rustc_hir::attrs::CfgEntry;
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrPath, RustcVersion, Target};
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
use rustc_parse::{exp, parse_in};
use rustc_session::Session;
use rustc_session::config::ExpectedValues;
@ -25,7 +25,7 @@ use crate::session_diagnostics::{
AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
ParsedDescription,
};
use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics};
use crate::{AttributeParser, parse_version, session_diagnostics};
pub const CFG_TEMPLATE: AttributeTemplate = template!(
List: &["predicate"],
@ -141,7 +141,7 @@ fn parse_cfg_entry_target<S: Stage>(
cx.sess(),
sym::cfg_target_compact,
meta_span,
fluent_generated::attr_parsing_unstable_cfg_target_compact,
inline_fluent!("compact `cfg(target(..))` is experimental and subject to change"),
)
.emit();
}
@ -360,8 +360,10 @@ fn parse_cfg_attr_internal<'a>(
) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
// Parse cfg predicate
let pred_start = parser.token.span;
let meta =
MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints { recover: true })?;
let meta = MetaItemOrLitParser::parse_single(
parser,
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
)?;
let pred_span = pred_start.with_hi(parser.token.span.hi());
let cfg_predicate = AttributeParser::parse_single_args(
@ -376,7 +378,7 @@ fn parse_cfg_attr_internal<'a>(
CRATE_NODE_ID,
Target::Crate,
features,
ShouldEmit::ErrorsAndLints { recover: true },
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
&meta,
parse_cfg_entry,
&CFG_ATTR_TEMPLATE,

View file

@ -5,7 +5,7 @@ use rustc_feature::{AttributeTemplate, Features};
use rustc_hir::attrs::CfgEntry;
use rustc_hir::{AttrPath, Target};
use rustc_parse::exp;
use rustc_parse::parser::Parser;
use rustc_parse::parser::{Parser, Recovery};
use rustc_session::Session;
use rustc_span::{ErrorGuaranteed, Span, sym};
@ -78,9 +78,11 @@ pub fn parse_cfg_select(
}
}
} else {
let meta =
MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints { recover: true })
.map_err(|diag| diag.emit())?;
let meta = MetaItemOrLitParser::parse_single(
p,
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
)
.map_err(|diag| diag.emit())?;
let cfg_span = meta.span();
let cfg = AttributeParser::parse_single_args(
sess,
@ -95,7 +97,7 @@ pub fn parse_cfg_select(
// Doesn't matter what the target actually is here.
Target::Crate,
features,
ShouldEmit::ErrorsAndLints { recover: true },
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
&meta,
parse_cfg_entry,
&AttributeTemplate::default(),

View file

@ -181,7 +181,7 @@ impl<S: Stage> SingleAttributeParser<S> for ObjcClassParser {
cx.emit_err(NullOnObjcClass { span: nv.value_span });
return None;
}
Some(AttributeKind::ObjcClass { classname, span: cx.attr_span })
Some(AttributeKind::RustcObjcClass { classname, span: cx.attr_span })
}
}
@ -213,7 +213,7 @@ impl<S: Stage> SingleAttributeParser<S> for ObjcSelectorParser {
cx.emit_err(NullOnObjcSelector { span: nv.value_span });
return None;
}
Some(AttributeKind::ObjcSelector { methname, span: cx.attr_span })
Some(AttributeKind::RustcObjcSelector { methname, span: cx.attr_span })
}
}

View file

@ -43,7 +43,7 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
return None;
}
Some(AttributeKind::Confusables {
Some(AttributeKind::RustcConfusables {
symbols: self.confusables,
first_span: self.first_span.unwrap(),
})

View file

@ -274,3 +274,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for NoBuiltinsParser {
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins;
}
pub(crate) struct RustcPreserveUbChecksParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcPreserveUbChecksParser {
const PATH: &[Symbol] = &[sym::rustc_preserve_ub_checks];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPreserveUbChecks;
}

View file

@ -70,6 +70,42 @@ fn check_attr_crate_level<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, span: Spa
true
}
// FIXME: To be removed once merged and replace with `cx.expected_name_value(span, _name)`.
fn expected_name_value<S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
span: Span,
_name: Option<Symbol>,
) {
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::ExpectedNameValue,
span,
);
}
// FIXME: remove this method once merged and use `cx.expected_no_args(span)` instead.
fn expected_no_args<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, span: Span) {
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::ExpectedNoArgs,
span,
);
}
// FIXME: remove this method once merged and use `cx.expected_no_args(span)` instead.
// cx.expected_string_literal(span, _actual_literal);
fn expected_string_literal<S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
span: Span,
_actual_literal: Option<&MetaItemLit>,
) {
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::MalformedDoc,
span,
);
}
fn parse_keyword_and_attribute<S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
path: &OwnedPathParser,
@ -78,12 +114,12 @@ fn parse_keyword_and_attribute<S: Stage>(
attr_name: Symbol,
) {
let Some(nv) = args.name_value() else {
cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym());
expected_name_value(cx, args.span().unwrap_or(path.span()), path.word_sym());
return;
};
let Some(value) = nv.value_as_str() else {
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
expected_string_literal(cx, nv.value_span, Some(nv.value_as_lit()));
return;
};
@ -127,12 +163,21 @@ impl DocParser {
match path.word_sym() {
Some(sym::no_crate_inject) => {
if let Err(span) = args.no_args() {
cx.expected_no_args(span);
expected_no_args(cx, span);
return;
}
if self.attribute.no_crate_inject.is_some() {
cx.duplicate_key(path.span(), sym::no_crate_inject);
if let Some(used_span) = self.attribute.no_crate_inject {
let unused_span = path.span();
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::UnusedDuplicate {
this: unused_span,
other: used_span,
warning: true,
},
unused_span,
);
return;
}
@ -144,7 +189,14 @@ impl DocParser {
}
Some(sym::attr) => {
let Some(list) = args.list() else {
cx.expected_list(cx.attr_span, args);
// FIXME: remove this method once merged and uncomment the line below instead.
// cx.expected_list(cx.attr_span, args);
let span = cx.attr_span;
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::MalformedDoc,
span,
);
return;
};
@ -246,7 +298,7 @@ impl DocParser {
inline: DocInline,
) {
if let Err(span) = args.no_args() {
cx.expected_no_args(span);
expected_no_args(cx, span);
return;
}
@ -328,7 +380,14 @@ impl DocParser {
match sub_item.args() {
a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => {
let Some(name) = sub_item.path().word_sym() else {
cx.expected_identifier(sub_item.path().span());
// FIXME: remove this method once merged and uncomment the line
// below instead.
// cx.expected_identifier(sub_item.path().span());
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::MalformedDoc,
sub_item.path().span(),
);
continue;
};
if let Ok(CfgEntry::NameValue { name, value, .. }) =
@ -391,7 +450,7 @@ impl DocParser {
macro_rules! no_args {
($ident: ident) => {{
if let Err(span) = args.no_args() {
cx.expected_no_args(span);
expected_no_args(cx, span);
return;
}
@ -410,7 +469,7 @@ impl DocParser {
macro_rules! no_args_and_not_crate_level {
($ident: ident) => {{
if let Err(span) = args.no_args() {
cx.expected_no_args(span);
expected_no_args(cx, span);
return;
}
let span = path.span();
@ -423,7 +482,7 @@ impl DocParser {
macro_rules! no_args_and_crate_level {
($ident: ident) => {{
if let Err(span) = args.no_args() {
cx.expected_no_args(span);
expected_no_args(cx, span);
return;
}
let span = path.span();
@ -436,12 +495,12 @@ impl DocParser {
macro_rules! string_arg_and_crate_level {
($ident: ident) => {{
let Some(nv) = args.name_value() else {
cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym());
expected_name_value(cx, args.span().unwrap_or(path.span()), path.word_sym());
return;
};
let Some(s) = nv.value_as_str() else {
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
expected_string_literal(cx, nv.value_span, Some(nv.value_as_lit()));
return;
};
@ -512,7 +571,14 @@ impl DocParser {
self.parse_single_test_doc_attr_item(cx, mip);
}
MetaItemOrLitParser::Lit(lit) => {
cx.unexpected_literal(lit.span);
// FIXME: remove this method once merged and uncomment the line
// below instead.
// cx.unexpected_literal(lit.span);
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::MalformedDoc,
lit.span,
);
}
}
}
@ -582,7 +648,7 @@ impl DocParser {
let suggestions = cx.suggestions();
let span = cx.attr_span;
cx.emit_lint(
rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT,
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None },
span,
);
@ -595,14 +661,14 @@ impl DocParser {
self.parse_single_doc_attr_item(cx, mip);
}
MetaItemOrLitParser::Lit(lit) => {
cx.expected_name_value(lit.span, None);
expected_name_value(cx, lit.span, None);
}
}
}
}
ArgParser::NameValue(nv) => {
if nv.value_as_str().is_none() {
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
expected_string_literal(cx, nv.value_span, Some(nv.value_as_lit()));
} else {
unreachable!(
"Should have been handled at the same time as sugar-syntaxed doc comments"

View file

@ -16,6 +16,6 @@ impl<S: Stage> SingleAttributeParser<S> for DummyParser {
const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really
fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser) -> Option<AttributeKind> {
Some(AttributeKind::Dummy)
Some(AttributeKind::RustcDummy)
}
}

View file

@ -1,3 +1,4 @@
use rustc_errors::inline_fluent;
use rustc_feature::Features;
use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
use rustc_hir::attrs::*;
@ -10,12 +11,11 @@ use rustc_target::spec::{Arch, BinaryFormat};
use super::prelude::*;
use super::util::parse_single_integer;
use crate::attributes::cfg::parse_cfg_entry;
use crate::fluent_generated;
use crate::session_diagnostics::{
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ImportNameTypeRaw, ImportNameTypeX86,
IncompatibleWasmLink, InvalidLinkModifier, LinkFrameworkApple, LinkOrdinalOutOfRange,
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
WholeArchiveNeedsStatic,
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
};
pub(crate) struct LinkNameParser;
@ -165,6 +165,14 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
cx.emit_err(BundleNeedsStatic { span });
}
(sym::export_symbols, Some(NativeLibKind::Static { export_symbols, .. })) => {
assign_modifier(export_symbols)
}
(sym::export_symbols, _) => {
cx.emit_err(ExportSymbolsNeedsStatic { span });
}
(sym::verbatim, _) => assign_modifier(&mut verbatim),
(
@ -190,6 +198,7 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
span,
&[
sym::bundle,
sym::export_symbols,
sym::verbatim,
sym::whole_dash_archive,
sym::as_dash_needed,
@ -285,7 +294,9 @@ impl LinkParser {
};
let link_kind = match link_kind {
kw::Static => NativeLibKind::Static { bundle: None, whole_archive: None },
kw::Static => {
NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
}
sym::dylib => NativeLibKind::Dylib { as_needed: None },
sym::framework => {
if !sess.target.is_like_darwin {
@ -305,7 +316,7 @@ impl LinkParser {
sess,
sym::raw_dylib_elf,
nv.value_span,
fluent_generated::attr_parsing_raw_dylib_elf_unstable,
inline_fluent!("link kind `raw-dylib` is unstable on ELF platforms"),
)
.emit();
} else {
@ -320,7 +331,7 @@ impl LinkParser {
sess,
sym::link_arg_attribute,
nv.value_span,
fluent_generated::attr_parsing_link_arg_unstable,
inline_fluent!("link kind `link-arg` is unstable"),
)
.emit();
}
@ -385,13 +396,8 @@ impl LinkParser {
return true;
};
if !features.link_cfg() {
feature_err(
sess,
sym::link_cfg,
item.span(),
fluent_generated::attr_parsing_link_cfg_unstable,
)
.emit();
feature_err(sess, sym::link_cfg, item.span(), inline_fluent!("link cfg is unstable"))
.emit();
}
*cfg = parse_cfg_entry(cx, link_cfg).ok();
true
@ -529,7 +535,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser {
Allow(Target::Static),
Allow(Target::ForeignStatic),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::StdInternalSymbol;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStdInternalSymbol;
}
pub(crate) struct LinkOrdinalParser;

View file

@ -11,7 +11,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for AsPtrParser {
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::TraitImpl)),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::AsPtr;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAsPtr;
}
pub(crate) struct PubTransparentParser;
@ -23,7 +23,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for PubTransparentParser {
Allow(Target::Enum),
Allow(Target::Union),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PubTransparent;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPubTransparent;
}
pub(crate) struct PassByValueParser;
@ -35,7 +35,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for PassByValueParser {
Allow(Target::Enum),
Allow(Target::TyAlias),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PassByValue;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassByValue;
}
pub(crate) struct RustcShouldNotBeCalledOnConstItems;

View file

@ -7,36 +7,36 @@ use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
use crate::context::Stage;
use crate::target_checking::AllowedTargets;
pub(crate) struct RustcDumpUserArgs;
pub(crate) struct RustcDumpUserArgsParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpUserArgs {
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpUserArgsParser {
const PATH: &[Symbol] = &[sym::rustc_dump_user_args];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs;
}
pub(crate) struct RustcDumpDefParents;
pub(crate) struct RustcDumpDefParentsParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParents {
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParentsParser {
const PATH: &[Symbol] = &[sym::rustc_dump_def_parents];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents;
}
pub(crate) struct RustcDumpItemBounds;
pub(crate) struct RustcDumpItemBoundsParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBounds {
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBoundsParser {
const PATH: &[Symbol] = &[sym::rustc_dump_item_bounds];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds;
}
pub(crate) struct RustcDumpPredicates;
pub(crate) struct RustcDumpPredicatesParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicates {
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicatesParser {
const PATH: &[Symbol] = &[sym::rustc_dump_predicates];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
@ -49,9 +49,9 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicates {
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates;
}
pub(crate) struct RustcDumpVtable;
pub(crate) struct RustcDumpVtableParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVtable {
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVtableParser {
const PATH: &[Symbol] = &[sym::rustc_dump_vtable];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[

View file

@ -1,4 +1,7 @@
use std::path::PathBuf;
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
use rustc_hir::attrs::{BorrowckGraphvizFormatKind, RustcLayoutType, RustcMirKind};
use rustc_session::errors;
use super::prelude::*;
@ -306,6 +309,14 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParse
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;
}
pub(crate) struct RustcHiddenTypeOfOpaquesParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcHiddenTypeOfOpaquesParser {
const PATH: &[Symbol] = &[sym::rustc_hidden_type_of_opaques];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHiddenTypeOfOpaques;
}
pub(crate) struct RustcNounwindParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcNounwindParser {
@ -329,3 +340,160 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcOffloadKernelParser {
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;
}
pub(crate) struct RustcLayoutParser;
impl<S: Stage> CombineAttributeParser<S> for RustcLayoutParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_layout];
type Item = RustcLayoutType;
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcLayout(items);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
Allow(Target::Union),
Allow(Target::TyAlias),
]);
const TEMPLATE: AttributeTemplate =
template!(List: &["abi", "align", "size", "homogenous_aggregate", "debug"]);
fn extend(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser,
) -> impl IntoIterator<Item = Self::Item> {
let ArgParser::List(items) = args else {
cx.expected_list(cx.attr_span, args);
return vec![];
};
let mut result = Vec::new();
for item in items.mixed() {
let Some(arg) = item.meta_item() else {
cx.unexpected_literal(item.span());
continue;
};
let Some(ident) = arg.ident() else {
cx.expected_identifier(arg.span());
return vec![];
};
let ty = match ident.name {
sym::abi => RustcLayoutType::Abi,
sym::align => RustcLayoutType::Align,
sym::size => RustcLayoutType::Size,
sym::homogeneous_aggregate => RustcLayoutType::HomogenousAggregate,
sym::debug => RustcLayoutType::Debug,
_ => {
cx.expected_specific_argument(
ident.span,
&[sym::abi, sym::align, sym::size, sym::homogeneous_aggregate, sym::debug],
);
continue;
}
};
result.push(ty);
}
result
}
}
pub(crate) struct RustcMirParser;
impl<S: Stage> CombineAttributeParser<S> for RustcMirParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_mir];
type Item = RustcMirKind;
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcMir(items);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Trait { body: false })),
Allow(Target::Method(MethodKind::Trait { body: true })),
]);
const TEMPLATE: AttributeTemplate = template!(List: &["arg1, arg2, ..."]);
fn extend(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser,
) -> impl IntoIterator<Item = Self::Item> {
let Some(list) = args.list() else {
cx.expected_list(cx.attr_span, args);
return ThinVec::new();
};
list.mixed()
.filter_map(|arg| arg.meta_item())
.filter_map(|mi| {
if let Some(ident) = mi.ident() {
match ident.name {
sym::rustc_peek_maybe_init => Some(RustcMirKind::PeekMaybeInit),
sym::rustc_peek_maybe_uninit => Some(RustcMirKind::PeekMaybeUninit),
sym::rustc_peek_liveness => Some(RustcMirKind::PeekLiveness),
sym::stop_after_dataflow => Some(RustcMirKind::StopAfterDataflow),
sym::borrowck_graphviz_postflow => {
let Some(nv) = mi.args().name_value() else {
cx.expected_name_value(
mi.span(),
Some(sym::borrowck_graphviz_postflow),
);
return None;
};
let Some(path) = nv.value_as_str() else {
cx.expected_string_literal(nv.value_span, None);
return None;
};
let path = PathBuf::from(path.to_string());
if path.file_name().is_some() {
Some(RustcMirKind::BorrowckGraphvizPostflow { path })
} else {
cx.expected_filename_literal(nv.value_span);
None
}
}
sym::borrowck_graphviz_format => {
let Some(nv) = mi.args().name_value() else {
cx.expected_name_value(
mi.span(),
Some(sym::borrowck_graphviz_format),
);
return None;
};
let Some(format) = nv.value_as_ident() else {
cx.expected_identifier(nv.value_span);
return None;
};
match format.name {
sym::two_phase => Some(RustcMirKind::BorrowckGraphvizFormat {
format: BorrowckGraphvizFormatKind::TwoPhase,
}),
_ => {
cx.expected_specific_argument(format.span, &[sym::two_phase]);
None
}
}
}
_ => None,
}
} else {
None
}
})
.collect()
}
}
pub(crate) struct RustcNonConstTraitMethodParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcNonConstTraitMethodParser {
const PATH: &'static [Symbol] = &[sym::rustc_non_const_trait_method];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::Trait { body: false })),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonConstTraitMethod;
}

View file

@ -173,7 +173,7 @@ impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
let (stability, span) = self.stability?;
Some(AttributeKind::BodyStability { stability, span })
Some(AttributeKind::RustcBodyStability { stability, span })
}
}
@ -185,7 +185,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for ConstStabilityIndirectParser {
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ConstStabilityIndirect;
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConstStabilityIndirect;
}
#[derive(Default)]
@ -258,7 +258,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
let (stability, span) = self.stability?;
Some(AttributeKind::ConstStability { stability, span })
Some(AttributeKind::RustcConstStability { stability, span })
}
}

View file

@ -50,7 +50,11 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
cx.duplicate_key(arg.span(), key);
}
}
Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span })
Some(AttributeKind::RustcSkipDuringMethodDispatch {
array,
boxed_slice,
span: cx.attr_span,
})
}
}
@ -59,7 +63,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for ParenSugarParser {
const PATH: &[Symbol] = &[sym::rustc_paren_sugar];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ParenSugar;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcParenSugar;
}
pub(crate) struct TypeConstParser;
@ -91,7 +95,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for DenyExplicitImplParser {
const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DenyExplicitImpl;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDenyExplicitImpl;
}
pub(crate) struct DynIncompatibleTraitParser;
@ -99,7 +103,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for DynIncompatibleTraitParser {
const PATH: &[Symbol] = &[sym::rustc_dyn_incompatible_trait];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DynIncompatibleTrait;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDynIncompatibleTrait;
}
// Specialization
@ -109,7 +113,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for SpecializationTraitParser {
const PATH: &[Symbol] = &[sym::rustc_specialization_trait];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::SpecializationTrait;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcSpecializationTrait;
}
pub(crate) struct UnsafeSpecializationMarkerParser;
@ -117,7 +121,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for UnsafeSpecializationMarkerParser {
const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::UnsafeSpecializationMarker;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcUnsafeSpecializationMarker;
}
// Coherence
@ -127,7 +131,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for CoinductiveParser {
const PATH: &[Symbol] = &[sym::rustc_coinductive];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::Coinductive;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoinductive;
}
pub(crate) struct AllowIncoherentImplParser;
@ -136,7 +140,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowIncoherentImplParser {
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAllowIncoherentImpl;
}
pub(crate) struct FundamentalParser;

View file

@ -32,6 +32,6 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
}
None => None,
}
.map(AttributeKind::MacroTransparency)
.map(AttributeKind::RustcMacroTransparency)
}
}

View file

@ -10,93 +10,48 @@ use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrPath, HirId};
use rustc_parse::parser::Recovery;
use rustc_session::Session;
use rustc_session::lint::{Lint, LintId};
use rustc_span::{ErrorGuaranteed, Span, Symbol};
use crate::AttributeParser;
use crate::attributes::allow_unstable::{
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
};
use crate::attributes::body::CoroutineParser;
use crate::attributes::cfi_encoding::CfiEncodingParser;
use crate::attributes::codegen_attrs::{
ColdParser, CoverageParser, EiiForeignItemParser, ExportNameParser, ForceTargetFeatureParser,
NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
PatchableFunctionEntryParser, RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser,
TargetFeatureParser, ThreadLocalParser, TrackCallerParser, UsedParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::crate_level::{
CrateNameParser, CrateTypeParser, MoveSizeLimitParser, NeedsPanicRuntimeParser,
NoBuiltinsParser, NoCoreParser, NoMainParser, NoStdParser, PanicRuntimeParser,
PatternComplexityLimitParser, ProfilerRuntimeParser, RecursionLimitParser,
RustcCoherenceIsCoreParser, TypeLengthLimitParser, WindowsSubsystemParser,
};
use crate::attributes::debugger::DebuggerViualizerParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::do_not_recommend::DoNotRecommendParser;
use crate::attributes::doc::DocParser;
use crate::attributes::dummy::DummyParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
use crate::attributes::instruction_set::InstructionSetParser;
use crate::attributes::link_attrs::{
CompilerBuiltinsParser, ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser,
LinkOrdinalParser, LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser,
StdInternalSymbolParser,
};
use crate::attributes::lint_helpers::{
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
RustcShouldNotBeCalledOnConstItems,
};
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::macro_attrs::{
AllowInternalUnsafeParser, CollapseDebugInfoParser, MacroEscapeParser, MacroExportParser,
MacroUseParser,
};
use crate::attributes::must_not_suspend::MustNotSuspendParser;
use crate::attributes::must_use::MustUseParser;
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
use crate::attributes::no_link::NoLinkParser;
use crate::attributes::non_exhaustive::NonExhaustiveParser;
// Glob imports to avoid big, bitrotty import lists
use crate::attributes::allow_unstable::*;
use crate::attributes::body::*;
use crate::attributes::cfi_encoding::*;
use crate::attributes::codegen_attrs::*;
use crate::attributes::confusables::*;
use crate::attributes::crate_level::*;
use crate::attributes::debugger::*;
use crate::attributes::deprecation::*;
use crate::attributes::do_not_recommend::*;
use crate::attributes::doc::*;
use crate::attributes::dummy::*;
use crate::attributes::inline::*;
use crate::attributes::instruction_set::*;
use crate::attributes::link_attrs::*;
use crate::attributes::lint_helpers::*;
use crate::attributes::loop_match::*;
use crate::attributes::macro_attrs::*;
use crate::attributes::must_not_suspend::*;
use crate::attributes::must_use::*;
use crate::attributes::no_implicit_prelude::*;
use crate::attributes::no_link::*;
use crate::attributes::non_exhaustive::*;
use crate::attributes::path::PathParser as PathAttributeParser;
use crate::attributes::pin_v2::PinV2Parser;
use crate::attributes::proc_macro_attrs::{
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
};
use crate::attributes::prototype::CustomMirParser;
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
use crate::attributes::rustc_allocator::{
RustcAllocatorParser, RustcAllocatorZeroedParser, RustcAllocatorZeroedVariantParser,
RustcDeallocatorParser, RustcReallocatorParser,
};
use crate::attributes::rustc_dump::{
RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs,
RustcDumpVtable,
};
use crate::attributes::rustc_internal::{
RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser,
RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser,
RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser,
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, RustcNounwindParser,
RustcObjectLifetimeDefaultParser, RustcOffloadKernelParser, RustcScalableVectorParser,
RustcSimdMonomorphizeLaneLimitParser,
};
use crate::attributes::semantics::MayDangleParser;
use crate::attributes::stability::{
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
};
use crate::attributes::test_attrs::{
IgnoreParser, RustcVarianceOfOpaquesParser, RustcVarianceParser, ShouldPanicParser,
};
use crate::attributes::traits::{
AllowIncoherentImplParser, CoinductiveParser, DenyExplicitImplParser,
DynIncompatibleTraitParser, FundamentalParser, MarkerParser, ParenSugarParser, PointeeParser,
SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
UnsafeSpecializationMarkerParser,
};
use crate::attributes::transparency::TransparencyParser;
use crate::attributes::pin_v2::*;
use crate::attributes::proc_macro_attrs::*;
use crate::attributes::prototype::*;
use crate::attributes::repr::*;
use crate::attributes::rustc_allocator::*;
use crate::attributes::rustc_dump::*;
use crate::attributes::rustc_internal::*;
use crate::attributes::semantics::*;
use crate::attributes::stability::*;
use crate::attributes::test_attrs::*;
use crate::attributes::traits::*;
use crate::attributes::transparency::*;
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
use crate::parser::{ArgParser, RefPathParser};
use crate::session_diagnostics::{
@ -198,6 +153,8 @@ attribute_parsers!(
Combine<ForceTargetFeatureParser>,
Combine<LinkParser>,
Combine<ReprParser>,
Combine<RustcLayoutParser>,
Combine<RustcMirParser>,
Combine<TargetFeatureParser>,
Combine<UnstableFeatureBoundParser>,
// tidy-alphabetical-end
@ -292,21 +249,24 @@ attribute_parsers!(
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
Single<WithoutArgs<RustcDeallocatorParser>>,
Single<WithoutArgs<RustcDumpDefParents>>,
Single<WithoutArgs<RustcDumpItemBounds>>,
Single<WithoutArgs<RustcDumpPredicates>>,
Single<WithoutArgs<RustcDumpUserArgs>>,
Single<WithoutArgs<RustcDumpVtable>>,
Single<WithoutArgs<RustcDumpDefParentsParser>>,
Single<WithoutArgs<RustcDumpItemBoundsParser>>,
Single<WithoutArgs<RustcDumpPredicatesParser>>,
Single<WithoutArgs<RustcDumpUserArgsParser>>,
Single<WithoutArgs<RustcDumpVtableParser>>,
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
Single<WithoutArgs<RustcLintOptTyParser>>,
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>,
Single<WithoutArgs<RustcMainParser>>,
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
Single<WithoutArgs<RustcNonConstTraitMethodParser>>,
Single<WithoutArgs<RustcNounwindParser>>,
Single<WithoutArgs<RustcOffloadKernelParser>>,
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
Single<WithoutArgs<RustcPreserveUbChecksParser>>,
Single<WithoutArgs<RustcReallocatorParser>>,
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
Single<WithoutArgs<RustcVarianceOfOpaquesParser>>,
@ -381,7 +341,7 @@ impl Stage for Late {
}
fn should_emit(&self) -> ShouldEmit {
ShouldEmit::ErrorsAndLints { recover: true }
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }
}
}
@ -510,6 +470,11 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
)
}
/// Error that a filename string literal was expected.
pub(crate) fn expected_filename_literal(&self, span: Span) {
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedFilenameLiteral);
}
pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed {
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIntegerLiteral)
}
@ -768,10 +733,10 @@ pub enum ShouldEmit {
ErrorsAndLints {
/// Whether [`ArgParser`] will attempt to recover from errors.
///
/// If true, it will attempt to recover from bad input (like an invalid literal). Setting
/// this to false will instead return early, and not raise errors except at the top level
/// (in [`ArgParser::from_attr_args`]).
recover: bool,
/// Whether it is allowed to recover from bad input (like an invalid literal). Setting
/// this to `Forbidden` will instead return early, and not raise errors except at the top
/// level (in [`ArgParser::from_attr_args`]).
recovery: Recovery,
},
/// The operation will *not* emit errors and lints.
///

View file

@ -113,5 +113,3 @@ pub use attributes::util::{is_builtin_attr, parse_version};
pub use context::{Early, Late, OmitDoc, ShouldEmit};
pub use interface::AttributeParser;
pub use session_diagnostics::ParsedDescription;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

View file

@ -15,7 +15,7 @@ use rustc_ast_pretty::pprust;
use rustc_errors::{Diag, PResult};
use rustc_hir::{self as hir, AttrPath};
use rustc_parse::exp;
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr};
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, Recovery, token_descr};
use rustc_session::errors::create_lit_error;
use rustc_session::parse::ParseSess;
use rustc_span::{Ident, Span, Symbol, sym};
@ -121,7 +121,7 @@ impl ArgParser {
&args.tokens,
args.dspan.entire(),
psess,
ShouldEmit::ErrorsAndLints { recover: false },
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden },
) {
Ok(p) => return Some(ArgParser::List(p)),
Err(e) => {
@ -373,7 +373,10 @@ fn expr_to_lit<'sess>(
}
Err(err) => {
let err = create_lit_error(psess, err, token_lit, expr.span);
if matches!(should_emit, ShouldEmit::ErrorsAndLints { recover: false }) {
if matches!(
should_emit,
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
) {
Err(err)
} else {
let lit = MetaItemLit {
@ -431,7 +434,10 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
if !lit.kind.is_unsuffixed() {
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
let err = self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span });
if matches!(self.should_emit, ShouldEmit::ErrorsAndLints { recover: false }) {
if matches!(
self.should_emit,
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
) {
return Err(err);
} else {
self.should_emit.emit_err(err)
@ -569,6 +575,10 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
should_emit: ShouldEmit,
) -> PResult<'sess, MetaItemListParser> {
let mut parser = Parser::new(psess, tokens, None);
if let ShouldEmit::ErrorsAndLints { recovery } = should_emit {
parser = parser.recovery(recovery);
}
let mut this = MetaItemListParserContext { parser: &mut parser, should_emit };
// Presumably, the majority of the time there will only be one attr.

View file

@ -11,10 +11,8 @@ use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Span, Symbol};
use rustc_target::spec::TargetTuple;
use crate::fluent_generated as fluent;
#[derive(Diagnostic)]
#[diag(attr_parsing_invalid_predicate, code = E0537)]
#[diag("invalid predicate `{$predicate}`", code = E0537)]
pub(crate) struct InvalidPredicate {
#[primary_span]
pub span: Span,
@ -23,7 +21,7 @@ pub(crate) struct InvalidPredicate {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_doc_alias_empty)]
#[diag("{$attr_str} attribute cannot have empty value")]
pub(crate) struct DocAliasEmpty<'a> {
#[primary_span]
pub span: Span,
@ -31,7 +29,7 @@ pub(crate) struct DocAliasEmpty<'a> {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_doc_alias_bad_char)]
#[diag("{$char_} character isn't allowed in {$attr_str}")]
pub(crate) struct DocAliasBadChar<'a> {
#[primary_span]
pub span: Span,
@ -40,7 +38,7 @@ pub(crate) struct DocAliasBadChar<'a> {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_doc_alias_start_end)]
#[diag("{$attr_str} cannot start or end with ' '")]
pub(crate) struct DocAliasStartEnd<'a> {
#[primary_span]
pub span: Span,
@ -48,7 +46,7 @@ pub(crate) struct DocAliasStartEnd<'a> {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_doc_attr_not_crate_level)]
#[diag("`#![doc({$attr_name} = \"...\")]` isn't allowed as a crate-level attribute")]
pub(crate) struct DocAttrNotCrateLevel {
#[primary_span]
pub span: Span,
@ -56,8 +54,8 @@ pub(crate) struct DocAttrNotCrateLevel {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_doc_keyword_not_keyword)]
#[help]
#[diag("nonexistent keyword `{$keyword}` used in `#[doc(keyword = \"...\")]`")]
#[help("only existing keywords are allowed in core/std")]
pub(crate) struct DocKeywordNotKeyword {
#[primary_span]
pub span: Span,
@ -65,8 +63,8 @@ pub(crate) struct DocKeywordNotKeyword {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_doc_attribute_not_attribute)]
#[help]
#[diag("nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = \"...\")]`")]
#[help("only existing builtin attributes are allowed in core/std")]
pub(crate) struct DocAttributeNotAttribute {
#[primary_span]
pub span: Span,
@ -74,28 +72,28 @@ pub(crate) struct DocAttributeNotAttribute {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_missing_since, code = E0542)]
#[diag("missing 'since'", code = E0542)]
pub(crate) struct MissingSince {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_missing_note, code = E0543)]
#[diag("missing 'note'", code = E0543)]
pub(crate) struct MissingNote {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_multiple_stability_levels, code = E0544)]
#[diag("multiple stability levels", code = E0544)]
pub(crate) struct MultipleStabilityLevels {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_invalid_issue_string, code = E0545)]
#[diag("`issue` must be a non-zero numeric string or \"none\"", code = E0545)]
pub(crate) struct InvalidIssueString {
#[primary_span]
pub span: Span,
@ -108,31 +106,31 @@ pub(crate) struct InvalidIssueString {
// translatable.
#[derive(Subdiagnostic)]
pub(crate) enum InvalidIssueStringCause {
#[label(attr_parsing_must_not_be_zero)]
#[label("`issue` must not be \"0\", use \"none\" instead")]
MustNotBeZero {
#[primary_span]
span: Span,
},
#[label(attr_parsing_empty)]
#[label("cannot parse integer from empty string")]
Empty {
#[primary_span]
span: Span,
},
#[label(attr_parsing_invalid_digit)]
#[label("invalid digit found in string")]
InvalidDigit {
#[primary_span]
span: Span,
},
#[label(attr_parsing_pos_overflow)]
#[label("number too large to fit in target type")]
PosOverflow {
#[primary_span]
span: Span,
},
#[label(attr_parsing_neg_overflow)]
#[label("number too small to fit in target type")]
NegOverflow {
#[primary_span]
span: Span,
@ -153,21 +151,21 @@ impl InvalidIssueStringCause {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_missing_feature, code = E0546)]
#[diag("missing 'feature'", code = E0546)]
pub(crate) struct MissingFeature {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_non_ident_feature, code = E0546)]
#[diag("'feature' is not an identifier", code = E0546)]
pub(crate) struct NonIdentFeature {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_missing_issue, code = E0547)]
#[diag("missing 'issue'", code = E0547)]
pub(crate) struct MissingIssue {
#[primary_span]
pub span: Span,
@ -176,20 +174,20 @@ pub(crate) struct MissingIssue {
// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`?
// It is more similar to `IncorrectReprFormatGeneric`.
#[derive(Diagnostic)]
#[diag(attr_parsing_incorrect_repr_format_packed_one_or_zero_arg, code = E0552)]
#[diag("incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all", code = E0552)]
pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_incorrect_repr_format_packed_expect_integer, code = E0552)]
#[diag("incorrect `repr(packed)` attribute format: `packed` expects a literal integer as argument", code = E0552)]
pub(crate) struct IncorrectReprFormatPackedExpectInteger {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_invalid_repr_hint_no_paren, code = E0552)]
#[diag("invalid representation hint: `{$name}` does not take a parenthesized argument list", code = E0552)]
pub(crate) struct InvalidReprHintNoParen {
#[primary_span]
pub span: Span,
@ -198,7 +196,7 @@ pub(crate) struct InvalidReprHintNoParen {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_invalid_repr_hint_no_value, code = E0552)]
#[diag("invalid representation hint: `{$name}` does not take a value", code = E0552)]
pub(crate) struct InvalidReprHintNoValue {
#[primary_span]
pub span: Span,
@ -207,15 +205,19 @@ pub(crate) struct InvalidReprHintNoValue {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_invalid_repr_align_need_arg, code = E0589)]
#[diag("invalid `repr(align)` attribute: `align` needs an argument", code = E0589)]
pub(crate) struct InvalidReprAlignNeedArg {
#[primary_span]
#[suggestion(code = "align(...)", applicability = "has-placeholders")]
#[suggestion(
"supply an argument here",
code = "align(...)",
applicability = "has-placeholders"
)]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_invalid_repr_generic, code = E0589)]
#[diag("invalid `repr({$repr_arg})` attribute: {$error_part}", code = E0589)]
pub(crate) struct InvalidReprGeneric<'a> {
#[primary_span]
pub span: Span,
@ -225,21 +227,21 @@ pub(crate) struct InvalidReprGeneric<'a> {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_incorrect_repr_format_align_one_arg, code = E0693)]
#[diag("incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses", code = E0693)]
pub(crate) struct IncorrectReprFormatAlignOneArg {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_incorrect_repr_format_expect_literal_integer, code = E0693)]
#[diag("incorrect `repr(align)` attribute format: `align` expects a literal integer as argument", code = E0693)]
pub(crate) struct IncorrectReprFormatExpectInteger {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_incorrect_repr_format_generic, code = E0693)]
#[diag("incorrect `repr({$repr_arg})` attribute format", code = E0693)]
pub(crate) struct IncorrectReprFormatGeneric {
#[primary_span]
pub span: Span,
@ -253,7 +255,7 @@ pub(crate) struct IncorrectReprFormatGeneric {
#[derive(Subdiagnostic)]
pub(crate) enum IncorrectReprFormatGenericCause {
#[suggestion(
attr_parsing_suggestion,
"use parentheses instead",
code = "{name}({value})",
applicability = "machine-applicable"
)]
@ -269,7 +271,7 @@ pub(crate) enum IncorrectReprFormatGenericCause {
},
#[suggestion(
attr_parsing_suggestion,
"use parentheses instead",
code = "{name}({value})",
applicability = "machine-applicable"
)]
@ -298,48 +300,48 @@ impl IncorrectReprFormatGenericCause {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_rustc_promotable_pairing, code = E0717)]
#[diag("`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute", code = E0717)]
pub(crate) struct RustcPromotablePairing {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_rustc_allowed_unstable_pairing, code = E0789)]
#[diag("`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute", code = E0789)]
pub(crate) struct RustcAllowedUnstablePairing {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_deprecated_item_suggestion)]
#[diag("suggestions on deprecated items are unstable")]
pub(crate) struct DeprecatedItemSuggestion {
#[primary_span]
pub span: Span,
#[help]
#[help("add `#![feature(deprecated_suggestion)]` to the crate root")]
pub is_nightly: bool,
#[note]
#[note("see #94785 for more details")]
pub details: (),
}
#[derive(Diagnostic)]
#[diag(attr_parsing_expected_single_version_literal)]
#[diag("expected single version literal")]
pub(crate) struct ExpectedSingleVersionLiteral {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_expected_version_literal)]
#[diag("expected a version literal")]
pub(crate) struct ExpectedVersionLiteral {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_expects_feature_list)]
#[diag("`{$name}` expects a list of feature names")]
pub(crate) struct ExpectsFeatureList {
#[primary_span]
pub span: Span,
@ -348,7 +350,7 @@ pub(crate) struct ExpectsFeatureList {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_expects_features)]
#[diag("`{$name}` expects feature names")]
pub(crate) struct ExpectsFeatures {
#[primary_span]
pub span: Span,
@ -357,21 +359,21 @@ pub(crate) struct ExpectsFeatures {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_invalid_since)]
#[diag("'since' must be a Rust version number, such as \"1.31.0\"")]
pub(crate) struct InvalidSince {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_soft_no_args)]
#[diag("`soft` should not have any arguments")]
pub(crate) struct SoftNoArgs {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_unknown_version_literal)]
#[diag("unknown version literal format, assuming it refers to a future version")]
pub(crate) struct UnknownVersionLiteral {
#[primary_span]
pub span: Span,
@ -379,78 +381,83 @@ pub(crate) struct UnknownVersionLiteral {
// FIXME(jdonszelmann) duplicated from `rustc_passes`, remove once `check_attr` is integrated.
#[derive(Diagnostic)]
#[diag(attr_parsing_unused_multiple)]
#[diag("multiple `{$name}` attributes")]
pub(crate) struct UnusedMultiple {
#[primary_span]
#[suggestion(code = "", applicability = "machine-applicable")]
#[suggestion("remove this attribute", code = "", applicability = "machine-applicable")]
pub this: Span,
#[note]
#[note("attribute also specified here")]
pub other: Span,
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_null_on_export, code = E0648)]
#[diag("`export_name` may not contain null characters", code = E0648)]
pub(crate) struct NullOnExport {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_null_on_link_section, code = E0648)]
#[diag("`link_section` may not contain null characters", code = E0648)]
pub(crate) struct NullOnLinkSection {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_null_on_objc_class)]
#[diag("`objc::class!` may not contain null characters")]
pub(crate) struct NullOnObjcClass {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_null_on_objc_selector)]
#[diag("`objc::selector!` may not contain null characters")]
pub(crate) struct NullOnObjcSelector {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_objc_class_expected_string_literal)]
#[diag("`objc::class!` expected a string literal")]
pub(crate) struct ObjcClassExpectedStringLiteral {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_objc_selector_expected_string_literal)]
#[diag("`objc::selector!` expected a string literal")]
pub(crate) struct ObjcSelectorExpectedStringLiteral {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_stability_outside_std, code = E0734)]
#[diag("stability attributes may not be used outside of the standard library", code = E0734)]
pub(crate) struct StabilityOutsideStd {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_empty_confusables)]
#[diag("expected at least one confusable name")]
pub(crate) struct EmptyConfusables {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[help]
#[diag(attr_parsing_invalid_target)]
#[help("`#[{$name}]` can {$only}be applied to {$applied}")]
#[diag("`#[{$name}]` attribute cannot be used on {$target}")]
pub(crate) struct InvalidTarget {
#[primary_span]
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
#[suggestion(
"remove the attribute",
code = "",
applicability = "machine-applicable",
style = "tool-only"
)]
pub span: Span,
pub name: AttrPath,
pub target: &'static str,
@ -459,7 +466,7 @@ pub(crate) struct InvalidTarget {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_invalid_alignment_value, code = E0589)]
#[diag("invalid alignment value: {$error_part}", code = E0589)]
pub(crate) struct InvalidAlignmentValue {
#[primary_span]
pub span: Span,
@ -467,43 +474,49 @@ pub(crate) struct InvalidAlignmentValue {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_repr_ident, code = E0565)]
#[diag("meta item in `repr` must be an identifier", code = E0565)]
pub(crate) struct ReprIdent {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_unrecognized_repr_hint, code = E0552)]
#[help]
#[note]
#[diag("unrecognized representation hint", code = E0552)]
#[help(
"valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`"
)]
#[note(
"for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>"
)]
pub(crate) struct UnrecognizedReprHint {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_unstable_feature_bound_incompatible_stability)]
#[help]
#[diag("item annotated with `#[unstable_feature_bound]` should not be stable")]
#[help(
"if this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`"
)]
pub(crate) struct UnstableFeatureBoundIncompatibleStability {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_naked_functions_incompatible_attribute, code = E0736)]
#[diag("attribute incompatible with `#[unsafe(naked)]`", code = E0736)]
pub(crate) struct NakedFunctionIncompatibleAttribute {
#[primary_span]
#[label]
#[label("the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`")]
pub span: Span,
#[label(attr_parsing_naked_attribute)]
#[label("function marked with `#[unsafe(naked)]` here")]
pub naked_span: Span,
pub attr: String,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_link_ordinal_out_of_range)]
#[note]
#[diag("ordinal value in `link_ordinal` is too large: `{$ordinal}`")]
#[note("the value may not exceed `u16::MAX`")]
pub(crate) struct LinkOrdinalOutOfRange {
#[primary_span]
pub span: Span,
@ -511,8 +524,8 @@ pub(crate) struct LinkOrdinalOutOfRange {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_rustc_scalable_vector_count_out_of_range)]
#[note]
#[diag("element count in `rustc_scalable_vector` is too large: `{$n}`")]
#[note("the value may not exceed `u16::MAX`")]
pub(crate) struct RustcScalableVectorCountOutOfRange {
#[primary_span]
pub span: Span,
@ -524,6 +537,7 @@ pub(crate) enum AttributeParseErrorReason<'a> {
ExpectedStringLiteral {
byte_string: Option<Span>,
},
ExpectedFilenameLiteral,
ExpectedIntegerLiteral,
ExpectedIntegerLiteralInRange {
lower_bound: isize,
@ -586,7 +600,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
if let Some(start_point_span) = byte_string {
diag.span_suggestion(
start_point_span,
fluent::attr_parsing_unsupported_literal_suggestion,
"consider removing the prefix",
"",
Applicability::MaybeIncorrect,
);
@ -597,6 +611,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
diag.span_label(self.span, "expected a string literal here");
}
}
AttributeParseErrorReason::ExpectedFilenameLiteral => {
diag.span_label(self.span, "expected a filename string literal here");
}
AttributeParseErrorReason::ExpectedIntegerLiteral => {
diag.span_label(self.span, "expected an integer literal here");
}
@ -751,30 +768,27 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_invalid_attr_unsafe)]
#[note]
#[diag("`{$name}` is not an unsafe attribute")]
#[note("extraneous unsafe is not allowed in attributes")]
pub(crate) struct InvalidAttrUnsafe {
#[primary_span]
#[label]
#[label("this is not an unsafe attribute")]
pub span: Span,
pub name: AttrPath,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_unsafe_attr_outside_unsafe)]
#[diag("unsafe attribute used without unsafe")]
pub(crate) struct UnsafeAttrOutsideUnsafe {
#[primary_span]
#[label]
#[label("usage of unsafe attribute")]
pub span: Span,
#[subdiagnostic]
pub suggestion: Option<UnsafeAttrOutsideUnsafeSuggestion>,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
attr_parsing_unsafe_attr_outside_unsafe_suggestion,
applicability = "machine-applicable"
)]
#[multipart_suggestion("wrap the attribute in `unsafe(...)`", applicability = "machine-applicable")]
pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
#[suggestion_part(code = "unsafe(")]
pub left: Span,
@ -783,7 +797,7 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_meta_bad_delim)]
#[diag("wrong meta list delimiters")]
pub(crate) struct MetaBadDelim {
#[primary_span]
pub span: Span,
@ -793,7 +807,7 @@ pub(crate) struct MetaBadDelim {
#[derive(Subdiagnostic)]
#[multipart_suggestion(
attr_parsing_meta_bad_delim_suggestion,
"the delimiters should be `(` and `)`",
applicability = "machine-applicable"
)]
pub(crate) struct MetaBadDelimSugg {
@ -804,7 +818,7 @@ pub(crate) struct MetaBadDelimSugg {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_invalid_meta_item)]
#[diag("expected a literal (`1u8`, `1.0f32`, `\"string\"`, etc.) here, found {$descr}")]
pub(crate) struct InvalidMetaItem {
#[primary_span]
pub span: Span,
@ -813,12 +827,15 @@ pub(crate) struct InvalidMetaItem {
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
#[subdiagnostic]
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
#[label]
#[label("{$descr}s are not allowed here")]
pub label: Option<Span>,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(attr_parsing_quote_ident_sugg, applicability = "machine-applicable")]
#[multipart_suggestion(
"surround the identifier with quotation marks to make it into a string literal",
applicability = "machine-applicable"
)]
pub(crate) struct InvalidMetaItemQuoteIdentSugg {
#[suggestion_part(code = "\"")]
pub before: Span,
@ -827,73 +844,80 @@ pub(crate) struct InvalidMetaItemQuoteIdentSugg {
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(attr_parsing_remove_neg_sugg, applicability = "machine-applicable")]
#[multipart_suggestion(
"negative numbers are not literals, try removing the `-` sign",
applicability = "machine-applicable"
)]
pub(crate) struct InvalidMetaItemRemoveNegSugg {
#[suggestion_part(code = "")]
pub negative_sign: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_suffixed_literal_in_attribute)]
#[help]
#[diag("suffixed literals are not allowed in attributes")]
#[help(
"instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)"
)]
pub(crate) struct SuffixedLiteralInAttribute {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_empty_link_name, code = E0454)]
#[diag("link name must not be empty", code = E0454)]
pub(crate) struct EmptyLinkName {
#[primary_span]
#[label]
#[label("empty link name")]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_link_framework_apple, code = E0455)]
#[diag("link kind `framework` is only supported on Apple targets", code = E0455)]
pub(crate) struct LinkFrameworkApple {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_incompatible_wasm_link)]
#[diag("`wasm_import_module` is incompatible with other arguments in `#[link]` attributes")]
pub(crate) struct IncompatibleWasmLink {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_link_requires_name, code = E0459)]
#[diag("`#[link]` attribute requires a `name = \"string\"` argument", code = E0459)]
pub(crate) struct LinkRequiresName {
#[primary_span]
#[label]
#[label("missing `name` argument")]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_raw_dylib_no_nul)]
#[diag("link name must not contain NUL characters if link kind is `raw-dylib`")]
pub(crate) struct RawDylibNoNul {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_raw_dylib_only_windows, code = E0455)]
#[diag("link kind `raw-dylib` is only supported on Windows targets", code = E0455)]
pub(crate) struct RawDylibOnlyWindows {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_invalid_link_modifier)]
#[diag(
"invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed, export-symbols"
)]
pub(crate) struct InvalidLinkModifier {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_multiple_modifiers)]
#[diag("multiple `{$modifier}` modifiers in a single `modifiers` argument")]
pub(crate) struct MultipleModifiers {
#[primary_span]
pub span: Span,
@ -901,52 +925,61 @@ pub(crate) struct MultipleModifiers {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_import_name_type_x86)]
#[diag("import name type is only supported on x86")]
pub(crate) struct ImportNameTypeX86 {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_bundle_needs_static)]
#[diag("linking modifier `bundle` is only compatible with `static` linking kind")]
pub(crate) struct BundleNeedsStatic {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_whole_archive_needs_static)]
#[diag("linking modifier `export-symbols` is only compatible with `static` linking kind")]
pub(crate) struct ExportSymbolsNeedsStatic {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag("linking modifier `whole-archive` is only compatible with `static` linking kind")]
pub(crate) struct WholeArchiveNeedsStatic {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_as_needed_compatibility)]
#[diag(
"linking modifier `as-needed` is only compatible with `dylib`, `framework` and `raw-dylib` linking kinds"
)]
pub(crate) struct AsNeededCompatibility {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_import_name_type_raw)]
#[diag("import name type can only be used with link kind `raw-dylib`")]
pub(crate) struct ImportNameTypeRaw {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_limit_invalid)]
#[diag("`limit` must be a non-negative integer")]
pub(crate) struct LimitInvalid<'a> {
#[primary_span]
pub span: Span,
#[label]
#[label("{$error_str}")]
pub value_span: Span,
pub error_str: &'a str,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_cfg_attr_bad_delim)]
#[diag("wrong `cfg_attr` delimiters")]
pub(crate) struct CfgAttrBadDelim {
#[primary_span]
pub span: Span,
@ -955,14 +988,16 @@ pub(crate) struct CfgAttrBadDelim {
}
#[derive(Diagnostic)]
#[diag(attr_parsing_doc_alias_malformed)]
#[diag(
"doc alias attribute expects a string `#[doc(alias = \"a\")]` or a list of strings `#[doc(alias(\"a\", \"b\"))]`"
)]
pub(crate) struct DocAliasMalformed {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_unsupported_instruction_set)]
#[diag("target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]`")]
pub(crate) struct UnsupportedInstructionSet<'a> {
#[primary_span]
pub span: Span,

View file

@ -205,7 +205,7 @@ pub(crate) fn allowed_targets_applied(
];
const IMPL_LIKE: &[Target] =
&[Target::Impl { of_trait: false }, Target::Impl { of_trait: true }];
const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum];
const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum, Target::Union];
let mut added_fake_targets = Vec::new();
filter_targets(

View file

@ -169,7 +169,7 @@ pub(crate) trait TypeOpInfo<'tcx> {
let placeholder_region = ty::Region::new_placeholder(
tcx,
ty::Placeholder::new(adjusted_universe.into(), placeholder.bound),
ty::PlaceholderRegion::new(adjusted_universe.into(), placeholder.bound),
);
let error_region =
@ -179,7 +179,7 @@ pub(crate) trait TypeOpInfo<'tcx> {
adjusted_universe.map(|adjusted| {
ty::Region::new_placeholder(
tcx,
ty::Placeholder::new(adjusted.into(), error_placeholder.bound),
ty::PlaceholderRegion::new(adjusted.into(), error_placeholder.bound),
)
})
} else {

View file

@ -2309,12 +2309,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
tcx: TyCtxt<'hir>,
issue_span: Span,
expr_span: Span,
body_expr: Option<&'hir hir::Expr<'hir>>,
loop_bind: Option<&'hir Ident>,
loop_span: Option<Span>,
head_span: Option<Span>,
pat_span: Option<Span>,
head: Option<&'hir hir::Expr<'hir>>,
body_expr: Option<&'hir hir::Expr<'hir>> = None,
loop_bind: Option<&'hir Ident> = None,
loop_span: Option<Span> = None,
head_span: Option<Span> = None,
pat_span: Option<Span> = None,
head: Option<&'hir hir::Expr<'hir>> = None,
}
impl<'hir> Visitor<'hir> for ExprFinder<'hir> {
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
@ -2380,17 +2380,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
hir::intravisit::walk_expr(self, ex);
}
}
let mut finder = ExprFinder {
tcx,
expr_span: span,
issue_span,
loop_bind: None,
body_expr: None,
head_span: None,
loop_span: None,
pat_span: None,
head: None,
};
let mut finder = ExprFinder { tcx, expr_span: span, issue_span, .. };
finder.visit_expr(tcx.hir_body(body_id).value);
if let Some(body_expr) = finder.body_expr
@ -2625,13 +2615,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
struct ExpressionFinder<'tcx> {
capture_span: Span,
closure_change_spans: Vec<Span>,
closure_arg_span: Option<Span>,
in_closure: bool,
suggest_arg: String,
closure_change_spans: Vec<Span> = vec![],
closure_arg_span: Option<Span> = None,
in_closure: bool = false,
suggest_arg: String = String::new(),
tcx: TyCtxt<'tcx>,
closure_local_id: Option<hir::HirId>,
closure_call_changes: Vec<(Span, String)>,
closure_local_id: Option<hir::HirId> = None,
closure_call_changes: Vec<(Span, String)> = vec![],
}
impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
@ -2712,16 +2702,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}) = self.infcx.tcx.hir_node(self.mir_hir_id())
&& let hir::Node::Expr(expr) = self.infcx.tcx.hir_node(body_id.hir_id)
{
let mut finder = ExpressionFinder {
capture_span: *capture_kind_span,
closure_change_spans: vec![],
closure_arg_span: None,
in_closure: false,
suggest_arg: String::new(),
closure_local_id: None,
closure_call_changes: vec![],
tcx: self.infcx.tcx,
};
let mut finder =
ExpressionFinder { capture_span: *capture_kind_span, tcx: self.infcx.tcx, .. };
finder.visit_expr(expr);
if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {

View file

@ -1,3 +1,4 @@
use rustc_abi::FieldIdx;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diag};
use rustc_hir::intravisit::Visitor;
@ -7,7 +8,7 @@ use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
use rustc_span::def_id::DefId;
use rustc_span::{BytePos, DUMMY_SP, ExpnKind, MacroKind, Span};
use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
use rustc_trait_selection::infer::InferCtxtExt;
use tracing::debug;
@ -472,49 +473,30 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
if def_id.as_local() == Some(self.mir_def_id())
&& let Some(upvar_field) = upvar_field =>
{
let closure_kind_ty = closure_args.as_closure().kind_ty();
let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind,
Some(ty::ClosureKind::FnOnce) => {
bug!("closure kind does not match first argument type")
}
None => bug!("closure kind not inferred by borrowck"),
};
let capture_description =
format!("captured variable in an `{closure_kind}` closure");
let upvar = &self.upvars[upvar_field.index()];
let upvar_hir_id = upvar.get_root_variable();
let upvar_name = upvar.to_string(tcx);
let upvar_span = tcx.hir_span(upvar_hir_id);
let place_name = self.describe_any_place(move_place.as_ref());
let place_description =
if self.is_upvar_field_projection(move_place.as_ref()).is_some() {
format!("{place_name}, a {capture_description}")
} else {
format!("{place_name}, as `{upvar_name}` is a {capture_description}")
};
debug!(
"report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}",
closure_kind_ty, closure_kind, place_description,
);
let closure_span = tcx.def_span(def_id);
self.cannot_move_out_of(span, &place_description)
.with_span_label(upvar_span, "captured outer variable")
.with_span_label(
closure_span,
format!("captured by this `{closure_kind}` closure"),
)
.with_span_help(
self.get_closure_bound_clause_span(*def_id),
"`Fn` and `FnMut` closures require captured values to be able to be \
consumed multiple times, but `FnOnce` closures may consume them only once",
)
self.report_closure_move_error(
span,
move_place,
*def_id,
closure_args.as_closure().kind_ty(),
upvar_field,
ty::Asyncness::No,
)
}
ty::CoroutineClosure(def_id, closure_args)
if def_id.as_local() == Some(self.mir_def_id())
&& let Some(upvar_field) = upvar_field
&& self
.get_closure_bound_clause_span(*def_id, ty::Asyncness::Yes)
.is_some() =>
{
self.report_closure_move_error(
span,
move_place,
*def_id,
closure_args.as_coroutine_closure().kind_ty(),
upvar_field,
ty::Asyncness::Yes,
)
}
_ => {
let source = self.borrowed_content_source(deref_base);
@ -563,45 +545,134 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
err
}
fn get_closure_bound_clause_span(&self, def_id: DefId) -> Span {
fn report_closure_move_error(
&self,
span: Span,
move_place: Place<'tcx>,
def_id: DefId,
closure_kind_ty: Ty<'tcx>,
upvar_field: FieldIdx,
asyncness: ty::Asyncness,
) -> Diag<'infcx> {
let tcx = self.infcx.tcx;
let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind,
Some(ty::ClosureKind::FnOnce) => {
bug!("closure kind does not match first argument type")
}
None => bug!("closure kind not inferred by borrowck"),
};
let async_prefix = if asyncness.is_async() { "Async" } else { "" };
let capture_description =
format!("captured variable in an `{async_prefix}{closure_kind}` closure");
let upvar = &self.upvars[upvar_field.index()];
let upvar_hir_id = upvar.get_root_variable();
let upvar_name = upvar.to_string(tcx);
let upvar_span = tcx.hir_span(upvar_hir_id);
let place_name = self.describe_any_place(move_place.as_ref());
let place_description = if self.is_upvar_field_projection(move_place.as_ref()).is_some() {
format!("{place_name}, a {capture_description}")
} else {
format!("{place_name}, as `{upvar_name}` is a {capture_description}")
};
debug!(?closure_kind_ty, ?closure_kind, ?place_description);
let closure_span = tcx.def_span(def_id);
let help_msg = format!(
"`{async_prefix}Fn` and `{async_prefix}FnMut` closures require captured values to \
be able to be consumed multiple times, but `{async_prefix}FnOnce` closures may \
consume them only once"
);
let mut err = self
.cannot_move_out_of(span, &place_description)
.with_span_label(upvar_span, "captured outer variable")
.with_span_label(
closure_span,
format!("captured by this `{async_prefix}{closure_kind}` closure"),
);
if let Some(bound_span) = self.get_closure_bound_clause_span(def_id, asyncness) {
err.span_help(bound_span, help_msg);
} else if !asyncness.is_async() {
// For sync closures, always emit the help message even without a span.
// For async closures, we only enter this branch if we found a valid span
// (due to the match guard), so no fallback is needed.
err.help(help_msg);
}
err
}
fn get_closure_bound_clause_span(
&self,
def_id: DefId,
asyncness: ty::Asyncness,
) -> Option<Span> {
let tcx = self.infcx.tcx;
let typeck_result = tcx.typeck(self.mir_def_id());
// Check whether the closure is an argument to a call, if so,
// get the instantiated where-bounds of that call.
let closure_hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return DUMMY_SP };
let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return None };
let predicates = match parent.kind {
hir::ExprKind::Call(callee, _) => {
let Some(ty) = typeck_result.node_type_opt(callee.hir_id) else { return DUMMY_SP };
let ty::FnDef(fn_def_id, args) = ty.kind() else { return DUMMY_SP };
let ty = typeck_result.node_type_opt(callee.hir_id)?;
let ty::FnDef(fn_def_id, args) = ty.kind() else { return None };
tcx.predicates_of(fn_def_id).instantiate(tcx, args)
}
hir::ExprKind::MethodCall(..) => {
let Some((_, method)) = typeck_result.type_dependent_def(parent.hir_id) else {
return DUMMY_SP;
};
let (_, method) = typeck_result.type_dependent_def(parent.hir_id)?;
let args = typeck_result.node_args(parent.hir_id);
tcx.predicates_of(method).instantiate(tcx, args)
}
_ => return DUMMY_SP,
_ => return None,
};
// Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`.
// Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`
// or `AsyncFn[Mut]`.
for (pred, span) in predicates.predicates.iter().zip(predicates.spans.iter()) {
if let Some(clause) = pred.as_trait_clause()
&& let ty::Closure(clause_closure_def_id, _) = clause.self_ty().skip_binder().kind()
&& *clause_closure_def_id == def_id
&& (tcx.lang_items().fn_mut_trait() == Some(clause.def_id())
|| tcx.lang_items().fn_trait() == Some(clause.def_id()))
{
// Found `<TyOfCapturingClosure as FnMut>`
// We point at the `Fn()` or `FnMut()` bound that coerced the closure, which
// could be changed to `FnOnce()` to avoid the move error.
return *span;
let dominated_by_fn_trait = self
.closure_clause_kind(*pred, def_id, asyncness)
.is_some_and(|kind| matches!(kind, ty::ClosureKind::Fn | ty::ClosureKind::FnMut));
if dominated_by_fn_trait {
// Found `<TyOfCapturingClosure as FnMut>` or
// `<TyOfCapturingClosure as AsyncFnMut>`.
// We point at the bound that coerced the closure, which could be changed
// to `FnOnce()` or `AsyncFnOnce()` to avoid the move error.
return Some(*span);
}
}
DUMMY_SP
None
}
/// If `pred` is a trait clause binding the closure `def_id` to `Fn`/`FnMut`/`FnOnce`
/// (or their async equivalents based on `asyncness`), returns the corresponding
/// `ClosureKind`. Otherwise returns `None`.
fn closure_clause_kind(
&self,
pred: ty::Clause<'tcx>,
def_id: DefId,
asyncness: ty::Asyncness,
) -> Option<ty::ClosureKind> {
let tcx = self.infcx.tcx;
let clause = pred.as_trait_clause()?;
let kind = match asyncness {
ty::Asyncness::Yes => tcx.async_fn_trait_kind_from_def_id(clause.def_id()),
ty::Asyncness::No => tcx.fn_trait_kind_from_def_id(clause.def_id()),
}?;
match clause.self_ty().skip_binder().kind() {
ty::Closure(id, _) | ty::CoroutineClosure(id, _) if *id == def_id => Some(kind),
_ => None,
}
}
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {

View file

@ -62,57 +62,23 @@ impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
}
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
enum PlaceholderReachability {
/// This SCC reaches no placeholders.
NoPlaceholders,
/// This SCC reaches at least one placeholder.
Placeholders {
/// The largest-universed placeholder we can reach
max_universe: (UniverseIndex, RegionVid),
struct PlaceholderReachability {
/// The largest-universed placeholder we can reach
max_universe: (UniverseIndex, RegionVid),
/// The placeholder with the smallest ID
min_placeholder: RegionVid,
/// The placeholder with the smallest ID
min_placeholder: RegionVid,
/// The placeholder with the largest ID
max_placeholder: RegionVid,
},
/// The placeholder with the largest ID
max_placeholder: RegionVid,
}
impl PlaceholderReachability {
/// Merge the reachable placeholders of two graph components.
fn merge(self, other: PlaceholderReachability) -> PlaceholderReachability {
use PlaceholderReachability::*;
match (self, other) {
(NoPlaceholders, NoPlaceholders) => NoPlaceholders,
(NoPlaceholders, p @ Placeholders { .. })
| (p @ Placeholders { .. }, NoPlaceholders) => p,
(
Placeholders {
min_placeholder: min_pl,
max_placeholder: max_pl,
max_universe: max_u,
},
Placeholders { min_placeholder, max_placeholder, max_universe },
) => Placeholders {
min_placeholder: min_pl.min(min_placeholder),
max_placeholder: max_pl.max(max_placeholder),
max_universe: max_u.max(max_universe),
},
}
}
fn max_universe(&self) -> Option<(UniverseIndex, RegionVid)> {
match self {
Self::NoPlaceholders => None,
Self::Placeholders { max_universe, .. } => Some(*max_universe),
}
}
/// If we have reached placeholders, determine if they can
/// be named from this universe.
fn can_be_named_by(&self, from: UniverseIndex) -> bool {
self.max_universe()
.is_none_or(|(max_placeholder_universe, _)| from.can_name(max_placeholder_universe))
fn merge(&mut self, other: &Self) {
self.max_universe = self.max_universe.max(other.max_universe);
self.min_placeholder = self.min_placeholder.min(other.min_placeholder);
self.max_placeholder = self.max_placeholder.max(other.max_placeholder);
}
}
@ -120,7 +86,7 @@ impl PlaceholderReachability {
/// the values of its elements. This annotates a single SCC.
#[derive(Copy, Debug, Clone)]
pub(crate) struct RegionTracker {
reachable_placeholders: PlaceholderReachability,
reachable_placeholders: Option<PlaceholderReachability>,
/// The largest universe nameable from this SCC.
/// It is the smallest nameable universes of all
@ -135,13 +101,13 @@ impl RegionTracker {
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
let reachable_placeholders =
if matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)) {
PlaceholderReachability::Placeholders {
Some(PlaceholderReachability {
max_universe: (definition.universe, rvid),
min_placeholder: rvid,
max_placeholder: rvid,
}
})
} else {
PlaceholderReachability::NoPlaceholders
None
};
Self {
@ -159,43 +125,46 @@ impl RegionTracker {
}
pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex {
if let Some((universe, _)) = self.reachable_placeholders.max_universe() {
universe
} else {
UniverseIndex::ROOT
}
self.reachable_placeholders.map(|pls| pls.max_universe.0).unwrap_or(UniverseIndex::ROOT)
}
/// Can all reachable placeholders be named from `from`?
/// True vacuously in case no placeholders were reached.
fn placeholders_can_be_named_by(&self, from: UniverseIndex) -> bool {
self.reachable_placeholders.is_none_or(|pls| from.can_name(pls.max_universe.0))
}
/// Determine if we can name all the placeholders in `other`.
pub(crate) fn can_name_all_placeholders(&self, other: Self) -> bool {
other.reachable_placeholders.can_be_named_by(self.max_nameable_universe.0)
// HACK: We first check whether we can name the highest existential universe
// of `other`. This only exists to avoid errors in case that scc already
// depends on a placeholder it cannot name itself.
self.max_nameable_universe().can_name(other.max_nameable_universe())
|| other.placeholders_can_be_named_by(self.max_nameable_universe.0)
}
/// If this SCC reaches a placeholder it can't name, return it.
fn unnameable_placeholder(&self) -> Option<(UniverseIndex, RegionVid)> {
self.reachable_placeholders.max_universe().filter(|&(placeholder_universe, _)| {
!self.max_nameable_universe().can_name(placeholder_universe)
})
self.reachable_placeholders
.filter(|pls| !self.max_nameable_universe().can_name(pls.max_universe.0))
.map(|pls| pls.max_universe)
}
}
impl scc::Annotation for RegionTracker {
fn merge_scc(self, other: Self) -> Self {
fn update_scc(&mut self, other: &Self) {
trace!("{:?} << {:?}", self.representative, other.representative);
Self {
representative: self.representative.min(other.representative),
max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
}
self.representative = self.representative.min(other.representative);
self.update_reachable(other);
}
fn merge_reached(self, other: Self) -> Self {
Self {
max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
representative: self.representative,
}
fn update_reachable(&mut self, other: &Self) {
self.max_nameable_universe = self.max_nameable_universe.min(other.max_nameable_universe);
match (self.reachable_placeholders.as_mut(), other.reachable_placeholders.as_ref()) {
(None, None) | (Some(_), None) => (),
(None, Some(theirs)) => self.reachable_placeholders = Some(*theirs),
(Some(ours), Some(theirs)) => ours.merge(theirs),
};
}
}

View file

@ -4,6 +4,7 @@
#![allow(internal_features)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(default_field_values)]
#![feature(file_buffered)]
#![feature(if_let_guard)]
#![feature(negative_impls)]

View file

@ -52,7 +52,7 @@ fn render_region_vid<'tcx>(
format!(" (for<{}>)", tcx.item_name(def_id))
}
ty::BoundRegionKind::ClosureEnv | ty::BoundRegionKind::Anon => " (for<'_>)".to_string(),
ty::BoundRegionKind::NamedAnon(_) => {
ty::BoundRegionKind::NamedForPrinting(_) => {
bug!("only used for pretty printing")
}
},

View file

@ -10,8 +10,8 @@ use rustc_middle::ty::{self, RegionVid};
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
use tracing::debug;
use crate::BorrowIndex;
use crate::polonius::LiveLoans;
use crate::{BorrowIndex, TyCtxt};
rustc_index::newtype_index! {
/// A single integer representing a `ty::Placeholder`.
@ -420,18 +420,18 @@ impl ToElementIndex<'_> for RegionVid {
impl<'tcx> ToElementIndex<'tcx> for ty::PlaceholderRegion<'tcx> {
fn add_to_row<N: Idx>(self, values: &mut RegionValues<'tcx, N>, row: N) -> bool
where
Self: Into<ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion>>,
Self: Into<ty::PlaceholderRegion<'tcx>>,
{
let placeholder: ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion> = self.into();
let placeholder: ty::PlaceholderRegion<'tcx> = self.into();
let index = values.placeholder_indices.lookup_index(placeholder);
values.placeholders.insert(row, index)
}
fn contained_in_row<N: Idx>(self, values: &RegionValues<'tcx, N>, row: N) -> bool
where
Self: Into<ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion>>,
Self: Into<ty::PlaceholderRegion<'tcx>>,
{
let placeholder: ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion> = self.into();
let placeholder: ty::PlaceholderRegion<'tcx> = self.into();
let index = values.placeholder_indices.lookup_index(placeholder);
values.placeholders.contains(row, index)
}

View file

@ -343,8 +343,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
return;
}
// FIXME: Ideally MIR types are normalized, but this is not always true.
let mir_ty = self.normalize(mir_ty, Locations::All(span));
// This is a hack. `body.local_decls` are not necessarily normalized in the old
// solver due to not deeply normalizing in writeback. So we must re-normalize here.
//
// I am not sure of a test case where this actually matters. There is a similar
// hack in `equate_inputs_and_outputs` which does have associated test cases.
let mir_ty = match self.infcx.next_trait_solver() {
true => mir_ty,
false => self.normalize(mir_ty, Locations::All(span)),
};
let cause = ObligationCause::dummy_with_span(span);
let param_env = self.infcx.param_env;
@ -353,6 +360,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::Boring,
type_op::custom::CustomTypeOp::new(
|ocx| {
// The `AscribeUserType` query would normally emit a wf
// obligation for the unnormalized user_ty here. This is
// where the "incorrectly skips the WF checks we normally do"
// happens
let user_ty = ocx.normalize(&cause, param_env, user_ty);
ocx.eq(&cause, param_env, user_ty, mir_ty)?;
Ok(())

View file

@ -126,6 +126,31 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}
// FIXME(BoxyUwU): This should probably be part of a larger borrowck dev-guide chapter
//
/// Enforce that the types of the locals corresponding to the inputs and output of
/// the body are equal to those of the (normalized) signature.
///
/// This is necessary for two reasons:
/// - Locals in the MIR all start out with `'erased` regions and then are replaced
/// with unconstrained nll vars. If we have a function returning `&'a u32` then
/// the local `_0: &'?10 u32` needs to have its region var equated with the nll
/// var representing `'a`. i.e. borrow check must uphold that `'?10 = 'a`.
/// - When computing the normalized signature we may introduce new unconstrained nll
/// vars due to higher ranked where clauses ([#136547]). We then wind up with implied
/// bounds involving these vars.
///
/// For this reason it is important that we equate with the *normalized* signature
/// which was produced when computing implied bounds. If we do not do so then we will
/// wind up with implied bounds on nll vars which cannot actually be used as the nll
/// var never gets related to anything.
///
/// For 'closure-like' bodies this function effectively relates the *inferred* signature
/// of the closure against the locals corresponding to the closure's inputs/output. It *does
/// not* relate the user provided types for the signature to the locals, this is handled
/// separately by: [`TypeChecker::check_signature_annotation`].
///
/// [#136547]: <https://www.github.com/rust-lang/rust/issues/136547>
#[instrument(skip(self), level = "debug")]
pub(super) fn equate_inputs_and_outputs(&mut self, normalized_inputs_and_output: &[Ty<'tcx>]) {
let (&normalized_output_ty, normalized_input_tys) =
@ -173,38 +198,44 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}
// Return types are a bit more complex. They may contain opaque `impl Trait` types.
let mir_output_ty = self.body.local_decls[RETURN_PLACE].ty;
// Equate expected output ty with the type of the RETURN_PLACE in MIR
let mir_output_ty = self.body.return_ty();
let output_span = self.body.local_decls[RETURN_PLACE].source_info.span;
self.equate_normalized_input_or_output(normalized_output_ty, mir_output_ty, output_span);
}
#[instrument(skip(self), level = "debug")]
fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
if self.infcx.next_trait_solver() {
return self
.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
.unwrap_or_else(|terr| {
span_mirbug!(
self,
Location::START,
"equate_normalized_input_or_output: `{a:?}=={b:?}` failed with `{terr:?}`",
);
});
}
// This is a hack. `body.local_decls` are not necessarily normalized in the old
// solver due to not deeply normalizing in writeback. So we must re-normalize here.
//
// However, in most cases normalizing is unnecessary so we only do so if it may be
// necessary for type equality to hold. This leads to some (very minor) performance
// wins.
if let Err(_) =
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
{
// FIXME(jackh726): This is a hack. It's somewhat like
// `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
// like to normalize *before* inserting into `local_decls`, but
// doing so ends up causing some other trouble.
let b = self.normalize(b, Locations::All(span));
// Note: if we have to introduce new placeholders during normalization above, then we
// won't have added those universes to the universe info, which we would want in
// `relate_tys`.
if let Err(terr) =
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
{
span_mirbug!(
self,
Location::START,
"equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
a,
b,
terr
);
}
}
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
.unwrap_or_else(|terr| {
span_mirbug!(
self,
Location::START,
"equate_normalized_input_or_output: `{a:?}=={b:?}` failed with `{terr:?}`",
);
});
};
}
}

View file

@ -123,16 +123,19 @@ pub(crate) fn type_check<'tcx>(
known_type_outlives_obligations,
} = free_region_relations::create(infcx, universal_regions, &mut constraints);
let pre_obligations = infcx.take_registered_region_obligations();
assert!(
pre_obligations.is_empty(),
"there should be no incoming region obligations = {pre_obligations:#?}",
);
let pre_assumptions = infcx.take_registered_region_assumptions();
assert!(
pre_assumptions.is_empty(),
"there should be no incoming region assumptions = {pre_assumptions:#?}",
);
{
// Scope these variables so it's clear they're not used later
let pre_obligations = infcx.take_registered_region_obligations();
assert!(
pre_obligations.is_empty(),
"there should be no incoming region obligations = {pre_obligations:#?}",
);
let pre_assumptions = infcx.take_registered_region_assumptions();
assert!(
pre_assumptions.is_empty(),
"there should be no incoming region assumptions = {pre_assumptions:#?}",
);
}
debug!(?normalized_inputs_and_output);
@ -772,7 +775,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
ty::BoundRegionKind::Anon => sym::anon,
ty::BoundRegionKind::Named(def_id) => tcx.item_name(def_id),
ty::BoundRegionKind::ClosureEnv => sym::env,
ty::BoundRegionKind::NamedAnon(_) => {
ty::BoundRegionKind::NamedForPrinting(_) => {
bug!("only used for pretty printing")
}
};

View file

@ -174,7 +174,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
let infcx = self.type_checker.infcx;
let mut lazy_universe = None;
let delegate = FnMutDelegate {
regions: &mut |br: ty::BoundRegion| {
regions: &mut |br: ty::BoundRegion<'tcx>| {
// The first time this closure is called, create a
// new universe for the placeholders we will make
// from here out.
@ -191,10 +191,10 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
placeholder_reg
},
types: &mut |_bound_ty: ty::BoundTy| {
types: &mut |_bound_ty: ty::BoundTy<'tcx>| {
unreachable!("we only replace regions in nll_relate, not types")
},
consts: &mut |_bound_const: ty::BoundConst| {
consts: &mut |_bound_const: ty::BoundConst<'tcx>| {
unreachable!("we only replace regions in nll_relate, not consts")
},
};
@ -218,7 +218,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
let infcx = self.type_checker.infcx;
let mut reg_map = FxHashMap::default();
let delegate = FnMutDelegate {
regions: &mut |br: ty::BoundRegion| {
regions: &mut |br: ty::BoundRegion<'tcx>| {
if let Some(ex_reg_var) = reg_map.get(&br) {
*ex_reg_var
} else {
@ -230,10 +230,10 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
ex_reg_var
}
},
types: &mut |_bound_ty: ty::BoundTy| {
types: &mut |_bound_ty: ty::BoundTy<'tcx>| {
unreachable!("we only replace regions in nll_relate, not types")
},
consts: &mut |_bound_const: ty::BoundConst| {
consts: &mut |_bound_const: ty::BoundConst<'tcx>| {
unreachable!("we only replace regions in nll_relate, not consts")
},
};
@ -268,7 +268,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
ty::BoundRegionKind::Anon => sym::anon,
ty::BoundRegionKind::Named(def_id) => self.type_checker.tcx().item_name(def_id),
ty::BoundRegionKind::ClosureEnv => sym::env,
ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"),
ty::BoundRegionKind::NamedForPrinting(_) => bug!("only used for pretty printing"),
};
if cfg!(debug_assertions) {

View file

@ -13,6 +13,7 @@ use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpa
use rustc_hir::attrs::CfgEntry;
use rustc_hir::{AttrPath, Target};
use rustc_parse::exp;
use rustc_parse::parser::Recovery;
use rustc_span::{ErrorGuaranteed, Span, sym};
use crate::errors;
@ -42,7 +43,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
let meta = MetaItemOrLitParser::parse_single(
&mut parser,
ShouldEmit::ErrorsAndLints { recover: true },
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
)
.map_err(|diag| diag.emit())?;
let cfg = AttributeParser::parse_single_args(
@ -58,7 +59,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
// Doesn't matter what the target actually is here.
Target::Crate,
Some(cx.ecfg.features),
ShouldEmit::ErrorsAndLints { recover: true },
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
&meta,
parse_cfg_entry,
&CFG_TEMPLATE,

View file

@ -275,7 +275,15 @@ fn load_binary_file(
}
};
match cx.source_map().load_binary_file(&resolved_path) {
Ok(data) => Ok(data),
Ok(data) => {
cx.sess
.psess
.file_depinfo
.borrow_mut()
.insert(Symbol::intern(&resolved_path.to_string_lossy()));
Ok(data)
}
Err(io_err) => {
let mut err = cx.dcx().struct_span_err(
macro_span,

View file

@ -125,11 +125,6 @@ pub struct CraneliftCodegenBackend {
}
impl CodegenBackend for CraneliftCodegenBackend {
fn locale_resource(&self) -> &'static str {
// FIXME(rust-lang/rust#100717) - cranelift codegen backend is not yet translated
""
}
fn name(&self) -> &'static str {
"cranelift"
}

View file

@ -1,6 +1,3 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
// SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org)
#![no_std]
#![feature(allocator_api, rustc_private)]

View file

@ -1,8 +0,0 @@
codegen_gcc_unwinding_inline_asm =
GCC backend does not support unwinding from inline asm
codegen_gcc_copy_bitcode = failed to copy bitcode to object file: {$err}
codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err})
codegen_gcc_explicit_tail_calls_unsupported = explicit tail calls with the 'become' keyword are not implemented in the GCC backend

View file

@ -2,24 +2,24 @@ use rustc_macros::Diagnostic;
use rustc_span::Span;
#[derive(Diagnostic)]
#[diag(codegen_gcc_unwinding_inline_asm)]
#[diag("GCC backend does not support unwinding from inline asm")]
pub(crate) struct UnwindingInlineAsm {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_gcc_copy_bitcode)]
#[diag("failed to copy bitcode to object file: {$err}")]
pub(crate) struct CopyBitcode {
pub err: std::io::Error,
}
#[derive(Diagnostic)]
#[diag(codegen_gcc_lto_bitcode_from_rlib)]
#[diag("failed to get bitcode from object file for LTO ({$gcc_err})")]
pub(crate) struct LtoBitcodeFromRlib {
pub gcc_err: String,
}
#[derive(Diagnostic)]
#[diag(codegen_gcc_explicit_tail_calls_unsupported)]
#[diag("explicit tail calls with the 'become' keyword are not implemented in the GCC backend")]
pub(crate) struct ExplicitTailCallsUnsupported;

View file

@ -27,7 +27,6 @@ extern crate rustc_ast;
extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate rustc_fluent_macro;
extern crate rustc_fs_util;
extern crate rustc_hir;
extern crate rustc_index;
@ -105,8 +104,6 @@ use tempfile::TempDir;
use crate::back::lto::ModuleBuffer;
use crate::gcc_util::{target_cpu, to_gcc_features};
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
pub struct PrintOnPanic<F: Fn() -> String>(pub F);
impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
@ -197,10 +194,6 @@ fn load_libgccjit_if_needed(libgccjit_target_lib_file: &Path) {
}
impl CodegenBackend for GccCodegenBackend {
fn locale_resource(&self) -> &'static str {
crate::DEFAULT_LOCALE_RESOURCE
}
fn name(&self) -> &'static str {
"gcc"
}

View file

@ -23,7 +23,6 @@ rustc_ast = { path = "../rustc_ast" }
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_hashes = { path = "../rustc_hashes" }
rustc_hir = { path = "../rustc_hir" }

View file

@ -1,75 +0,0 @@
codegen_llvm_autodiff_component_missing = autodiff backend not found in the sysroot: {$err}
.note = it will be distributed via rustup in the future
codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend: {$err}
codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable
codegen_llvm_autodiff_without_lto = using the autodiff feature requires setting `lto="fat"` in your Cargo.toml
codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
codegen_llvm_from_llvm_diag = {$message}
codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$err})
codegen_llvm_mismatch_data_layout =
data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}`
codegen_llvm_offload_bundleimages_failed = call to BundleImages failed, `host.out` was not created
codegen_llvm_offload_embed_failed = call to EmbedBufferInModule failed, `host.o` was not created
codegen_llvm_offload_no_abs_path = using the `-Z offload=Host=/absolute/path/to/host.out` flag requires an absolute path
codegen_llvm_offload_no_host_out = using the `-Z offload=Host=/absolute/path/to/host.out` flag must point to a `host.out` file
codegen_llvm_offload_nonexisting = the given path/file to `host.out` does not exist. Did you forget to run the device compilation first?
codegen_llvm_offload_without_enable = using the offload feature requires -Z offload=<Device or Host=/absolute/path/to/host.out>
codegen_llvm_offload_without_fat_lto = using the offload feature requires -C lto=fat
codegen_llvm_parse_bitcode = failed to parse bitcode for LTO module
codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO module: {$llvm_err}
codegen_llvm_parse_target_machine_config =
failed to parse target machine config to target machine: {$error}
codegen_llvm_prepare_autodiff = failed to prepare autodiff: src: {$src}, target: {$target}, {$error}
codegen_llvm_prepare_autodiff_with_llvm_err = failed to prepare autodiff: {$llvm_err}, src: {$src}, target: {$target}, {$error}
codegen_llvm_prepare_thin_lto_context = failed to prepare thin LTO context
codegen_llvm_prepare_thin_lto_context_with_llvm_err = failed to prepare thin LTO context: {$llvm_err}
codegen_llvm_prepare_thin_lto_module = failed to prepare thin LTO module
codegen_llvm_prepare_thin_lto_module_with_llvm_err = failed to prepare thin LTO module: {$llvm_err}
codegen_llvm_run_passes = failed to run LLVM passes
codegen_llvm_run_passes_with_llvm_err = failed to run LLVM passes: {$llvm_err}
codegen_llvm_sanitizer_kcfi_arity_requires_llvm_21_0_0 = `-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later.
codegen_llvm_sanitizer_memtag_requires_mte =
`-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`
codegen_llvm_serialize_module = failed to serialize module {$name}
codegen_llvm_serialize_module_with_llvm_err = failed to serialize module {$name}: {$llvm_err}
codegen_llvm_symbol_already_defined =
symbol `{$symbol_name}` is already defined
codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}
codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
codegen_llvm_write_ir = failed to write LLVM IR to {$path}
codegen_llvm_write_ir_with_llvm_err = failed to write LLVM IR to {$path}: {$llvm_err}
codegen_llvm_write_output = could not write output to {$path}
codegen_llvm_write_output_with_llvm_err = could not write output to {$path}: {$llvm_err}
codegen_llvm_write_thinlto_key = error while writing ThinLTO key data: {$err}
codegen_llvm_write_thinlto_key_with_llvm_err = error while writing ThinLTO key data: {$err}: {$llvm_err}

View file

@ -188,19 +188,6 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
load
}
}
fn memset(&mut self, ptr: &'ll Value, fill_byte: &'ll Value, size: &'ll Value, align: Align) {
unsafe {
llvm::LLVMRustBuildMemSet(
self.llbuilder,
ptr,
align.bytes() as c_uint,
fill_byte,
size,
false,
);
}
}
}
/// Empty string, to be used where LLVM expects an instruction name, indicating

View file

@ -19,8 +19,6 @@ pub(crate) struct OffloadGlobals<'ll> {
pub launcher_fn: &'ll llvm::Value,
pub launcher_ty: &'ll llvm::Type,
pub bin_desc: &'ll llvm::Type,
pub kernel_args_ty: &'ll llvm::Type,
pub offload_entry_ty: &'ll llvm::Type,
@ -31,8 +29,8 @@ pub(crate) struct OffloadGlobals<'ll> {
pub ident_t_global: &'ll llvm::Value,
pub register_lib: &'ll llvm::Value,
pub unregister_lib: &'ll llvm::Value,
// FIXME(offload): Drop this, once we fully automated our offload compilation pipeline, since
// LLVM will initialize them for us if it sees gpu kernels being registered.
pub init_rtls: &'ll llvm::Value,
}
@ -44,15 +42,6 @@ impl<'ll> OffloadGlobals<'ll> {
let (begin_mapper, _, end_mapper, mapper_fn_ty) = gen_tgt_data_mappers(cx);
let ident_t_global = generate_at_one(cx);
let tptr = cx.type_ptr();
let ti32 = cx.type_i32();
let tgt_bin_desc_ty = vec![ti32, tptr, tptr, tptr];
let bin_desc = cx.type_named_struct("struct.__tgt_bin_desc");
cx.set_struct_body(bin_desc, &tgt_bin_desc_ty, false);
let reg_lib_decl = cx.type_func(&[cx.type_ptr()], cx.type_void());
let register_lib = declare_offload_fn(&cx, "__tgt_register_lib", reg_lib_decl);
let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", reg_lib_decl);
let init_ty = cx.type_func(&[], cx.type_void());
let init_rtls = declare_offload_fn(cx, "__tgt_init_all_rtls", init_ty);
@ -63,20 +52,84 @@ impl<'ll> OffloadGlobals<'ll> {
OffloadGlobals {
launcher_fn,
launcher_ty,
bin_desc,
kernel_args_ty,
offload_entry_ty,
begin_mapper,
end_mapper,
mapper_fn_ty,
ident_t_global,
register_lib,
unregister_lib,
init_rtls,
}
}
}
// We need to register offload before using it. We also should unregister it once we are done, for
// good measures. Previously we have done so before and after each individual offload intrinsic
// call, but that comes at a performance cost. The repeated (un)register calls might also confuse
// the LLVM ompOpt pass, which tries to move operations to a better location. The easiest solution,
// which we copy from clang, is to just have those two calls once, in the global ctor/dtor section
// of the final binary.
pub(crate) fn register_offload<'ll>(cx: &CodegenCx<'ll, '_>) {
// First we check quickly whether we already have done our setup, in which case we return early.
// Shouldn't be needed for correctness.
let register_lib_name = "__tgt_register_lib";
if cx.get_function(register_lib_name).is_some() {
return;
}
let reg_lib_decl = cx.type_func(&[cx.type_ptr()], cx.type_void());
let register_lib = declare_offload_fn(&cx, register_lib_name, reg_lib_decl);
let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", reg_lib_decl);
let ptr_null = cx.const_null(cx.type_ptr());
let const_struct = cx.const_struct(&[cx.get_const_i32(0), ptr_null, ptr_null, ptr_null], false);
let omp_descriptor =
add_global(cx, ".omp_offloading.descriptor", const_struct, InternalLinkage);
// @.omp_offloading.descriptor = internal constant %__tgt_bin_desc { i32 1, ptr @.omp_offloading.device_images, ptr @__start_llvm_offload_entries, ptr @__stop_llvm_offload_entries }
// @.omp_offloading.descriptor = internal constant %__tgt_bin_desc { i32 0, ptr null, ptr null, ptr null }
let atexit = cx.type_func(&[cx.type_ptr()], cx.type_i32());
let atexit_fn = declare_offload_fn(cx, "atexit", atexit);
let desc_ty = cx.type_func(&[], cx.type_void());
let reg_name = ".omp_offloading.descriptor_reg";
let unreg_name = ".omp_offloading.descriptor_unreg";
let desc_reg_fn = declare_offload_fn(cx, reg_name, desc_ty);
let desc_unreg_fn = declare_offload_fn(cx, unreg_name, desc_ty);
llvm::set_linkage(desc_reg_fn, InternalLinkage);
llvm::set_linkage(desc_unreg_fn, InternalLinkage);
llvm::set_section(desc_reg_fn, c".text.startup");
llvm::set_section(desc_unreg_fn, c".text.startup");
// define internal void @.omp_offloading.descriptor_reg() section ".text.startup" {
// entry:
// call void @__tgt_register_lib(ptr @.omp_offloading.descriptor)
// %0 = call i32 @atexit(ptr @.omp_offloading.descriptor_unreg)
// ret void
// }
let bb = Builder::append_block(cx, desc_reg_fn, "entry");
let mut a = Builder::build(cx, bb);
a.call(reg_lib_decl, None, None, register_lib, &[omp_descriptor], None, None);
a.call(atexit, None, None, atexit_fn, &[desc_unreg_fn], None, None);
a.ret_void();
// define internal void @.omp_offloading.descriptor_unreg() section ".text.startup" {
// entry:
// call void @__tgt_unregister_lib(ptr @.omp_offloading.descriptor)
// ret void
// }
let bb = Builder::append_block(cx, desc_unreg_fn, "entry");
let mut a = Builder::build(cx, bb);
a.call(reg_lib_decl, None, None, unregister_lib, &[omp_descriptor], None, None);
a.ret_void();
// @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 101, ptr @.omp_offloading.descriptor_reg, ptr null }]
let args = vec![cx.get_const_i32(101), desc_reg_fn, ptr_null];
let const_struct = cx.const_struct(&args, false);
let arr = cx.const_array(cx.val_ty(const_struct), &[const_struct]);
add_global(cx, "llvm.global_ctors", arr, AppendingLinkage);
}
pub(crate) struct OffloadKernelDims<'ll> {
num_workgroups: &'ll Value,
threads_per_block: &'ll Value,
@ -487,9 +540,6 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
let tgt_decl = offload_globals.launcher_fn;
let tgt_target_kernel_ty = offload_globals.launcher_ty;
// %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr }
let tgt_bin_desc = offload_globals.bin_desc;
let tgt_kernel_decl = offload_globals.kernel_args_ty;
let begin_mapper_decl = offload_globals.begin_mapper;
let end_mapper_decl = offload_globals.end_mapper;
@ -513,12 +563,9 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
}
// Step 0)
// %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr }
// %6 = alloca %struct.__tgt_bin_desc, align 8
unsafe {
llvm::LLVMRustPositionBuilderPastAllocas(&builder.llbuilder, builder.llfn());
}
let tgt_bin_desc_alloca = builder.direct_alloca(tgt_bin_desc, Align::EIGHT, "EmptyDesc");
let ty = cx.type_array(cx.type_ptr(), num_args);
// Baseptr are just the input pointer to the kernel, stored in a local alloca
@ -536,7 +583,6 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
unsafe {
llvm::LLVMPositionBuilderAtEnd(&builder.llbuilder, bb);
}
builder.memset(tgt_bin_desc_alloca, cx.get_const_i8(0), cx.get_const_i64(32), Align::EIGHT);
// Now we allocate once per function param, a copy to be passed to one of our maps.
let mut vals = vec![];
@ -574,15 +620,9 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
geps.push(gep);
}
let mapper_fn_ty = cx.type_func(&[cx.type_ptr()], cx.type_void());
let register_lib_decl = offload_globals.register_lib;
let unregister_lib_decl = offload_globals.unregister_lib;
let init_ty = cx.type_func(&[], cx.type_void());
let init_rtls_decl = offload_globals.init_rtls;
// FIXME(offload): Later we want to add them to the wrapper code, rather than our main function.
// call void @__tgt_register_lib(ptr noundef %6)
builder.call(mapper_fn_ty, None, None, register_lib_decl, &[tgt_bin_desc_alloca], None, None);
// call void @__tgt_init_all_rtls()
builder.call(init_ty, None, None, init_rtls_decl, &[], None, None);
@ -679,6 +719,4 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
num_args,
s_ident_t,
);
builder.call(mapper_fn_ty, None, None, unregister_lib_decl, &[tgt_bin_desc_alloca], None, None);
}

View file

@ -124,6 +124,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
pub(crate) fn const_null(&self, t: &'ll Type) -> &'ll Value {
unsafe { llvm::LLVMConstNull(t) }
}
pub(crate) fn const_struct(&self, elts: &[&'ll Value], packed: bool) -> &'ll Value {
struct_in_context(self.llcx(), elts, packed)
}
}
impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {

View file

@ -2,14 +2,12 @@ use std::ffi::CString;
use std::path::Path;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, inline_fluent};
use rustc_macros::Diagnostic;
use rustc_span::Span;
use crate::fluent_generated as fluent;
#[derive(Diagnostic)]
#[diag(codegen_llvm_symbol_already_defined)]
#[diag("symbol `{$symbol_name}` is already defined")]
pub(crate) struct SymbolAlreadyDefined<'a> {
#[primary_span]
pub span: Span,
@ -17,7 +15,7 @@ pub(crate) struct SymbolAlreadyDefined<'a> {
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_sanitizer_memtag_requires_mte)]
#[diag("`-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`")]
pub(crate) struct SanitizerMemtagRequiresMte;
pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>);
@ -27,89 +25,97 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> {
let diag: Diag<'_, G> = self.0.into_diag(dcx, level);
let (message, _) = diag.messages.first().expect("`LlvmError` with no message");
let message = dcx.eagerly_translate_to_string(message.clone(), diag.args.iter());
Diag::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config)
.with_arg("error", message)
Diag::new(
dcx,
level,
inline_fluent!("failed to parse target machine config to target machine: {$error}"),
)
.with_arg("error", message)
}
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_autodiff_component_unavailable)]
#[diag("failed to load our autodiff backend: {$err}")]
pub(crate) struct AutoDiffComponentUnavailable {
pub err: String,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_autodiff_component_missing)]
#[note]
#[diag("autodiff backend not found in the sysroot: {$err}")]
#[note("it will be distributed via rustup in the future")]
pub(crate) struct AutoDiffComponentMissing {
pub err: String,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_autodiff_without_lto)]
#[diag("using the autodiff feature requires setting `lto=\"fat\"` in your Cargo.toml")]
pub(crate) struct AutoDiffWithoutLto;
#[derive(Diagnostic)]
#[diag(codegen_llvm_autodiff_without_enable)]
#[diag("using the autodiff feature requires -Z autodiff=Enable")]
pub(crate) struct AutoDiffWithoutEnable;
#[derive(Diagnostic)]
#[diag(codegen_llvm_offload_without_enable)]
#[diag("using the offload feature requires -Z offload=<Device or Host=/absolute/path/to/host.out>")]
pub(crate) struct OffloadWithoutEnable;
#[derive(Diagnostic)]
#[diag(codegen_llvm_offload_without_fat_lto)]
#[diag("using the offload feature requires -C lto=fat")]
pub(crate) struct OffloadWithoutFatLTO;
#[derive(Diagnostic)]
#[diag(codegen_llvm_offload_no_abs_path)]
#[diag("using the `-Z offload=Host=/absolute/path/to/host.out` flag requires an absolute path")]
pub(crate) struct OffloadWithoutAbsPath;
#[derive(Diagnostic)]
#[diag(codegen_llvm_offload_no_host_out)]
#[diag(
"using the `-Z offload=Host=/absolute/path/to/host.out` flag must point to a `host.out` file"
)]
pub(crate) struct OffloadWrongFileName;
#[derive(Diagnostic)]
#[diag(codegen_llvm_offload_nonexisting)]
#[diag(
"the given path/file to `host.out` does not exist. Did you forget to run the device compilation first?"
)]
pub(crate) struct OffloadNonexistingPath;
#[derive(Diagnostic)]
#[diag(codegen_llvm_offload_bundleimages_failed)]
#[diag("call to BundleImages failed, `host.out` was not created")]
pub(crate) struct OffloadBundleImagesFailed;
#[derive(Diagnostic)]
#[diag(codegen_llvm_offload_embed_failed)]
#[diag("call to EmbedBufferInModule failed, `host.o` was not created")]
pub(crate) struct OffloadEmbedFailed;
#[derive(Diagnostic)]
#[diag(codegen_llvm_lto_bitcode_from_rlib)]
#[diag("failed to get bitcode from object file for LTO ({$err})")]
pub(crate) struct LtoBitcodeFromRlib {
pub err: String,
}
#[derive(Diagnostic)]
pub enum LlvmError<'a> {
#[diag(codegen_llvm_write_output)]
#[diag("could not write output to {$path}")]
WriteOutput { path: &'a Path },
#[diag(codegen_llvm_target_machine)]
#[diag("could not create LLVM TargetMachine for triple: {$triple}")]
CreateTargetMachine { triple: SmallCStr },
#[diag(codegen_llvm_run_passes)]
#[diag("failed to run LLVM passes")]
RunLlvmPasses,
#[diag(codegen_llvm_serialize_module)]
#[diag("failed to serialize module {$name}")]
SerializeModule { name: &'a str },
#[diag(codegen_llvm_write_ir)]
#[diag("failed to write LLVM IR to {$path}")]
WriteIr { path: &'a Path },
#[diag(codegen_llvm_prepare_thin_lto_context)]
#[diag("failed to prepare thin LTO context")]
PrepareThinLtoContext,
#[diag(codegen_llvm_load_bitcode)]
#[diag("failed to load bitcode of module \"{$name}\"")]
LoadBitcode { name: CString },
#[diag(codegen_llvm_write_thinlto_key)]
#[diag("error while writing ThinLTO key data: {$err}")]
WriteThinLtoKey { err: std::io::Error },
#[diag(codegen_llvm_prepare_thin_lto_module)]
#[diag("failed to prepare thin LTO module")]
PrepareThinLtoModule,
#[diag(codegen_llvm_parse_bitcode)]
#[diag("failed to parse bitcode for LTO module")]
ParseBitcode,
#[diag(codegen_llvm_prepare_autodiff)]
#[diag("failed to prepare autodiff: src: {$src}, target: {$target}, {$error}")]
PrepareAutoDiff { src: String, target: String, error: String },
}
@ -119,17 +125,31 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for WithLlvmError<'_> {
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
use LlvmError::*;
let msg_with_llvm_err = match &self.0 {
WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err,
CreateTargetMachine { .. } => fluent::codegen_llvm_target_machine_with_llvm_err,
RunLlvmPasses => fluent::codegen_llvm_run_passes_with_llvm_err,
SerializeModule { .. } => fluent::codegen_llvm_serialize_module_with_llvm_err,
WriteIr { .. } => fluent::codegen_llvm_write_ir_with_llvm_err,
PrepareThinLtoContext => fluent::codegen_llvm_prepare_thin_lto_context_with_llvm_err,
LoadBitcode { .. } => fluent::codegen_llvm_load_bitcode_with_llvm_err,
WriteThinLtoKey { .. } => fluent::codegen_llvm_write_thinlto_key_with_llvm_err,
PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err,
ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err,
PrepareAutoDiff { .. } => fluent::codegen_llvm_prepare_autodiff_with_llvm_err,
WriteOutput { .. } => inline_fluent!("could not write output to {$path}: {$llvm_err}"),
CreateTargetMachine { .. } => inline_fluent!(
"could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}"
),
RunLlvmPasses => inline_fluent!("failed to run LLVM passes: {$llvm_err}"),
SerializeModule { .. } => {
inline_fluent!("failed to serialize module {$name}: {$llvm_err}")
}
WriteIr { .. } => inline_fluent!("failed to write LLVM IR to {$path}: {$llvm_err}"),
PrepareThinLtoContext => {
inline_fluent!("failed to prepare thin LTO context: {$llvm_err}")
}
LoadBitcode { .. } => {
inline_fluent!("failed to load bitcode of module \"{$name}\": {$llvm_err}")
}
WriteThinLtoKey { .. } => {
inline_fluent!("error while writing ThinLTO key data: {$err}: {$llvm_err}")
}
PrepareThinLtoModule => {
inline_fluent!("failed to prepare thin LTO module: {$llvm_err}")
}
ParseBitcode => inline_fluent!("failed to parse bitcode for LTO module: {$llvm_err}"),
PrepareAutoDiff { .. } => inline_fluent!(
"failed to prepare autodiff: {$llvm_err}, src: {$src}, target: {$target}, {$error}"
),
};
self.0
.into_diag(dcx, level)
@ -139,7 +159,7 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for WithLlvmError<'_> {
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_from_llvm_optimization_diag)]
#[diag("{$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}")]
pub(crate) struct FromLlvmOptimizationDiag<'a> {
pub filename: &'a str,
pub line: std::ffi::c_uint,
@ -150,32 +170,36 @@ pub(crate) struct FromLlvmOptimizationDiag<'a> {
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_from_llvm_diag)]
#[diag("{$message}")]
pub(crate) struct FromLlvmDiag {
pub message: String,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_write_bytecode)]
#[diag("failed to write bytecode to {$path}: {$err}")]
pub(crate) struct WriteBytecode<'a> {
pub path: &'a Path,
pub err: std::io::Error,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_copy_bitcode)]
#[diag("failed to copy bitcode to object file: {$err}")]
pub(crate) struct CopyBitcode {
pub err: std::io::Error,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_unknown_debuginfo_compression)]
#[diag(
"unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo"
)]
pub(crate) struct UnknownCompression {
pub algorithm: &'static str,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_mismatch_data_layout)]
#[diag(
"data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}`"
)]
pub(crate) struct MismatchedDataLayout<'a> {
pub rustc_target: &'a str,
pub rustc_layout: &'a str,
@ -184,11 +208,11 @@ pub(crate) struct MismatchedDataLayout<'a> {
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_fixed_x18_invalid_arch)]
#[diag("the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture")]
pub(crate) struct FixedX18InvalidArch<'a> {
pub arch: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_sanitizer_kcfi_arity_requires_llvm_21_0_0)]
#[diag("`-Zsanitizer-kcfi-arity` requires LLVM 21.0.0 or later.")]
pub(crate) struct SanitizerKcfiArityRequiresLLVM2100;

View file

@ -30,7 +30,9 @@ use tracing::debug;
use crate::abi::FnAbiLlvmExt;
use crate::builder::Builder;
use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call};
use crate::builder::gpu_offload::{OffloadKernelDims, gen_call_handling, gen_define_handling};
use crate::builder::gpu_offload::{
OffloadKernelDims, gen_call_handling, gen_define_handling, register_offload,
};
use crate::context::CodegenCx;
use crate::declare::declare_raw_fn;
use crate::errors::{
@ -1402,6 +1404,7 @@ fn codegen_offload<'ll, 'tcx>(
return;
}
};
register_offload(cx);
let offload_data = gen_define_handling(&cx, &metadata, target_symbol, offload_globals);
gen_call_handling(bx, &offload_data, &args, &types, &metadata, offload_globals, &offload_dims);
}

View file

@ -43,7 +43,7 @@ use rustc_middle::ty::TyCtxt;
use rustc_middle::util::Providers;
use rustc_session::Session;
use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest};
use rustc_span::Symbol;
use rustc_span::{Symbol, sym};
use rustc_target::spec::{RelocModel, TlsModel};
use crate::llvm::ToLlvmBool;
@ -74,8 +74,6 @@ mod typetree;
mod va_arg;
mod value;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
pub(crate) use macros::TryFromU32;
#[derive(Clone)]
@ -241,10 +239,6 @@ impl LlvmCodegenBackend {
}
impl CodegenBackend for LlvmCodegenBackend {
fn locale_resource(&self) -> &'static str {
crate::DEFAULT_LOCALE_RESOURCE
}
fn name(&self) -> &'static str {
"llvm"
}
@ -350,6 +344,10 @@ impl CodegenBackend for LlvmCodegenBackend {
target_config(sess)
}
fn replaced_intrinsics(&self) -> Vec<Symbol> {
vec![sym::unchecked_funnel_shl, sym::unchecked_funnel_shr, sym::carrying_mul_add]
}
fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> {
Box::new(rustc_codegen_ssa::base::codegen_crate(
LlvmCodegenBackend(()),

View file

@ -28,7 +28,6 @@ rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" }
rustc_metadata = { path = "../rustc_metadata" }
rustc_middle = { path = "../rustc_middle" }
rustc_query_system = { path = "../rustc_query_system" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }

View file

@ -11,10 +11,11 @@ use std::{env, fmt, fs, io, mem, str};
use find_msvc_tools;
use itertools::Itertools;
use object::{Object, ObjectSection, ObjectSymbol};
use regex::Regex;
use rustc_arena::TypedArena;
use rustc_attr_parsing::eval_config_entry;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
@ -2185,6 +2186,71 @@ fn add_rpath_args(
}
}
fn add_c_staticlib_symbols(
sess: &Session,
lib: &NativeLib,
out: &mut Vec<(String, SymbolExportKind)>,
) -> io::Result<()> {
let file_path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess);
let archive_map = unsafe { Mmap::map(File::open(&file_path)?)? };
let archive = object::read::archive::ArchiveFile::parse(&*archive_map)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
for member in archive.members() {
let member = member.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let data = member
.data(&*archive_map)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
// clang LTO: raw LLVM bitcode
if data.starts_with(b"BC\xc0\xde") {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"LLVM bitcode object in C static library (LTO not supported)",
));
}
let object = object::File::parse(&*data)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
// gcc / clang ELF / Mach-O LTO
if object.sections().any(|s| {
s.name().map(|n| n.starts_with(".gnu.lto_") || n == ".llvm.lto").unwrap_or(false)
}) {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"LTO object in C static library is not supported",
));
}
for symbol in object.symbols() {
if symbol.scope() != object::SymbolScope::Dynamic {
continue;
}
let name = match symbol.name() {
Ok(n) => n,
Err(_) => continue,
};
let export_kind = match symbol.kind() {
object::SymbolKind::Text => SymbolExportKind::Text,
object::SymbolKind::Data => SymbolExportKind::Data,
_ => continue,
};
// FIXME:The symbol mangle rules are slightly different in Windows(32-bit) and Apple.
// Need to be resolved.
out.push((name.to_string(), export_kind));
}
}
Ok(())
}
/// Produce the linker command line containing linker path and arguments.
///
/// When comments in the function say "order-(in)dependent" they mean order-dependence between
@ -2217,6 +2283,25 @@ fn linker_with_args(
);
let link_output_kind = link_output_kind(sess, crate_type);
let mut export_symbols = codegen_results.crate_info.exported_symbols[&crate_type].clone();
if crate_type == CrateType::Cdylib {
let mut seen = FxHashSet::default();
for lib in &codegen_results.crate_info.used_libraries {
if let NativeLibKind::Static { export_symbols: Some(true), .. } = lib.kind
&& seen.insert((lib.name, lib.verbatim))
{
if let Err(err) = add_c_staticlib_symbols(&sess, lib, &mut export_symbols) {
sess.dcx().fatal(format!(
"failed to process C static library `{}`: {}",
lib.name, err
));
}
}
}
}
// ------------ Early order-dependent options ------------
// If we're building something like a dynamic library then some platforms
@ -2224,11 +2309,7 @@ fn linker_with_args(
// dynamic library.
// Must be passed before any libraries to prevent the symbols to export from being thrown away,
// at least on some platforms (e.g. windows-gnu).
cmd.export_symbols(
tmpdir,
crate_type,
&codegen_results.crate_info.exported_symbols[&crate_type],
);
cmd.export_symbols(tmpdir, crate_type, &export_symbols);
// Can be used for adding custom CRT objects or overriding order-dependent options above.
// FIXME: In practice built-in target specs use this for arbitrary order-independent options,
@ -2678,7 +2759,7 @@ fn add_native_libs_from_crate(
let name = lib.name.as_str();
let verbatim = lib.verbatim;
match lib.kind {
NativeLibKind::Static { bundle, whole_archive } => {
NativeLibKind::Static { bundle, whole_archive, .. } => {
if link_static {
let bundle = bundle.unwrap_or(true);
let whole_archive = whole_archive == Some(true);

View file

@ -1208,10 +1208,23 @@ impl<'a> Linker for EmLinker<'a> {
fn set_output_kind(
&mut self,
_output_kind: LinkOutputKind,
output_kind: LinkOutputKind,
_crate_type: CrateType,
_out_filename: &Path,
) {
match output_kind {
LinkOutputKind::DynamicNoPicExe | LinkOutputKind::DynamicPicExe => {
self.cmd.arg("-sMAIN_MODULE=2");
}
LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
self.cmd.arg("-sSIDE_MODULE=2");
}
// -fno-pie is the default on Emscripten.
LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => {}
LinkOutputKind::WasiReactorExe => {
unreachable!();
}
}
}
fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {

View file

@ -189,7 +189,7 @@ fn process_builtin_attrs(
},
AttributeKind::FfiConst(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST,
AttributeKind::FfiPure(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE,
AttributeKind::StdInternalSymbol(_) => {
AttributeKind::RustcStdInternalSymbol(_) => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
}
AttributeKind::Linkage(linkage, span) => {
@ -217,10 +217,10 @@ fn process_builtin_attrs(
AttributeKind::Sanitize { span, .. } => {
interesting_spans.sanitize = Some(*span);
}
AttributeKind::ObjcClass { classname, .. } => {
AttributeKind::RustcObjcClass { classname, .. } => {
codegen_fn_attrs.objc_class = Some(*classname);
}
AttributeKind::ObjcSelector { methname, .. } => {
AttributeKind::RustcObjcSelector { methname, .. } => {
codegen_fn_attrs.objc_selector = Some(*methname);
}
AttributeKind::EiiForeignItem => {

View file

@ -24,7 +24,7 @@ use rustc_data_structures::unord::UnordMap;
use rustc_hir::CRATE_HIR_ID;
use rustc_hir::attrs::{CfgEntry, NativeLibKind, WindowsSubsystemKind};
use rustc_hir::def_id::CrateNum;
use rustc_macros::{Decodable, Encodable, HashStable};
use rustc_macros::{Decodable, Encodable};
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::WorkProduct;
use rustc_middle::lint::LevelAndSource;
@ -175,7 +175,12 @@ bitflags::bitflags! {
}
}
#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
// This is the same as `rustc_session::cstore::NativeLib`, except:
// - (important) the `foreign_module` field is missing, because it contains a `DefId`, which can't
// be encoded with `FileEncoder`.
// - (less important) the `verbatim` field is a `bool` rather than an `Option<bool>`, because here
// we can treat `false` and `absent` the same.
#[derive(Clone, Debug, Encodable, Decodable)]
pub struct NativeLib {
pub kind: NativeLibKind,
pub name: Symbol,

View file

@ -37,10 +37,6 @@ pub trait BackendTypes {
}
pub trait CodegenBackend {
/// Locale resources for diagnostic messages - a string the content of the Fluent resource.
/// Called before `init` so that all other functions are able to emit translatable diagnostics.
fn locale_resource(&self) -> &'static str;
fn name(&self) -> &'static str;
fn init(&self, _sess: &Session) {}
@ -78,6 +74,12 @@ pub trait CodegenBackend {
fn print_version(&self) {}
/// Returns a list of all intrinsics that this backend definitely
/// replaces, which means their fallback bodies do not need to be monomorphized.
fn replaced_intrinsics(&self) -> Vec<Symbol> {
vec![]
}
/// Value printed by `--print=backend-has-zstd`.
///
/// Used by compiletest to determine whether tests involving zstd compression

View file

@ -774,16 +774,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// Attempting to call a trait method?
if let Some(trait_did) = tcx.trait_of_assoc(callee) {
// We can't determine the actual callee here, so we have to do different checks
// than usual.
// We can't determine the actual callee (the underlying impl of the trait) here, so we have
// to do different checks than usual.
trace!("attempting to call a trait method");
let trait_is_const = tcx.is_const_trait(trait_did);
let is_const = tcx.constness(callee) == hir::Constness::Const;
// Only consider a trait to be const if the const conditions hold.
// Otherwise, it's really misleading to call something "conditionally"
// const when it's very obviously not conditionally const.
if trait_is_const && has_const_conditions == Some(ConstConditionsHold::Yes) {
if is_const && has_const_conditions == Some(ConstConditionsHold::Yes) {
// Trait calls are always conditionally-const.
self.check_op(ops::ConditionallyConstCall {
callee,

View file

@ -83,7 +83,7 @@ pub fn rustc_allow_const_fn_unstable(
) -> bool {
let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
find_attr!(attrs, AttributeKind::AllowConstFnUnstable(syms, _) if syms.contains(&feature_gate))
find_attr!(attrs, AttributeKind::RustcAllowConstFnUnstable(syms, _) if syms.contains(&feature_gate))
}
/// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable".

View file

@ -0,0 +1,178 @@
use rustc_middle::mir::interpret::{CtfeProvenance, InterpResult, Scalar, interp_ok};
use rustc_middle::ty::{Region, Ty};
use rustc_middle::{span_bug, ty};
use rustc_span::def_id::DefId;
use rustc_span::sym;
use crate::const_eval::CompileTimeMachine;
use crate::interpret::{Immediate, InterpCx, MPlaceTy, MemoryKind, Writeable};
impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
pub(crate) fn write_dyn_trait_type_info(
&mut self,
dyn_place: impl Writeable<'tcx, CtfeProvenance>,
data: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
region: Region<'tcx>,
) -> InterpResult<'tcx> {
let tcx = self.tcx.tcx;
// Find the principal trait ref (for super trait collection), collect auto traits,
// and collect all projection predicates (used when computing TypeId for each supertrait).
let mut principal: Option<ty::Binder<'tcx, ty::ExistentialTraitRef<'tcx>>> = None;
let mut auto_traits_def_ids: Vec<ty::Binder<'tcx, DefId>> = Vec::new();
let mut projections: Vec<ty::Binder<'tcx, ty::ExistentialProjection<'tcx>>> = Vec::new();
for b in data.iter() {
match b.skip_binder() {
ty::ExistentialPredicate::Trait(tr) => principal = Some(b.rebind(tr)),
ty::ExistentialPredicate::AutoTrait(did) => auto_traits_def_ids.push(b.rebind(did)),
ty::ExistentialPredicate::Projection(p) => projections.push(b.rebind(p)),
}
}
// This is to make principal dyn type include Trait and projection predicates, excluding auto traits.
let principal_ty: Option<Ty<'tcx>> = principal.map(|_tr| {
let preds = tcx
.mk_poly_existential_predicates_from_iter(data.iter().filter(|b| {
!matches!(b.skip_binder(), ty::ExistentialPredicate::AutoTrait(_))
}));
Ty::new_dynamic(tcx, preds, region)
});
// DynTrait { predicates: &'static [Trait] }
for (field_idx, field) in
dyn_place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&dyn_place, field_idx)?;
match field.name {
sym::predicates => {
self.write_dyn_trait_predicates_slice(
&field_place,
principal_ty,
&auto_traits_def_ids,
region,
)?;
}
other => {
span_bug!(self.tcx.def_span(field.did), "unimplemented DynTrait field {other}")
}
}
}
interp_ok(())
}
fn mk_dyn_principal_auto_trait_ty(
&self,
auto_trait_def_id: ty::Binder<'tcx, DefId>,
region: Region<'tcx>,
) -> Ty<'tcx> {
let tcx = self.tcx.tcx;
// Preserve the binder vars from the original auto-trait predicate.
let pred_inner = ty::ExistentialPredicate::AutoTrait(auto_trait_def_id.skip_binder());
let pred = ty::Binder::bind_with_vars(pred_inner, auto_trait_def_id.bound_vars());
let preds = tcx.mk_poly_existential_predicates_from_iter([pred].into_iter());
Ty::new_dynamic(tcx, preds, region)
}
fn write_dyn_trait_predicates_slice(
&mut self,
slice_place: &impl Writeable<'tcx, CtfeProvenance>,
principal_ty: Option<Ty<'tcx>>,
auto_trait_def_ids: &[ty::Binder<'tcx, DefId>],
region: Region<'tcx>,
) -> InterpResult<'tcx> {
let tcx = self.tcx.tcx;
// total entries in DynTrait predicates
let total_len = principal_ty.map(|_| 1).unwrap_or(0) + auto_trait_def_ids.len();
// element type = DynTraitPredicate
let slice_ty = slice_place.layout().ty.builtin_deref(false).unwrap(); // [DynTraitPredicate]
let elem_ty = slice_ty.sequence_element_type(tcx); // DynTraitPredicate
let arr_layout = self.layout_of(Ty::new_array(tcx, elem_ty, total_len as u64))?;
let arr_place = self.allocate(arr_layout, MemoryKind::Stack)?;
let mut elems = self.project_array_fields(&arr_place)?;
// principal entry (if any) - NOT an auto trait
if let Some(principal_ty) = principal_ty {
let Some((_i, elem_place)) = elems.next(self)? else {
span_bug!(self.tcx.span, "DynTrait.predicates length computed wrong (principal)");
};
self.write_dyn_trait_predicate(elem_place, principal_ty, false)?;
}
// auto trait entries - these ARE auto traits
for auto in auto_trait_def_ids {
let Some((_i, elem_place)) = elems.next(self)? else {
span_bug!(self.tcx.span, "DynTrait.predicates length computed wrong (auto)");
};
let auto_ty = self.mk_dyn_principal_auto_trait_ty(*auto, region);
self.write_dyn_trait_predicate(elem_place, auto_ty, true)?;
}
let arr_place = arr_place.map_provenance(CtfeProvenance::as_immutable);
let imm = Immediate::new_slice(arr_place.ptr(), total_len as u64, self);
self.write_immediate(imm, slice_place)
}
fn write_dyn_trait_predicate(
&mut self,
predicate_place: MPlaceTy<'tcx>,
trait_ty: Ty<'tcx>,
is_auto: bool,
) -> InterpResult<'tcx> {
// DynTraitPredicate { trait_ty: Trait }
for (field_idx, field) in predicate_place
.layout
.ty
.ty_adt_def()
.unwrap()
.non_enum_variant()
.fields
.iter_enumerated()
{
let field_place = self.project_field(&predicate_place, field_idx)?;
match field.name {
sym::trait_ty => {
// Now write the Trait struct
self.write_trait(field_place, trait_ty, is_auto)?;
}
other => {
span_bug!(
self.tcx.def_span(field.did),
"unimplemented DynTraitPredicate field {other}"
)
}
}
}
interp_ok(())
}
fn write_trait(
&mut self,
trait_place: MPlaceTy<'tcx>,
trait_ty: Ty<'tcx>,
is_auto: bool,
) -> InterpResult<'tcx> {
// Trait { ty: TypeId, is_auto: bool }
for (field_idx, field) in
trait_place.layout.ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&trait_place, field_idx)?;
match field.name {
sym::ty => {
self.write_type_id(trait_ty, &field_place)?;
}
sym::is_auto => {
self.write_scalar(Scalar::from_bool(is_auto), &field_place)?;
}
other => {
span_bug!(self.tcx.def_span(field.did), "unimplemented Trait field {other}")
}
}
}
interp_ok(())
}
}

View file

@ -1,7 +1,8 @@
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{
Constness, ExprKind, ForeignItemKind, ImplItem, ImplItemImplKind, ImplItemKind, Item, ItemKind,
Node, TraitItem, TraitItemKind, VariantData,
Node, TraitItem, TraitItemKind, VariantData, find_attr,
};
use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
@ -36,7 +37,13 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Constness {
Constness::NotConst => tcx.constness(tcx.local_parent(def_id)),
}
}
Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(..), .. }) => tcx.trait_def(tcx.local_parent(def_id)).constness,
Node::TraitItem(ti @ TraitItem { kind: TraitItemKind::Fn(..), .. }) => {
if find_attr!(tcx.hir_attrs(ti.hir_id()), AttributeKind::RustcNonConstTraitMethod) {
Constness::NotConst
} else {
tcx.trait_def(tcx.local_parent(def_id)).constness
}
}
_ => {
tcx.dcx().span_bug(
tcx.def_span(def_id),

View file

@ -9,6 +9,7 @@ use tracing::instrument;
use crate::interpret::InterpCx;
mod dummy_machine;
mod dyn_trait;
mod error;
mod eval_queries;
mod fn_queries;

View file

@ -129,13 +129,18 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
variant
}
ty::Dynamic(predicates, region) => {
let (variant, variant_place) = downcast(sym::DynTrait)?;
let dyn_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?;
variant
}
ty::Adt(_, _)
| ty::Foreign(_)
| ty::Pat(_, _)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::UnsafeBinder(..)
| ty::Dynamic(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)

View file

@ -5,8 +5,8 @@
use either::{Either, Left, Right};
use rustc_abi::{BackendRepr, HasDataLayout, Size};
use rustc_data_structures::assert_matches;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Ty};
use rustc_middle::{bug, mir, span_bug};
use tracing::field::Empty;
use tracing::{instrument, trace};
@ -884,10 +884,38 @@ where
dest.layout().ty,
);
}
// If the source has padding, we want to always do a mem-to-mem copy to ensure consistent
// padding in the target independent of layout choices.
let src_has_padding = match src.layout().backend_repr {
BackendRepr::Scalar(_) => false,
BackendRepr::ScalarPair(left, right)
if matches!(src.layout().ty.kind(), ty::Ref(..) | ty::RawPtr(..)) =>
{
// Wide pointers never have padding, so we can avoid calling `size()`.
debug_assert_eq!(left.size(self) + right.size(self), src.layout().size);
false
}
BackendRepr::ScalarPair(left, right) => {
let left_size = left.size(self);
let right_size = right.size(self);
// We have padding if the sizes don't add up to the total.
left_size + right_size != src.layout().size
}
// Everything else can only exist in memory anyway, so it doesn't matter.
BackendRepr::SimdVector { .. }
| BackendRepr::ScalableVector { .. }
| BackendRepr::Memory { .. } => true,
};
// Let us see if the layout is simple so we take a shortcut,
// avoid force_allocation.
let src = match self.read_immediate_raw(src)? {
let src_val = if src_has_padding {
// Do our best to get an mplace. If there's no mplace, then this is stored as an
// "optimized" local, so its padding is definitely uninitialized and we are fine.
src.to_op(self)?.as_mplace_or_imm()
} else {
// Do our best to get an immediate, to avoid having to force_allocate the destination.
self.read_immediate_raw(src)?
};
let src = match src_val {
Right(src_val) => {
assert!(!src.layout().is_unsized());
assert!(!dest.layout().is_unsized());

View file

@ -97,7 +97,7 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug {
}
/// Convert this to an `OpTy`. This might be an irreversible transformation, but is useful for
/// reading from this thing.
/// reading from this thing. This will never actually do a read from memory!
fn to_op<M: Machine<'tcx, Provenance = Prov>>(
&self,
ecx: &InterpCx<'tcx, M>,

View file

@ -1,11 +1,9 @@
use std::hash::BuildHasherDefault;
pub use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet, FxHasher};
pub type StdEntry<'a, K, V> = std::collections::hash_map::Entry<'a, K, V>;
pub type FxIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
pub type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
pub type FxIndexMap<K, V> = indexmap::IndexMap<K, V, FxBuildHasher>;
pub type FxIndexSet<V> = indexmap::IndexSet<V, FxBuildHasher>;
pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>;
pub type IndexOccupiedEntry<'a, K, V> = indexmap::map::OccupiedEntry<'a, K, V>;

View file

@ -27,26 +27,18 @@ mod tests;
/// the max/min element of the SCC, or all of the above.
///
/// Concretely, the both merge operations must commute, e.g. where `merge`
/// is `merge_scc` and `merge_reached`: `a.merge(b) == b.merge(a)`
/// is `update_scc` and `update_reached`: `a.merge(b) == b.merge(a)`
///
/// In general, what you want is probably always min/max according
/// to some ordering, potentially with side constraints (min x such
/// that P holds).
pub trait Annotation: Debug + Copy {
/// Merge two existing annotations into one during
/// path compression.o
fn merge_scc(self, other: Self) -> Self;
/// path compression.
fn update_scc(&mut self, other: &Self);
/// Merge a successor into this annotation.
fn merge_reached(self, other: Self) -> Self;
fn update_scc(&mut self, other: Self) {
*self = self.merge_scc(other)
}
fn update_reachable(&mut self, other: Self) {
*self = self.merge_reached(other)
}
fn update_reachable(&mut self, other: &Self);
}
/// An accumulator for annotations.
@ -70,12 +62,8 @@ impl<N: Idx, S: Idx + Ord> Annotations<N> for NoAnnotations<S> {
/// The empty annotation, which does nothing.
impl Annotation for () {
fn merge_reached(self, _other: Self) -> Self {
()
}
fn merge_scc(self, _other: Self) -> Self {
()
}
fn update_reachable(&mut self, _other: &Self) {}
fn update_scc(&mut self, _other: &Self) {}
}
/// Strongly connected components (SCC) of a graph. The type `N` is
@ -614,7 +602,7 @@ where
*min_depth = successor_min_depth;
*min_cycle_root = successor_node;
}
current_component_annotation.update_scc(successor_annotation);
current_component_annotation.update_scc(&successor_annotation);
}
// The starting node `node` is succeeded by a fully identified SCC
// which is now added to the set under `scc_index`.
@ -629,7 +617,7 @@ where
// the `successors_stack` for later.
trace!(?node, ?successor_scc_index);
successors_stack.push(successor_scc_index);
current_component_annotation.update_reachable(successor_annotation);
current_component_annotation.update_reachable(&successor_annotation);
}
// `node` has no more (direct) successors; search recursively.
None => {

View file

@ -32,12 +32,12 @@ impl Maxes {
}
impl Annotation for MaxReached {
fn merge_scc(self, other: Self) -> Self {
Self(std::cmp::max(other.0, self.0))
fn update_scc(&mut self, other: &Self) {
self.0 = self.0.max(other.0);
}
fn merge_reached(self, other: Self) -> Self {
Self(std::cmp::max(other.0, self.0))
fn update_reachable(&mut self, other: &Self) {
self.0 = self.0.max(other.0);
}
}
@ -75,13 +75,12 @@ impl Annotations<usize> for MinMaxes {
}
impl Annotation for MinMaxIn {
fn merge_scc(self, other: Self) -> Self {
Self { min: std::cmp::min(self.min, other.min), max: std::cmp::max(self.max, other.max) }
fn update_scc(&mut self, other: &Self) {
self.min = self.min.min(other.min);
self.max = self.max.max(other.max);
}
fn merge_reached(self, _other: Self) -> Self {
self
}
fn update_reachable(&mut self, _other: &Self) {}
}
#[test]

View file

@ -49,6 +49,10 @@ pub use std::{assert_matches, debug_assert_matches};
pub use atomic_ref::AtomicRef;
pub use ena::{snapshot_vec, undo_log, unify};
// Re-export `hashbrown::hash_table`, because it's part of our API
// (via `ShardedHashMap`), and because it lets other compiler crates use the
// lower-level `HashTable` API without a tricky `hashbrown` dependency.
pub use hashbrown::hash_table;
pub use rustc_index::static_assert_size;
// Re-export some data-structure crates which are part of our public API.
pub use {either, indexmap, smallvec, thin_vec};

View file

@ -3,7 +3,7 @@ use std::hash::{Hash, Hasher};
use std::{iter, mem};
use either::Either;
use hashbrown::hash_table::{Entry, HashTable};
use hashbrown::hash_table::{self, Entry, HashTable};
use crate::fx::FxHasher;
use crate::sync::{CacheAligned, Lock, LockGuard, Mode, is_dyn_thread_safe};
@ -140,7 +140,7 @@ pub fn shards() -> usize {
1
}
pub type ShardedHashMap<K, V> = Sharded<HashTable<(K, V)>>;
pub type ShardedHashMap<K, V> = Sharded<hash_table::HashTable<(K, V)>>;
impl<K: Eq, V> ShardedHashMap<K, V> {
pub fn with_capacity(cap: usize) -> Self {

View file

@ -8,10 +8,10 @@ use std::hash::Hash;
use std::iter::{Product, Sum};
use std::ops::Index;
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
use rustc_macros::{Decodable_NoContext, Encodable_NoContext};
use crate::fingerprint::Fingerprint;
use crate::fx::{FxBuildHasher, FxHashMap, FxHashSet};
use crate::stable_hasher::{HashStable, StableCompare, StableHasher, ToStableHashKey};
/// `UnordItems` is the order-less version of `Iterator`. It only contains methods

View file

@ -29,8 +29,6 @@ struct Slot<V> {
struct SlotIndex {
// the index of the bucket in VecCache (0 to 20)
bucket_idx: usize,
// number of entries in that bucket
entries: usize,
// the index of the slot within the bucket
index_in_bucket: usize,
}
@ -39,12 +37,12 @@ struct SlotIndex {
// compile-time. Visiting all powers of two is enough to hit all the buckets.
//
// We confirm counts are accurate in the slot_index_exhaustive test.
const ENTRIES_BY_BUCKET: [usize; 21] = {
let mut entries = [0; 21];
const ENTRIES_BY_BUCKET: [usize; BUCKETS] = {
let mut entries = [0; BUCKETS];
let mut key = 0;
loop {
let si = SlotIndex::from_index(key);
entries[si.bucket_idx] = si.entries;
entries[si.bucket_idx] = si.entries();
if key == 0 {
key = 1;
} else if key == (1 << 31) {
@ -56,7 +54,14 @@ const ENTRIES_BY_BUCKET: [usize; 21] = {
entries
};
const BUCKETS: usize = 21;
impl SlotIndex {
/// The total possible number of entries in the bucket
const fn entries(&self) -> usize {
if self.bucket_idx == 0 { 1 << 12 } else { 1 << (self.bucket_idx + 11) }
}
// This unpacks a flat u32 index into identifying which bucket it belongs to and the offset
// within that bucket. As noted in the VecCache docs, buckets double in size with each index.
// Typically that would mean 31 buckets (2^0 + 2^1 ... + 2^31 = u32::MAX - 1), but to reduce
@ -70,18 +75,13 @@ impl SlotIndex {
const fn from_index(idx: u32) -> Self {
const FIRST_BUCKET_SHIFT: usize = 12;
if idx < (1 << FIRST_BUCKET_SHIFT) {
return SlotIndex {
bucket_idx: 0,
entries: 1 << FIRST_BUCKET_SHIFT,
index_in_bucket: idx as usize,
};
return SlotIndex { bucket_idx: 0, index_in_bucket: idx as usize };
}
// We already ruled out idx 0, so this `ilog2` never panics (and the check optimizes away)
let bucket = idx.ilog2() as usize;
let entries = 1 << bucket;
SlotIndex {
bucket_idx: bucket - FIRST_BUCKET_SHIFT + 1,
entries,
index_in_bucket: idx as usize - entries,
}
}
@ -98,7 +98,7 @@ impl SlotIndex {
if ptr.is_null() {
return None;
}
assert!(self.index_in_bucket < self.entries);
debug_assert!(self.index_in_bucket < self.entries());
// SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this
// must be inbounds.
let slot = unsafe { ptr.add(self.index_in_bucket) };
@ -126,11 +126,12 @@ impl SlotIndex {
fn bucket_ptr<V>(&self, bucket: &AtomicPtr<Slot<V>>) -> *mut Slot<V> {
let ptr = bucket.load(Ordering::Acquire);
if ptr.is_null() { self.initialize_bucket(bucket) } else { ptr }
if ptr.is_null() { Self::initialize_bucket(bucket, self.bucket_idx) } else { ptr }
}
#[cold]
fn initialize_bucket<V>(&self, bucket: &AtomicPtr<Slot<V>>) -> *mut Slot<V> {
#[inline(never)]
fn initialize_bucket<V>(bucket: &AtomicPtr<Slot<V>>, bucket_idx: usize) -> *mut Slot<V> {
static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
// If we are initializing the bucket, then acquire a global lock.
@ -144,8 +145,8 @@ impl SlotIndex {
// OK, now under the allocator lock, if we're still null then it's definitely us that will
// initialize this bucket.
if ptr.is_null() {
let bucket_layout =
std::alloc::Layout::array::<Slot<V>>(self.entries as usize).unwrap();
let bucket_len = SlotIndex { bucket_idx, index_in_bucket: 0 }.entries();
let bucket_layout = std::alloc::Layout::array::<Slot<V>>(bucket_len).unwrap();
// This is more of a sanity check -- this code is very cold, so it's safe to pay a
// little extra cost here.
assert!(bucket_layout.size() > 0);
@ -171,7 +172,7 @@ impl SlotIndex {
let bucket = unsafe { buckets.get_unchecked(self.bucket_idx) };
let ptr = self.bucket_ptr(bucket);
assert!(self.index_in_bucket < self.entries);
debug_assert!(self.index_in_bucket < self.entries());
// SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this
// must be inbounds.
let slot = unsafe { ptr.add(self.index_in_bucket) };
@ -204,6 +205,31 @@ impl SlotIndex {
Err(_) => false,
}
}
/// Inserts into the map, given that the slot is unique, so it won't race with other threads.
#[inline]
unsafe fn put_unique<V>(&self, buckets: &[AtomicPtr<Slot<V>>; 21], value: V, extra: u32) {
// SAFETY: `bucket_idx` is ilog2(u32).saturating_sub(11), which is at most 21, i.e.,
// in-bounds of buckets.
let bucket = unsafe { buckets.get_unchecked(self.bucket_idx) };
let ptr = self.bucket_ptr(bucket);
debug_assert!(self.index_in_bucket < self.entries());
// SAFETY: `bucket` was allocated (so <= isize in total bytes) to hold `entries`, so this
// must be inbounds.
let slot = unsafe { ptr.add(self.index_in_bucket) };
// SAFETY: We known our slot is unique as a precondition of this function, so this can't race.
unsafe {
(&raw mut (*slot).value).write(value);
}
// SAFETY: initialized bucket has zeroed all memory within the bucket, so we are valid for
// AtomicU32 access.
let index_and_lock = unsafe { &(*slot).index_and_lock };
index_and_lock.store(extra.checked_add(2).unwrap(), Ordering::Release);
}
}
/// In-memory cache for queries whose keys are densely-numbered IDs
@ -229,11 +255,11 @@ pub struct VecCache<K: Idx, V, I> {
// Bucket 19: 1073741824
// Bucket 20: 2147483648
// The total number of entries if all buckets are initialized is u32::MAX-1.
buckets: [AtomicPtr<Slot<V>>; 21],
buckets: [AtomicPtr<Slot<V>>; BUCKETS],
// In the compiler's current usage these are only *read* during incremental and self-profiling.
// They are an optimization over iterating the full buckets array.
present: [AtomicPtr<Slot<()>>; 21],
present: [AtomicPtr<Slot<()>>; BUCKETS],
len: AtomicUsize,
key: PhantomData<(K, I)>,
@ -307,9 +333,11 @@ where
let slot_idx = SlotIndex::from_index(key);
if slot_idx.put(&self.buckets, value, index.index() as u32) {
let present_idx = self.len.fetch_add(1, Ordering::Relaxed);
let slot = SlotIndex::from_index(present_idx as u32);
// We should always be uniquely putting due to `len` fetch_add returning unique values.
assert!(slot.put(&self.present, (), key));
let slot = SlotIndex::from_index(u32::try_from(present_idx).unwrap());
// SAFETY: We should always be uniquely putting due to `len` fetch_add returning unique values.
// We can't get here if `len` overflows because `put` will not succeed u32::MAX + 1 times
// as it will run out of slots.
unsafe { slot.put_unique(&self.present, (), key) };
}
}
@ -331,6 +359,10 @@ where
}
}
}
pub fn len(&self) -> usize {
self.len.load(Ordering::Acquire)
}
}
#[cfg(test)]

View file

@ -68,6 +68,13 @@ fn slot_entries_table() {
);
}
#[test]
fn bucket_entries_matches() {
for i in 0..BUCKETS {
assert_eq!(SlotIndex { bucket_idx: i, index_in_bucket: 0 }.entries(), ENTRIES_BY_BUCKET[i]);
}
}
#[test]
#[cfg(not(miri))]
fn slot_index_exhaustive() {
@ -81,14 +88,18 @@ fn slot_index_exhaustive() {
let mut prev = slot_idx;
for idx in 1..=u32::MAX {
let slot_idx = SlotIndex::from_index(idx);
// SAFETY: Ensure indices don't go out of bounds of buckets.
assert!(slot_idx.index_in_bucket < slot_idx.entries());
if prev.bucket_idx == slot_idx.bucket_idx {
assert_eq!(prev.index_in_bucket + 1, slot_idx.index_in_bucket);
} else {
assert_eq!(slot_idx.index_in_bucket, 0);
}
assert_eq!(buckets[slot_idx.bucket_idx], slot_idx.entries as u32);
assert_eq!(ENTRIES_BY_BUCKET[slot_idx.bucket_idx], slot_idx.entries, "{}", idx);
assert_eq!(buckets[slot_idx.bucket_idx], slot_idx.entries() as u32);
assert_eq!(ENTRIES_BY_BUCKET[slot_idx.bucket_idx], slot_idx.entries(), "{}", idx);
prev = slot_idx;
}

View file

@ -12,7 +12,6 @@ rustc_ast = { path = "../rustc_ast" }
rustc_ast_lowering = { path = "../rustc_ast_lowering" }
rustc_ast_passes = { path = "../rustc_ast_passes" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr_parsing = { path = "../rustc_attr_parsing" }
rustc_borrowck = { path = "../rustc_borrowck" }
rustc_builtin_macros = { path = "../rustc_builtin_macros" }
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
@ -21,13 +20,10 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_expand = { path = "../rustc_expand" }
rustc_feature = { path = "../rustc_feature" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_hir_typeck = { path = "../rustc_hir_typeck" }
rustc_incremental = { path = "../rustc_incremental" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_interface = { path = "../rustc_interface" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_lint = { path = "../rustc_lint" }
@ -36,21 +32,16 @@ rustc_macros = { path = "../rustc_macros" }
rustc_metadata = { path = "../rustc_metadata" }
rustc_middle = { path = "../rustc_middle" }
rustc_mir_build = { path = "../rustc_mir_build" }
rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
rustc_mir_transform = { path = "../rustc_mir_transform" }
rustc_monomorphize = { path = "../rustc_monomorphize" }
rustc_parse = { path = "../rustc_parse" }
rustc_passes = { path = "../rustc_passes" }
rustc_pattern_analysis = { path = "../rustc_pattern_analysis" }
rustc_privacy = { path = "../rustc_privacy" }
rustc_public = { path = "../rustc_public", features = ["rustc_internal"] }
rustc_query_system = { path = "../rustc_query_system" }
rustc_resolve = { path = "../rustc_resolve" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
serde_json = "1.0.59"
shlex = "1.0"
tracing = { version = "0.1.35" }

View file

@ -1,29 +0,0 @@
driver_impl_cant_emit_mir = could not emit MIR: {$error}
driver_impl_ice = the compiler unexpectedly panicked. this is a bug.
driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
driver_impl_ice_bug_report_internal_feature = using internal features is not supported and expected to cause internal compiler errors when used incorrectly
driver_impl_ice_bug_report_update_note = please make sure that you have updated to the latest nightly
driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
driver_impl_ice_flags = compiler flags: {$flags}
driver_impl_ice_path = please attach the file at `{$path}` to your bug report
driver_impl_ice_path_error = the ICE couldn't be written to `{$path}`: {$error}
driver_impl_ice_path_error_env = the environment variable `RUSTC_ICE` is set to `{$env_var}`
driver_impl_ice_version = rustc {$version} running on {$triple}
driver_impl_rlink_corrupt_file = corrupt metadata encountered in `{$file}`
driver_impl_rlink_empty_version_number = the input does not contain version number
driver_impl_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}`
driver_impl_rlink_no_a_file = rlink must be a file
driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}`
driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}`
driver_impl_rlink_wrong_file_type = the input does not look like a .rlink file
driver_impl_unstable_feature_usage = cannot dump feature usage metrics: {$error}

View file

@ -108,18 +108,14 @@ use crate::session_diagnostics::{
RLinkWrongFileType, RlinkCorruptFile, RlinkNotAFile, RlinkUnableToRead, UnstableFeatureUsage,
};
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
pub fn default_translator() -> Translator {
Translator::with_fallback_bundle(DEFAULT_LOCALE_RESOURCES.to_vec(), false)
}
pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
// tidy-alphabetical-start
crate::DEFAULT_LOCALE_RESOURCE,
rustc_ast_lowering::DEFAULT_LOCALE_RESOURCE,
rustc_ast_passes::DEFAULT_LOCALE_RESOURCE,
rustc_attr_parsing::DEFAULT_LOCALE_RESOURCE,
rustc_borrowck::DEFAULT_LOCALE_RESOURCE,
rustc_builtin_macros::DEFAULT_LOCALE_RESOURCE,
rustc_codegen_ssa::DEFAULT_LOCALE_RESOURCE,
@ -128,25 +124,16 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
rustc_expand::DEFAULT_LOCALE_RESOURCE,
rustc_hir_analysis::DEFAULT_LOCALE_RESOURCE,
rustc_hir_typeck::DEFAULT_LOCALE_RESOURCE,
rustc_incremental::DEFAULT_LOCALE_RESOURCE,
rustc_infer::DEFAULT_LOCALE_RESOURCE,
rustc_interface::DEFAULT_LOCALE_RESOURCE,
rustc_lint::DEFAULT_LOCALE_RESOURCE,
rustc_metadata::DEFAULT_LOCALE_RESOURCE,
rustc_middle::DEFAULT_LOCALE_RESOURCE,
rustc_mir_build::DEFAULT_LOCALE_RESOURCE,
rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE,
rustc_mir_transform::DEFAULT_LOCALE_RESOURCE,
rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,
rustc_parse::DEFAULT_LOCALE_RESOURCE,
rustc_passes::DEFAULT_LOCALE_RESOURCE,
rustc_pattern_analysis::DEFAULT_LOCALE_RESOURCE,
rustc_privacy::DEFAULT_LOCALE_RESOURCE,
rustc_query_system::DEFAULT_LOCALE_RESOURCE,
rustc_resolve::DEFAULT_LOCALE_RESOURCE,
rustc_session::DEFAULT_LOCALE_RESOURCE,
rustc_trait_selection::DEFAULT_LOCALE_RESOURCE,
rustc_ty_utils::DEFAULT_LOCALE_RESOURCE,
// tidy-alphabetical-end
];
@ -491,10 +478,18 @@ fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, col
}
text.push('\n');
}
// If output is a terminal, use a pager to display the content.
if io::stdout().is_terminal() {
show_md_content_with_pager(&text, color);
} else {
safe_print!("{text}");
// Otherwise, if the user has requested colored output
// print the content in color, else print the md content.
if color == ColorConfig::Always {
show_colored_md_content(&text);
} else {
safe_print!("{text}");
}
}
} else {
early_dcx.early_fatal(format!("{code} is not a valid error code"));
@ -564,6 +559,33 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) {
safe_print!("{content}");
}
/// Prints the markdown content with colored output.
///
/// This function is used when the output is not a terminal,
/// but the user has requested colored output with `--color=always`.
fn show_colored_md_content(content: &str) {
// Try to prettify the raw markdown text.
let mut pretty_data = {
let mdstream = markdown::MdStream::parse_str(content);
let bufwtr = markdown::create_stdout_bufwtr();
let mut mdbuf = Vec::new();
if mdstream.write_anstream_buf(&mut mdbuf, Some(&highlighter::highlight)).is_ok() {
Some((bufwtr, mdbuf))
} else {
None
}
};
if let Some((bufwtr, mdbuf)) = &mut pretty_data
&& bufwtr.write_all(&mdbuf).is_ok()
{
return;
}
// Everything failed. Print the raw markdown text.
safe_print!("{content}");
}
fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
assert!(sess.opts.unstable_opts.link_only);
let dcx = sess.dcx();

View file

@ -3,82 +3,88 @@ use std::error::Error;
use rustc_macros::{Diagnostic, Subdiagnostic};
#[derive(Diagnostic)]
#[diag(driver_impl_cant_emit_mir)]
#[diag("could not emit MIR: {$error}")]
pub struct CantEmitMIR {
pub error: std::io::Error,
}
#[derive(Diagnostic)]
#[diag(driver_impl_rlink_unable_to_read)]
#[diag("failed to read rlink file: `{$err}`")]
pub(crate) struct RlinkUnableToRead {
pub err: std::io::Error,
}
#[derive(Diagnostic)]
#[diag(driver_impl_rlink_wrong_file_type)]
#[diag("the input does not look like a .rlink file")]
pub(crate) struct RLinkWrongFileType;
#[derive(Diagnostic)]
#[diag(driver_impl_rlink_empty_version_number)]
#[diag("the input does not contain version number")]
pub(crate) struct RLinkEmptyVersionNumber;
#[derive(Diagnostic)]
#[diag(driver_impl_rlink_encoding_version_mismatch)]
#[diag(
".rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}`"
)]
pub(crate) struct RLinkEncodingVersionMismatch {
pub version_array: String,
pub rlink_version: u32,
}
#[derive(Diagnostic)]
#[diag(driver_impl_rlink_rustc_version_mismatch)]
#[diag(
".rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}`"
)]
pub(crate) struct RLinkRustcVersionMismatch<'a> {
pub rustc_version: String,
pub current_version: &'a str,
}
#[derive(Diagnostic)]
#[diag(driver_impl_rlink_no_a_file)]
#[diag("rlink must be a file")]
pub(crate) struct RlinkNotAFile;
#[derive(Diagnostic)]
#[diag(driver_impl_rlink_corrupt_file)]
#[diag("corrupt metadata encountered in `{$file}`")]
pub(crate) struct RlinkCorruptFile<'a> {
pub file: &'a std::path::Path,
}
#[derive(Diagnostic)]
#[diag(driver_impl_ice)]
#[diag("the compiler unexpectedly panicked. this is a bug.")]
pub(crate) struct Ice;
#[derive(Diagnostic)]
#[diag(driver_impl_ice_bug_report)]
#[diag("we would appreciate a bug report: {$bug_report_url}")]
pub(crate) struct IceBugReport<'a> {
pub bug_report_url: &'a str,
}
#[derive(Diagnostic)]
#[diag(driver_impl_ice_bug_report_update_note)]
#[diag("please make sure that you have updated to the latest nightly")]
pub(crate) struct UpdateNightlyNote;
#[derive(Diagnostic)]
#[diag(driver_impl_ice_bug_report_internal_feature)]
#[diag(
"using internal features is not supported and expected to cause internal compiler errors when used incorrectly"
)]
pub(crate) struct IceBugReportInternalFeature;
#[derive(Diagnostic)]
#[diag(driver_impl_ice_version)]
#[diag("rustc {$version} running on {$triple}")]
pub(crate) struct IceVersion<'a> {
pub version: &'a str,
pub triple: &'a str,
}
#[derive(Diagnostic)]
#[diag(driver_impl_ice_path)]
#[diag("please attach the file at `{$path}` to your bug report")]
pub(crate) struct IcePath {
pub path: std::path::PathBuf,
}
#[derive(Diagnostic)]
#[diag(driver_impl_ice_path_error)]
#[diag("the ICE couldn't be written to `{$path}`: {$error}")]
pub(crate) struct IcePathError {
pub path: std::path::PathBuf,
pub error: String,
@ -87,23 +93,23 @@ pub(crate) struct IcePathError {
}
#[derive(Subdiagnostic)]
#[note(driver_impl_ice_path_error_env)]
#[note("the environment variable `RUSTC_ICE` is set to `{$env_var}`")]
pub(crate) struct IcePathErrorEnv {
pub env_var: std::path::PathBuf,
}
#[derive(Diagnostic)]
#[diag(driver_impl_ice_flags)]
#[diag("compiler flags: {$flags}")]
pub(crate) struct IceFlags {
pub flags: String,
}
#[derive(Diagnostic)]
#[diag(driver_impl_ice_exclude_cargo_defaults)]
#[diag("some of the compiler flags provided by cargo are hidden")]
pub(crate) struct IceExcludeCargoDefaults;
#[derive(Diagnostic)]
#[diag(driver_impl_unstable_feature_usage)]
#[diag("cannot dump feature usage metrics: {$error}")]
pub(crate) struct UnstableFeatureUsage {
pub error: Box<dyn Error>,
}

View file

@ -44,3 +44,14 @@ fn h1() -> i32 {
// did you mean `a::I`?
}
```
### Enum types used as values
Enums are types and cannot be used directly as values.
```compile_fail,E0423
fn main(){
let x = Option::<i32>;
//~^ ERROR expected value,found enum `Option`
}
```

View file

@ -247,6 +247,9 @@ pub enum SubdiagMessage {
/// Identifier of a Fluent message. Instances of this variant are generated by the
/// `Subdiagnostic` derive.
FluentIdentifier(FluentId),
/// An inline Fluent message. Instances of this variant are generated by the
/// `Subdiagnostic` derive.
Inline(Cow<'static, str>),
/// Attribute of a Fluent message. Needs to be combined with a Fluent identifier to produce an
/// actual translated message. Instances of this variant are generated by the `fluent_messages`
/// macro.
@ -291,6 +294,8 @@ pub enum DiagMessage {
/// <https://projectfluent.org/fluent/guide/hello.html>
/// <https://projectfluent.org/fluent/guide/attributes.html>
FluentIdentifier(FluentId, Option<FluentId>),
/// An inline Fluent message, containing the to be translated diagnostic message.
Inline(Cow<'static, str>),
}
impl DiagMessage {
@ -305,21 +310,22 @@ impl DiagMessage {
SubdiagMessage::FluentIdentifier(id) => {
return DiagMessage::FluentIdentifier(id, None);
}
SubdiagMessage::Inline(s) => return DiagMessage::Inline(s),
SubdiagMessage::FluentAttr(attr) => attr,
};
match self {
DiagMessage::Str(s) => DiagMessage::Str(s.clone()),
DiagMessage::FluentIdentifier(id, _) => {
DiagMessage::FluentIdentifier(id.clone(), Some(attr))
}
_ => panic!("Tried to add a subdiagnostic to a message without a fluent identifier"),
}
}
pub fn as_str(&self) -> Option<&str> {
match self {
DiagMessage::Str(s) => Some(s),
DiagMessage::FluentIdentifier(_, _) => None,
DiagMessage::FluentIdentifier(_, _) | DiagMessage::Inline(_) => None,
}
}
}
@ -353,6 +359,7 @@ impl From<DiagMessage> for SubdiagMessage {
// There isn't really a sensible behaviour for this because it loses information but
// this is the most sensible of the behaviours.
DiagMessage::FluentIdentifier(_, Some(attr)) => SubdiagMessage::FluentAttr(attr),
DiagMessage::Inline(s) => SubdiagMessage::Inline(s),
}
}
}

View file

@ -3,11 +3,13 @@ use std::env;
use std::error::Report;
use std::sync::Arc;
use rustc_error_messages::langid;
pub use rustc_error_messages::{FluentArgs, LazyFallbackBundle};
use tracing::{debug, trace};
use crate::error::{TranslateError, TranslateErrorKind};
use crate::{DiagArg, DiagMessage, FluentBundle, Style};
use crate::fluent_bundle::FluentResource;
use crate::{DiagArg, DiagMessage, FluentBundle, Style, fluent_bundle};
/// Convert diagnostic arguments (a rustc internal type that exists to implement
/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
@ -79,6 +81,28 @@ impl Translator {
return Ok(Cow::Borrowed(msg));
}
DiagMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
// This translates an inline fluent diagnostic message
// It does this by creating a new `FluentBundle` with only one message,
// and then translating using this bundle.
DiagMessage::Inline(msg) => {
const GENERATED_MSG_ID: &str = "generated_msg";
let resource =
FluentResource::try_new(format!("{GENERATED_MSG_ID} = {msg}\n")).unwrap();
let mut bundle = fluent_bundle::FluentBundle::new(vec![langid!("en-US")]);
bundle.set_use_isolating(false);
bundle.add_resource(resource).unwrap();
let message = bundle.get_message(GENERATED_MSG_ID).unwrap();
let value = message.value().unwrap();
let mut errs = vec![];
let translated = bundle.format_pattern(value, Some(args), &mut errs).to_string();
debug!(?translated, ?errs);
return if errs.is_empty() {
Ok(Cow::Owned(translated))
} else {
Err(TranslateError::fluent(&Cow::Borrowed(GENERATED_MSG_ID), args, errs))
};
}
};
let translate_with_bundle =
|bundle: &'a FluentBundle| -> Result<Cow<'_, str>, TranslateError<'_>> {
@ -142,3 +166,14 @@ impl Translator {
}
}
}
/// This macro creates a translatable `DiagMessage` from a literal string.
/// It should be used in places where a translatable message is needed, but struct diagnostics are undesired.
///
/// This is a macro because in the future we may want to globally register these messages.
#[macro_export]
macro_rules! inline_fluent {
($inline: literal) => {
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed($inline))
};
}

View file

@ -849,6 +849,9 @@ pub struct SyntaxExtension {
/// Should debuginfo for the macro be collapsed to the outermost expansion site (in other
/// words, was the macro definition annotated with `#[collapse_debuginfo]`)?
pub collapse_debuginfo: bool,
/// Suppresses the "this error originates in the macro" note when a diagnostic points at this
/// macro.
pub hide_backtrace: bool,
}
impl SyntaxExtension {
@ -882,6 +885,7 @@ impl SyntaxExtension {
allow_internal_unsafe: false,
local_inner_macros: false,
collapse_debuginfo: false,
hide_backtrace: false,
}
}
@ -912,6 +916,12 @@ impl SyntaxExtension {
collapse_table[flag as usize][attr as usize]
}
fn get_hide_backtrace(attrs: &[hir::Attribute]) -> bool {
// FIXME(estebank): instead of reusing `#[rustc_diagnostic_item]` as a proxy, introduce a
// new attribute purely for this under the `#[diagnostic]` namespace.
ast::attr::find_by_name(attrs, sym::rustc_diagnostic_item).is_some()
}
/// Constructs a syntax extension with the given properties
/// and other properties converted from attributes.
pub fn new(
@ -948,17 +958,21 @@ impl SyntaxExtension {
// Not a built-in macro
None => (None, helper_attrs),
};
let hide_backtrace = builtin_name.is_some() || Self::get_hide_backtrace(attrs);
let stability = find_attr!(attrs, AttributeKind::Stability { stability, .. } => *stability);
// FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
if let Some(sp) = find_attr!(attrs, AttributeKind::ConstStability { span, .. } => *span) {
if let Some(sp) =
find_attr!(attrs, AttributeKind::RustcConstStability { span, .. } => *span)
{
sess.dcx().emit_err(errors::MacroConstStability {
span: sp,
head_span: sess.source_map().guess_head_span(span),
});
}
if let Some(sp) = find_attr!(attrs, AttributeKind::BodyStability{ span, .. } => *span) {
if let Some(sp) = find_attr!(attrs, AttributeKind::RustcBodyStability{ span, .. } => *span)
{
sess.dcx().emit_err(errors::MacroBodyStability {
span: sp,
head_span: sess.source_map().guess_head_span(span),
@ -982,6 +996,7 @@ impl SyntaxExtension {
allow_internal_unsafe,
local_inner_macros,
collapse_debuginfo,
hide_backtrace,
}
}
@ -1061,7 +1076,7 @@ impl SyntaxExtension {
self.allow_internal_unsafe,
self.local_inner_macros,
self.collapse_debuginfo,
self.builtin_name.is_some(),
self.hide_backtrace,
)
}
}

View file

@ -20,6 +20,7 @@ use rustc_feature::{
UNSTABLE_LANG_FEATURES,
};
use rustc_hir::Target;
use rustc_parse::parser::Recovery;
use rustc_session::Session;
use rustc_session::parse::feature_err;
use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym};
@ -395,7 +396,9 @@ impl<'a> StripUnconfigured<'a> {
fn in_cfg(&self, attrs: &[Attribute]) -> bool {
attrs.iter().all(|attr| {
!is_cfg(attr)
|| self.cfg_true(attr, ShouldEmit::ErrorsAndLints { recover: true }).as_bool()
|| self
.cfg_true(attr, ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed })
.as_bool()
})
}

View file

@ -26,7 +26,7 @@ use rustc_hir::def::MacroKinds;
use rustc_hir::limit::Limit;
use rustc_parse::parser::{
AllowConstBlockItems, AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser,
RecoverColon, RecoverComma, token_descr,
RecoverColon, RecoverComma, Recovery, token_descr,
};
use rustc_session::Session;
use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
@ -508,6 +508,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
// Unresolved macros produce dummy outputs as a recovery measure.
invocations.reverse();
let mut expanded_fragments = Vec::new();
let mut expanded_fragments_len = 0;
let mut undetermined_invocations = Vec::new();
let (mut progress, mut force) = (false, !self.monotonic);
loop {
@ -602,6 +603,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
expanded_fragments.push(Vec::new());
}
expanded_fragments[depth - 1].push((expn_id, expanded_fragment));
expanded_fragments_len += 1;
invocations.extend(derive_invocations.into_iter().rev());
}
ExpandResult::Retry(invoc) => {
@ -622,7 +624,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
self.cx.force_mode = orig_force_mode;
// Finally incorporate all the expanded macros into the input AST fragment.
let mut placeholder_expander = PlaceholderExpander::default();
let mut placeholder_expander = PlaceholderExpander::with_capacity(expanded_fragments_len);
while let Some(expanded_fragments) = expanded_fragments.pop() {
for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() {
placeholder_expander
@ -2170,7 +2172,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
call.span(),
self.cx.current_expansion.lint_node_id,
Some(self.cx.ecfg.features),
ShouldEmit::ErrorsAndLints { recover: true },
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
);
let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
@ -2220,7 +2222,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
// Target doesn't matter for `cfg` parsing.
Target::Crate,
self.cfg().features,
ShouldEmit::ErrorsAndLints { recover: true },
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
parse_cfg,
&CFG_TEMPLATE,
) else {

View file

@ -819,7 +819,7 @@ pub fn compile_declarative_macro(
}
assert!(!kinds.is_empty());
let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x)
let transparency = find_attr!(attrs, AttributeKind::RustcMacroTransparency(x) => *x)
.unwrap_or(Transparency::fallback(macro_rules));
if let Some(guar) = guar {

View file

@ -218,12 +218,17 @@ pub(crate) fn placeholder(
}
}
#[derive(Default)]
pub(crate) struct PlaceholderExpander {
expanded_fragments: FxHashMap<ast::NodeId, AstFragment>,
}
impl PlaceholderExpander {
pub(crate) fn with_capacity(capacity: usize) -> Self {
PlaceholderExpander {
expanded_fragments: FxHashMap::with_capacity_and_hasher(capacity, Default::default()),
}
}
pub(crate) fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment) {
fragment.mut_visit_with(self);
self.expanded_fragments.insert(id, fragment);

View file

@ -458,13 +458,11 @@ impl<'a, 'b> Rustc<'a, 'b> {
}
}
impl server::Types for Rustc<'_, '_> {
impl server::Server for Rustc<'_, '_> {
type TokenStream = TokenStream;
type Span = Span;
type Symbol = Symbol;
}
impl server::Server for Rustc<'_, '_> {
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
ExpnGlobals {
def_site: self.def_site,

View file

@ -1329,6 +1329,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
"`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`"
),
rustc_attr!(
rustc_non_const_trait_method, AttributeType::Normal, template!(Word),
ErrorFollowing, EncodeCrossCrate::No,
"`#[rustc_non_const_trait_method]` should only used by the standard library to mark trait methods \
as non-const to allow large traits an easier transition to const"
),
BuiltinAttribute {
name: sym::rustc_diagnostic_item,

View file

@ -331,6 +331,8 @@ pub enum NativeLibKind {
bundle: Option<bool>,
/// Whether to link static library without throwing any object files away
whole_archive: Option<bool>,
/// Whether to export c static library symbols
export_symbols: Option<bool>,
},
/// Dynamic library (e.g. `libfoo.so` on Linux)
/// or an import library corresponding to a dynamic library (e.g. `foo.lib` on Windows/MSVC).
@ -363,8 +365,8 @@ pub enum NativeLibKind {
impl NativeLibKind {
pub fn has_modifiers(&self) -> bool {
match self {
NativeLibKind::Static { bundle, whole_archive } => {
bundle.is_some() || whole_archive.is_some()
NativeLibKind::Static { bundle, whole_archive, export_symbols } => {
bundle.is_some() || whole_archive.is_some() || export_symbols.is_some()
}
NativeLibKind::Dylib { as_needed }
| NativeLibKind::Framework { as_needed }
@ -690,6 +692,30 @@ impl IntoDiagArg for CrateType {
}
}
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
pub enum RustcLayoutType {
Abi,
Align,
Size,
HomogenousAggregate,
Debug,
}
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute, PartialEq, Eq)]
pub enum RustcMirKind {
PeekMaybeInit,
PeekMaybeUninit,
PeekLiveness,
StopAfterDataflow,
BorrowckGraphvizPostflow { path: PathBuf },
BorrowckGraphvizFormat { format: BorrowckGraphvizFormatKind },
}
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute, PartialEq, Eq)]
pub enum BorrowckGraphvizFormatKind {
TwoPhase,
}
/// Represents parsed *built-in* inert attributes.
///
/// ## Overview
@ -746,31 +772,15 @@ pub enum AttributeKind {
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
Align { align: Align, span: Span },
/// Represents `#[rustc_allow_const_fn_unstable]`.
AllowConstFnUnstable(ThinVec<Symbol>, Span),
/// Represents `#[rustc_allow_incoherent_impl]`.
AllowIncoherentImpl(Span),
/// Represents `#[allow_internal_unsafe]`.
AllowInternalUnsafe(Span),
/// Represents `#[allow_internal_unstable]`.
AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span),
/// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
AsPtr(Span),
/// Represents `#[automatically_derived]`
AutomaticallyDerived(Span),
/// Represents `#[rustc_default_body_unstable]`.
BodyStability {
stability: DefaultBodyStability,
/// Span of the `#[rustc_default_body_unstable(...)]` attribute
span: Span,
},
/// Represents the trace attribute of `#[cfg_attr]`
CfgAttrTrace,
@ -780,9 +790,6 @@ pub enum AttributeKind {
/// Represents `#[cfi_encoding]`
CfiEncoding { encoding: Symbol },
/// Represents `#[rustc_coinductive]`.
Coinductive(Span),
/// Represents `#[cold]`.
Cold(Span),
@ -792,26 +799,9 @@ pub enum AttributeKind {
/// Represents `#[compiler_builtins]`.
CompilerBuiltins,
/// Represents `#[rustc_confusables]`.
Confusables {
symbols: ThinVec<Symbol>,
// FIXME(jdonszelmann): remove when target validation code is moved
first_span: Span,
},
/// Represents `#[const_continue]`.
ConstContinue(Span),
/// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`.
ConstStability {
stability: PartialConstStability,
/// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute
span: Span,
},
/// Represents `#[rustc_const_stable_indirect]`.
ConstStabilityIndirect,
/// Represents `#[coroutine]`.
Coroutine(Span),
@ -830,9 +820,6 @@ pub enum AttributeKind {
/// Represents `#[debugger_visualizer]`.
DebuggerVisualizer(ThinVec<DebugVisualizer>),
/// Represents `#[rustc_deny_explicit_impl]`.
DenyExplicitImpl(Span),
/// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
Deprecation { deprecation: Deprecation, span: Span },
@ -848,12 +835,6 @@ pub enum AttributeKind {
/// i.e. doc comments.
DocComment { style: AttrStyle, kind: DocFragmentKind, span: Span, comment: Symbol },
/// Represents `#[rustc_dummy]`.
Dummy,
/// Represents `#[rustc_dyn_incompatible_trait]`.
DynIncompatibleTrait(Span),
/// Implementation detail of `#[eii]`
EiiDeclaration(EiiDecl),
@ -920,9 +901,6 @@ pub enum AttributeKind {
/// Represents [`#[macro_export]`](https://doc.rust-lang.org/reference/macros-by-example.html#r-macro.decl.scope.path).
MacroExport { span: Span, local_inner_macros: bool },
/// Represents `#[rustc_macro_transparency]`.
MacroTransparency(Transparency),
/// Represents `#[macro_use]`.
MacroUse { span: Span, arguments: MacroUseArgs },
@ -978,24 +956,12 @@ pub enum AttributeKind {
/// Represents `#[non_exhaustive]`
NonExhaustive(Span),
/// Represents `#[rustc_objc_class]`
ObjcClass { classname: Symbol, span: Span },
/// Represents `#[rustc_objc_selector]`
ObjcSelector { methname: Symbol, span: Span },
/// Represents `#[optimize(size|speed)]`
Optimize(OptimizeAttr, Span),
/// Represents `#[panic_runtime]`
PanicRuntime,
/// Represents `#[rustc_paren_sugar]`.
ParenSugar(Span),
/// Represents `#[rustc_pass_by_value]` (used by the `rustc_pass_by_value` lint).
PassByValue(Span),
/// Represents `#[patchable_function_entry]`
PatchableFunctionEntry { prefix: u8, entry: u8 },
@ -1023,9 +989,6 @@ pub enum AttributeKind {
/// Represents `#[profiler_runtime]`
ProfilerRuntime,
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
PubTransparent(Span),
/// Represents [`#[recursion_limit]`](https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute)
RecursionLimit { attr_span: Span, limit_span: Span, limit: Limit },
@ -1041,15 +1004,55 @@ pub enum AttributeKind {
/// Represents `#[rustc_allocator_zeroed_variant]`
RustcAllocatorZeroedVariant { name: Symbol },
/// Represents `#[rustc_allow_const_fn_unstable]`.
RustcAllowConstFnUnstable(ThinVec<Symbol>, Span),
/// Represents `#[rustc_allow_incoherent_impl]`.
RustcAllowIncoherentImpl(Span),
/// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
RustcAsPtr(Span),
/// Represents `#[rustc_default_body_unstable]`.
RustcBodyStability {
stability: DefaultBodyStability,
/// Span of the `#[rustc_default_body_unstable(...)]` attribute
span: Span,
},
/// Represents `#[rustc_builtin_macro]`.
RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span },
/// Represents `#[rustc_coherence_is_core]`
RustcCoherenceIsCore(Span),
/// Represents `#[rustc_coinductive]`.
RustcCoinductive(Span),
/// Represents `#[rustc_confusables]`.
RustcConfusables {
symbols: ThinVec<Symbol>,
// FIXME(jdonszelmann): remove when target validation code is moved
first_span: Span,
},
/// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`.
RustcConstStability {
stability: PartialConstStability,
/// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute
span: Span,
},
/// Represents `#[rustc_const_stable_indirect]`.
RustcConstStabilityIndirect,
/// Represents `#[rustc_deallocator]`
RustcDeallocator,
/// Represents `#[rustc_deny_explicit_impl]`.
RustcDenyExplicitImpl(Span),
/// Represents `#[rustc_dummy]`.
RustcDummy,
/// Represents `#[rustc_dump_def_parents]`
RustcDumpDefParents,
@ -1065,9 +1068,18 @@ pub enum AttributeKind {
/// Represents `#[rustc_dump_vtable]`
RustcDumpVtable(Span),
/// Represents `#[rustc_dyn_incompatible_trait]`.
RustcDynIncompatibleTrait(Span),
/// Represents `#[rustc_has_incoherent_inherent_impls]`
RustcHasIncoherentInherentImpls,
/// Represents `#[rustc_hidden_type_of_opaques]`
RustcHiddenTypeOfOpaques,
/// Represents `#[rustc_layout]`
RustcLayout(ThinVec<RustcLayoutType>),
/// Represents `#[rustc_layout_scalar_valid_range_end]`.
RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
@ -1089,9 +1101,15 @@ pub enum AttributeKind {
/// Represents `#[rustc_lint_untracked_query_information]`
RustcLintUntrackedQueryInformation,
/// Represents `#[rustc_macro_transparency]`.
RustcMacroTransparency(Transparency),
/// Represents `#[rustc_main]`.
RustcMain,
/// Represents `#[rustc_mir]`.
RustcMir(ThinVec<RustcMirKind>),
/// Represents `#[rustc_must_implement_one_of]`
RustcMustImplementOneOf { attr_span: Span, fn_names: ThinVec<Ident> },
@ -1101,18 +1119,39 @@ pub enum AttributeKind {
/// Represents `#[rustc_no_implicit_autorefs]`
RustcNoImplicitAutorefs,
/// Represents `#[rustc_non_const_trait_method]`.
RustcNonConstTraitMethod,
/// Represents `#[rustc_nounwind]`
RustcNounwind,
/// Represents `#[rustc_objc_class]`
RustcObjcClass { classname: Symbol, span: Span },
/// Represents `#[rustc_objc_selector]`
RustcObjcSelector { methname: Symbol, span: Span },
/// Represents `#[rustc_object_lifetime_default]`.
RustcObjectLifetimeDefault,
/// Represents `#[rustc_offload_kernel]`
RustcOffloadKernel,
/// Represents `#[rustc_paren_sugar]`.
RustcParenSugar(Span),
/// Represents `#[rustc_pass_by_value]` (used by the `rustc_pass_by_value` lint).
RustcPassByValue(Span),
/// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]`
RustcPassIndirectlyInNonRusticAbis(Span),
/// Represents `#[rustc_preserve_ub_checks]`
RustcPreserveUbChecks,
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
RustcPubTransparent(Span),
/// Represents `#[rustc_reallocator]`
RustcReallocator,
@ -1130,6 +1169,18 @@ pub enum AttributeKind {
/// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`.
RustcSimdMonomorphizeLaneLimit(Limit),
/// Represents `#[rustc_skip_during_method_dispatch]`.
RustcSkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
/// Represents `#[rustc_specialization_trait]`.
RustcSpecializationTrait(Span),
/// Represents `#[rustc_std_internal_symbol]`.
RustcStdInternalSymbol(Span),
/// Represents `#[rustc_unsafe_specialization_marker]`.
RustcUnsafeSpecializationMarker(Span),
/// Represents `#[rustc_variance]`
RustcVariance,
@ -1151,22 +1202,12 @@ pub enum AttributeKind {
/// Represents `#[should_panic]`
ShouldPanic { reason: Option<Symbol>, span: Span },
/// Represents `#[rustc_skip_during_method_dispatch]`.
SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
/// Represents `#[rustc_specialization_trait]`.
SpecializationTrait(Span),
/// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`.
Stability {
stability: Stability,
/// Span of the attribute.
span: Span,
},
/// Represents `#[rustc_std_internal_symbol]`.
StdInternalSymbol(Span),
/// Represents `#[target_feature(enable = "...")]` and
/// `#[unsafe(force_target_feature(enable = "...")]`.
TargetFeature { features: ThinVec<(Symbol, Span)>, attr_span: Span, was_forced: bool },
@ -1183,9 +1224,6 @@ pub enum AttributeKind {
/// Represents `#[type_length_limit]`
TypeLengthLimit { attr_span: Span, limit_span: Span, limit: Limit },
/// Represents `#[rustc_unsafe_specialization_marker]`.
UnsafeSpecializationMarker(Span),
/// Represents `#[unstable_feature_bound]`.
UnstableFeatureBound(ThinVec<(Symbol, Span)>),

View file

@ -19,37 +19,26 @@ impl AttributeKind {
match self {
// tidy-alphabetical-start
Align { .. } => No,
AllowConstFnUnstable(..) => No,
AllowIncoherentImpl(..) => No,
AllowInternalUnsafe(..) => Yes,
AllowInternalUnstable(..) => Yes,
AsPtr(..) => Yes,
AutomaticallyDerived(..) => Yes,
BodyStability { .. } => No,
CfgAttrTrace => Yes,
CfgTrace(..) => Yes,
CfiEncoding { .. } => Yes,
Coinductive(..) => No,
Cold(..) => No,
CollapseDebugInfo(..) => Yes,
CompilerBuiltins => No,
Confusables { .. } => Yes,
ConstContinue(..) => No,
ConstStability { .. } => Yes,
ConstStabilityIndirect => No,
Coroutine(..) => No,
Coverage(..) => No,
CrateName { .. } => No,
CrateType(_) => No,
CustomMir(_, _, _) => Yes,
DebuggerVisualizer(..) => No,
DenyExplicitImpl(..) => No,
Deprecation { .. } => Yes,
DoNotRecommend { .. } => Yes,
Doc(_) => Yes,
DocComment { .. } => Yes,
Dummy => No,
DynIncompatibleTrait(..) => No,
EiiDeclaration(_) => Yes,
EiiForeignItem => No,
EiiImpls(..) => No,
@ -69,7 +58,6 @@ impl AttributeKind {
LoopMatch(..) => No,
MacroEscape(..) => No,
MacroExport { .. } => Yes,
MacroTransparency(..) => Yes,
MacroUse { .. } => No,
Marker(..) => No,
MayDangle(..) => No,
@ -87,12 +75,8 @@ impl AttributeKind {
NoMangle(..) => Yes, // Needed for rustdoc
NoStd(..) => No,
NonExhaustive(..) => Yes, // Needed for rustdoc
ObjcClass { .. } => No,
ObjcSelector { .. } => No,
Optimize(..) => No,
PanicRuntime => No,
ParenSugar(..) => No,
PassByValue(..) => Yes,
PatchableFunctionEntry { .. } => Yes,
Path(..) => No,
PatternComplexityLimit { .. } => No,
@ -102,21 +86,33 @@ impl AttributeKind {
ProcMacroAttribute(..) => No,
ProcMacroDerive { .. } => No,
ProfilerRuntime => No,
PubTransparent(..) => Yes,
RecursionLimit { .. } => No,
Repr { .. } => No,
RustcAllocator => No,
RustcAllocatorZeroed => No,
RustcAllocatorZeroedVariant { .. } => Yes,
RustcAllowConstFnUnstable(..) => No,
RustcAllowIncoherentImpl(..) => No,
RustcAsPtr(..) => Yes,
RustcBodyStability { .. } => No,
RustcBuiltinMacro { .. } => Yes,
RustcCoherenceIsCore(..) => No,
RustcCoinductive(..) => No,
RustcConfusables { .. } => Yes,
RustcConstStability { .. } => Yes,
RustcConstStabilityIndirect => No,
RustcDeallocator => No,
RustcDenyExplicitImpl(..) => No,
RustcDummy => No,
RustcDumpDefParents => No,
RustcDumpItemBounds => No,
RustcDumpPredicates => No,
RustcDumpUserArgs => No,
RustcDumpVtable(..) => No,
RustcDynIncompatibleTrait(..) => No,
RustcHasIncoherentInherentImpls => Yes,
RustcHiddenTypeOfOpaques => No,
RustcLayout(..) => No,
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcLegacyConstGenerics { .. } => Yes,
@ -124,32 +120,41 @@ impl AttributeKind {
RustcLintOptTy => Yes,
RustcLintQueryInstability => Yes,
RustcLintUntrackedQueryInformation => Yes,
RustcMacroTransparency(..) => Yes,
RustcMain => No,
RustcMir(..) => Yes,
RustcMustImplementOneOf { .. } => No,
RustcNeverReturnsNullPointer => Yes,
RustcNoImplicitAutorefs => Yes,
RustcNonConstTraitMethod => No, // should be reported via other queries like `constness`
RustcNounwind => No,
RustcObjcClass { .. } => No,
RustcObjcSelector { .. } => No,
RustcObjectLifetimeDefault => No,
RustcOffloadKernel => Yes,
RustcParenSugar(..) => No,
RustcPassByValue(..) => Yes,
RustcPassIndirectlyInNonRusticAbis(..) => No,
RustcPreserveUbChecks => No,
RustcPubTransparent(..) => Yes,
RustcReallocator => No,
RustcScalableVector { .. } => Yes,
RustcShouldNotBeCalledOnConstItems(..) => Yes,
RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
RustcSkipDuringMethodDispatch { .. } => No,
RustcSpecializationTrait(..) => No,
RustcStdInternalSymbol(..) => No,
RustcUnsafeSpecializationMarker(..) => No,
RustcVariance => No,
RustcVarianceOfOpaques => No,
Sanitize { .. } => No,
ShouldPanic { .. } => No,
SkipDuringMethodDispatch { .. } => No,
SpecializationTrait(..) => No,
Stability { .. } => Yes,
StdInternalSymbol(..) => No,
TargetFeature { .. } => No,
ThreadLocal => No,
TrackCaller(..) => Yes,
TypeConst(..) => Yes,
TypeLengthLimit { .. } => No,
UnsafeSpecializationMarker(..) => No,
UnstableFeatureBound(..) => No,
Used { .. } => No,
WindowsSubsystem(..) => No,

View file

@ -1,5 +1,6 @@
use std::num::NonZero;
use std::ops::Deref;
use std::path::PathBuf;
use rustc_abi::Align;
use rustc_ast::attr::data_structures::CfgEntry;
@ -96,7 +97,15 @@ impl<T: PrintAttribute> PrintAttribute for FxIndexMap<T, Span> {
p.word("]");
}
}
impl PrintAttribute for PathBuf {
fn should_render(&self) -> bool {
true
}
fn print_attribute(&self, p: &mut Printer) {
p.word(self.display().to_string());
}
}
macro_rules! print_skip {
($($t: ty),* $(,)?) => {$(
impl PrintAttribute for $t {

View file

@ -224,6 +224,10 @@ hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a par
hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
.note = parent implementation is in crate `{$cname}`
hir_analysis_impl_unpin_for_pin_projected_type = explicit impls for the `Unpin` trait are not permitted for structurally pinned types
.label = impl of `Unpin` not allowed
.help = `{$adt_name}` is structurally pinned because it is marked as `#[pin_v2]`
hir_analysis_inherent_dyn = cannot define inherent `impl` for a dyn auto trait
.label = impl requires at least one non-auto trait
.note = define and implement a new trait or type instead

View file

@ -1701,7 +1701,10 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
ty::Array(ty, _) => check_unsuited(tcx, typing_env, *ty),
ty::Adt(def, args) => {
if !def.did().is_local()
&& !find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::PubTransparent(_))
&& !find_attr!(
tcx.get_all_attrs(def.did()),
AttributeKind::RustcPubTransparent(_)
)
{
let non_exhaustive = def.is_variant_list_non_exhaustive()
|| def.variants().iter().any(ty::VariantDef::is_field_list_non_exhaustive);

View file

@ -218,7 +218,7 @@ fn compare_method_predicate_entailment<'tcx>(
trait_m_predicates.instantiate_own(tcx, trait_to_impl_args).map(|(predicate, _)| predicate),
);
let is_conditionally_const = tcx.is_conditionally_const(impl_def_id);
let is_conditionally_const = tcx.is_conditionally_const(impl_m.def_id);
if is_conditionally_const {
// Augment the hybrid param-env with the const conditions
// of the impl header and the trait method.
@ -592,7 +592,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
ty,
Ty::new_placeholder(
tcx,
ty::Placeholder::new(
ty::PlaceholderType::new(
universe,
ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon },
),
@ -2551,7 +2551,7 @@ fn param_env_with_gat_bounds<'tcx>(
}
};
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind<'tcx>; 8]> =
smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).own_params.len());
// Extend the impl's identity args with late-bound GAT vars
let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id)
@ -2587,7 +2587,7 @@ fn param_env_with_gat_bounds<'tcx>(
ty::Const::new_bound(
tcx,
ty::INNERMOST,
ty::BoundConst { var: ty::BoundVar::from_usize(bound_vars.len() - 1) },
ty::BoundConst::new(ty::BoundVar::from_usize(bound_vars.len() - 1)),
)
.into()
}

View file

@ -38,6 +38,7 @@ pub(super) fn check_trait<'tcx>(
checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
checker.check(lang_items.async_drop_trait(), visit_implementation_of_drop)?;
checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
checker.check(lang_items.unpin_trait(), visit_implementation_of_unpin)?;
checker.check(lang_items.const_param_ty_trait(), |checker| {
visit_implementation_of_const_param_ty(checker)
})?;
@ -134,6 +135,41 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
}
}
fn visit_implementation_of_unpin(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
let tcx = checker.tcx;
let impl_header = checker.impl_header;
let impl_did = checker.impl_def_id;
debug!("visit_implementation_of_unpin: impl_did={:?}", impl_did);
let self_type = impl_header.trait_ref.instantiate_identity().self_ty();
debug!("visit_implementation_of_unpin: self_type={:?}", self_type);
let span = tcx.def_span(impl_did);
if tcx.features().pin_ergonomics() {
match self_type.kind() {
// Soundness concerns: a type `T` annotated with `#[pin_v2]` is allowed to project
// `Pin<&mut T>` to its field `Pin<&mut U>` safely (even if `U: !Unpin`).
// If `T` is allowed to impl `Unpin` manually (note that `Unpin` is a safe trait,
// which cannot carry safety properties), then `&mut U` could be obtained from
// `&mut T` that dereferenced by `Pin<&mut T>`, which breaks the safety contract of
// `Pin<&mut U>` for `U: !Unpin`.
ty::Adt(adt, _) if adt.is_pin_project() => {
return Err(tcx.dcx().emit_err(crate::errors::ImplUnpinForPinProjectedType {
span,
adt_span: tcx.def_span(adt.did()),
adt_name: tcx.item_name(adt.did()),
}));
}
ty::Adt(_, _) => {}
_ => {
return Err(tcx.dcx().span_delayed_bug(span, "impl of `Unpin` for a non-adt type"));
}
};
}
Ok(())
}
fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
let tcx = checker.tcx;
let header = checker.impl_header;

View file

@ -91,7 +91,7 @@ impl<'tcx> InherentCollect<'tcx> {
for &impl_item in items {
if !find_attr!(
self.tcx.get_all_attrs(impl_item),
AttributeKind::AllowIncoherentImpl(_)
AttributeKind::RustcAllowIncoherentImpl(_)
) {
let impl_span = self.tcx.def_span(impl_def_id);
return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsideRelevant {
@ -125,7 +125,7 @@ impl<'tcx> InherentCollect<'tcx> {
for &impl_item in items {
if !find_attr!(
self.tcx.get_all_attrs(impl_item),
AttributeKind::AllowIncoherentImpl(_)
AttributeKind::RustcAllowIncoherentImpl(_)
) {
let span = self.tcx.def_span(impl_def_id);
return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsidePrimitive {

Some files were not shown because too many files have changed in this diff Show more