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:
bors 2025-08-23 23:30:43 +00:00
commit f6d23413c3
51 changed files with 733 additions and 449 deletions

View file

@ -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"

View file

@ -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 })
}
}

View file

@ -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>,

View file

@ -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

View file

@ -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
}

View file

@ -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 {

View file

@ -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)?;

View file

@ -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 },

View file

@ -73,6 +73,7 @@ impl AttributeKind {
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcObjectLifetimeDefault => No,
Sanitize { .. } => No,
ShouldPanic { .. } => No,
SkipDuringMethodDispatch { .. } => No,
SpecializationTrait(..) => No,

View file

@ -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,
);

View file

@ -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 {

View file

@ -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)
}

View file

@ -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,

View file

@ -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)
})
}

View file

@ -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.

View file

@ -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, ")")?;
}

View file

@ -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;
}
}

View file

@ -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
};

View file

@ -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);
}

View file

@ -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()
}

View file

@ -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>>,
}

View file

@ -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() }
}

View file

@ -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);
}
}

View file

@ -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> ")?;
}

View file

@ -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 %}

View file

@ -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"

View file

@ -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"

View file

@ -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)']

View file

@ -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) => {

View file

@ -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.

View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -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)?;

View file

@ -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);

View file

@ -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"

View file

@ -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() {}

View file

@ -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 {}

View file

@ -1,4 +1,4 @@
<code>pub enum TypeAlias {
#[non_exhaustive]
<div class="code-attribute">#[non_exhaustive]</div>
Variant,
}</code>
}</code>

View file

@ -1,4 +1,4 @@
<code>pub enum Type {
#[non_exhaustive]
<div class="code-attribute">#[non_exhaustive]</div>
Variant,
}</code>
}</code>

View file

@ -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

View file

@ -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
|

View 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
}

View 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`.

View file

@ -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),) => {}
}
}

View file

@ -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

View file

@ -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() {}

View file

@ -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`.

View 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() {}

View 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() {}

View 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`.