Auto merge of #147282 - Zalathar:rollup-7wz3k9r, r=Zalathar
Rollup of 6 pull requests Successful merges: - rust-lang/rust#141839 (make rust-analyzer use a dedicated build directory) - rust-lang/rust#146166 (Implement range support in `//@ edition`) - rust-lang/rust#147259 (cg_llvm: Use helper methods for all calls to `LLVMMDNodeInContext2`) - rust-lang/rust#147263 (Disable triagebot auto stable-regression compiler backport nominations pending redesign) - rust-lang/rust#147268 (add arm-maintainers to various targets) - rust-lang/rust#147270 (Move doc_cfg-specific code into `cfg.rs`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
3b8665c5ab
35 changed files with 839 additions and 425 deletions
|
|
@ -538,9 +538,7 @@ pub(crate) fn inline_asm_call<'ll>(
|
|||
bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)),
|
||||
)
|
||||
}));
|
||||
let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) };
|
||||
let md = bx.get_metadata_value(md);
|
||||
llvm::LLVMSetMetadata(call, kind, md);
|
||||
bx.cx.set_metadata_node(call, kind, &srcloc);
|
||||
|
||||
Some(call)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use std::borrow::{Borrow, Cow};
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
use std::{iter, ptr};
|
||||
|
||||
use rustc_ast::expand::typetree::FncTree;
|
||||
pub(crate) mod autodiff;
|
||||
pub(crate) mod gpu_offload;
|
||||
|
||||
use libc::{c_char, c_uint, size_t};
|
||||
use libc::{c_char, c_uint};
|
||||
use rustc_abi as abi;
|
||||
use rustc_abi::{Align, Size, WrappingRange};
|
||||
use rustc_codegen_ssa::MemFlags;
|
||||
|
|
@ -396,10 +396,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
md.push(weight(is_cold));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let md_node = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len() as size_t);
|
||||
self.cx.set_metadata(switch, llvm::MD_prof, md_node);
|
||||
}
|
||||
self.cx.set_metadata_node(switch, llvm::MD_prof, &md);
|
||||
}
|
||||
|
||||
fn invoke(
|
||||
|
|
@ -801,22 +798,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let llty = self.cx.val_ty(load);
|
||||
let md = [
|
||||
llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)),
|
||||
llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))),
|
||||
];
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len());
|
||||
self.set_metadata(load, llvm::MD_range, md);
|
||||
}
|
||||
let llty = self.cx.val_ty(load);
|
||||
let md = [
|
||||
llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)),
|
||||
llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))),
|
||||
];
|
||||
self.set_metadata_node(load, llvm::MD_range, &md);
|
||||
}
|
||||
|
||||
fn nonnull_metadata(&mut self, load: &'ll Value) {
|
||||
unsafe {
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0);
|
||||
self.set_metadata(load, llvm::MD_nonnull, md);
|
||||
}
|
||||
self.set_metadata_node(load, llvm::MD_nonnull, &[]);
|
||||
}
|
||||
|
||||
fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
|
||||
|
|
@ -865,8 +856,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
//
|
||||
// [1]: https://llvm.org/docs/LangRef.html#store-instruction
|
||||
let one = llvm::LLVMValueAsMetadata(self.cx.const_i32(1));
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, &one, 1);
|
||||
self.set_metadata(store, llvm::MD_nontemporal, md);
|
||||
self.set_metadata_node(store, llvm::MD_nontemporal, &[one]);
|
||||
}
|
||||
}
|
||||
store
|
||||
|
|
@ -1381,10 +1371,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
fn set_invariant_load(&mut self, load: &'ll Value) {
|
||||
unsafe {
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0);
|
||||
self.set_metadata(load, llvm::MD_invariant_load, md);
|
||||
}
|
||||
self.set_metadata_node(load, llvm::MD_invariant_load, &[]);
|
||||
}
|
||||
|
||||
fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) {
|
||||
|
|
@ -1528,25 +1515,16 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
|
|||
}
|
||||
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
||||
fn align_metadata(&mut self, load: &'ll Value, align: Align) {
|
||||
unsafe {
|
||||
let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))];
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len());
|
||||
self.set_metadata(load, llvm::MD_align, md);
|
||||
}
|
||||
let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))];
|
||||
self.set_metadata_node(load, llvm::MD_align, &md);
|
||||
}
|
||||
|
||||
fn noundef_metadata(&mut self, load: &'ll Value) {
|
||||
unsafe {
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0);
|
||||
self.set_metadata(load, llvm::MD_noundef, md);
|
||||
}
|
||||
self.set_metadata_node(load, llvm::MD_noundef, &[]);
|
||||
}
|
||||
|
||||
pub(crate) fn set_unpredictable(&mut self, inst: &'ll Value) {
|
||||
unsafe {
|
||||
let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0);
|
||||
self.set_metadata(inst, llvm::MD_unpredictable, md);
|
||||
}
|
||||
self.set_metadata_node(inst, llvm::MD_unpredictable, &[]);
|
||||
}
|
||||
}
|
||||
impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
|
||||
|
|
|
|||
|
|
@ -494,16 +494,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len());
|
||||
let alloc = self.create_metadata(bytes);
|
||||
let data = [section, alloc];
|
||||
let meta =
|
||||
unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) };
|
||||
let val = self.get_metadata_value(meta);
|
||||
unsafe {
|
||||
llvm::LLVMAddNamedMetadataOperand(
|
||||
self.llmod,
|
||||
c"wasm.custom_sections".as_ptr(),
|
||||
val,
|
||||
)
|
||||
};
|
||||
self.module_add_named_metadata_node(self.llmod(), c"wasm.custom_sections", &data);
|
||||
}
|
||||
} else {
|
||||
base::set_link_section(g, attrs);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ use smallvec::SmallVec;
|
|||
use crate::back::write::to_llvm_code_model;
|
||||
use crate::callee::get_fn;
|
||||
use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
|
||||
use crate::llvm::{Metadata, MetadataKindId};
|
||||
use crate::llvm::{Metadata, MetadataKindId, Module};
|
||||
use crate::type_::Type;
|
||||
use crate::value::Value;
|
||||
use crate::{attributes, common, coverageinfo, debuginfo, llvm, llvm_util};
|
||||
|
|
@ -495,14 +495,7 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"));
|
||||
|
||||
let name_metadata = cx.create_metadata(rustc_producer.as_bytes());
|
||||
|
||||
unsafe {
|
||||
llvm::LLVMAddNamedMetadataOperand(
|
||||
llmod,
|
||||
c"llvm.ident".as_ptr(),
|
||||
&cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)),
|
||||
);
|
||||
}
|
||||
cx.module_add_named_metadata_node(llmod, c"llvm.ident", &[name_metadata]);
|
||||
|
||||
// Emit RISC-V specific target-abi metadata
|
||||
// to workaround lld as the LTO plugin not
|
||||
|
|
@ -1002,6 +995,11 @@ impl CodegenCx<'_, '_> {
|
|||
}
|
||||
|
||||
impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
||||
/// Wrapper for `LLVMMDNodeInContext2`, i.e. `llvm::MDNode::get`.
|
||||
pub(crate) fn md_node_in_context(&self, md_list: &[&'ll Metadata]) -> &'ll Metadata {
|
||||
unsafe { llvm::LLVMMDNodeInContext2(self.llcx(), md_list.as_ptr(), md_list.len()) }
|
||||
}
|
||||
|
||||
/// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`.
|
||||
pub(crate) fn set_metadata<'a>(
|
||||
&self,
|
||||
|
|
@ -1012,6 +1010,61 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
|||
let node = self.get_metadata_value(md);
|
||||
llvm::LLVMSetMetadata(val, kind_id, node);
|
||||
}
|
||||
|
||||
/// Helper method for the sequence of calls:
|
||||
/// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata)
|
||||
/// - `LLVMMetadataAsValue` (to adapt that node to an `llvm::Value`)
|
||||
/// - `LLVMSetMetadata` (to set that node as metadata of `kind_id` for `instruction`)
|
||||
pub(crate) fn set_metadata_node(
|
||||
&self,
|
||||
instruction: &'ll Value,
|
||||
kind_id: MetadataKindId,
|
||||
md_list: &[&'ll Metadata],
|
||||
) {
|
||||
let md = self.md_node_in_context(md_list);
|
||||
self.set_metadata(instruction, kind_id, md);
|
||||
}
|
||||
|
||||
/// Helper method for the sequence of calls:
|
||||
/// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata)
|
||||
/// - `LLVMMetadataAsValue` (to adapt that node to an `llvm::Value`)
|
||||
/// - `LLVMAddNamedMetadataOperand` (to set that node as metadata of `kind_name` for `module`)
|
||||
pub(crate) fn module_add_named_metadata_node(
|
||||
&self,
|
||||
module: &'ll Module,
|
||||
kind_name: &CStr,
|
||||
md_list: &[&'ll Metadata],
|
||||
) {
|
||||
let md = self.md_node_in_context(md_list);
|
||||
let md_as_val = self.get_metadata_value(md);
|
||||
unsafe { llvm::LLVMAddNamedMetadataOperand(module, kind_name.as_ptr(), md_as_val) };
|
||||
}
|
||||
|
||||
/// Helper method for the sequence of calls:
|
||||
/// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata)
|
||||
/// - `LLVMRustGlobalAddMetadata` (to set that node as metadata of `kind_id` for `global`)
|
||||
pub(crate) fn global_add_metadata_node(
|
||||
&self,
|
||||
global: &'ll Value,
|
||||
kind_id: MetadataKindId,
|
||||
md_list: &[&'ll Metadata],
|
||||
) {
|
||||
let md = self.md_node_in_context(md_list);
|
||||
unsafe { llvm::LLVMRustGlobalAddMetadata(global, kind_id, md) };
|
||||
}
|
||||
|
||||
/// Helper method for the sequence of calls:
|
||||
/// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata)
|
||||
/// - `LLVMGlobalSetMetadata` (to set that node as metadata of `kind_id` for `global`)
|
||||
pub(crate) fn global_set_metadata_node(
|
||||
&self,
|
||||
global: &'ll Value,
|
||||
kind_id: MetadataKindId,
|
||||
md_list: &[&'ll Metadata],
|
||||
) {
|
||||
let md = self.md_node_in_context(md_list);
|
||||
unsafe { llvm::LLVMGlobalSetMetadata(global, kind_id, md) };
|
||||
}
|
||||
}
|
||||
|
||||
impl HasDataLayout for CodegenCx<'_, '_> {
|
||||
|
|
|
|||
|
|
@ -1607,17 +1607,11 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
|
|||
let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref);
|
||||
let typeid = cx.create_metadata(trait_ref_typeid.as_bytes());
|
||||
|
||||
unsafe {
|
||||
let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid];
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
vtable,
|
||||
llvm::MD_type,
|
||||
llvm::LLVMMDNodeInContext2(cx.llcx, v.as_ptr(), v.len()),
|
||||
);
|
||||
let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64));
|
||||
let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1);
|
||||
llvm::LLVMGlobalSetMetadata(vtable, llvm::MD_vcall_visibility, vcall_visibility_metadata);
|
||||
}
|
||||
let type_ = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid];
|
||||
cx.global_add_metadata_node(vtable, llvm::MD_type, &type_);
|
||||
|
||||
let vcall_visibility = [llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64))];
|
||||
cx.global_set_metadata_node(vtable, llvm::MD_vcall_visibility, &vcall_visibility);
|
||||
}
|
||||
|
||||
/// Creates debug information for the given vtable, which is for the
|
||||
|
|
|
|||
|
|
@ -302,26 +302,14 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) {
|
||||
let typeid_metadata = self.create_metadata(typeid);
|
||||
unsafe {
|
||||
let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
function,
|
||||
llvm::MD_type,
|
||||
llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()),
|
||||
)
|
||||
}
|
||||
let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
|
||||
self.global_add_metadata_node(function, llvm::MD_type, &v);
|
||||
}
|
||||
|
||||
fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) {
|
||||
let typeid_metadata = self.create_metadata(typeid);
|
||||
unsafe {
|
||||
let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
|
||||
llvm::LLVMGlobalSetMetadata(
|
||||
function,
|
||||
llvm::MD_type,
|
||||
llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()),
|
||||
)
|
||||
}
|
||||
let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
|
||||
self.global_set_metadata_node(function, llvm::MD_type, &v);
|
||||
}
|
||||
|
||||
fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> {
|
||||
|
|
@ -329,32 +317,12 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
}
|
||||
|
||||
fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) {
|
||||
let kcfi_type_metadata = self.const_u32(kcfi_typeid);
|
||||
unsafe {
|
||||
llvm::LLVMRustGlobalAddMetadata(
|
||||
function,
|
||||
llvm::MD_kcfi_type,
|
||||
llvm::LLVMMDNodeInContext2(
|
||||
self.llcx,
|
||||
&llvm::LLVMValueAsMetadata(kcfi_type_metadata),
|
||||
1,
|
||||
),
|
||||
)
|
||||
}
|
||||
let kcfi_type_metadata = [llvm::LLVMValueAsMetadata(self.const_u32(kcfi_typeid))];
|
||||
self.global_add_metadata_node(function, llvm::MD_kcfi_type, &kcfi_type_metadata);
|
||||
}
|
||||
|
||||
fn set_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) {
|
||||
let kcfi_type_metadata = self.const_u32(kcfi_typeid);
|
||||
unsafe {
|
||||
llvm::LLVMGlobalSetMetadata(
|
||||
function,
|
||||
llvm::MD_kcfi_type,
|
||||
llvm::LLVMMDNodeInContext2(
|
||||
self.llcx,
|
||||
&llvm::LLVMValueAsMetadata(kcfi_type_metadata),
|
||||
1,
|
||||
),
|
||||
)
|
||||
}
|
||||
let kcfi_type_metadata = [llvm::LLVMValueAsMetadata(self.const_u32(kcfi_typeid))];
|
||||
self.global_set_metadata_node(function, llvm::MD_kcfi_type, &kcfi_type_metadata);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -587,6 +587,7 @@ Select which editor you would like to set up [default: None]: ";
|
|||
"631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9",
|
||||
"080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce",
|
||||
"f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1",
|
||||
"e260553b71e4773c30a63c4b23b42b279fc73e72f95b775c47b7b7c511c51595",
|
||||
],
|
||||
EditorKind::Helix => &[
|
||||
"2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233",
|
||||
|
|
@ -594,6 +595,7 @@ Select which editor you would like to set up [default: None]: ";
|
|||
"f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5",
|
||||
"198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5",
|
||||
"1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1",
|
||||
"eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6",
|
||||
],
|
||||
EditorKind::Vim | EditorKind::VsCode => &[
|
||||
"ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
|
||||
|
|
@ -610,6 +612,7 @@ Select which editor you would like to set up [default: None]: ";
|
|||
"f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
|
||||
"701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12",
|
||||
"a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054",
|
||||
"02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47",
|
||||
],
|
||||
EditorKind::Zed => &[
|
||||
"bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c",
|
||||
|
|
@ -617,6 +620,7 @@ Select which editor you would like to set up [default: None]: ";
|
|||
"2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26",
|
||||
"4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6",
|
||||
"f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382",
|
||||
"5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f",
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,6 +262,20 @@ Consider writing the test as a proper incremental test instead.
|
|||
|
||||
</div>
|
||||
|
||||
#### The edition directive
|
||||
|
||||
The `//@ edition` directive can take an exact edition, a bounded half-open range of editions or a left-bounded half-open range of editions, this affects which edition is used by `./x test` to run the test. For example:
|
||||
|
||||
- A test with the `//@ edition: 2018` directive will only run under the 2018 edition.
|
||||
- A test with the `//@ edition: 2015..2021` directive can be run under both the 2015 and 2018 editions. However, CI will only run the test with the lowest edition possible (2015 in this case).
|
||||
- A test with the `//@ edition: 2018..` directive will run under any edition greater or equal than 2018. However, CI will only run the test with the lowest edition possible (2018 in this case).
|
||||
|
||||
You can also force `./x test` to use a specific edition by passing the `-- --edition=` argument. However, tests with the `//@ edition` directive will clamp the value passed to the argument. For example, if we run `./x test -- --edition=2015`:
|
||||
|
||||
- A test with the `//@ edition: 2018` will run with the 2018 edition.
|
||||
- A test with the `//@ edition: 2015..2021` will be run with the 2015 edition.
|
||||
- A test with the `//@ edition: 2018..` will run with the 2018 edition.
|
||||
|
||||
### Rustdoc
|
||||
|
||||
| Directive | Explanation | Supported test suites | Possible values |
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
- [\*-apple-watchos](platform-support/apple-watchos.md)
|
||||
- [\*-apple-visionos](platform-support/apple-visionos.md)
|
||||
- [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
|
||||
- [aarch64-unknown-linux-gnu](platform-support/aarch64-unknown-linux-gnu.md)
|
||||
- [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md)
|
||||
- [aarch64-unknown-none*](platform-support/aarch64-unknown-none.md)
|
||||
- [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md)
|
||||
|
|
@ -67,6 +68,7 @@
|
|||
- [arm\*-unknown-linux-\*](./platform-support/arm-linux.md)
|
||||
- [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
|
||||
- [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md)
|
||||
- [armv7-unknown-linux-gnueabi](platform-support/armv7-unknown-linux-gnueabi.md)
|
||||
- [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
|
||||
- [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
|
||||
- [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ target | notes
|
|||
-------|-------
|
||||
[`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
|
||||
[`aarch64-pc-windows-msvc`](platform-support/windows-msvc.md) | ARM64 Windows MSVC
|
||||
`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+)
|
||||
[`aarch64-unknown-linux-gnu`](platform-support/aarch64-unknown-linux-gnu.md) | ARM64 Linux (kernel 4.1+, glibc 2.17+)
|
||||
[`i686-pc-windows-msvc`](platform-support/windows-msvc.md) | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
|
||||
`i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI]
|
||||
[`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+)
|
||||
|
|
@ -93,7 +93,7 @@ target | notes
|
|||
[`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony
|
||||
`arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2+, glibc 2.17)
|
||||
`arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2+, glibc 2.17)
|
||||
`armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17)
|
||||
[`armv7-unknown-linux-gnueabihf`](platform-support/armv7-unknown-linux-gnueabi.md) | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17)
|
||||
[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony
|
||||
[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, glibc 2.36), LSX required
|
||||
[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, musl 1.2.5), LSX required
|
||||
|
|
@ -159,7 +159,7 @@ target | std | notes
|
|||
[`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4+, glibc 2.23)
|
||||
`armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3
|
||||
[`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android
|
||||
`armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27)
|
||||
[`armv7-unknown-linux-gnueabi`](platform-support/armv7-unknown-linux-gnueabi.md) | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27)
|
||||
`armv7-unknown-linux-musleabi` | ✓ | Armv7-A Linux with musl 1.2.3
|
||||
`armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat
|
||||
[`armv7a-none-eabi`](platform-support/armv7a-none-eabi.md) | * | Bare Armv7-A
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
# `aarch64-unknown-linux-gnu`
|
||||
|
||||
**Tier: 1 (with Host Tools)**
|
||||
|
||||
Target for 64-bit little endian ARMv8-A Linux 4.1+ programs using glibc 2.17+.
|
||||
|
||||
## Target maintainers
|
||||
|
||||
- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
|
||||
|
||||
[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
|
||||
[arm_email]: mailto:rust@arm.com
|
||||
|
||||
## Requirements
|
||||
|
||||
Building the target itself requires a 64-bit little endian ARMv8-A compiler that is supported by
|
||||
`cc-rs`.
|
||||
|
||||
## Building the target
|
||||
|
||||
The target can be built by enabling it for a `rustc` build:
|
||||
|
||||
```toml
|
||||
[build]
|
||||
target = ["aarch64-unknown-linux-gnu"]
|
||||
```
|
||||
|
||||
If cross-compiling, make sure your C compiler is included in `$PATH`, then add it to the
|
||||
`bootstrap.toml`:
|
||||
|
||||
```toml
|
||||
[target.aarch64-unknown-linux-musl]
|
||||
cc = "aarch64-linux-gnu-gcc"
|
||||
cxx = "aarch64-linux-gnu-g++"
|
||||
ar = "aarch64-linux-gnu-ar"
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
```
|
||||
|
||||
## Building Rust programs
|
||||
|
||||
This target is distributed through `rustup`, and otherwise requires no special configuration.
|
||||
|
||||
## Cross-compilation
|
||||
|
||||
This target can be cross-compiled from any host.
|
||||
|
||||
## Testing
|
||||
|
||||
This target can be tested as normal with `x.py` on a 64-bit little endian ARMv8-A host or via QEMU
|
||||
emulation.
|
||||
|
|
@ -14,9 +14,12 @@ Processors in this family include the [Arm Cortex-A35, 53, 76, etc][aarch64-cpus
|
|||
|
||||
## Target maintainers
|
||||
|
||||
[Rust Embedded Devices Working Group Arm Team]
|
||||
- [Rust Embedded Devices Working Group Arm Team]
|
||||
- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
|
||||
|
||||
[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
|
||||
[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
|
||||
[arm_email]: mailto:rust@arm.com
|
||||
|
||||
## Target CPU and Target Feature options
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ Linux (but not Android). Those targets are:
|
|||
* [`armv5te-unknown-linux-gnueabi`](armv5te-unknown-linux-gnueabi.md)
|
||||
* `armv5te-unknown-linux-musleabi`
|
||||
* `armv5te-unknown-linux-uclibceabi`
|
||||
* `armv7-unknown-linux-gnueabi`
|
||||
* `armv7-unknown-linux-gnueabihf`
|
||||
* [`armv7-unknown-linux-gnueabi`](armv7-unknown-linux-gnueabi.md)
|
||||
* [`armv7-unknown-linux-gnueabihf`](armv7-unknown-linux-gnueabi.md)
|
||||
* `armv7-unknown-linux-musleabi`
|
||||
* `armv7-unknown-linux-musleabihf`
|
||||
* `armv7-unknown-linux-ohos`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
# `armv7-unknown-linux-gnueabi` and `armv7-unknown-linux-gnueabihf`
|
||||
|
||||
* **Tier: 2 (with Host Tools)** for `armv7-unknown-linux-gnueabihf`
|
||||
* **Tier: 2** for `armv7-unknown-linux-gnueabi`
|
||||
|
||||
Target for 32-bit little endian ARMv7-A Linux 3.2+ programs using glibc 2.17+.
|
||||
|
||||
## Target maintainers
|
||||
|
||||
- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
|
||||
|
||||
[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
|
||||
[arm_email]: mailto:rust@arm.com
|
||||
|
||||
## Requirements
|
||||
|
||||
Building the targets themselves requires a 32-bit little endian ARMv7-A compiler that is supported
|
||||
by `cc-rs`.
|
||||
|
||||
## Building the target
|
||||
|
||||
These targets can be built by enabling it for a `rustc` build:
|
||||
|
||||
```toml
|
||||
[build]
|
||||
target = ["armv7-unknown-linux-gnueabihf", "armv7-unknown-linux-gnueabi"]
|
||||
```
|
||||
|
||||
If cross-compiling, make sure your C compiler is included in `$PATH`, then add it to the
|
||||
`bootstrap.toml`:
|
||||
|
||||
```toml
|
||||
[target.aarch64-unknown-linux-musl]
|
||||
cc = "arm-linux-gnu-gcc"
|
||||
cxx = "arm-linux-gnu-g++"
|
||||
ar = "arm-linux-gnu-ar"
|
||||
linker = "arm-linux-gnu-gcc"
|
||||
```
|
||||
|
||||
## Building Rust programs
|
||||
|
||||
These targets is distributed through `rustup`, and otherwise requires no special configuration.
|
||||
|
||||
## Cross-compilation
|
||||
|
||||
These targets can be cross-compiled from any host.
|
||||
|
||||
## Testing
|
||||
|
||||
These targets can be tested as normal with `x.py` on a 32-bit little endian ARMv7-A host or via
|
||||
QEMU emulation.
|
||||
|
|
@ -19,9 +19,12 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
|
|||
|
||||
## Target maintainers
|
||||
|
||||
[Rust Embedded Devices Working Group Arm Team]
|
||||
- [Rust Embedded Devices Working Group Arm Team]
|
||||
- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
|
||||
|
||||
[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
|
||||
[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
|
||||
[arm_email]: mailto:rust@arm.com
|
||||
|
||||
## Requirements
|
||||
|
||||
|
|
|
|||
|
|
@ -15,10 +15,13 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
|
|||
|
||||
## Target maintainers
|
||||
|
||||
[@chrisnc](https://github.com/chrisnc)
|
||||
[Rust Embedded Devices Working Group Arm Team]
|
||||
- [@chrisnc](https://github.com/chrisnc)
|
||||
- [Rust Embedded Devices Working Group Arm Team]
|
||||
- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
|
||||
|
||||
[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
|
||||
[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
|
||||
[arm_email]: mailto:rust@arm.com
|
||||
|
||||
## Requirements
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,13 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
|
|||
|
||||
## Target maintainers
|
||||
|
||||
[@chrisnc](https://github.com/chrisnc)
|
||||
[Rust Embedded Devices Working Group Arm Team]
|
||||
- [@chrisnc](https://github.com/chrisnc)
|
||||
- [Rust Embedded Devices Working Group Arm Team]
|
||||
- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
|
||||
|
||||
[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
|
||||
[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
|
||||
[arm_email]: mailto:rust@arm.com
|
||||
|
||||
## Requirements
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,11 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
|
|||
|
||||
## Target maintainers
|
||||
|
||||
[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
|
||||
- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
|
||||
- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
|
||||
|
||||
[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
|
||||
[arm_email]: mailto:rust@arm.com
|
||||
|
||||
## Target CPU and Target Feature options
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,11 @@ only option because there is no FPU support in [Armv7-M].
|
|||
|
||||
## Target maintainers
|
||||
|
||||
[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
|
||||
- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
|
||||
- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
|
||||
|
||||
[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
|
||||
[arm_email]: mailto:rust@arm.com
|
||||
|
||||
## Target CPU and Target Feature options
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,11 @@ only option because there is no FPU support in [Armv8-M] Baseline.
|
|||
|
||||
## Target maintainers
|
||||
|
||||
[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
|
||||
- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
|
||||
- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
|
||||
|
||||
[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
|
||||
[arm_email]: mailto:rust@arm.com
|
||||
|
||||
## Target CPU and Target Feature options
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,11 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
|
|||
|
||||
## Target maintainers
|
||||
|
||||
[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
|
||||
- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
|
||||
- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
|
||||
|
||||
[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
|
||||
[arm_email]: mailto:rust@arm.com
|
||||
|
||||
## Target CPU and Target Feature options
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,12 @@ Available targets:
|
|||
|
||||
## Target maintainers
|
||||
|
||||
[@dvdhrm](https://github.com/dvdhrm)
|
||||
[@nicholasbishop](https://github.com/nicholasbishop)
|
||||
- [@dvdhrm](https://github.com/dvdhrm)
|
||||
- [@nicholasbishop](https://github.com/nicholasbishop)
|
||||
- (for `aarch64-unknown-uefi` only) [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
|
||||
|
||||
[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
|
||||
[arm_email]: mailto:rust@arm.com
|
||||
|
||||
## Requirements
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
:overrideCommand ["python3"
|
||||
"x.py"
|
||||
"check"
|
||||
"--build-dir"
|
||||
"build-rust-analyzer"
|
||||
"--json-output"])
|
||||
:linkedProjects ["Cargo.toml"
|
||||
"compiler/rustc_codegen_cranelift/Cargo.toml"
|
||||
|
|
@ -13,9 +15,9 @@
|
|||
"library/Cargo.toml"
|
||||
"src/bootstrap/Cargo.toml"
|
||||
"src/tools/rust-analyzer/Cargo.toml"]
|
||||
:rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt"
|
||||
:rustfmt ( :overrideCommand ["build-rust-analyzer/host/rustfmt/bin/rustfmt"
|
||||
"--edition=2024"])
|
||||
:procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv"
|
||||
:procMacro ( :server "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv"
|
||||
:enable t)
|
||||
:cargo ( :buildScripts ( :enable t
|
||||
:invocationLocation "root"
|
||||
|
|
@ -23,6 +25,8 @@
|
|||
:overrideCommand ["python3"
|
||||
"x.py"
|
||||
"check"
|
||||
"--build-dir"
|
||||
"build-rust-analyzer"
|
||||
"--json-output"
|
||||
"--compile-time-deps"])]
|
||||
:sysrootSrc "./library"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
# This config uses a separate build directory for rust-analyzer,
|
||||
# so that r-a's checks don't block user `x` commands and vice-verse.
|
||||
# R-a's build directory is located in `build/rust-analyzer`.
|
||||
# R-a's build directory is located in `build-rust-analyzer`.
|
||||
#
|
||||
# To build rustfmt and proc macro server for r-a run the following command:
|
||||
# ```
|
||||
# x b proc-macro-srv-cli rustfmt --stage 0 --build-dir build/rust-analyzer
|
||||
# x b proc-macro-srv-cli rustfmt --stage 0 --build-dir build-rust-analyzer
|
||||
# ```
|
||||
|
||||
[language-server.rust-analyzer.config]
|
||||
|
|
@ -26,17 +26,17 @@ overrideCommand = [
|
|||
"check",
|
||||
"--json-output",
|
||||
"--build-dir",
|
||||
"build/rust-analyzer",
|
||||
"build-rust-analyzer",
|
||||
]
|
||||
|
||||
[language-server.rust-analyzer.config.rustfmt]
|
||||
overrideCommand = [
|
||||
"build/rust-analyzer/host/rustfmt/bin/rustfmt",
|
||||
"build-rust-analyzer/host/rustfmt/bin/rustfmt",
|
||||
"--edition=2024"
|
||||
]
|
||||
|
||||
[language-server.rust-analyzer.config.procMacro]
|
||||
server = "build/rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv"
|
||||
server = "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv"
|
||||
enable = true
|
||||
|
||||
[language-server.rust-analyzer.config.rustc]
|
||||
|
|
@ -58,6 +58,6 @@ overrideCommand = [
|
|||
"check",
|
||||
"--json-output",
|
||||
"--build-dir",
|
||||
"build/rust-analyzer",
|
||||
"--compile-time-deps"
|
||||
"build-rust-analyzer",
|
||||
"--compile-time-deps",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
"python3",
|
||||
"x.py",
|
||||
"check",
|
||||
"--build-dir",
|
||||
"build-rust-analyzer",
|
||||
"--json-output"
|
||||
],
|
||||
"rust-analyzer.linkedProjects": [
|
||||
|
|
@ -16,10 +18,10 @@
|
|||
"src/tools/rust-analyzer/Cargo.toml"
|
||||
],
|
||||
"rust-analyzer.rustfmt.overrideCommand": [
|
||||
"${workspaceFolder}/build/host/rustfmt/bin/rustfmt",
|
||||
"${workspaceFolder}/build-rust-analyzer/host/rustfmt/bin/rustfmt",
|
||||
"--edition=2024"
|
||||
],
|
||||
"rust-analyzer.procMacro.server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv",
|
||||
"rust-analyzer.procMacro.server": "${workspaceFolder}/build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv",
|
||||
"rust-analyzer.procMacro.enable": true,
|
||||
"rust-analyzer.cargo.buildScripts.enable": true,
|
||||
"rust-analyzer.cargo.buildScripts.invocationStrategy": "once",
|
||||
|
|
@ -27,6 +29,8 @@
|
|||
"python3",
|
||||
"x.py",
|
||||
"check",
|
||||
"--build-dir",
|
||||
"build-rust-analyzer",
|
||||
"--json-output",
|
||||
"--compile-time-deps"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -7,7 +7,15 @@
|
|||
"enable": true,
|
||||
"invocationLocation": "root",
|
||||
"invocationStrategy": "once",
|
||||
"overrideCommand": ["python3", "x.py", "check", "--json-output", "--compile-time-deps"]
|
||||
"overrideCommand": [
|
||||
"python3",
|
||||
"x.py",
|
||||
"check",
|
||||
"--build-dir",
|
||||
"build-rust-analyzer",
|
||||
"--compile-time-deps",
|
||||
"--json-output"
|
||||
]
|
||||
},
|
||||
"extraEnv": {
|
||||
"RUSTC_BOOTSTRAP": "1"
|
||||
|
|
@ -17,7 +25,14 @@
|
|||
"check": {
|
||||
"invocationLocation": "root",
|
||||
"invocationStrategy": "once",
|
||||
"overrideCommand": ["python3", "x.py", "check", "--json-output"]
|
||||
"overrideCommand": [
|
||||
"python3",
|
||||
"x.py",
|
||||
"check",
|
||||
"--json-output",
|
||||
"--build-dir",
|
||||
"build-rust-analyzer"
|
||||
]
|
||||
},
|
||||
"linkedProjects": [
|
||||
"Cargo.toml",
|
||||
|
|
@ -29,14 +44,14 @@
|
|||
],
|
||||
"procMacro": {
|
||||
"enable": true,
|
||||
"server": "build/host/stage0/libexec/rust-analyzer-proc-macro-srv"
|
||||
"server": "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv"
|
||||
},
|
||||
"rustc": {
|
||||
"source": "./Cargo.toml"
|
||||
},
|
||||
"rustfmt": {
|
||||
"overrideCommand": [
|
||||
"build/host/rustfmt/bin/rustfmt",
|
||||
"build-rust-analyzer/host/rustfmt/bin/rustfmt",
|
||||
"--edition=2024"
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,14 +3,18 @@
|
|||
// FIXME: Once the portability lint RFC is implemented (see tracking issue #41619),
|
||||
// switch to use those structures instead.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::{fmt, mem, ops};
|
||||
|
||||
use itertools::Either;
|
||||
use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::{Symbol, sym};
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
use crate::display::{Joined as _, MaybeDisplay, Wrapped};
|
||||
use crate::html::escape::Escape;
|
||||
|
|
@ -600,3 +604,264 @@ impl fmt::Display for Display<'_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This type keeps track of (doc) cfg information as we go down the item tree.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct CfgInfo {
|
||||
/// List of currently active `doc(auto_cfg(hide(...)))` cfgs, minus currently active
|
||||
/// `doc(auto_cfg(show(...)))` cfgs.
|
||||
hidden_cfg: FxHashSet<Cfg>,
|
||||
/// Current computed `cfg`. Each time we enter a new item, this field is updated as well while
|
||||
/// taking into account the `hidden_cfg` information.
|
||||
current_cfg: Cfg,
|
||||
/// Whether the `doc(auto_cfg())` feature is enabled or not at this point.
|
||||
auto_cfg_active: bool,
|
||||
/// If the parent item used `doc(cfg(...))`, then we don't want to overwrite `current_cfg`,
|
||||
/// instead we will concatenate with it. However, if it's not the case, we need to overwrite
|
||||
/// `current_cfg`.
|
||||
parent_is_doc_cfg: bool,
|
||||
}
|
||||
|
||||
impl Default for CfgInfo {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
hidden_cfg: FxHashSet::from_iter([
|
||||
Cfg::Cfg(sym::test, None),
|
||||
Cfg::Cfg(sym::doc, None),
|
||||
Cfg::Cfg(sym::doctest, None),
|
||||
]),
|
||||
current_cfg: Cfg::True,
|
||||
auto_cfg_active: true,
|
||||
parent_is_doc_cfg: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show_hide_show_conflict_error(
|
||||
tcx: TyCtxt<'_>,
|
||||
item_span: rustc_span::Span,
|
||||
previous: rustc_span::Span,
|
||||
) {
|
||||
let mut diag = tcx.sess.dcx().struct_span_err(
|
||||
item_span,
|
||||
format!(
|
||||
"same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item"
|
||||
),
|
||||
);
|
||||
diag.span_note(previous, "first change was here");
|
||||
diag.emit();
|
||||
}
|
||||
|
||||
/// This functions updates the `hidden_cfg` field of the provided `cfg_info` argument.
|
||||
///
|
||||
/// It also checks if a same `cfg` is present in both `auto_cfg(hide(...))` and
|
||||
/// `auto_cfg(show(...))` on the same item and emits an error if it's the case.
|
||||
///
|
||||
/// Because we go through a list of `cfg`s, we keep track of the `cfg`s we saw in `new_show_attrs`
|
||||
/// and in `new_hide_attrs` arguments.
|
||||
fn handle_auto_cfg_hide_show(
|
||||
tcx: TyCtxt<'_>,
|
||||
cfg_info: &mut CfgInfo,
|
||||
sub_attr: &MetaItemInner,
|
||||
is_show: bool,
|
||||
new_show_attrs: &mut FxHashMap<(Symbol, Option<Symbol>), rustc_span::Span>,
|
||||
new_hide_attrs: &mut FxHashMap<(Symbol, Option<Symbol>), rustc_span::Span>,
|
||||
) {
|
||||
if let MetaItemInner::MetaItem(item) = sub_attr
|
||||
&& let MetaItemKind::List(items) = &item.kind
|
||||
{
|
||||
for item in items {
|
||||
// FIXME: Report in case `Cfg::parse` reports an error?
|
||||
if let Ok(Cfg::Cfg(key, value)) = Cfg::parse(item) {
|
||||
if is_show {
|
||||
if let Some(span) = new_hide_attrs.get(&(key, value)) {
|
||||
show_hide_show_conflict_error(tcx, item.span(), *span);
|
||||
} else {
|
||||
new_show_attrs.insert((key, value), item.span());
|
||||
}
|
||||
cfg_info.hidden_cfg.remove(&Cfg::Cfg(key, value));
|
||||
} else {
|
||||
if let Some(span) = new_show_attrs.get(&(key, value)) {
|
||||
show_hide_show_conflict_error(tcx, item.span(), *span);
|
||||
} else {
|
||||
new_hide_attrs.insert((key, value), item.span());
|
||||
}
|
||||
cfg_info.hidden_cfg.insert(Cfg::Cfg(key, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
|
||||
attrs: I,
|
||||
tcx: TyCtxt<'_>,
|
||||
cfg_info: &mut CfgInfo,
|
||||
) -> Option<Arc<Cfg>> {
|
||||
fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
|
||||
let mut iter = it.into_iter();
|
||||
let item = iter.next()?;
|
||||
if iter.next().is_some() {
|
||||
return None;
|
||||
}
|
||||
Some(item)
|
||||
}
|
||||
|
||||
fn check_changed_auto_active_status(
|
||||
changed_auto_active_status: &mut Option<rustc_span::Span>,
|
||||
attr: &ast::MetaItem,
|
||||
cfg_info: &mut CfgInfo,
|
||||
tcx: TyCtxt<'_>,
|
||||
new_value: bool,
|
||||
) -> bool {
|
||||
if let Some(first_change) = changed_auto_active_status {
|
||||
if cfg_info.auto_cfg_active != new_value {
|
||||
tcx.sess
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
vec![*first_change, attr.span],
|
||||
"`auto_cfg` was disabled and enabled more than once on the same item",
|
||||
)
|
||||
.emit();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
*changed_auto_active_status = Some(attr.span);
|
||||
}
|
||||
cfg_info.auto_cfg_active = new_value;
|
||||
false
|
||||
}
|
||||
|
||||
let mut new_show_attrs = FxHashMap::default();
|
||||
let mut new_hide_attrs = FxHashMap::default();
|
||||
|
||||
let mut doc_cfg = attrs
|
||||
.clone()
|
||||
.filter(|attr| attr.has_name(sym::doc))
|
||||
.flat_map(|attr| attr.meta_item_list().unwrap_or_default())
|
||||
.filter(|attr| attr.has_name(sym::cfg))
|
||||
.peekable();
|
||||
// If the item uses `doc(cfg(...))`, then we ignore the other `cfg(...)` attributes.
|
||||
if doc_cfg.peek().is_some() {
|
||||
let sess = tcx.sess;
|
||||
// We overwrite existing `cfg`.
|
||||
if !cfg_info.parent_is_doc_cfg {
|
||||
cfg_info.current_cfg = Cfg::True;
|
||||
cfg_info.parent_is_doc_cfg = true;
|
||||
}
|
||||
for attr in doc_cfg {
|
||||
if let Some(cfg_mi) =
|
||||
attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg(attr, sess))
|
||||
{
|
||||
match Cfg::parse(cfg_mi) {
|
||||
Ok(new_cfg) => cfg_info.current_cfg &= new_cfg,
|
||||
Err(e) => {
|
||||
sess.dcx().span_err(e.span, e.msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cfg_info.parent_is_doc_cfg = false;
|
||||
}
|
||||
|
||||
let mut changed_auto_active_status = None;
|
||||
|
||||
// We get all `doc(auto_cfg)`, `cfg` and `target_feature` attributes.
|
||||
for attr in attrs {
|
||||
if let Some(ident) = attr.ident()
|
||||
&& ident.name == sym::doc
|
||||
&& let Some(attrs) = attr.meta_item_list()
|
||||
{
|
||||
for attr in attrs.iter().filter(|attr| attr.has_name(sym::auto_cfg)) {
|
||||
let MetaItemInner::MetaItem(attr) = attr else {
|
||||
continue;
|
||||
};
|
||||
match &attr.kind {
|
||||
MetaItemKind::Word => {
|
||||
if check_changed_auto_active_status(
|
||||
&mut changed_auto_active_status,
|
||||
attr,
|
||||
cfg_info,
|
||||
tcx,
|
||||
true,
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
MetaItemKind::NameValue(lit) => {
|
||||
if let LitKind::Bool(value) = lit.kind {
|
||||
if check_changed_auto_active_status(
|
||||
&mut changed_auto_active_status,
|
||||
attr,
|
||||
cfg_info,
|
||||
tcx,
|
||||
value,
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
MetaItemKind::List(sub_attrs) => {
|
||||
if check_changed_auto_active_status(
|
||||
&mut changed_auto_active_status,
|
||||
attr,
|
||||
cfg_info,
|
||||
tcx,
|
||||
true,
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
for sub_attr in sub_attrs.iter() {
|
||||
if let Some(ident) = sub_attr.ident()
|
||||
&& (ident.name == sym::show || ident.name == sym::hide)
|
||||
{
|
||||
handle_auto_cfg_hide_show(
|
||||
tcx,
|
||||
cfg_info,
|
||||
&sub_attr,
|
||||
ident.name == sym::show,
|
||||
&mut new_show_attrs,
|
||||
&mut new_hide_attrs,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr {
|
||||
// Treat `#[target_feature(enable = "feat")]` attributes as if they were
|
||||
// `#[doc(cfg(target_feature = "feat"))]` attributes as well.
|
||||
for (feature, _) in features {
|
||||
cfg_info.current_cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
|
||||
}
|
||||
continue;
|
||||
} else if !cfg_info.parent_is_doc_cfg
|
||||
&& let Some(ident) = attr.ident()
|
||||
&& matches!(ident.name, sym::cfg | sym::cfg_trace)
|
||||
&& let Some(attr) = single(attr.meta_item_list()?)
|
||||
&& let Ok(new_cfg) = Cfg::parse(&attr)
|
||||
{
|
||||
cfg_info.current_cfg &= new_cfg;
|
||||
}
|
||||
}
|
||||
|
||||
// If `doc(auto_cfg)` feature is disabled and `doc(cfg())` wasn't used, there is nothing
|
||||
// to be done here.
|
||||
if !cfg_info.auto_cfg_active && !cfg_info.parent_is_doc_cfg {
|
||||
None
|
||||
} else if cfg_info.parent_is_doc_cfg {
|
||||
if cfg_info.current_cfg == Cfg::True {
|
||||
None
|
||||
} else {
|
||||
Some(Arc::new(cfg_info.current_cfg.clone()))
|
||||
}
|
||||
} else {
|
||||
// If `doc(auto_cfg)` feature is enabled, we want to collect all `cfg` items, we remove the
|
||||
// hidden ones afterward.
|
||||
match cfg_info.current_cfg.strip_hidden(&cfg_info.hidden_cfg) {
|
||||
None | Some(Cfg::True) => None,
|
||||
Some(cfg) => Some(Arc::new(cfg)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ use tracing::{debug, instrument};
|
|||
use utils::*;
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
pub(crate) use self::cfg::{CfgInfo, extract_cfg_from_attrs};
|
||||
pub(crate) use self::types::*;
|
||||
pub(crate) use self::utils::{krate, register_res, synthesize_auto_trait_and_blanket_impls};
|
||||
use crate::core::DocContext;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ use std::{fmt, iter};
|
|||
use arrayvec::ArrayVec;
|
||||
use itertools::Either;
|
||||
use rustc_abi::{ExternAbi, VariantIdx};
|
||||
use rustc_ast::ast::{LitKind, MetaItemInner, MetaItemKind};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation};
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
|
||||
|
|
@ -922,267 +921,6 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
|
|||
.flatten()
|
||||
}
|
||||
|
||||
/// This type keeps track of (doc) cfg information as we go down the item tree.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct CfgInfo {
|
||||
/// List of currently active `doc(auto_cfg(hide(...)))` cfgs, minus currently active
|
||||
/// `doc(auto_cfg(show(...)))` cfgs.
|
||||
hidden_cfg: FxHashSet<Cfg>,
|
||||
/// Current computed `cfg`. Each time we enter a new item, this field is updated as well while
|
||||
/// taking into account the `hidden_cfg` information.
|
||||
current_cfg: Cfg,
|
||||
/// Whether the `doc(auto_cfg())` feature is enabled or not at this point.
|
||||
auto_cfg_active: bool,
|
||||
/// If the parent item used `doc(cfg(...))`, then we don't want to overwrite `current_cfg`,
|
||||
/// instead we will concatenate with it. However, if it's not the case, we need to overwrite
|
||||
/// `current_cfg`.
|
||||
parent_is_doc_cfg: bool,
|
||||
}
|
||||
|
||||
impl Default for CfgInfo {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
hidden_cfg: FxHashSet::from_iter([
|
||||
Cfg::Cfg(sym::test, None),
|
||||
Cfg::Cfg(sym::doc, None),
|
||||
Cfg::Cfg(sym::doctest, None),
|
||||
]),
|
||||
current_cfg: Cfg::True,
|
||||
auto_cfg_active: true,
|
||||
parent_is_doc_cfg: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show_hide_show_conflict_error(
|
||||
tcx: TyCtxt<'_>,
|
||||
item_span: rustc_span::Span,
|
||||
previous: rustc_span::Span,
|
||||
) {
|
||||
let mut diag = tcx.sess.dcx().struct_span_err(
|
||||
item_span,
|
||||
format!(
|
||||
"same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item"
|
||||
),
|
||||
);
|
||||
diag.span_note(previous, "first change was here");
|
||||
diag.emit();
|
||||
}
|
||||
|
||||
/// This functions updates the `hidden_cfg` field of the provided `cfg_info` argument.
|
||||
///
|
||||
/// It also checks if a same `cfg` is present in both `auto_cfg(hide(...))` and
|
||||
/// `auto_cfg(show(...))` on the same item and emits an error if it's the case.
|
||||
///
|
||||
/// Because we go through a list of `cfg`s, we keep track of the `cfg`s we saw in `new_show_attrs`
|
||||
/// and in `new_hide_attrs` arguments.
|
||||
fn handle_auto_cfg_hide_show(
|
||||
tcx: TyCtxt<'_>,
|
||||
cfg_info: &mut CfgInfo,
|
||||
sub_attr: &MetaItemInner,
|
||||
is_show: bool,
|
||||
new_show_attrs: &mut FxHashMap<(Symbol, Option<Symbol>), rustc_span::Span>,
|
||||
new_hide_attrs: &mut FxHashMap<(Symbol, Option<Symbol>), rustc_span::Span>,
|
||||
) {
|
||||
if let MetaItemInner::MetaItem(item) = sub_attr
|
||||
&& let MetaItemKind::List(items) = &item.kind
|
||||
{
|
||||
for item in items {
|
||||
// FIXME: Report in case `Cfg::parse` reports an error?
|
||||
if let Ok(Cfg::Cfg(key, value)) = Cfg::parse(item) {
|
||||
if is_show {
|
||||
if let Some(span) = new_hide_attrs.get(&(key, value)) {
|
||||
show_hide_show_conflict_error(tcx, item.span(), *span);
|
||||
} else {
|
||||
new_show_attrs.insert((key, value), item.span());
|
||||
}
|
||||
cfg_info.hidden_cfg.remove(&Cfg::Cfg(key, value));
|
||||
} else {
|
||||
if let Some(span) = new_show_attrs.get(&(key, value)) {
|
||||
show_hide_show_conflict_error(tcx, item.span(), *span);
|
||||
} else {
|
||||
new_hide_attrs.insert((key, value), item.span());
|
||||
}
|
||||
cfg_info.hidden_cfg.insert(Cfg::Cfg(key, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
|
||||
attrs: I,
|
||||
tcx: TyCtxt<'_>,
|
||||
cfg_info: &mut CfgInfo,
|
||||
) -> Option<Arc<Cfg>> {
|
||||
fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
|
||||
let mut iter = it.into_iter();
|
||||
let item = iter.next()?;
|
||||
if iter.next().is_some() {
|
||||
return None;
|
||||
}
|
||||
Some(item)
|
||||
}
|
||||
|
||||
fn check_changed_auto_active_status(
|
||||
changed_auto_active_status: &mut Option<rustc_span::Span>,
|
||||
attr: &ast::MetaItem,
|
||||
cfg_info: &mut CfgInfo,
|
||||
tcx: TyCtxt<'_>,
|
||||
new_value: bool,
|
||||
) -> bool {
|
||||
if let Some(first_change) = changed_auto_active_status {
|
||||
if cfg_info.auto_cfg_active != new_value {
|
||||
tcx.sess
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
vec![*first_change, attr.span],
|
||||
"`auto_cfg` was disabled and enabled more than once on the same item",
|
||||
)
|
||||
.emit();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
*changed_auto_active_status = Some(attr.span);
|
||||
}
|
||||
cfg_info.auto_cfg_active = new_value;
|
||||
false
|
||||
}
|
||||
|
||||
let mut new_show_attrs = FxHashMap::default();
|
||||
let mut new_hide_attrs = FxHashMap::default();
|
||||
|
||||
let mut doc_cfg = attrs
|
||||
.clone()
|
||||
.filter(|attr| attr.has_name(sym::doc))
|
||||
.flat_map(|attr| attr.meta_item_list().unwrap_or_default())
|
||||
.filter(|attr| attr.has_name(sym::cfg))
|
||||
.peekable();
|
||||
// If the item uses `doc(cfg(...))`, then we ignore the other `cfg(...)` attributes.
|
||||
if doc_cfg.peek().is_some() {
|
||||
let sess = tcx.sess;
|
||||
// We overwrite existing `cfg`.
|
||||
if !cfg_info.parent_is_doc_cfg {
|
||||
cfg_info.current_cfg = Cfg::True;
|
||||
cfg_info.parent_is_doc_cfg = true;
|
||||
}
|
||||
for attr in doc_cfg {
|
||||
if let Some(cfg_mi) =
|
||||
attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg(attr, sess))
|
||||
{
|
||||
match Cfg::parse(cfg_mi) {
|
||||
Ok(new_cfg) => cfg_info.current_cfg &= new_cfg,
|
||||
Err(e) => {
|
||||
sess.dcx().span_err(e.span, e.msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cfg_info.parent_is_doc_cfg = false;
|
||||
}
|
||||
|
||||
let mut changed_auto_active_status = None;
|
||||
|
||||
// We get all `doc(auto_cfg)`, `cfg` and `target_feature` attributes.
|
||||
for attr in attrs {
|
||||
if let Some(ident) = attr.ident()
|
||||
&& ident.name == sym::doc
|
||||
&& let Some(attrs) = attr.meta_item_list()
|
||||
{
|
||||
for attr in attrs.iter().filter(|attr| attr.has_name(sym::auto_cfg)) {
|
||||
let MetaItemInner::MetaItem(attr) = attr else {
|
||||
continue;
|
||||
};
|
||||
match &attr.kind {
|
||||
MetaItemKind::Word => {
|
||||
if check_changed_auto_active_status(
|
||||
&mut changed_auto_active_status,
|
||||
attr,
|
||||
cfg_info,
|
||||
tcx,
|
||||
true,
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
MetaItemKind::NameValue(lit) => {
|
||||
if let LitKind::Bool(value) = lit.kind {
|
||||
if check_changed_auto_active_status(
|
||||
&mut changed_auto_active_status,
|
||||
attr,
|
||||
cfg_info,
|
||||
tcx,
|
||||
value,
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
MetaItemKind::List(sub_attrs) => {
|
||||
if check_changed_auto_active_status(
|
||||
&mut changed_auto_active_status,
|
||||
attr,
|
||||
cfg_info,
|
||||
tcx,
|
||||
true,
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
for sub_attr in sub_attrs.iter() {
|
||||
if let Some(ident) = sub_attr.ident()
|
||||
&& (ident.name == sym::show || ident.name == sym::hide)
|
||||
{
|
||||
handle_auto_cfg_hide_show(
|
||||
tcx,
|
||||
cfg_info,
|
||||
&sub_attr,
|
||||
ident.name == sym::show,
|
||||
&mut new_show_attrs,
|
||||
&mut new_hide_attrs,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr {
|
||||
// Treat `#[target_feature(enable = "feat")]` attributes as if they were
|
||||
// `#[doc(cfg(target_feature = "feat"))]` attributes as well.
|
||||
for (feature, _) in features {
|
||||
cfg_info.current_cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
|
||||
}
|
||||
continue;
|
||||
} else if !cfg_info.parent_is_doc_cfg
|
||||
&& let Some(ident) = attr.ident()
|
||||
&& matches!(ident.name, sym::cfg | sym::cfg_trace)
|
||||
&& let Some(attr) = single(attr.meta_item_list()?)
|
||||
&& let Ok(new_cfg) = Cfg::parse(&attr)
|
||||
{
|
||||
cfg_info.current_cfg &= new_cfg;
|
||||
}
|
||||
}
|
||||
|
||||
// If `doc(auto_cfg)` feature is disabled and `doc(cfg())` wasn't used, there is nothing
|
||||
// to be done here.
|
||||
if !cfg_info.auto_cfg_active && !cfg_info.parent_is_doc_cfg {
|
||||
None
|
||||
} else if cfg_info.parent_is_doc_cfg {
|
||||
if cfg_info.current_cfg == Cfg::True {
|
||||
None
|
||||
} else {
|
||||
Some(Arc::new(cfg_info.current_cfg.clone()))
|
||||
}
|
||||
} else {
|
||||
// If `doc(auto_cfg)` feature is enabled, we want to collect all `cfg` items, we remove the
|
||||
// hidden ones afterward.
|
||||
match cfg_info.current_cfg.strip_hidden(&cfg_info.hidden_cfg) {
|
||||
None | Some(Cfg::True) => None,
|
||||
Some(cfg) => Some(Arc::new(cfg)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait NestedAttributesExt {
|
||||
/// Returns `true` if the attribute list contains a specific `word`
|
||||
fn has_word(self, word: Symbol) -> bool
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use build_helper::git::GitConfig;
|
|||
use camino::{Utf8Path, Utf8PathBuf};
|
||||
use semver::Version;
|
||||
|
||||
use crate::edition::Edition;
|
||||
use crate::executor::ColorConfig;
|
||||
use crate::fatal;
|
||||
use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum};
|
||||
|
|
@ -612,10 +613,7 @@ pub struct Config {
|
|||
pub git_hash: bool,
|
||||
|
||||
/// The default Rust edition.
|
||||
///
|
||||
/// FIXME: perform stronger validation for this. There are editions that *definitely* exists,
|
||||
/// but there might also be "future" edition.
|
||||
pub edition: Option<String>,
|
||||
pub edition: Option<Edition>,
|
||||
|
||||
// Configuration for various run-make tests frobbing things like C compilers or querying about
|
||||
// various LLVM component information.
|
||||
|
|
|
|||
|
|
@ -16,10 +16,11 @@ use crate::directives::directive_names::{
|
|||
KNOWN_DIRECTIVE_NAMES, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
|
||||
};
|
||||
use crate::directives::needs::CachedNeedsConditions;
|
||||
use crate::edition::{Edition, parse_edition};
|
||||
use crate::errors::ErrorKind;
|
||||
use crate::executor::{CollectedTestDesc, ShouldPanic};
|
||||
use crate::help;
|
||||
use crate::util::static_regex;
|
||||
use crate::{fatal, help};
|
||||
|
||||
pub(crate) mod auxiliary;
|
||||
mod cfg;
|
||||
|
|
@ -437,10 +438,13 @@ impl TestProps {
|
|||
panic!("`compiler-flags` directive should be spelled `compile-flags`");
|
||||
}
|
||||
|
||||
if let Some(edition) = config.parse_edition(ln, testfile) {
|
||||
if let Some(range) = parse_edition_range(config, ln, testfile) {
|
||||
// The edition is added at the start, since flags from //@compile-flags must
|
||||
// be passed to rustc last.
|
||||
self.compile_flags.insert(0, format!("--edition={}", edition.trim()));
|
||||
self.compile_flags.insert(
|
||||
0,
|
||||
format!("--edition={}", range.edition_to_test(config.edition)),
|
||||
);
|
||||
has_edition = true;
|
||||
}
|
||||
|
||||
|
|
@ -1124,10 +1128,6 @@ impl Config {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_edition(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option<String> {
|
||||
self.parse_name_value_directive(line, "edition", testfile)
|
||||
}
|
||||
|
||||
fn set_name_directive(&self, line: &DirectiveLine<'_>, directive: &str, value: &mut bool) {
|
||||
// If the flag is already true, don't bother looking at the directive.
|
||||
*value = *value || self.parse_name_directive(line, directive);
|
||||
|
|
@ -1769,3 +1769,86 @@ enum IgnoreDecision {
|
|||
Continue,
|
||||
Error { message: String },
|
||||
}
|
||||
|
||||
fn parse_edition_range(
|
||||
config: &Config,
|
||||
line: &DirectiveLine<'_>,
|
||||
testfile: &Utf8Path,
|
||||
) -> Option<EditionRange> {
|
||||
let raw = config.parse_name_value_directive(line, "edition", testfile)?;
|
||||
let line_number = line.line_number;
|
||||
|
||||
// Edition range is half-open: `[lower_bound, upper_bound)`
|
||||
if let Some((lower_bound, upper_bound)) = raw.split_once("..") {
|
||||
Some(match (maybe_parse_edition(lower_bound), maybe_parse_edition(upper_bound)) {
|
||||
(Some(lower_bound), Some(upper_bound)) if upper_bound <= lower_bound => {
|
||||
fatal!(
|
||||
"{testfile}:{line_number}: the left side of `//@ edition` cannot be greater than or equal to the right side"
|
||||
);
|
||||
}
|
||||
(Some(lower_bound), Some(upper_bound)) => {
|
||||
EditionRange::Range { lower_bound, upper_bound }
|
||||
}
|
||||
(Some(lower_bound), None) => EditionRange::RangeFrom(lower_bound),
|
||||
(None, Some(_)) => {
|
||||
fatal!(
|
||||
"{testfile}:{line_number}: `..edition` is not a supported range in `//@ edition`"
|
||||
);
|
||||
}
|
||||
(None, None) => {
|
||||
fatal!("{testfile}:{line_number}: `..` is not a supported range in `//@ edition`");
|
||||
}
|
||||
})
|
||||
} else {
|
||||
match maybe_parse_edition(&raw) {
|
||||
Some(edition) => Some(EditionRange::Exact(edition)),
|
||||
None => {
|
||||
fatal!("{testfile}:{line_number}: empty value for `//@ edition`");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_parse_edition(mut input: &str) -> Option<Edition> {
|
||||
input = input.trim();
|
||||
if input.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(parse_edition(input))
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
enum EditionRange {
|
||||
Exact(Edition),
|
||||
RangeFrom(Edition),
|
||||
/// Half-open range: `[lower_bound, upper_bound)`
|
||||
Range {
|
||||
lower_bound: Edition,
|
||||
upper_bound: Edition,
|
||||
},
|
||||
}
|
||||
|
||||
impl EditionRange {
|
||||
fn edition_to_test(&self, requested: impl Into<Option<Edition>>) -> Edition {
|
||||
let min_edition = Edition::Year(2015);
|
||||
let requested = requested.into().unwrap_or(min_edition);
|
||||
|
||||
match *self {
|
||||
EditionRange::Exact(exact) => exact,
|
||||
EditionRange::RangeFrom(lower_bound) => {
|
||||
if requested >= lower_bound {
|
||||
requested
|
||||
} else {
|
||||
lower_bound
|
||||
}
|
||||
}
|
||||
EditionRange::Range { lower_bound, upper_bound } => {
|
||||
if requested >= lower_bound && requested < upper_bound {
|
||||
requested
|
||||
} else {
|
||||
lower_bound
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ use camino::Utf8Path;
|
|||
use semver::Version;
|
||||
|
||||
use super::{
|
||||
DirectivesCache, EarlyProps, extract_llvm_version, extract_version_range, iter_directives,
|
||||
parse_normalize_rule,
|
||||
DirectivesCache, EarlyProps, Edition, EditionRange, extract_llvm_version,
|
||||
extract_version_range, iter_directives, parse_normalize_rule,
|
||||
};
|
||||
use crate::common::{Config, Debugger, TestMode};
|
||||
use crate::directives::parse_edition;
|
||||
use crate::executor::{CollectedTestDesc, ShouldPanic};
|
||||
|
||||
fn make_test_description<R: Read>(
|
||||
|
|
@ -73,6 +74,7 @@ fn test_parse_normalize_rule() {
|
|||
struct ConfigBuilder {
|
||||
mode: Option<String>,
|
||||
channel: Option<String>,
|
||||
edition: Option<Edition>,
|
||||
host: Option<String>,
|
||||
target: Option<String>,
|
||||
stage: Option<u32>,
|
||||
|
|
@ -96,6 +98,11 @@ impl ConfigBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
fn edition(&mut self, e: Edition) -> &mut Self {
|
||||
self.edition = Some(e);
|
||||
self
|
||||
}
|
||||
|
||||
fn host(&mut self, s: &str) -> &mut Self {
|
||||
self.host = Some(s.to_owned());
|
||||
self
|
||||
|
|
@ -183,6 +190,10 @@ impl ConfigBuilder {
|
|||
];
|
||||
let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
|
||||
|
||||
if let Some(edition) = &self.edition {
|
||||
args.push(format!("--edition={edition}"));
|
||||
}
|
||||
|
||||
if let Some(ref llvm_version) = self.llvm_version {
|
||||
args.push("--llvm-version".to_owned());
|
||||
args.push(llvm_version.clone());
|
||||
|
|
@ -941,3 +952,130 @@ fn test_needs_target_std() {
|
|||
let config = cfg().target("x86_64-unknown-linux-gnu").build();
|
||||
assert!(!check_ignore(&config, "//@ needs-target-std"));
|
||||
}
|
||||
|
||||
fn parse_edition_range(line: &str) -> Option<EditionRange> {
|
||||
let config = cfg().build();
|
||||
let line = super::DirectiveLine { line_number: 0, revision: None, raw_directive: line };
|
||||
|
||||
super::parse_edition_range(&config, &line, "tmp.rs".into())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_edition_range() {
|
||||
assert_eq!(None, parse_edition_range("hello-world"));
|
||||
assert_eq!(None, parse_edition_range("edition"));
|
||||
|
||||
assert_eq!(Some(EditionRange::Exact(2018.into())), parse_edition_range("edition: 2018"));
|
||||
assert_eq!(Some(EditionRange::Exact(2021.into())), parse_edition_range("edition:2021"));
|
||||
assert_eq!(Some(EditionRange::Exact(2024.into())), parse_edition_range("edition: 2024 "));
|
||||
assert_eq!(Some(EditionRange::Exact(Edition::Future)), parse_edition_range("edition: future"));
|
||||
|
||||
assert_eq!(Some(EditionRange::RangeFrom(2018.into())), parse_edition_range("edition: 2018.."));
|
||||
assert_eq!(Some(EditionRange::RangeFrom(2021.into())), parse_edition_range("edition:2021 .."));
|
||||
assert_eq!(
|
||||
Some(EditionRange::RangeFrom(2024.into())),
|
||||
parse_edition_range("edition: 2024 .. ")
|
||||
);
|
||||
assert_eq!(
|
||||
Some(EditionRange::RangeFrom(Edition::Future)),
|
||||
parse_edition_range("edition: future.. ")
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Some(EditionRange::Range { lower_bound: 2018.into(), upper_bound: 2024.into() }),
|
||||
parse_edition_range("edition: 2018..2024")
|
||||
);
|
||||
assert_eq!(
|
||||
Some(EditionRange::Range { lower_bound: 2015.into(), upper_bound: 2021.into() }),
|
||||
parse_edition_range("edition:2015 .. 2021 ")
|
||||
);
|
||||
assert_eq!(
|
||||
Some(EditionRange::Range { lower_bound: 2021.into(), upper_bound: 2027.into() }),
|
||||
parse_edition_range("edition: 2021 .. 2027 ")
|
||||
);
|
||||
assert_eq!(
|
||||
Some(EditionRange::Range { lower_bound: 2021.into(), upper_bound: Edition::Future }),
|
||||
parse_edition_range("edition: 2021..future")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_parse_edition_range_empty() {
|
||||
parse_edition_range("edition:");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_parse_edition_range_invalid_edition() {
|
||||
parse_edition_range("edition: hello");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_parse_edition_range_double_dots() {
|
||||
parse_edition_range("edition: ..");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_parse_edition_range_inverted_range() {
|
||||
parse_edition_range("edition: 2021..2015");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_parse_edition_range_inverted_range_future() {
|
||||
parse_edition_range("edition: future..2015");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_parse_edition_range_empty_range() {
|
||||
parse_edition_range("edition: 2021..2021");
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_edition_to_test(
|
||||
expected: impl Into<Edition>,
|
||||
range: EditionRange,
|
||||
default: Option<Edition>,
|
||||
) {
|
||||
let mut cfg = cfg();
|
||||
if let Some(default) = default {
|
||||
cfg.edition(default);
|
||||
}
|
||||
assert_eq!(expected.into(), range.edition_to_test(cfg.build().edition));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edition_range_edition_to_test() {
|
||||
let e2015 = parse_edition("2015");
|
||||
let e2018 = parse_edition("2018");
|
||||
let e2021 = parse_edition("2021");
|
||||
let e2024 = parse_edition("2024");
|
||||
let efuture = parse_edition("future");
|
||||
|
||||
let exact = EditionRange::Exact(2021.into());
|
||||
assert_edition_to_test(2021, exact, None);
|
||||
assert_edition_to_test(2021, exact, Some(e2018));
|
||||
assert_edition_to_test(2021, exact, Some(efuture));
|
||||
|
||||
assert_edition_to_test(Edition::Future, EditionRange::Exact(Edition::Future), None);
|
||||
|
||||
let greater_equal_than = EditionRange::RangeFrom(2021.into());
|
||||
assert_edition_to_test(2021, greater_equal_than, None);
|
||||
assert_edition_to_test(2021, greater_equal_than, Some(e2015));
|
||||
assert_edition_to_test(2021, greater_equal_than, Some(e2018));
|
||||
assert_edition_to_test(2021, greater_equal_than, Some(e2021));
|
||||
assert_edition_to_test(2024, greater_equal_than, Some(e2024));
|
||||
assert_edition_to_test(Edition::Future, greater_equal_than, Some(efuture));
|
||||
|
||||
let range = EditionRange::Range { lower_bound: 2018.into(), upper_bound: 2024.into() };
|
||||
assert_edition_to_test(2018, range, None);
|
||||
assert_edition_to_test(2018, range, Some(e2015));
|
||||
assert_edition_to_test(2018, range, Some(e2018));
|
||||
assert_edition_to_test(2021, range, Some(e2021));
|
||||
assert_edition_to_test(2018, range, Some(e2024));
|
||||
assert_edition_to_test(2018, range, Some(efuture));
|
||||
}
|
||||
|
|
|
|||
35
src/tools/compiletest/src/edition.rs
Normal file
35
src/tools/compiletest/src/edition.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
use crate::fatal;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub enum Edition {
|
||||
// Note that the ordering here is load-bearing, as we want the future edition to be greater than
|
||||
// any year-based edition.
|
||||
Year(u32),
|
||||
Future,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Edition {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Edition::Year(year) => write!(f, "{year}"),
|
||||
Edition::Future => f.write_str("future"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Edition {
|
||||
fn from(value: u32) -> Self {
|
||||
Edition::Year(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_edition(mut input: &str) -> Edition {
|
||||
input = input.trim();
|
||||
if input == "future" {
|
||||
Edition::Future
|
||||
} else {
|
||||
Edition::Year(input.parse().unwrap_or_else(|_| {
|
||||
fatal!("`{input}` doesn't look like an edition");
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ pub mod common;
|
|||
mod debuggers;
|
||||
pub mod diagnostics;
|
||||
pub mod directives;
|
||||
pub mod edition;
|
||||
pub mod errors;
|
||||
mod executor;
|
||||
mod json;
|
||||
|
|
@ -39,6 +40,7 @@ use crate::common::{
|
|||
expected_output_path, output_base_dir, output_relative_path,
|
||||
};
|
||||
use crate::directives::DirectivesCache;
|
||||
use crate::edition::parse_edition;
|
||||
use crate::executor::{CollectedTest, ColorConfig};
|
||||
|
||||
/// Creates the `Config` instance for this invocation of compiletest.
|
||||
|
|
@ -449,7 +451,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
has_enzyme,
|
||||
channel: matches.opt_str("channel").unwrap(),
|
||||
git_hash: matches.opt_present("git-hash"),
|
||||
edition: matches.opt_str("edition"),
|
||||
edition: matches.opt_str("edition").as_deref().map(parse_edition),
|
||||
|
||||
cc: matches.opt_str("cc").unwrap(),
|
||||
cxx: matches.opt_str("cxx").unwrap(),
|
||||
|
|
|
|||
|
|
@ -61,10 +61,6 @@ required-issue-label = "regression-from-stable-to-beta"
|
|||
# if the above conditions matches, the PR will receive these labels
|
||||
add-labels = ["beta-nominated"]
|
||||
|
||||
[backport.t-compiler-stable-backport]
|
||||
required-pr-labels = ["T-compiler"]
|
||||
required-issue-label = "regression-from-stable-to-stable"
|
||||
add-labels = ["stable-nominated"]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Ping groups
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue