Auto merge of #145796 - samueltardieu:rollup-linfi86, r=samueltardieu
Rollup of 14 pull requests Successful merges: - rust-lang/rust#143898 (opt-dist: rebuild rustc when doing static LLVM builds) - rust-lang/rust#144452 (std/sys/fd: Relax `READ_LIMIT` on Darwin) - rust-lang/rust#145234 (match exhaustiveness diagnostics: show a trailing comma on singleton tuple consructors in witness patterns (and clean up a little)) - rust-lang/rust#145515 (Optimize `char::encode_utf8`) - rust-lang/rust#145540 (interpret/allocation: get_range on ProvenanceMap) - rust-lang/rust#145670 (port `sanitize` attribute to the new parsing infrastructure) - rust-lang/rust#145713 (next-solver: fix `feature(const_trait_impl)` bootstrap) - rust-lang/rust#145729 (Remove two duplicated crates) - rust-lang/rust#145744 (miri: also detect aliasing of in-place argument and return place) - rust-lang/rust#145774 (Remove default opts from config) - rust-lang/rust#145781 (Remove profile section from Clippy) - rust-lang/rust#145782 (rustdoc: make attributes render consistently) - rust-lang/rust#145787 (citool: cleanup `mismatched_lifetime_syntaxes` warnings) - rust-lang/rust#145791 (Fix ICE when validating transmuting ZST to inhabited enum) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
f6d23413c3
51 changed files with 733 additions and 449 deletions
33
Cargo.lock
33
Cargo.lock
|
|
@ -315,7 +315,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"sha2",
|
||||
"tar",
|
||||
"toml 0.5.11",
|
||||
"toml 0.7.8",
|
||||
"xz2",
|
||||
]
|
||||
|
||||
|
|
@ -336,7 +336,7 @@ dependencies = [
|
|||
"curl",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"toml 0.5.11",
|
||||
"toml 0.7.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1129,16 +1129,16 @@ version = "6.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
|
||||
dependencies = [
|
||||
"dirs-sys 0.5.0",
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys 0.4.1",
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1151,18 +1151,6 @@ dependencies = [
|
|||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.4.6",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.5.0"
|
||||
|
|
@ -5545,15 +5533,6 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.8"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, UsedBy};
|
||||
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, SanitizerSet, UsedBy};
|
||||
use rustc_session::parse::feature_err;
|
||||
|
||||
use super::prelude::*;
|
||||
|
|
@ -464,6 +464,12 @@ impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
|
|||
was_forced: true,
|
||||
};
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
|
|
@ -471,11 +477,106 @@ impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
|
|||
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||
parse_tf_attribute(cx, args)
|
||||
}
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
}
|
||||
|
||||
pub(crate) struct SanitizeParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
|
||||
const PATH: &[Symbol] = &[sym::sanitize];
|
||||
|
||||
// FIXME: still checked in check_attrs.rs
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &[
|
||||
r#"address = "on|off""#,
|
||||
r#"kernel_address = "on|off""#,
|
||||
r#"cfi = "on|off""#,
|
||||
r#"hwaddress = "on|off""#,
|
||||
r#"kcfi = "on|off""#,
|
||||
r#"memory = "on|off""#,
|
||||
r#"memtag = "on|off""#,
|
||||
r#"shadow_call_stack = "on|off""#,
|
||||
r#"thread = "on|off""#
|
||||
]);
|
||||
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut on_set = SanitizerSet::empty();
|
||||
let mut off_set = SanitizerSet::empty();
|
||||
|
||||
for item in list.mixed() {
|
||||
let Some(item) = item.meta_item() else {
|
||||
cx.expected_name_value(item.span(), None);
|
||||
continue;
|
||||
};
|
||||
|
||||
let path = item.path().word_sym();
|
||||
let Some(value) = item.args().name_value() else {
|
||||
cx.expected_name_value(item.span(), path);
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut apply = |s: SanitizerSet| {
|
||||
let is_on = match value.value_as_str() {
|
||||
Some(sym::on) => true,
|
||||
Some(sym::off) => false,
|
||||
Some(_) => {
|
||||
cx.expected_specific_argument_strings(
|
||||
value.value_span,
|
||||
&[sym::on, sym::off],
|
||||
);
|
||||
return;
|
||||
}
|
||||
None => {
|
||||
cx.expected_string_literal(value.value_span, Some(value.value_as_lit()));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if is_on {
|
||||
on_set |= s;
|
||||
} else {
|
||||
off_set |= s;
|
||||
}
|
||||
};
|
||||
|
||||
match path {
|
||||
Some(sym::address) | Some(sym::kernel_address) => {
|
||||
apply(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS)
|
||||
}
|
||||
Some(sym::cfi) => apply(SanitizerSet::CFI),
|
||||
Some(sym::kcfi) => apply(SanitizerSet::KCFI),
|
||||
Some(sym::memory) => apply(SanitizerSet::MEMORY),
|
||||
Some(sym::memtag) => apply(SanitizerSet::MEMTAG),
|
||||
Some(sym::shadow_call_stack) => apply(SanitizerSet::SHADOWCALLSTACK),
|
||||
Some(sym::thread) => apply(SanitizerSet::THREAD),
|
||||
Some(sym::hwaddress) => apply(SanitizerSet::HWADDRESS),
|
||||
_ => {
|
||||
cx.expected_specific_argument_strings(
|
||||
item.path().span(),
|
||||
&[
|
||||
sym::address,
|
||||
sym::cfi,
|
||||
sym::kcfi,
|
||||
sym::memory,
|
||||
sym::memtag,
|
||||
sym::shadow_call_stack,
|
||||
sym::thread,
|
||||
sym::hwaddress,
|
||||
],
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(AttributeKind::Sanitize { on_set, off_set, span: cx.attr_span })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ use crate::attributes::allow_unstable::{
|
|||
use crate::attributes::body::CoroutineParser;
|
||||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser,
|
||||
NoMangleParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser,
|
||||
NoMangleParser, OptimizeParser, SanitizeParser, TargetFeatureParser, TrackCallerParser,
|
||||
UsedParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
|
|
@ -184,6 +185,7 @@ attribute_parsers!(
|
|||
Single<RustcLayoutScalarValidRangeEnd>,
|
||||
Single<RustcLayoutScalarValidRangeStart>,
|
||||
Single<RustcObjectLifetimeDefaultParser>,
|
||||
Single<SanitizeParser>,
|
||||
Single<ShouldPanicParser>,
|
||||
Single<SkipDuringMethodDispatchParser>,
|
||||
Single<TransparencyParser>,
|
||||
|
|
|
|||
|
|
@ -171,9 +171,6 @@ codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphizati
|
|||
|
||||
codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
|
||||
|
||||
codegen_ssa_invalid_sanitize = invalid argument for `sanitize`
|
||||
.note = expected one of: `address`, `kernel_address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow_call_stack`, or `thread`
|
||||
|
||||
codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed
|
||||
|
||||
codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64
|
||||
|
|
|
|||
|
|
@ -293,6 +293,9 @@ fn process_builtin_attrs(
|
|||
codegen_fn_attrs.linkage = linkage;
|
||||
}
|
||||
}
|
||||
AttributeKind::Sanitize { span, .. } => {
|
||||
interesting_spans.sanitize = Some(*span);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -310,7 +313,6 @@ fn process_builtin_attrs(
|
|||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
|
||||
}
|
||||
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
|
||||
sym::sanitize => interesting_spans.sanitize = Some(attr.span()),
|
||||
sym::instruction_set => {
|
||||
codegen_fn_attrs.instruction_set = parse_instruction_set_attr(tcx, attr)
|
||||
}
|
||||
|
|
@ -560,79 +562,9 @@ fn opt_trait_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
|
|||
}
|
||||
}
|
||||
|
||||
/// For an attr that has the `sanitize` attribute, read the list of
|
||||
/// disabled sanitizers. `current_attr` holds the information about
|
||||
/// previously parsed attributes.
|
||||
fn parse_sanitize_attr(
|
||||
tcx: TyCtxt<'_>,
|
||||
attr: &Attribute,
|
||||
current_attr: SanitizerSet,
|
||||
) -> SanitizerSet {
|
||||
let mut result = current_attr;
|
||||
if let Some(list) = attr.meta_item_list() {
|
||||
for item in list.iter() {
|
||||
let MetaItemInner::MetaItem(set) = item else {
|
||||
tcx.dcx().emit_err(errors::InvalidSanitize { span: attr.span() });
|
||||
break;
|
||||
};
|
||||
let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
|
||||
match segments.as_slice() {
|
||||
// Similar to clang, sanitize(address = ..) and
|
||||
// sanitize(kernel_address = ..) control both ASan and KASan
|
||||
// Source: https://reviews.llvm.org/D44981.
|
||||
[sym::address] | [sym::kernel_address] if set.value_str() == Some(sym::off) => {
|
||||
result |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
|
||||
}
|
||||
[sym::address] | [sym::kernel_address] if set.value_str() == Some(sym::on) => {
|
||||
result &= !SanitizerSet::ADDRESS;
|
||||
result &= !SanitizerSet::KERNELADDRESS;
|
||||
}
|
||||
[sym::cfi] if set.value_str() == Some(sym::off) => result |= SanitizerSet::CFI,
|
||||
[sym::cfi] if set.value_str() == Some(sym::on) => result &= !SanitizerSet::CFI,
|
||||
[sym::kcfi] if set.value_str() == Some(sym::off) => result |= SanitizerSet::KCFI,
|
||||
[sym::kcfi] if set.value_str() == Some(sym::on) => result &= !SanitizerSet::KCFI,
|
||||
[sym::memory] if set.value_str() == Some(sym::off) => {
|
||||
result |= SanitizerSet::MEMORY
|
||||
}
|
||||
[sym::memory] if set.value_str() == Some(sym::on) => {
|
||||
result &= !SanitizerSet::MEMORY
|
||||
}
|
||||
[sym::memtag] if set.value_str() == Some(sym::off) => {
|
||||
result |= SanitizerSet::MEMTAG
|
||||
}
|
||||
[sym::memtag] if set.value_str() == Some(sym::on) => {
|
||||
result &= !SanitizerSet::MEMTAG
|
||||
}
|
||||
[sym::shadow_call_stack] if set.value_str() == Some(sym::off) => {
|
||||
result |= SanitizerSet::SHADOWCALLSTACK
|
||||
}
|
||||
[sym::shadow_call_stack] if set.value_str() == Some(sym::on) => {
|
||||
result &= !SanitizerSet::SHADOWCALLSTACK
|
||||
}
|
||||
[sym::thread] if set.value_str() == Some(sym::off) => {
|
||||
result |= SanitizerSet::THREAD
|
||||
}
|
||||
[sym::thread] if set.value_str() == Some(sym::on) => {
|
||||
result &= !SanitizerSet::THREAD
|
||||
}
|
||||
[sym::hwaddress] if set.value_str() == Some(sym::off) => {
|
||||
result |= SanitizerSet::HWADDRESS
|
||||
}
|
||||
[sym::hwaddress] if set.value_str() == Some(sym::on) => {
|
||||
result &= !SanitizerSet::HWADDRESS
|
||||
}
|
||||
_ => {
|
||||
tcx.dcx().emit_err(errors::InvalidSanitize { span: attr.span() });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet {
|
||||
// Backtrack to the crate root.
|
||||
let disabled = match tcx.opt_local_parent(did) {
|
||||
let mut disabled = match tcx.opt_local_parent(did) {
|
||||
// Check the parent (recursively).
|
||||
Some(parent) => tcx.disabled_sanitizers_for(parent),
|
||||
// We reached the crate root without seeing an attribute, so
|
||||
|
|
@ -641,8 +573,17 @@ fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet {
|
|||
};
|
||||
|
||||
// Check for a sanitize annotation directly on this def.
|
||||
if let Some(attr) = tcx.get_attr(did, sym::sanitize) {
|
||||
return parse_sanitize_attr(tcx, attr, disabled);
|
||||
if let Some((on_set, off_set)) = find_attr!(tcx.get_all_attrs(did), AttributeKind::Sanitize {on_set, off_set, ..} => (on_set, off_set))
|
||||
{
|
||||
// the on set is the set of sanitizers explicitly enabled.
|
||||
// we mask those out since we want the set of disabled sanitizers here
|
||||
disabled &= !*on_set;
|
||||
// the off set is the set of sanitizers explicitly disabled.
|
||||
// we or those in here.
|
||||
disabled |= *off_set;
|
||||
// the on set and off set are distjoint since there's a third option: unset.
|
||||
// a node may not set the sanitizer setting in which case it inherits from parents.
|
||||
// the code above in this function does this backtracking
|
||||
}
|
||||
disabled
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1120,14 +1120,6 @@ impl IntoDiagArg for ExpectedPointerMutability {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_invalid_sanitize)]
|
||||
#[note]
|
||||
pub(crate) struct InvalidSanitize {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_target_feature_safe_trait)]
|
||||
pub(crate) struct TargetFeatureSafeTrait {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
//!
|
||||
//! The main entry point is the `step` method.
|
||||
|
||||
use std::iter;
|
||||
|
||||
use either::Either;
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
|
@ -426,6 +428,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
terminator: &mir::Terminator<'tcx>,
|
||||
func: &mir::Operand<'tcx>,
|
||||
args: &[Spanned<mir::Operand<'tcx>>],
|
||||
dest: &mir::Place<'tcx>,
|
||||
) -> InterpResult<'tcx, EvaluatedCalleeAndArgs<'tcx, M>> {
|
||||
let func = self.eval_operand(func, None)?;
|
||||
|
||||
|
|
@ -435,14 +438,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
// protection, but then we'd force *a lot* of arguments into memory. So we do some syntactic
|
||||
// pre-processing here where if all `move` arguments are syntactically distinct local
|
||||
// variables (and none is indirect), we can skip the in-memory forcing.
|
||||
// We have to include `dest` in that list so that we can detect aliasing of an in-place
|
||||
// argument with the return place.
|
||||
let move_definitely_disjoint = 'move_definitely_disjoint: {
|
||||
let mut previous_locals = FxHashSet::<mir::Local>::default();
|
||||
for arg in args {
|
||||
let mir::Operand::Move(place) = arg.node else {
|
||||
continue; // we can skip non-`Move` arguments.
|
||||
};
|
||||
for place in args
|
||||
.iter()
|
||||
.filter_map(|a| {
|
||||
// We only have to care about `Move` arguments.
|
||||
if let mir::Operand::Move(place) = &a.node { Some(place) } else { None }
|
||||
})
|
||||
.chain(iter::once(dest))
|
||||
{
|
||||
if place.is_indirect_first_projection() {
|
||||
// An indirect `Move` argument could alias with anything else...
|
||||
// An indirect in-place argument could alias with anything else...
|
||||
break 'move_definitely_disjoint false;
|
||||
}
|
||||
if !previous_locals.insert(place.local) {
|
||||
|
|
@ -544,7 +553,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let old_loc = self.frame().loc;
|
||||
|
||||
let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
|
||||
self.eval_callee_and_args(terminator, func, args)?;
|
||||
self.eval_callee_and_args(terminator, func, args, &destination)?;
|
||||
|
||||
let destination = self.eval_place(destination)?;
|
||||
self.init_fn_call(
|
||||
|
|
@ -567,7 +576,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let old_frame_idx = self.frame_idx();
|
||||
|
||||
let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
|
||||
self.eval_callee_and_args(terminator, func, args)?;
|
||||
self.eval_callee_and_args(terminator, func, args, &mir::Place::return_place())?;
|
||||
|
||||
self.init_fn_tail_call(callee, (fn_sig.abi, fn_abi), &args, with_caller_location)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
|
|||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
pub use rustc_target::spec::SanitizerSet;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::attrs::pretty_printing::PrintAttribute;
|
||||
|
|
@ -505,6 +506,12 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_object_lifetime_default]`.
|
||||
RustcObjectLifetimeDefault,
|
||||
|
||||
/// Represents `#[sanitize]`
|
||||
///
|
||||
/// the on set and off set are distjoint since there's a third option: unset.
|
||||
/// a node may not set the sanitizer setting in which case it inherits from parents.
|
||||
Sanitize { on_set: SanitizerSet, off_set: SanitizerSet, span: Span },
|
||||
|
||||
/// Represents `#[should_panic]`
|
||||
ShouldPanic { reason: Option<Symbol>, span: Span },
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ impl AttributeKind {
|
|||
RustcLayoutScalarValidRangeEnd(..) => Yes,
|
||||
RustcLayoutScalarValidRangeStart(..) => Yes,
|
||||
RustcObjectLifetimeDefault => No,
|
||||
Sanitize { .. } => No,
|
||||
ShouldPanic { .. } => No,
|
||||
SkipDuringMethodDispatch { .. } => No,
|
||||
SpecializationTrait(..) => No,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use rustc_ast::{AttrStyle, IntTy, UintTy};
|
|||
use rustc_ast_pretty::pp::Printer;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
|
||||
use rustc_target::spec::SanitizerSet;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
/// This trait is used to print attributes in `rustc_hir_pretty`.
|
||||
|
|
@ -146,4 +147,14 @@ macro_rules! print_tup {
|
|||
print_tup!(A B C D E F G H);
|
||||
print_skip!(Span, (), ErrorGuaranteed);
|
||||
print_disp!(u16, bool, NonZero<u32>);
|
||||
print_debug!(Symbol, Ident, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
|
||||
print_debug!(
|
||||
Symbol,
|
||||
Ident,
|
||||
UintTy,
|
||||
IntTy,
|
||||
Align,
|
||||
AttrStyle,
|
||||
CommentKind,
|
||||
Transparency,
|
||||
SanitizerSet,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -120,6 +120,17 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the provenances of all bytes (including from pointers) in a range.
|
||||
pub fn get_range(
|
||||
&self,
|
||||
cx: &impl HasDataLayout,
|
||||
range: AllocRange,
|
||||
) -> impl Iterator<Item = Prov> {
|
||||
let ptr_provs = self.range_ptrs_get(range, cx).iter().map(|(_, p)| *p);
|
||||
let byte_provs = self.range_bytes_get(range).iter().map(|(_, (p, _))| *p);
|
||||
ptr_provs.chain(byte_provs)
|
||||
}
|
||||
|
||||
/// Attempt to merge per-byte provenance back into ptr chunks, if the right fragments
|
||||
/// sit next to each other. Return `false` is that is not possible due to partial pointers.
|
||||
pub fn merge_bytes(&mut self, cx: &impl HasDataLayout) -> bool {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use rustc_errors::{
|
|||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, LintEmitter, MultiSpan,
|
||||
};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{CtorKind, DefKind};
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState};
|
||||
use rustc_hir::intravisit::VisitorExt;
|
||||
|
|
@ -445,7 +445,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
}
|
||||
|
||||
fn fn_is_const(self, def_id: DefId) -> bool {
|
||||
debug_assert_matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn);
|
||||
debug_assert_matches!(
|
||||
self.def_kind(def_id),
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(CtorOf::Struct, CtorKind::Fn)
|
||||
);
|
||||
self.is_conditionally_const(def_id)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,21 @@ impl<'tcx> crate::MirPass<'tcx> for CheckEnums {
|
|||
let new_block = split_block(basic_blocks, location);
|
||||
|
||||
match check {
|
||||
EnumCheckType::Direct { op_size, .. }
|
||||
| EnumCheckType::WithNiche { op_size, .. }
|
||||
if op_size.bytes() == 0 =>
|
||||
{
|
||||
// It is never valid to use a ZST as a discriminant for an inhabited enum, but that will
|
||||
// have been caught by the type checker. Do nothing but ensure that a bug has been signaled.
|
||||
tcx.dcx().span_delayed_bug(
|
||||
source_info.span,
|
||||
"cannot build enum discriminant from zero-sized type",
|
||||
);
|
||||
basic_blocks[block].terminator = Some(Terminator {
|
||||
source_info,
|
||||
kind: TerminatorKind::Goto { target: new_block },
|
||||
});
|
||||
}
|
||||
EnumCheckType::Direct { source_op, discr, op_size, valid_discrs } => {
|
||||
insert_direct_enum_check(
|
||||
tcx,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_type_ir::inherent::*;
|
|||
use rustc_type_ir::lang_items::TraitSolverLangItem;
|
||||
use rustc_type_ir::solve::SizedTraitKind;
|
||||
use rustc_type_ir::solve::inspect::ProbeKind;
|
||||
use rustc_type_ir::{self as ty, Interner, elaborate};
|
||||
use rustc_type_ir::{self as ty, Interner, TypingMode, elaborate};
|
||||
use tracing::instrument;
|
||||
|
||||
use super::assembly::{Candidate, structural_traits};
|
||||
|
|
@ -135,12 +135,16 @@ where
|
|||
}
|
||||
|
||||
let impl_polarity = cx.impl_polarity(impl_def_id);
|
||||
match impl_polarity {
|
||||
let certainty = match impl_polarity {
|
||||
ty::ImplPolarity::Negative => return Err(NoSolution),
|
||||
ty::ImplPolarity::Reservation => {
|
||||
unimplemented!("reservation impl for const trait: {:?}", goal)
|
||||
}
|
||||
ty::ImplPolarity::Positive => {}
|
||||
ty::ImplPolarity::Reservation => match ecx.typing_mode() {
|
||||
TypingMode::Coherence => Certainty::AMBIGUOUS,
|
||||
TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. }
|
||||
| TypingMode::PostAnalysis => return Err(NoSolution),
|
||||
},
|
||||
ty::ImplPolarity::Positive => Certainty::Yes,
|
||||
};
|
||||
|
||||
if !cx.impl_is_const(impl_def_id) {
|
||||
|
|
@ -171,7 +175,7 @@ where
|
|||
});
|
||||
ecx.add_goals(GoalSource::ImplWhereBound, const_conditions);
|
||||
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use rustc_feature::{
|
|||
ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP,
|
||||
BuiltinAttribute,
|
||||
};
|
||||
use rustc_hir::attrs::{AttributeKind, InlineAttr, MirDialect, MirPhase, ReprAttr};
|
||||
use rustc_hir::attrs::{AttributeKind, InlineAttr, MirDialect, MirPhase, ReprAttr, SanitizerSet};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalModDefId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
|
|
@ -197,6 +197,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
&Attribute::Parsed(AttributeKind::CustomMir(dialect, phase, attr_span)) => {
|
||||
self.check_custom_mir(dialect, phase, attr_span)
|
||||
}
|
||||
&Attribute::Parsed(AttributeKind::Sanitize { on_set, off_set, span: attr_span}) => {
|
||||
self.check_sanitize(attr_span, on_set | off_set, span, target);
|
||||
},
|
||||
Attribute::Parsed(
|
||||
AttributeKind::BodyStability { .. }
|
||||
| AttributeKind::ConstStabilityIndirect
|
||||
|
|
@ -258,9 +261,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
[sym::diagnostic, sym::on_unimplemented, ..] => {
|
||||
self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target)
|
||||
}
|
||||
[sym::sanitize, ..] => {
|
||||
self.check_sanitize(attr, span, target)
|
||||
}
|
||||
[sym::thread_local, ..] => self.check_thread_local(attr, span, target),
|
||||
[sym::doc, ..] => self.check_doc_attrs(
|
||||
attr,
|
||||
|
|
@ -483,42 +483,48 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
|
||||
/// Checks that the `#[sanitize(..)]` attribute is applied to a
|
||||
/// function/closure/method, or to an impl block or module.
|
||||
fn check_sanitize(&self, attr: &Attribute, target_span: Span, target: Target) {
|
||||
fn check_sanitize(
|
||||
&self,
|
||||
attr_span: Span,
|
||||
set: SanitizerSet,
|
||||
target_span: Span,
|
||||
target: Target,
|
||||
) {
|
||||
let mut not_fn_impl_mod = None;
|
||||
let mut no_body = None;
|
||||
|
||||
if let Some(list) = attr.meta_item_list() {
|
||||
for item in list.iter() {
|
||||
let MetaItemInner::MetaItem(set) = item else {
|
||||
return;
|
||||
};
|
||||
let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
|
||||
match target {
|
||||
Target::Fn
|
||||
| Target::Closure
|
||||
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
|
||||
| Target::Impl { .. }
|
||||
| Target::Mod => return,
|
||||
Target::Static if matches!(segments.as_slice(), [sym::address]) => return,
|
||||
|
||||
// These are "functions", but they aren't allowed because they don't
|
||||
// have a body, so the usual explanation would be confusing.
|
||||
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
|
||||
no_body = Some(target_span);
|
||||
}
|
||||
|
||||
_ => {
|
||||
not_fn_impl_mod = Some(target_span);
|
||||
}
|
||||
}
|
||||
match target {
|
||||
Target::Fn
|
||||
| Target::Closure
|
||||
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
|
||||
| Target::Impl { .. }
|
||||
| Target::Mod => return,
|
||||
Target::Static
|
||||
// if we mask out the address bits, i.e. *only* address was set,
|
||||
// we allow it
|
||||
if set & !(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS)
|
||||
== SanitizerSet::empty() =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// These are "functions", but they aren't allowed because they don't
|
||||
// have a body, so the usual explanation would be confusing.
|
||||
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
|
||||
no_body = Some(target_span);
|
||||
}
|
||||
|
||||
_ => {
|
||||
not_fn_impl_mod = Some(target_span);
|
||||
}
|
||||
self.dcx().emit_err(errors::SanitizeAttributeNotAllowed {
|
||||
attr_span: attr.span(),
|
||||
not_fn_impl_mod,
|
||||
no_body,
|
||||
help: (),
|
||||
});
|
||||
}
|
||||
|
||||
self.dcx().emit_err(errors::SanitizeAttributeNotAllowed {
|
||||
attr_span,
|
||||
not_fn_impl_mod,
|
||||
no_body,
|
||||
help: (),
|
||||
});
|
||||
}
|
||||
|
||||
/// Checks if `#[naked]` is applied to a function definition.
|
||||
|
|
|
|||
|
|
@ -101,23 +101,11 @@ pub(crate) fn write_struct_like<'tcx>(
|
|||
let num_fields = variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
|
||||
if num_fields != 0 || variant_and_name.is_none() {
|
||||
write!(f, "(")?;
|
||||
for i in 0..num_fields {
|
||||
write!(f, "{}", start_or_comma())?;
|
||||
|
||||
// Common case: the field is where we expect it.
|
||||
if let Some(p) = subpatterns.get(i) {
|
||||
if p.field.index() == i {
|
||||
write!(f, "{}", p.pattern)?;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, we have to go looking for it.
|
||||
if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
|
||||
write!(f, "{}", p.pattern)?;
|
||||
} else {
|
||||
write!(f, "_")?;
|
||||
}
|
||||
for FieldPat { pattern, .. } in subpatterns {
|
||||
write!(f, "{}{pattern}", start_or_comma())?;
|
||||
}
|
||||
if matches!(ty.kind(), ty::Tuple(..)) && num_fields == 1 {
|
||||
write!(f, ",")?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1872,28 +1872,33 @@ pub const unsafe fn encode_utf8_raw_unchecked(code: u32, dst: *mut u8) {
|
|||
// SAFETY: The caller must guarantee that the buffer pointed to by `dst`
|
||||
// is at least `len` bytes long.
|
||||
unsafe {
|
||||
match len {
|
||||
1 => {
|
||||
*dst = code as u8;
|
||||
}
|
||||
2 => {
|
||||
*dst = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
|
||||
*dst.add(1) = (code & 0x3F) as u8 | TAG_CONT;
|
||||
}
|
||||
3 => {
|
||||
*dst = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
|
||||
*dst.add(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
*dst.add(2) = (code & 0x3F) as u8 | TAG_CONT;
|
||||
}
|
||||
4 => {
|
||||
*dst = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
|
||||
*dst.add(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
||||
*dst.add(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
*dst.add(3) = (code & 0x3F) as u8 | TAG_CONT;
|
||||
}
|
||||
// SAFETY: `char` always takes between 1 and 4 bytes to encode in UTF-8.
|
||||
_ => crate::hint::unreachable_unchecked(),
|
||||
if len == 1 {
|
||||
*dst = code as u8;
|
||||
return;
|
||||
}
|
||||
|
||||
let last1 = (code >> 0 & 0x3F) as u8 | TAG_CONT;
|
||||
let last2 = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
let last3 = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
||||
let last4 = (code >> 18 & 0x3F) as u8 | TAG_FOUR_B;
|
||||
|
||||
if len == 2 {
|
||||
*dst = last2 | TAG_TWO_B;
|
||||
*dst.add(1) = last1;
|
||||
return;
|
||||
}
|
||||
|
||||
if len == 3 {
|
||||
*dst = last3 | TAG_THREE_B;
|
||||
*dst.add(1) = last2;
|
||||
*dst.add(2) = last1;
|
||||
return;
|
||||
}
|
||||
|
||||
*dst = last4;
|
||||
*dst.add(1) = last3;
|
||||
*dst.add(2) = last2;
|
||||
*dst.add(3) = last1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,10 +37,10 @@ pub struct FileDesc(OwnedFd);
|
|||
//
|
||||
// On Apple targets however, apparently the 64-bit libc is either buggy or
|
||||
// intentionally showing odd behavior by rejecting any read with a size
|
||||
// larger than or equal to INT_MAX. To handle both of these the read
|
||||
// size is capped on both platforms.
|
||||
// larger than INT_MAX. To handle both of these the read size is capped on
|
||||
// both platforms.
|
||||
const READ_LIMIT: usize = if cfg!(target_vendor = "apple") {
|
||||
libc::c_int::MAX as usize - 1
|
||||
libc::c_int::MAX as usize
|
||||
} else {
|
||||
libc::ssize_t::MAX as usize
|
||||
};
|
||||
|
|
|
|||
|
|
@ -327,59 +327,6 @@ pub struct Config {
|
|||
}
|
||||
|
||||
impl Config {
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::default_opts")
|
||||
)]
|
||||
pub fn default_opts() -> Config {
|
||||
#[cfg(feature = "tracing")]
|
||||
span!(target: "CONFIG_HANDLING", tracing::Level::TRACE, "constructing default config");
|
||||
|
||||
Config {
|
||||
bypass_bootstrap_lock: false,
|
||||
llvm_optimize: true,
|
||||
ninja_in_file: true,
|
||||
llvm_static_stdcpp: false,
|
||||
llvm_libzstd: false,
|
||||
backtrace: true,
|
||||
rust_optimize: RustOptimize::Bool(true),
|
||||
rust_optimize_tests: true,
|
||||
rust_randomize_layout: false,
|
||||
submodules: None,
|
||||
docs: true,
|
||||
docs_minification: true,
|
||||
rust_rpath: true,
|
||||
rust_strip: false,
|
||||
channel: "dev".to_string(),
|
||||
codegen_tests: true,
|
||||
rust_dist_src: true,
|
||||
rust_codegen_backends: vec![CodegenBackendKind::Llvm],
|
||||
deny_warnings: true,
|
||||
bindir: "bin".into(),
|
||||
dist_include_mingw_linker: true,
|
||||
dist_compression_profile: "fast".into(),
|
||||
|
||||
stdout_is_tty: std::io::stdout().is_terminal(),
|
||||
stderr_is_tty: std::io::stderr().is_terminal(),
|
||||
|
||||
// set by build.rs
|
||||
host_target: get_host_target(),
|
||||
|
||||
src: {
|
||||
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
// Undo `src/bootstrap`
|
||||
manifest_dir.parent().unwrap().parent().unwrap().to_owned()
|
||||
},
|
||||
out: PathBuf::from("build"),
|
||||
|
||||
// This is needed by codegen_ssa on macOS to ship `llvm-objcopy` aliased to
|
||||
// `rust-objcopy` to workaround bad `strip`s on macOS.
|
||||
llvm_tools_enabled: true,
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_dry_run(&mut self, dry_run: DryRun) {
|
||||
self.exec_ctx.set_dry_run(dry_run);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ fn format_build_step_diffs(current: &BuildStep, parent: &BuildStep) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_steps(step: &BuildStep) -> Vec<StepByName> {
|
||||
fn get_steps(step: &BuildStep) -> Vec<StepByName<'_>> {
|
||||
step.linearize_steps().into_iter().map(|v| StepByName(v)).collect()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ fn write_page<T: Template>(dir: &Path, name: &str, template: &T) -> anyhow::Resu
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn gather_test_suites(job_metrics: &HashMap<JobName, JobMetrics>) -> TestSuites {
|
||||
fn gather_test_suites(job_metrics: &HashMap<JobName, JobMetrics>) -> TestSuites<'_> {
|
||||
struct CoarseTestSuite<'a> {
|
||||
tests: BTreeMap<String, Test<'a>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,6 @@ where
|
|||
}
|
||||
|
||||
/// Normalizes Windows-style path delimiters to Unix-style paths.
|
||||
pub fn normalize_path_delimiters(name: &str) -> Cow<str> {
|
||||
pub fn normalize_path_delimiters(name: &str) -> Cow<'_, str> {
|
||||
if name.contains("\\") { name.replace('\\', "/").into() } else { name.into() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1029,6 +1029,7 @@ fn assoc_const(
|
|||
) -> impl fmt::Display {
|
||||
let tcx = cx.tcx();
|
||||
fmt::from_fn(move |w| {
|
||||
render_attributes_in_code(w, it, &" ".repeat(indent), cx);
|
||||
write!(
|
||||
w,
|
||||
"{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
|
||||
|
|
@ -1136,10 +1137,10 @@ fn assoc_method(
|
|||
let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
|
||||
header_len += 4;
|
||||
let indent_str = " ";
|
||||
write!(w, "{}", render_attributes_in_pre(meth, indent_str, cx))?;
|
||||
render_attributes_in_code(w, meth, indent_str, cx);
|
||||
(4, indent_str, Ending::NoNewline)
|
||||
} else {
|
||||
render_attributes_in_code(w, meth, cx);
|
||||
render_attributes_in_code(w, meth, "", cx);
|
||||
(0, "", Ending::Newline)
|
||||
};
|
||||
write!(
|
||||
|
|
@ -1309,28 +1310,28 @@ fn render_assoc_item(
|
|||
})
|
||||
}
|
||||
|
||||
// When an attribute is rendered inside a `<pre>` tag, it is formatted using
|
||||
// a whitespace prefix and newline.
|
||||
fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display {
|
||||
fmt::from_fn(move |f| {
|
||||
for a in it.attributes(cx.tcx(), cx.cache()) {
|
||||
writeln!(f, "{prefix}{a}")?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
struct CodeAttribute(String);
|
||||
|
||||
fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) {
|
||||
write!(w, "<div class=\"code-attribute\">{}</div>", code_attr.0).unwrap();
|
||||
fn render_code_attribute(prefix: &str, code_attr: CodeAttribute, w: &mut impl fmt::Write) {
|
||||
write!(
|
||||
w,
|
||||
"<div class=\"code-attribute\">{prefix}{attr}</div>",
|
||||
prefix = prefix,
|
||||
attr = code_attr.0
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// When an attribute is rendered inside a <code> tag, it is formatted using
|
||||
// a div to produce a newline after it.
|
||||
fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
|
||||
fn render_attributes_in_code(
|
||||
w: &mut impl fmt::Write,
|
||||
it: &clean::Item,
|
||||
prefix: &str,
|
||||
cx: &Context<'_>,
|
||||
) {
|
||||
for attr in it.attributes(cx.tcx(), cx.cache()) {
|
||||
render_code_attribute(CodeAttribute(attr), w);
|
||||
render_code_attribute(prefix, CodeAttribute(attr), w);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1342,7 +1343,7 @@ fn render_repr_attributes_in_code(
|
|||
item_type: ItemType,
|
||||
) {
|
||||
if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) {
|
||||
render_code_attribute(CodeAttribute(repr), w);
|
||||
render_code_attribute("", CodeAttribute(repr), w);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ use super::{
|
|||
AssocItemLink, AssocItemRender, Context, ImplRenderingParameters, RenderMode,
|
||||
collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
|
||||
item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
|
||||
render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre,
|
||||
render_impl, render_repr_attributes_in_code, render_rightside, render_stability_since_raw,
|
||||
render_assoc_item, render_assoc_items, render_attributes_in_code, render_impl,
|
||||
render_repr_attributes_in_code, render_rightside, render_stability_since_raw,
|
||||
render_stability_since_raw_with_extra, write_section_heading,
|
||||
};
|
||||
use crate::clean;
|
||||
|
|
@ -107,13 +107,6 @@ macro_rules! item_template_methods {
|
|||
}
|
||||
item_template_methods!($($rest)*);
|
||||
};
|
||||
(render_attributes_in_pre $($rest:tt)*) => {
|
||||
fn render_attributes_in_pre(&self) -> impl fmt::Display {
|
||||
let (item, cx) = self.item_and_cx();
|
||||
render_attributes_in_pre(item, "", cx)
|
||||
}
|
||||
item_template_methods!($($rest)*);
|
||||
};
|
||||
(render_assoc_items $($rest:tt)*) => {
|
||||
fn render_assoc_items(&self) -> impl fmt::Display {
|
||||
let (item, cx) = self.item_and_cx();
|
||||
|
|
@ -457,7 +450,12 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
|
|||
write!(
|
||||
w,
|
||||
"<dt{id}>\
|
||||
<code>{vis}{imp}</code>{stab_tags}\
|
||||
<code>"
|
||||
)?;
|
||||
render_attributes_in_code(w, myitem, "", cx);
|
||||
write!(
|
||||
w,
|
||||
"{vis}{imp}</code>{stab_tags}\
|
||||
</dt>",
|
||||
vis = visibility_print_with_space(myitem, cx),
|
||||
imp = import.print(cx)
|
||||
|
|
@ -625,11 +623,11 @@ fn item_function(cx: &Context<'_>, it: &clean::Item, f: &clean::Function) -> imp
|
|||
let notable_traits = notable_traits_button(&f.decl.output, cx).maybe_display();
|
||||
|
||||
wrap_item(w, |w| {
|
||||
render_attributes_in_code(w, it, "", cx);
|
||||
write!(
|
||||
w,
|
||||
"{attrs}{vis}{constness}{asyncness}{safety}{abi}fn \
|
||||
"{vis}{constness}{asyncness}{safety}{abi}fn \
|
||||
{name}{generics}{decl}{notable_traits}{where_clause}",
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
vis = visibility,
|
||||
constness = constness,
|
||||
asyncness = asyncness,
|
||||
|
|
@ -666,10 +664,10 @@ fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt:
|
|||
|
||||
// Output the trait definition
|
||||
wrap_item(w, |mut w| {
|
||||
render_attributes_in_code(&mut w, it, "", cx);
|
||||
write!(
|
||||
w,
|
||||
"{attrs}{vis}{safety}{is_auto}trait {name}{generics}{bounds}",
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
"{vis}{safety}{is_auto}trait {name}{generics}{bounds}",
|
||||
vis = visibility_print_with_space(it, cx),
|
||||
safety = t.safety(tcx).print_with_space(),
|
||||
is_auto = if t.is_auto(tcx) { "auto " } else { "" },
|
||||
|
|
@ -1240,10 +1238,10 @@ fn item_trait_alias(
|
|||
) -> impl fmt::Display {
|
||||
fmt::from_fn(|w| {
|
||||
wrap_item(w, |w| {
|
||||
render_attributes_in_code(w, it, "", cx);
|
||||
write!(
|
||||
w,
|
||||
"{attrs}trait {name}{generics} = {bounds}{where_clause};",
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
"trait {name}{generics} = {bounds}{where_clause};",
|
||||
name = it.name.unwrap(),
|
||||
generics = t.generics.print(cx),
|
||||
bounds = print_bounds(&t.bounds, true, cx),
|
||||
|
|
@ -1268,10 +1266,10 @@ fn item_trait_alias(
|
|||
fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> impl fmt::Display {
|
||||
fmt::from_fn(|w| {
|
||||
wrap_item(w, |w| {
|
||||
render_attributes_in_code(w, it, "", cx);
|
||||
write!(
|
||||
w,
|
||||
"{attrs}{vis}type {name}{generics}{where_clause} = {type_};",
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
"{vis}type {name}{generics}{where_clause} = {type_};",
|
||||
vis = visibility_print_with_space(it, cx),
|
||||
name = it.name.unwrap(),
|
||||
generics = t.generics.print(cx),
|
||||
|
|
@ -1452,7 +1450,14 @@ item_template!(
|
|||
|
||||
impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
|
||||
fn render_union(&self) -> impl Display {
|
||||
render_union(self.it, Some(self.generics), self.fields, self.cx)
|
||||
render_union(
|
||||
self.it,
|
||||
Some(self.generics),
|
||||
self.fields,
|
||||
self.def_id,
|
||||
self.is_type_alias,
|
||||
self.cx,
|
||||
)
|
||||
}
|
||||
|
||||
fn document_field(&self, field: &'a clean::Item) -> impl Display {
|
||||
|
|
@ -1479,27 +1484,6 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
|
|||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
fn render_attributes_in_pre(&self) -> impl fmt::Display {
|
||||
fmt::from_fn(move |f| {
|
||||
if self.is_type_alias {
|
||||
// For now the only attributes we render for type aliases are `repr` attributes.
|
||||
if let Some(repr) = clean::repr_attributes(
|
||||
self.cx.tcx(),
|
||||
self.cx.cache(),
|
||||
self.def_id,
|
||||
ItemType::Union,
|
||||
) {
|
||||
writeln!(f, "{repr}")?;
|
||||
};
|
||||
} else {
|
||||
for a in self.it.attributes(self.cx.tcx(), self.cx.cache()) {
|
||||
writeln!(f, "{a}")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt::Display {
|
||||
|
|
@ -1563,7 +1547,7 @@ impl<'clean> DisplayEnum<'clean> {
|
|||
// For now the only attributes we render for type aliases are `repr` attributes.
|
||||
render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Enum);
|
||||
} else {
|
||||
render_attributes_in_code(w, it, cx);
|
||||
render_attributes_in_code(w, it, "", cx);
|
||||
}
|
||||
write!(
|
||||
w,
|
||||
|
|
@ -1702,7 +1686,7 @@ fn render_enum_fields(
|
|||
if v.is_stripped() {
|
||||
continue;
|
||||
}
|
||||
write!(w, "{}", render_attributes_in_pre(v, TAB, cx))?;
|
||||
render_attributes_in_code(w, v, TAB, cx);
|
||||
w.write_str(TAB)?;
|
||||
match v.kind {
|
||||
clean::VariantItem(ref var) => match var.kind {
|
||||
|
|
@ -1882,6 +1866,7 @@ fn item_macro(cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) -> impl fmt:
|
|||
fmt::from_fn(|w| {
|
||||
wrap_item(w, |w| {
|
||||
// FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`.
|
||||
render_attributes_in_code(w, it, "", cx);
|
||||
if !t.macro_rules {
|
||||
write!(w, "{}", visibility_print_with_space(it, cx))?;
|
||||
}
|
||||
|
|
@ -1950,7 +1935,7 @@ fn item_constant(
|
|||
fmt::from_fn(|w| {
|
||||
wrap_item(w, |w| {
|
||||
let tcx = cx.tcx();
|
||||
render_attributes_in_code(w, it, cx);
|
||||
render_attributes_in_code(w, it, "", cx);
|
||||
|
||||
write!(
|
||||
w,
|
||||
|
|
@ -2018,7 +2003,7 @@ impl<'a> DisplayStruct<'a> {
|
|||
// For now the only attributes we render for type aliases are `repr` attributes.
|
||||
render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Struct);
|
||||
} else {
|
||||
render_attributes_in_code(w, it, cx);
|
||||
render_attributes_in_code(w, it, "", cx);
|
||||
}
|
||||
write!(
|
||||
w,
|
||||
|
|
@ -2115,7 +2100,7 @@ fn item_static(
|
|||
) -> impl fmt::Display {
|
||||
fmt::from_fn(move |w| {
|
||||
wrap_item(w, |w| {
|
||||
render_attributes_in_code(w, it, cx);
|
||||
render_attributes_in_code(w, it, "", cx);
|
||||
write!(
|
||||
w,
|
||||
"{vis}{safe}static {mutability}{name}: {typ}",
|
||||
|
|
@ -2135,7 +2120,7 @@ fn item_foreign_type(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display {
|
|||
fmt::from_fn(|w| {
|
||||
wrap_item(w, |w| {
|
||||
w.write_str("extern {\n")?;
|
||||
render_attributes_in_code(w, it, cx);
|
||||
render_attributes_in_code(w, it, "", cx);
|
||||
write!(w, " {}type {};\n}}", visibility_print_with_space(it, cx), it.name.unwrap(),)
|
||||
})?;
|
||||
|
||||
|
|
@ -2358,9 +2343,17 @@ fn render_union(
|
|||
it: &clean::Item,
|
||||
g: Option<&clean::Generics>,
|
||||
fields: &[clean::Item],
|
||||
def_id: DefId,
|
||||
is_type_alias: bool,
|
||||
cx: &Context<'_>,
|
||||
) -> impl Display {
|
||||
fmt::from_fn(move |mut f| {
|
||||
if is_type_alias {
|
||||
// For now the only attributes we render for type aliases are `repr` attributes.
|
||||
render_repr_attributes_in_code(f, cx, def_id, ItemType::Union);
|
||||
} else {
|
||||
render_attributes_in_code(f, it, "", cx);
|
||||
}
|
||||
write!(f, "{}union {}", visibility_print_with_space(it, cx), it.name.unwrap(),)?;
|
||||
|
||||
let where_displayed = if let Some(generics) = g {
|
||||
|
|
@ -2390,6 +2383,7 @@ fn render_union(
|
|||
|
||||
for field in fields {
|
||||
if let clean::StructFieldItem(ref ty) = field.kind {
|
||||
render_attributes_in_code(&mut f, field, " ", cx);
|
||||
writeln!(
|
||||
f,
|
||||
" {}{}: {},",
|
||||
|
|
@ -2481,11 +2475,15 @@ fn render_struct_fields(
|
|||
if toggle {
|
||||
toggle_open(&mut *w, format_args!("{count_fields} fields"));
|
||||
}
|
||||
if has_visible_fields {
|
||||
writeln!(w)?;
|
||||
}
|
||||
for field in fields {
|
||||
if let clean::StructFieldItem(ref ty) = field.kind {
|
||||
write!(
|
||||
render_attributes_in_code(w, field, &format!("{tab} "), cx);
|
||||
writeln!(
|
||||
w,
|
||||
"\n{tab} {vis}{name}: {ty},",
|
||||
"{tab} {vis}{name}: {ty},",
|
||||
vis = visibility_print_with_space(field, cx),
|
||||
name = field.name.unwrap(),
|
||||
ty = ty.print(cx)
|
||||
|
|
@ -2495,12 +2493,12 @@ fn render_struct_fields(
|
|||
|
||||
if has_visible_fields {
|
||||
if has_stripped_entries {
|
||||
write!(
|
||||
writeln!(
|
||||
w,
|
||||
"\n{tab} <span class=\"comment\">/* private fields */</span>"
|
||||
"{tab} <span class=\"comment\">/* private fields */</span>"
|
||||
)?;
|
||||
}
|
||||
write!(w, "\n{tab}")?;
|
||||
write!(w, "{tab}")?;
|
||||
} else if has_stripped_entries {
|
||||
write!(w, " <span class=\"comment\">/* private fields */</span> ")?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<pre class="rust item-decl"><code>
|
||||
{{ self.render_attributes_in_pre()|safe }}
|
||||
{{ self.render_union()|safe }}
|
||||
</code></pre>
|
||||
{% if !self.is_type_alias %}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
toml = "0.5"
|
||||
toml = "0.7"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
anyhow = "1.0.32"
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@ build_helper = { path = "../../build_helper" }
|
|||
curl = "0.4.38"
|
||||
indexmap = { version = "2.0.0", features = ["serde"] }
|
||||
serde = { version = "1.0.125", features = ["derive"] }
|
||||
toml = "0.5.7"
|
||||
toml = "0.7"
|
||||
|
|
|
|||
|
|
@ -65,13 +65,6 @@ harness = false
|
|||
name = "dogfood"
|
||||
harness = false
|
||||
|
||||
# quine-mc_cluskey makes up a significant part of the runtime in dogfood
|
||||
# due to the number of conditions in the clippy_lints crate
|
||||
# and enabling optimizations for that specific dependency helps a bit
|
||||
# without increasing total build times.
|
||||
[profile.dev.package.quine-mc_cluskey]
|
||||
opt-level = 3
|
||||
|
||||
[lints.rust.unexpected_cfgs]
|
||||
level = "warn"
|
||||
check-cfg = ['cfg(bootstrap)']
|
||||
|
|
|
|||
|
|
@ -242,14 +242,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
match evt {
|
||||
AccessEvent::Read(_) => {
|
||||
// FIXME: ProvenanceMap should have something like get_range().
|
||||
let p_map = alloc.provenance();
|
||||
for idx in overlap {
|
||||
// If a provenance was read by the foreign code, expose it.
|
||||
if let Some((prov, _idx)) = p_map.get_byte(Size::from_bytes(idx), this)
|
||||
{
|
||||
this.expose_provenance(prov)?;
|
||||
}
|
||||
// If a provenance was read by the foreign code, expose it.
|
||||
for prov in alloc.provenance().get_range(this, overlap.into()) {
|
||||
this.expose_provenance(prov)?;
|
||||
}
|
||||
}
|
||||
AccessEvent::Write(_, certain) => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! Ensure we detect aliasing of two in-place arguments for the tricky case where they do not
|
||||
//! live in memory.
|
||||
//@revisions: stack tree
|
||||
//@[tree]compile-flags: -Zmiri-tree-borrows
|
||||
// Validation forces more things into memory, which we can't have here.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
//! Ensure we detect aliasing of a in-place argument with the return place for the tricky case where
|
||||
//! they do not live in memory.
|
||||
//@revisions: stack tree
|
||||
//@[tree]compile-flags: -Zmiri-tree-borrows
|
||||
// Validation forces more things into memory, which we can't have here.
|
||||
//@compile-flags: -Zmiri-disable-validation
|
||||
#![feature(custom_mir, core_intrinsics)]
|
||||
use std::intrinsics::mir::*;
|
||||
|
||||
#[allow(unused)]
|
||||
pub struct S(i32);
|
||||
|
||||
#[custom_mir(dialect = "runtime", phase = "optimized")]
|
||||
fn main() {
|
||||
mir! {
|
||||
let _unit: ();
|
||||
{
|
||||
let staging = S(42); // This forces `staging` into memory...
|
||||
let _non_copy = staging; // ... so we move it to a non-inmemory local here.
|
||||
// This specifically uses a type with scalar representation to tempt Miri to use the
|
||||
// efficient way of storing local variables (outside adressable memory).
|
||||
Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue())
|
||||
//~[stack]^ ERROR: not granting access
|
||||
//~[tree]| ERROR: /reborrow .* forbidden/
|
||||
}
|
||||
after_call = {
|
||||
Return()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn callee(x: S) -> S {
|
||||
x
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected
|
||||
--> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
||||
|
|
||||
LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue())
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
|
||||
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
|
||||
help: <TAG> was created here, as the root tag for ALLOC
|
||||
--> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
||||
|
|
||||
LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue())
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: <TAG> is this argument
|
||||
--> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
||||
|
|
||||
LL | x
|
||||
| ^
|
||||
= note: BACKTRACE (of the first span):
|
||||
= note: inside `main` at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
error: Undefined Behavior: reborrow through <TAG> (root of the allocation) at ALLOC[0x0] is forbidden
|
||||
--> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
||||
|
|
||||
LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue())
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
|
||||
= help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child)
|
||||
= help: this reborrow (acting as a foreign read access) would cause the protected tag <TAG> (currently Active) to become Disabled
|
||||
= help: protected tags must never be Disabled
|
||||
help: the accessed tag <TAG> was created here
|
||||
--> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
||||
|
|
||||
LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue())
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: the protected tag <TAG> was created here, in the initial state Reserved
|
||||
--> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
||||
|
|
||||
LL | x
|
||||
| ^
|
||||
help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4]
|
||||
--> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
||||
|
|
||||
LL | x
|
||||
| ^
|
||||
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
|
||||
= note: BACKTRACE (of the first span):
|
||||
= note: inside `main` at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -189,6 +189,12 @@ impl Bootstrap {
|
|||
self
|
||||
}
|
||||
|
||||
/// Rebuild rustc in case of statically linked LLVM
|
||||
pub fn rustc_rebuild(mut self) -> Self {
|
||||
self.cmd = self.cmd.arg("--keep-stage").arg("0");
|
||||
self
|
||||
}
|
||||
|
||||
pub fn run(self, timer: &mut TimerSection) -> anyhow::Result<()> {
|
||||
self.cmd.run()?;
|
||||
let metrics = load_metrics(&self.metrics_path)?;
|
||||
|
|
|
|||
|
|
@ -375,8 +375,14 @@ fn execute_pipeline(
|
|||
|
||||
let mut dist = Bootstrap::dist(env, &dist_args)
|
||||
.llvm_pgo_optimize(llvm_pgo_profile.as_ref())
|
||||
.rustc_pgo_optimize(&rustc_pgo_profile)
|
||||
.avoid_rustc_rebuild();
|
||||
.rustc_pgo_optimize(&rustc_pgo_profile);
|
||||
|
||||
// if LLVM is not built we'll have PGO optimized rustc
|
||||
dist = if env.supports_shared_llvm() || !env.build_llvm() {
|
||||
dist.avoid_rustc_rebuild()
|
||||
} else {
|
||||
dist.rustc_rebuild()
|
||||
};
|
||||
|
||||
for bolt_profile in bolt_profiles {
|
||||
dist = dist.with_bolt_profile(bolt_profile);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ cargo_metadata = "0.18"
|
|||
clap = { version = "4.4.2", features = ["derive"] }
|
||||
clap-cargo = "0.12.0"
|
||||
diff = "0.1"
|
||||
dirs = "5.0"
|
||||
dirs = "6.0"
|
||||
getopts = "0.2"
|
||||
ignore = "0.4"
|
||||
itertools = "0.12"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#![crate_name = "foo"]
|
||||
|
||||
//@ has 'foo/fn.f.html'
|
||||
//@ has - //*[@'class="rust item-decl"]' '#[unsafe(export_name = "f")] pub fn f()'
|
||||
//@ has - //*[@'class="code-attribute"]' '#[unsafe(export_name = "f")]'
|
||||
//@ has - //*[@'class="rust item-decl"]' 'pub fn f()'
|
||||
#[unsafe(export_name = "\
|
||||
f")]
|
||||
pub fn f() {}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,77 @@
|
|||
//@ edition: 2024
|
||||
#![crate_name = "foo"]
|
||||
|
||||
//@ has foo/fn.f.html '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]'
|
||||
//@ has foo/fn.f.html '//*[@class="code-attribute"]' '#[unsafe(no_mangle)]'
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn f() {}
|
||||
|
||||
//@ has foo/fn.g.html '//pre[@class="rust item-decl"]' '#[unsafe(export_name = "bar")]'
|
||||
//@ has foo/fn.g.html '//*[@class="code-attribute"]' '#[unsafe(export_name = "bar")]'
|
||||
#[unsafe(export_name = "bar")]
|
||||
pub extern "C" fn g() {}
|
||||
|
||||
//@ has foo/fn.example.html '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".text")]'
|
||||
//@ has foo/fn.example.html '//*[@class="code-attribute"]' '#[unsafe(link_section = ".text")]'
|
||||
#[unsafe(link_section = ".text")]
|
||||
pub extern "C" fn example() {}
|
||||
|
||||
//@ has foo/struct.Repr.html '//pre[@class="rust item-decl"]' '#[repr(C, align(8))]'
|
||||
//@ has foo/struct.Repr.html '//*[@class="code-attribute"]' '#[repr(C, align(8))]'
|
||||
#[repr(C, align(8))]
|
||||
pub struct Repr;
|
||||
|
||||
//@ has foo/macro.macro_rule.html '//*[@class="code-attribute"]' '#[unsafe(link_section = ".text")]'
|
||||
#[unsafe(link_section = ".text")]
|
||||
#[macro_export]
|
||||
macro_rules! macro_rule {
|
||||
() => {};
|
||||
}
|
||||
|
||||
//@ has 'foo/enum.Enum.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "enum")]'
|
||||
#[unsafe(link_section = "enum")]
|
||||
pub enum Enum {
|
||||
//@ has 'foo/enum.Enum.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "a")]'
|
||||
#[unsafe(link_section = "a")]
|
||||
A,
|
||||
//@ has 'foo/enum.Enum.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "quz")]'
|
||||
#[unsafe(link_section = "quz")]
|
||||
Quz {
|
||||
//@ has 'foo/enum.Enum.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "b")]'
|
||||
#[unsafe(link_section = "b")]
|
||||
b: (),
|
||||
},
|
||||
}
|
||||
|
||||
//@ has 'foo/trait.Trait.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "trait")]'
|
||||
#[unsafe(link_section = "trait")]
|
||||
pub trait Trait {
|
||||
//@ has 'foo/trait.Trait.html'
|
||||
//@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]/*[@class="code-attribute"]' '#[unsafe(link_section = "bar")]'
|
||||
//@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' 'const BAR: u32 = 0u32'
|
||||
#[unsafe(link_section = "bar")]
|
||||
const BAR: u32 = 0;
|
||||
|
||||
//@ has - '//*[@class="code-attribute"]' '#[unsafe(link_section = "foo")]'
|
||||
#[unsafe(link_section = "foo")]
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
//@ has 'foo/union.Union.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "union")]'
|
||||
#[unsafe(link_section = "union")]
|
||||
pub union Union {
|
||||
//@ has 'foo/union.Union.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "x")]'
|
||||
#[unsafe(link_section = "x")]
|
||||
pub x: u32,
|
||||
y: f32,
|
||||
}
|
||||
|
||||
//@ has 'foo/struct.Struct.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "struct")]'
|
||||
#[unsafe(link_section = "struct")]
|
||||
pub struct Struct {
|
||||
//@ has 'foo/struct.Struct.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "x")]'
|
||||
#[unsafe(link_section = "x")]
|
||||
pub x: u32,
|
||||
y: f32,
|
||||
}
|
||||
|
||||
// Check that the attributes from the trait items show up consistently in the impl.
|
||||
//@ has 'foo/struct.Struct.html' '//*[@id="trait-implementations-list"]//*[@class="code-attribute"]' '#[unsafe(link_section = "bar")]'
|
||||
//@ has 'foo/struct.Struct.html' '//*[@id="trait-implementations-list"]//*[@class="code-attribute"]' '#[unsafe(link_section = "foo")]'
|
||||
impl Trait for Struct {}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<code>pub enum TypeAlias {
|
||||
#[non_exhaustive]
|
||||
<div class="code-attribute">#[non_exhaustive]</div>
|
||||
Variant,
|
||||
}</code>
|
||||
}</code>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<code>pub enum Type {
|
||||
#[non_exhaustive]
|
||||
<div class="code-attribute">#[non_exhaustive]</div>
|
||||
Variant,
|
||||
}</code>
|
||||
}</code>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ pub union Foo2 {
|
|||
}
|
||||
|
||||
//@ has 'foo/type.Bar2.html'
|
||||
//@ matches - '//*[@class="rust item-decl"]' '#\[repr\(C\)\]\npub union Bar2 \{*'
|
||||
//@ matches - '//*[@class="code-attribute"]' '#\[repr\(C\)\]'
|
||||
//@ matches - '//*[@class="rust item-decl"]' 'pub union Bar2 \{*'
|
||||
// Ensures that we see the doc comment of the type alias and not of the aliased type.
|
||||
//@ has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'bar'
|
||||
/// bar
|
||||
|
|
|
|||
|
|
@ -49,24 +49,6 @@ LL | #[crate_name]
|
|||
|
|
||||
= note: for more information, visit <https://doc.rust-lang.org/reference/crates-and-source-files.html#the-crate_name-attribute>
|
||||
|
||||
error: malformed `sanitize` attribute input
|
||||
--> $DIR/malformed-attrs.rs:92:1
|
||||
|
|
||||
LL | #[sanitize]
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
help: the following are the possible correct uses
|
||||
|
|
||||
LL | #[sanitize(address = "on|off")]
|
||||
| ++++++++++++++++++++
|
||||
LL | #[sanitize(cfi = "on|off")]
|
||||
| ++++++++++++++++
|
||||
LL | #[sanitize(hwaddress = "on|off")]
|
||||
| ++++++++++++++++++++++
|
||||
LL | #[sanitize(kcfi = "on|off")]
|
||||
| +++++++++++++++++
|
||||
= and 5 other candidates
|
||||
|
||||
error: malformed `instruction_set` attribute input
|
||||
--> $DIR/malformed-attrs.rs:106:1
|
||||
|
|
||||
|
|
@ -543,6 +525,24 @@ LL | #[coverage(off)]
|
|||
LL | #[coverage(on)]
|
||||
| ++++
|
||||
|
||||
error[E0539]: malformed `sanitize` attribute input
|
||||
--> $DIR/malformed-attrs.rs:92:1
|
||||
|
|
||||
LL | #[sanitize]
|
||||
| ^^^^^^^^^^^ expected this to be a list
|
||||
|
|
||||
help: try changing it to one of the following valid forms of the attribute
|
||||
|
|
||||
LL | #[sanitize(address = "on|off")]
|
||||
| ++++++++++++++++++++
|
||||
LL | #[sanitize(cfi = "on|off")]
|
||||
| ++++++++++++++++
|
||||
LL | #[sanitize(hwaddress = "on|off")]
|
||||
| ++++++++++++++++++++++
|
||||
LL | #[sanitize(kcfi = "on|off")]
|
||||
| +++++++++++++++++
|
||||
= and 5 other candidates
|
||||
|
||||
error[E0565]: malformed `no_implicit_prelude` attribute input
|
||||
--> $DIR/malformed-attrs.rs:97:1
|
||||
|
|
||||
|
|
|
|||
14
tests/ui/mir/validate/ice-zst-as-discr-145786.rs
Normal file
14
tests/ui/mir/validate/ice-zst-as-discr-145786.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// Do not attempt to take the discriminant as the source
|
||||
// converted to a `u128`, that won't work for ZST.
|
||||
//
|
||||
//@ compile-flags: -Zvalidate-mir
|
||||
|
||||
enum A {
|
||||
B,
|
||||
C,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: A = unsafe { std::mem::transmute(()) };
|
||||
//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
|
||||
}
|
||||
12
tests/ui/mir/validate/ice-zst-as-discr-145786.stderr
Normal file
12
tests/ui/mir/validate/ice-zst-as-discr-145786.stderr
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
|
||||
--> $DIR/ice-zst-as-discr-145786.rs:12:25
|
||||
|
|
||||
LL | let _: A = unsafe { std::mem::transmute(()) };
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: source type: `()` (0 bits)
|
||||
= note: target type: `A` (8 bits)
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0512`.
|
||||
|
|
@ -7,11 +7,11 @@ fn main() {
|
|||
(0 | 1, 2 | 3) => {}
|
||||
}
|
||||
match ((0u8,),) {
|
||||
//~^ ERROR non-exhaustive patterns: `((4_u8..=u8::MAX))`
|
||||
//~^ ERROR non-exhaustive patterns: `((4_u8..=u8::MAX,),)`
|
||||
((0 | 1,) | (2 | 3,),) => {}
|
||||
}
|
||||
match (Some(0u8),) {
|
||||
//~^ ERROR non-exhaustive patterns: `(Some(2_u8..=u8::MAX))`
|
||||
//~^ ERROR non-exhaustive patterns: `(Some(2_u8..=u8::MAX),)`
|
||||
(None | Some(0 | 1),) => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,30 +11,30 @@ LL ~ (0 | 1, 2 | 3) => {},
|
|||
LL + (2_u8..=u8::MAX, _) => todo!()
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered
|
||||
error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX,),)` not covered
|
||||
--> $DIR/exhaustiveness-non-exhaustive.rs:9:11
|
||||
|
|
||||
LL | match ((0u8,),) {
|
||||
| ^^^^^^^^^ pattern `((4_u8..=u8::MAX))` not covered
|
||||
| ^^^^^^^^^ pattern `((4_u8..=u8::MAX,),)` not covered
|
||||
|
|
||||
= note: the matched value is of type `((u8,),)`
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ ((0 | 1,) | (2 | 3,),) => {},
|
||||
LL + ((4_u8..=u8::MAX)) => todo!()
|
||||
LL + ((4_u8..=u8::MAX,),) => todo!()
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered
|
||||
error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX),)` not covered
|
||||
--> $DIR/exhaustiveness-non-exhaustive.rs:13:11
|
||||
|
|
||||
LL | match (Some(0u8),) {
|
||||
| ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` not covered
|
||||
| ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX),)` not covered
|
||||
|
|
||||
= note: the matched value is of type `(Option<u8>,)`
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ (None | Some(0 | 1),) => {},
|
||||
LL + (Some(2_u8..=u8::MAX)) => todo!()
|
||||
LL + (Some(2_u8..=u8::MAX),) => todo!()
|
||||
|
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
#![feature(sanitize)]
|
||||
|
||||
#[sanitize(brontosaurus = "off")] //~ ERROR invalid argument
|
||||
fn main() {
|
||||
}
|
||||
#[sanitize(brontosaurus = "off")] //~ ERROR malformed `sanitize` attribute input
|
||||
fn main() {}
|
||||
|
||||
#[sanitize(address = "off")] //~ ERROR multiple `sanitize` attributes
|
||||
#[sanitize(address = "off")]
|
||||
|
|
@ -12,11 +11,11 @@ fn multiple_consistent() {}
|
|||
#[sanitize(address = "off")]
|
||||
fn multiple_inconsistent() {}
|
||||
|
||||
#[sanitize(address = "bogus")] //~ ERROR invalid argument for `sanitize`
|
||||
#[sanitize(address = "bogus")] //~ ERROR malformed `sanitize` attribute input
|
||||
fn wrong_value() {}
|
||||
|
||||
#[sanitize = "off"] //~ ERROR malformed `sanitize` attribute input
|
||||
fn name_value () {}
|
||||
fn name_value() {}
|
||||
|
||||
#[sanitize] //~ ERROR malformed `sanitize` attribute input
|
||||
fn just_word() {}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,82 @@
|
|||
error: malformed `sanitize` attribute input
|
||||
--> $DIR/invalid-sanitize.rs:18:1
|
||||
error[E0539]: malformed `sanitize` attribute input
|
||||
--> $DIR/invalid-sanitize.rs:3:1
|
||||
|
|
||||
LL | #[sanitize(brontosaurus = "off")]
|
||||
| ^^^^^^^^^^^------------^^^^^^^^^^
|
||||
| |
|
||||
| valid arguments are "address", "cfi", "kcfi", "memory", "memtag", "shadow_call_stack", "thread" or "hwaddress"
|
||||
|
|
||||
help: try changing it to one of the following valid forms of the attribute
|
||||
|
|
||||
LL - #[sanitize(brontosaurus = "off")]
|
||||
LL + #[sanitize(address = "on|off")]
|
||||
|
|
||||
LL - #[sanitize(brontosaurus = "off")]
|
||||
LL + #[sanitize(cfi = "on|off")]
|
||||
|
|
||||
LL - #[sanitize(brontosaurus = "off")]
|
||||
LL + #[sanitize(hwaddress = "on|off")]
|
||||
|
|
||||
LL - #[sanitize(brontosaurus = "off")]
|
||||
LL + #[sanitize(kcfi = "on|off")]
|
||||
|
|
||||
= and 5 other candidates
|
||||
|
||||
error: multiple `sanitize` attributes
|
||||
--> $DIR/invalid-sanitize.rs:6:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
||||
|
|
||||
note: attribute also specified here
|
||||
--> $DIR/invalid-sanitize.rs:7:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: multiple `sanitize` attributes
|
||||
--> $DIR/invalid-sanitize.rs:10:1
|
||||
|
|
||||
LL | #[sanitize(address = "on")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
||||
|
|
||||
note: attribute also specified here
|
||||
--> $DIR/invalid-sanitize.rs:11:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0539]: malformed `sanitize` attribute input
|
||||
--> $DIR/invalid-sanitize.rs:14:1
|
||||
|
|
||||
LL | #[sanitize(address = "bogus")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^-------^^
|
||||
| |
|
||||
| valid arguments are "on" or "off"
|
||||
|
|
||||
help: try changing it to one of the following valid forms of the attribute
|
||||
|
|
||||
LL - #[sanitize(address = "bogus")]
|
||||
LL + #[sanitize(address = "on|off")]
|
||||
|
|
||||
LL - #[sanitize(address = "bogus")]
|
||||
LL + #[sanitize(cfi = "on|off")]
|
||||
|
|
||||
LL - #[sanitize(address = "bogus")]
|
||||
LL + #[sanitize(hwaddress = "on|off")]
|
||||
|
|
||||
LL - #[sanitize(address = "bogus")]
|
||||
LL + #[sanitize(kcfi = "on|off")]
|
||||
|
|
||||
= and 5 other candidates
|
||||
|
||||
error[E0539]: malformed `sanitize` attribute input
|
||||
--> $DIR/invalid-sanitize.rs:17:1
|
||||
|
|
||||
LL | #[sanitize = "off"]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^ expected this to be a list
|
||||
|
|
||||
help: the following are the possible correct uses
|
||||
help: try changing it to one of the following valid forms of the attribute
|
||||
|
|
||||
LL - #[sanitize = "off"]
|
||||
LL + #[sanitize(address = "on|off")]
|
||||
|
|
@ -20,13 +92,13 @@ LL + #[sanitize(kcfi = "on|off")]
|
|||
|
|
||||
= and 5 other candidates
|
||||
|
||||
error: malformed `sanitize` attribute input
|
||||
--> $DIR/invalid-sanitize.rs:21:1
|
||||
error[E0539]: malformed `sanitize` attribute input
|
||||
--> $DIR/invalid-sanitize.rs:20:1
|
||||
|
|
||||
LL | #[sanitize]
|
||||
| ^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^ expected this to be a list
|
||||
|
|
||||
help: the following are the possible correct uses
|
||||
help: try changing it to one of the following valid forms of the attribute
|
||||
|
|
||||
LL | #[sanitize(address = "on|off")]
|
||||
| ++++++++++++++++++++
|
||||
|
|
@ -38,45 +110,6 @@ LL | #[sanitize(kcfi = "on|off")]
|
|||
| +++++++++++++++++
|
||||
= and 5 other candidates
|
||||
|
||||
error: multiple `sanitize` attributes
|
||||
--> $DIR/invalid-sanitize.rs:7:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
||||
|
|
||||
note: attribute also specified here
|
||||
--> $DIR/invalid-sanitize.rs:8:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: multiple `sanitize` attributes
|
||||
--> $DIR/invalid-sanitize.rs:11:1
|
||||
|
|
||||
LL | #[sanitize(address = "on")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
||||
|
|
||||
note: attribute also specified here
|
||||
--> $DIR/invalid-sanitize.rs:12:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid argument for `sanitize`
|
||||
--> $DIR/invalid-sanitize.rs:3:1
|
||||
|
|
||||
LL | #[sanitize(brontosaurus = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: expected one of: `address`, `kernel_address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow_call_stack`, or `thread`
|
||||
|
||||
error: invalid argument for `sanitize`
|
||||
--> $DIR/invalid-sanitize.rs:15:1
|
||||
|
|
||||
LL | #[sanitize(address = "bogus")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: expected one of: `address`, `kernel_address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow_call_stack`, or `thread`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0539`.
|
||||
|
|
|
|||
15
tests/ui/traits/const-traits/constructor-const-fn.rs
Normal file
15
tests/ui/traits/const-traits/constructor-const-fn.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
//@ check-pass
|
||||
//@ compile-flags: -Znext-solver
|
||||
#![feature(const_trait_impl)]
|
||||
const fn impls_fn<F: ~const Fn(u32) -> Foo>(_: &F) {}
|
||||
|
||||
struct Foo(u32);
|
||||
|
||||
const fn foo() {
|
||||
// This previously triggered an incorrect assert
|
||||
// when checking whether the constructor of `Foo`
|
||||
// is const.
|
||||
impls_fn(&Foo)
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
13
tests/ui/traits/const-traits/reservation-impl-ice.rs
Normal file
13
tests/ui/traits/const-traits/reservation-impl-ice.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
//@ compile-flags: -Znext-solver
|
||||
#![feature(const_from, never_type, const_trait_impl)]
|
||||
|
||||
const fn impls_from<T: ~const From<!>>() {}
|
||||
|
||||
const fn foo() {
|
||||
// This previously ICE'd when encountering the reservation impl
|
||||
// from the standard library.
|
||||
impls_from::<()>();
|
||||
//~^ ERROR the trait bound `(): From<!>` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
25
tests/ui/traits/const-traits/reservation-impl-ice.stderr
Normal file
25
tests/ui/traits/const-traits/reservation-impl-ice.stderr
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
error[E0277]: the trait bound `(): From<!>` is not satisfied
|
||||
--> $DIR/reservation-impl-ice.rs:9:18
|
||||
|
|
||||
LL | impls_from::<()>();
|
||||
| ^^ the trait `From<!>` is not implemented for `()`
|
||||
|
|
||||
= help: the following other types implement trait `From<T>`:
|
||||
`(T, T)` implements `From<[T; 2]>`
|
||||
`(T, T, T)` implements `From<[T; 3]>`
|
||||
`(T, T, T, T)` implements `From<[T; 4]>`
|
||||
`(T, T, T, T, T)` implements `From<[T; 5]>`
|
||||
`(T, T, T, T, T, T)` implements `From<[T; 6]>`
|
||||
`(T, T, T, T, T, T, T)` implements `From<[T; 7]>`
|
||||
`(T, T, T, T, T, T, T, T)` implements `From<[T; 8]>`
|
||||
`(T, T, T, T, T, T, T, T, T)` implements `From<[T; 9]>`
|
||||
and 4 others
|
||||
note: required by a bound in `impls_from`
|
||||
--> $DIR/reservation-impl-ice.rs:4:24
|
||||
|
|
||||
LL | const fn impls_from<T: ~const From<!>>() {}
|
||||
| ^^^^^^^^^^^^^^ required by this bound in `impls_from`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue