Auto merge of #143074 - compiler-errors:rollup-cv64hdh, r=compiler-errors

Rollup of 18 pull requests

Successful merges:

 - rust-lang/rust#137843 (make RefCell unstably const)
 - rust-lang/rust#140942 (const-eval: allow constants to refer to mutable/external memory, but reject such constants as patterns)
 - rust-lang/rust#142549 (small iter.intersperse.fold() optimization)
 - rust-lang/rust#142637 (Remove some glob imports from the type system)
 - rust-lang/rust#142647 ([perf] Compute hard errors without diagnostics in impl_intersection_has_impossible_obligation)
 - rust-lang/rust#142700 (Remove incorrect comments in `Weak`)
 - rust-lang/rust#142927 (Add note to `find_const_ty_from_env`)
 - rust-lang/rust#142967 (Fix RwLock::try_write documentation for WouldBlock condition)
 - rust-lang/rust#142986 (Port `#[export_name]` to the new attribute parsing infrastructure)
 - rust-lang/rust#143001 (Rename run always )
 - rust-lang/rust#143010 (Update `browser-ui-test` version to `0.20.7`)
 - rust-lang/rust#143015 (Add `sym::macro_pin` diagnostic item for `core::pin::pin!()`)
 - rust-lang/rust#143033 (Expand const-stabilized API links in relnotes)
 - rust-lang/rust#143041 (Remove cache for citool)
 - rust-lang/rust#143056 (Move an ACE test out of the GCI directory)
 - rust-lang/rust#143059 (Fix 1.88 relnotes)
 - rust-lang/rust#143067 (Tracking issue number for `iter_macro`)
 - rust-lang/rust#143073 (Fix some fixmes that were waiting for let chains)

Failed merges:

 - rust-lang/rust#143020 (codegen_fn_attrs: make comment more precise)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-06-27 00:44:20 +00:00
commit e61dd437f3
158 changed files with 1249 additions and 916 deletions

View file

@ -11,10 +11,6 @@ name: CI
on:
push:
branches:
# CI on master only serves for caching citool builds for the `calculate_matrix` job.
# In order to use GHA cache on PR CI (and auto/try) jobs, we need to write to it
# from the default branch.
- master
- auto
- try
- try-perf
@ -57,13 +53,6 @@ jobs:
steps:
- name: Checkout the source code
uses: actions/checkout@v4
# Cache citool to make its build faster, as it's in the critical path.
# The rust-cache doesn't bleed into the main `job`, so it should not affect any other
# Rust compilation.
- name: Cache citool
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
with:
workspaces: src/ci/citool
- name: Test citool
# Only test citool on the auto branch, to reduce latency of the calculate matrix job
# on PR/try builds.

View file

@ -54,23 +54,35 @@ Stabilized APIs
---------------
- [`Cell::update`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#method.update)
- [`impl Default for *const T`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#impl-Default-for-*const+T)
- [`impl Default for *mut T`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#impl-Default-for-*mut+T)
- [`impl Default for *const T`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#impl-Default-for-*const+T)
- [`impl Default for *mut T`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#impl-Default-for-*mut+T)
- [`HashMap::extract_if`](https://doc.rust-lang.org/stable/std/collections/struct.HashMap.html#method.extract_if)
- [`HashSet::extract_if`](https://doc.rust-lang.org/stable/std/collections/struct.HashSet.html#method.extract_if)
- [`hint::select_unpredictable`](https://doc.rust-lang.org/stable/std/hint/fn.select_unpredictable.html)
- [`proc_macro::Span::line`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.line)
- [`proc_macro::Span::column`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.column)
- [`proc_macro::Span::start`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.start)
- [`proc_macro::Span::end`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.end)
- [`proc_macro::Span::file`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.file)
- [`proc_macro::Span::local_file`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.local_file)
- [`<[T]>::as_chunks`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_chunks)
- [`<[T]>::as_chunks_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_chunks_mut)
- [`<[T]>::as_chunks_unchecked`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_chunks_unchecked)
- [`<[T]>::as_chunks_unchecked_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_chunks_unchecked_mut)
- [`<[T]>::as_rchunks`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_rchunks)
- [`<[T]>::as_rchunks_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_rchunks_mut)
- [`mod ffi::c_str`](https://doc.rust-lang.org/stable/std/ffi/c_str/index.html)
These previously stable APIs are now stable in const contexts:
- [`NonNull<T>::replace`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.replace)
- [`<*mut T>::replace`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.replace)
- [`std::ptr::swap_nonoverlapping`](https://github.com/rust-lang/rust/pull/137280)
- [`Cell::{replace, get, get_mut, from_mut, as_slice_of_cells}`](https://github.com/rust-lang/rust/pull/137928)
- [`std::ptr::swap_nonoverlapping`](https://doc.rust-lang.org/stable/std/ptr/fn.swap_nonoverlapping.html)
- [`Cell::replace`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#method.replace)
- [`Cell::get`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#method.get)
- [`Cell::get_mut`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#method.get_mut)
- [`Cell::from_mut`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#method.from_mut)
- [`Cell::as_slice_of_cells`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#method.as_slice_of_cells)
<a id="1.88.0-Cargo"></a>

View file

@ -231,6 +231,14 @@ pub enum AttributeKind {
/// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html).
DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol },
/// Represents [`#[export_name]`](https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute).
ExportName {
/// The name to export this item with.
/// It may not contain \0 bytes as it will be converted to a null-terminated string.
name: Symbol,
span: Span,
},
/// Represents `#[inline]` and `#[rustc_force_inline]`.
Inline(InlineAttr, Span),

View file

@ -22,6 +22,7 @@ impl AttributeKind {
ConstStabilityIndirect => No,
Deprecation { .. } => Yes,
DocComment { .. } => Yes,
ExportName { .. } => Yes,
Inline(..) => No,
MacroTransparency(..) => Yes,
Repr(..) => No,

View file

@ -93,9 +93,12 @@ attr_parsing_naked_functions_incompatible_attribute =
attribute incompatible with `#[unsafe(naked)]`
.label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`
.naked_attribute = function marked with `#[unsafe(naked)]` here
attr_parsing_non_ident_feature =
'feature' is not an identifier
attr_parsing_null_on_export = `export_name` may not contain null characters
attr_parsing_repr_ident =
meta item in `repr` must be an identifier

View file

@ -6,7 +6,7 @@ use rustc_span::{Span, Symbol, sym};
use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, FinalizeContext, Stage};
use crate::parser::ArgParser;
use crate::session_diagnostics::NakedFunctionIncompatibleAttribute;
use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport};
pub(crate) struct OptimizeParser;
@ -59,6 +59,33 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser {
}
}
pub(crate) struct ExportNameParser;
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
let Some(name) = nv.value_as_str() else {
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
return None;
};
if name.as_str().contains('\0') {
// `#[export_name = ...]` will be converted to a null-terminated string,
// so it may not contain any null characters.
cx.emit_err(NullOnExport { span: cx.attr_span });
return None;
}
Some(AttributeKind::ExportName { name, span: cx.attr_span })
}
}
#[derive(Default)]
pub(crate) struct NakedParser {
span: Option<Span>,

View file

@ -16,7 +16,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
use crate::attributes::codegen_attrs::{
ColdParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser,
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
@ -117,6 +117,7 @@ attribute_parsers!(
Single<ConstContinueParser>,
Single<ConstStabilityIndirectParser>,
Single<DeprecationParser>,
Single<ExportNameParser>,
Single<InlineParser>,
Single<LoopMatchParser>,
Single<MayDangleParser>,

View file

@ -445,6 +445,13 @@ pub(crate) struct MustUseIllFormedAttributeInput {
pub suggestions: DiagArgValue,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_null_on_export, code = E0648)]
pub(crate) struct NullOnExport {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_stability_outside_std, code = E0734)]
pub(crate) struct StabilityOutsideStd {

View file

@ -10,7 +10,7 @@ use rustc_hir::def::Res::Def;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
use rustc_infer::infer::{NllRegionVariableOrigin, SubregionOrigin};
use rustc_middle::bug;
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint};
@ -329,7 +329,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.infcx.tcx,
type_test.generic_kind.to_ty(self.infcx.tcx),
);
let origin = RelateParamBound(type_test_span, generic_ty, None);
let origin =
SubregionOrigin::RelateParamBound(type_test_span, generic_ty, None);
self.buffer_error(self.infcx.err_ctxt().construct_generic_bound_failure(
self.body.source.def_id().expect_local(),
type_test_span,

View file

@ -3,7 +3,7 @@ use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
use rustc_infer::infer::{InferCtxt, SubregionOrigin};
use rustc_infer::traits::query::type_op::DeeplyNormalize;
use rustc_middle::bug;
use rustc_middle::ty::{
@ -172,7 +172,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(self.span, t1, None);
let origin = SubregionOrigin::RelateParamBound(self.span, t1, None);
TypeOutlives::new(
&mut *self,
tcx,

View file

@ -66,10 +66,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Ty::new_tup(self.tcx(), user_provided_sig.inputs()),
args.tupled_upvars_ty(),
args.coroutine_captures_by_ref_ty(),
self.infcx
.next_region_var(RegionVariableOrigin::MiscVariable(self.body.span), || {
RegionCtxt::Unknown
}),
self.infcx.next_region_var(RegionVariableOrigin::Misc(self.body.span), || {
RegionCtxt::Unknown
}),
);
let next_ty_var = || self.infcx.next_ty_var(self.body.span);

View file

@ -16,7 +16,7 @@ use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::infer::{
BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin,
BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin,
};
use rustc_infer::traits::PredicateObligations;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
@ -794,7 +794,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
};
self.infcx.next_region_var(
BoundRegion(
RegionVariableOrigin::BoundRegion(
term.source_info.span,
br.kind,
BoundRegionConversionTime::FnCall,

View file

@ -205,11 +205,6 @@ codegen_ssa_missing_features = add the missing features in a `target_feature` at
codegen_ssa_missing_query_depgraph =
found CGU-reuse attribute but `-Zquery-dep-graph` was not specified
codegen_ssa_mixed_export_name_and_no_mangle = `{$no_mangle_attr}` attribute may not be used in combination with `#[export_name]`
.label = `{$no_mangle_attr}` is ignored
.note = `#[export_name]` takes precedence
.suggestion = remove the `{$no_mangle_attr}` attribute
codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found
codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
@ -230,8 +225,6 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
codegen_ssa_no_saved_object_file = cached cgu {$cgu_name} should have an object file, but doesn't
codegen_ssa_null_on_export = `export_name` may not contain null characters
codegen_ssa_out_of_range_integer = integer value out of range
.label = value must be between `0` and `255`

View file

@ -9,7 +9,7 @@ use rustc_attr_data_structures::{
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
use rustc_hir::{self as hir, HirId, LangItem, lang_items};
use rustc_hir::{self as hir, LangItem, lang_items};
use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
};
@ -87,7 +87,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
let mut link_ordinal_span = None;
let mut no_sanitize_span = None;
let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default();
for attr in attrs.iter() {
// In some cases, attribute are only valid on functions, but it's the `check_attr`
@ -119,16 +118,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
.max();
}
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
AttributeKind::ExportName { name, .. } => {
codegen_fn_attrs.export_name = Some(*name);
}
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
AttributeKind::NoMangle(attr_span) => {
if tcx.opt_item_name(did.to_def_id()).is_some() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
mixed_export_name_no_mangle_lint_state.track_no_mangle(
*attr_span,
tcx.local_def_id_to_hir_id(did),
attr,
);
} else {
tcx.dcx().emit_err(NoMangleNameless {
span: *attr_span,
@ -223,17 +220,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
sym::export_name => {
if let Some(s) = attr.value_str() {
if s.as_str().contains('\0') {
// `#[export_name = ...]` will be converted to a null-terminated string,
// so it may not contain any null characters.
tcx.dcx().emit_err(errors::NullOnExport { span: attr.span() });
}
codegen_fn_attrs.export_name = Some(s);
mixed_export_name_no_mangle_lint_state.track_export_name(attr.span());
}
}
sym::target_feature => {
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
tcx.dcx().span_delayed_bug(attr.span(), "target_feature applied to non-fn");
@ -444,8 +430,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}
mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx);
// Apply the minimum function alignment here, so that individual backends don't have to.
codegen_fn_attrs.alignment =
Ord::max(codegen_fn_attrs.alignment, tcx.sess.opts.unstable_opts.min_function_alignment);
@ -672,49 +656,6 @@ fn check_link_name_xor_ordinal(
}
}
#[derive(Default)]
struct MixedExportNameAndNoMangleState<'a> {
export_name: Option<Span>,
hir_id: Option<HirId>,
no_mangle: Option<Span>,
no_mangle_attr: Option<&'a hir::Attribute>,
}
impl<'a> MixedExportNameAndNoMangleState<'a> {
fn track_export_name(&mut self, span: Span) {
self.export_name = Some(span);
}
fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: &'a hir::Attribute) {
self.no_mangle = Some(span);
self.hir_id = Some(hir_id);
self.no_mangle_attr = Some(attr_name);
}
/// Emit diagnostics if the lint condition is met.
fn lint_if_mixed(self, tcx: TyCtxt<'_>) {
if let Self {
export_name: Some(export_name),
no_mangle: Some(no_mangle),
hir_id: Some(hir_id),
no_mangle_attr: Some(_),
} = self
{
tcx.emit_node_span_lint(
lint::builtin::UNUSED_ATTRIBUTES,
hir_id,
no_mangle,
errors::MixedExportNameAndNoMangle {
no_mangle,
no_mangle_attr: "#[unsafe(no_mangle)]".to_string(),
export_name,
removal_span: no_mangle,
},
);
}
}
}
/// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)]
/// macros. There are two forms. The pure one without args to mark primal functions (the functions
/// being differentiated). The other form is #[rustc_autodiff(Mode, ActivityList)] on top of the

View file

@ -140,13 +140,6 @@ pub(crate) struct RequiresRustAbi {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_null_on_export, code = E0648)]
pub(crate) struct NullOnExport {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_unsupported_instruction_set, code = E0779)]
pub(crate) struct UnsupportedInstructionSet {
@ -1207,18 +1200,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> {
#[diag(codegen_ssa_aix_strip_not_used)]
pub(crate) struct AixStripNotUsed;
#[derive(LintDiagnostic)]
#[diag(codegen_ssa_mixed_export_name_and_no_mangle)]
pub(crate) struct MixedExportNameAndNoMangle {
#[label]
pub no_mangle: Span,
pub no_mangle_attr: String,
#[note]
pub export_name: Span,
#[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
pub removal_span: Span,
}
#[derive(Diagnostic, Debug)]
pub(crate) enum XcrunError {
#[diag(codegen_ssa_xcrun_failed_invoking)]

View file

@ -124,12 +124,13 @@ const_eval_incompatible_return_types =
const_eval_incompatible_types =
calling a function with argument of type {$callee_ty} passing data of type {$caller_ty}
const_eval_interior_mutable_ref_escaping =
{const_eval_const_context}s cannot refer to interior mutable data
.label = this borrow of an interior mutable value may end up in the final value
const_eval_interior_mutable_borrow_escaping =
interior mutable shared borrows of lifetime-extended temporaries in the top-level scope of a {const_eval_const_context} are not allowed
.label = this borrow of an interior mutable value refers to a lifetime-extended temporary
.help = to fix this, the value can be extracted to a separate `static` item and then referenced
.teach_note =
References that escape into the final value of a constant or static must be immutable.
This creates a raw pointer to a temporary that has its lifetime extended to last for the entire program.
Lifetime-extended temporaries in constants and statics must be immutable.
This is to avoid accidentally creating shared mutable state.
@ -207,34 +208,24 @@ const_eval_long_running =
.label = the const evaluator is currently interpreting this expression
.help = the constant being evaluated
const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
const_eval_memory_exhausted =
tried to allocate more memory than available to compiler
const_eval_modified_global =
modifying a static's initial value from another static's initializer
const_eval_mutable_borrow_escaping =
mutable borrows of lifetime-extended temporaries in the top-level scope of a {const_eval_const_context} are not allowed
.teach_note =
This creates a reference to a temporary that has its lifetime extended to last for the entire program.
Lifetime-extended temporaries in constants and statics must be immutable.
This is to avoid accidentally creating shared mutable state.
If you really want global mutable state, try using an interior mutable `static` or a `static mut`.
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
const_eval_mutable_raw_escaping =
raw mutable pointers are not allowed in the final value of {const_eval_const_context}s
.teach_note =
Pointers that escape into the final value of a constant or static must be immutable.
This is to avoid accidentally creating shared mutable state.
If you really want global mutable state, try using an interior mutable `static` or a `static mut`.
const_eval_mutable_ref_escaping =
mutable references are not allowed in the final value of {const_eval_const_context}s
.teach_note =
References that escape into the final value of a constant or static must be immutable.
This is to avoid accidentally creating shared mutable state.
If you really want global mutable state, try using an interior mutable `static` or a `static mut`.
const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead
const_eval_non_const_await =
@ -437,9 +428,6 @@ const_eval_unwind_past_top =
## (We'd love to sort this differently to make that more clear but tidy won't let us...)
const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty}
const_eval_validation_const_ref_to_extern = {$front_matter}: encountered reference to `extern` static in `const`
const_eval_validation_const_ref_to_mutable = {$front_matter}: encountered reference to mutable memory in `const`
const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance)
const_eval_validation_dangling_box_out_of_bounds = {$front_matter}: encountered a dangling box (going beyond the bounds of its allocation)
const_eval_validation_dangling_box_use_after_free = {$front_matter}: encountered a dangling box (use-after-free)
@ -479,6 +467,7 @@ const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid re
const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object
const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer
const_eval_validation_invalid_vtable_trait = {$front_matter}: wrong trait in wide pointer vtable: expected `{$expected_dyn_type}`, but encountered `{$vtable_dyn_type}`
const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in `const` value
const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
const_eval_validation_null_box = {$front_matter}: encountered a null box

View file

@ -595,11 +595,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut);
if !is_allowed && self.place_may_escape(place) {
self.check_op(ops::EscapingMutBorrow(if matches!(rvalue, Rvalue::Ref(..)) {
hir::BorrowKind::Ref
} else {
hir::BorrowKind::Raw
}));
self.check_op(ops::EscapingMutBorrow);
}
}

View file

@ -567,7 +567,7 @@ impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow {
DiagImportance::Secondary
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
ccx.dcx().create_err(errors::InteriorMutableRefEscaping {
ccx.dcx().create_err(errors::InteriorMutableBorrowEscaping {
span,
opt_help: matches!(ccx.const_kind(), hir::ConstContext::Static(_)),
kind: ccx.const_kind(),
@ -580,7 +580,7 @@ impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow {
/// This op is for `&mut` borrows in the trailing expression of a constant
/// which uses the "enclosing scopes rule" to leak its locals into anonymous
/// static or const items.
pub(crate) struct EscapingMutBorrow(pub hir::BorrowKind);
pub(crate) struct EscapingMutBorrow;
impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow {
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
@ -594,20 +594,11 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow {
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
match self.0 {
hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::MutableRawEscaping {
span,
kind: ccx.const_kind(),
teach: ccx.tcx.sess.teach(E0764),
}),
hir::BorrowKind::Ref | hir::BorrowKind::Pin => {
ccx.dcx().create_err(errors::MutableRefEscaping {
span,
kind: ccx.const_kind(),
teach: ccx.tcx.sess.teach(E0764),
})
}
}
ccx.dcx().create_err(errors::MutableBorrowEscaping {
span,
kind: ccx.const_kind(),
teach: ccx.tcx.sess.teach(E0764),
})
}
}

View file

@ -26,13 +26,6 @@ pub(crate) use self::valtrees::{eval_to_valtree, valtree_to_const_value};
// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
const VALTREE_MAX_NODES: usize = 100000;
pub(crate) enum ValTreeCreationError<'tcx> {
NodesOverflow,
/// Values of this type, or this particular value, are not supported as valtrees.
NonSupportedType(Ty<'tcx>),
}
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError<'tcx>>;
#[instrument(skip(tcx), level = "debug")]
pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
tcx: TyCtxt<'tcx>,

View file

@ -1,17 +1,16 @@
use rustc_abi::{BackendRepr, FieldIdx, VariantIdx};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ReportedErrorInfo};
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ValTreeCreationError};
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, mir};
use rustc_span::DUMMY_SP;
use tracing::{debug, instrument, trace};
use super::VALTREE_MAX_NODES;
use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const};
use super::machine::CompileTimeInterpCx;
use super::{VALTREE_MAX_NODES, ValTreeCreationError, ValTreeCreationResult};
use crate::const_eval::CanAccessMutGlobal;
use crate::errors::MaxNumNodesInConstErr;
use crate::interpret::{
ImmTy, Immediate, InternKind, MPlaceTy, MemPlaceMeta, MemoryKind, PlaceTy, Projectable, Scalar,
intern_const_alloc_recursive,
@ -24,7 +23,7 @@ fn branches<'tcx>(
field_count: usize,
variant: Option<VariantIdx>,
num_nodes: &mut usize,
) -> ValTreeCreationResult<'tcx> {
) -> EvalToValTreeResult<'tcx> {
let place = match variant {
Some(variant) => ecx.project_downcast(place, variant).unwrap(),
None => place.clone(),
@ -58,7 +57,7 @@ fn slice_branches<'tcx>(
ecx: &CompileTimeInterpCx<'tcx>,
place: &MPlaceTy<'tcx>,
num_nodes: &mut usize,
) -> ValTreeCreationResult<'tcx> {
) -> EvalToValTreeResult<'tcx> {
let n = place.len(ecx).unwrap_or_else(|_| panic!("expected to use len of place {place:?}"));
let mut elems = Vec::with_capacity(n as usize);
@ -76,7 +75,7 @@ fn const_to_valtree_inner<'tcx>(
ecx: &CompileTimeInterpCx<'tcx>,
place: &MPlaceTy<'tcx>,
num_nodes: &mut usize,
) -> ValTreeCreationResult<'tcx> {
) -> EvalToValTreeResult<'tcx> {
let tcx = *ecx.tcx;
let ty = place.layout.ty;
debug!("ty kind: {:?}", ty.kind());
@ -91,7 +90,7 @@ fn const_to_valtree_inner<'tcx>(
Ok(ty::ValTree::zst(tcx))
}
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
let val = ecx.read_immediate(place).unwrap();
let val = ecx.read_immediate(place).report_err()?;
let val = val.to_scalar_int().unwrap();
*num_nodes += 1;
@ -113,7 +112,7 @@ fn const_to_valtree_inner<'tcx>(
// equality at compile-time (see `ptr_guaranteed_cmp`).
// However we allow those that are just integers in disguise.
// First, get the pointer. Remember it might be wide!
let val = ecx.read_immediate(place).unwrap();
let val = ecx.read_immediate(place).report_err()?;
// We could allow wide raw pointers where both sides are integers in the future,
// but for now we reject them.
if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) {
@ -134,7 +133,7 @@ fn const_to_valtree_inner<'tcx>(
ty::FnPtr(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
ty::Ref(_, _, _) => {
let derefd_place = ecx.deref_pointer(place).unwrap();
let derefd_place = ecx.deref_pointer(place).report_err()?;
const_to_valtree_inner(ecx, &derefd_place, num_nodes)
}
@ -158,7 +157,7 @@ fn const_to_valtree_inner<'tcx>(
bug!("uninhabited types should have errored and never gotten converted to valtree")
}
let variant = ecx.read_discriminant(place).unwrap();
let variant = ecx.read_discriminant(place).report_err()?;
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
}
@ -249,24 +248,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
debug!(?place);
let mut num_nodes = 0;
let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes);
match valtree_result {
Ok(valtree) => Ok(Ok(valtree)),
Err(err) => {
let did = cid.instance.def_id();
let global_const_id = cid.display(tcx);
let span = tcx.hir_span_if_local(did);
match err {
ValTreeCreationError::NodesOverflow => {
let handled =
tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id });
Err(ReportedErrorInfo::allowed_in_infallible(handled).into())
}
ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)),
}
}
}
const_to_valtree_inner(&ecx, &place, &mut num_nodes)
}
/// Converts a `ValTree` to a `ConstValue`, which is needed after mir

View file

@ -92,14 +92,6 @@ pub(crate) struct PanicNonStrErr {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(const_eval_max_num_nodes_in_const)]
pub(crate) struct MaxNumNodesInConstErr {
#[primary_span]
pub span: Option<Span>,
pub global_const_id: String,
}
#[derive(Diagnostic)]
#[diag(const_eval_unallowed_fn_pointer_call)]
pub(crate) struct UnallowedFnPointerCall {
@ -158,8 +150,8 @@ pub(crate) struct UnmarkedIntrinsicExposed {
}
#[derive(Diagnostic)]
#[diag(const_eval_mutable_ref_escaping, code = E0764)]
pub(crate) struct MutableRefEscaping {
#[diag(const_eval_mutable_borrow_escaping, code = E0764)]
pub(crate) struct MutableBorrowEscaping {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
@ -167,15 +159,6 @@ pub(crate) struct MutableRefEscaping {
pub teach: bool,
}
#[derive(Diagnostic)]
#[diag(const_eval_mutable_raw_escaping, code = E0764)]
pub(crate) struct MutableRawEscaping {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
#[note(const_eval_teach_note)]
pub teach: bool,
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_fmt_macro_call, code = E0015)]
pub(crate) struct NonConstFmtMacroCall {
@ -233,8 +216,8 @@ pub(crate) struct UnallowedInlineAsm {
}
#[derive(Diagnostic)]
#[diag(const_eval_interior_mutable_ref_escaping, code = E0492)]
pub(crate) struct InteriorMutableRefEscaping {
#[diag(const_eval_interior_mutable_borrow_escaping, code = E0492)]
pub(crate) struct InteriorMutableBorrowEscaping {
#[primary_span]
#[label]
pub span: Span,
@ -655,9 +638,8 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
PointerAsInt { .. } => const_eval_validation_pointer_as_int,
PartialPointer => const_eval_validation_partial_pointer,
ConstRefToMutable => const_eval_validation_const_ref_to_mutable,
ConstRefToExtern => const_eval_validation_const_ref_to_extern,
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
NullFnPtr => const_eval_validation_null_fn_ptr,
NeverVal => const_eval_validation_never_val,
NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
@ -815,9 +797,8 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
err.arg("expected_dyn_type", expected_dyn_type.to_string());
}
NullPtr { .. }
| ConstRefToMutable
| ConstRefToExtern
| MutableRefToImmutable
| MutableRefInConst
| NullFnPtr
| NeverVal
| UnsafeCellInImmutable

View file

@ -570,6 +570,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
};
let (size, _align) =
global_alloc.size_and_align(*self.ecx.tcx, self.ecx.typing_env);
let alloc_actual_mutbl =
global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env);
if let GlobalAlloc::Static(did) = global_alloc {
let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else {
@ -597,9 +599,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
skip_recursive_check = !nested;
}
CtfeValidationMode::Const { .. } => {
// We can't recursively validate `extern static`, so we better reject them.
if self.ecx.tcx.is_foreign_item(did) {
throw_validation_failure!(self.path, ConstRefToExtern);
// If this is mutable memory or an `extern static`, there's no point in checking it -- we'd
// just get errors trying to read the value.
if alloc_actual_mutbl.is_mut() || self.ecx.tcx.is_foreign_item(did)
{
skip_recursive_check = true;
}
}
}
@ -618,9 +622,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
mutbl
}
};
// Determine what it actually points to.
let alloc_actual_mutbl =
global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env);
// Mutable pointer to immutable memory is no good.
if ptr_expected_mutbl == Mutability::Mut
&& alloc_actual_mutbl == Mutability::Not
@ -628,12 +629,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
// This can actually occur with transmutes.
throw_validation_failure!(self.path, MutableRefToImmutable);
}
// In a const, everything must be completely immutable.
// In a const, any kind of mutable reference is not good.
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. })) {
if ptr_expected_mutbl == Mutability::Mut
|| alloc_actual_mutbl == Mutability::Mut
{
throw_validation_failure!(self.path, ConstRefToMutable);
if ptr_expected_mutbl == Mutability::Mut {
throw_validation_failure!(self.path, MutableRefInConst);
}
}
}

View file

@ -312,7 +312,7 @@ fn check_opaque_meets_bounds<'tcx>(
// here rather than using ReErased.
let hidden_ty = tcx.type_of(def_id.to_def_id()).instantiate(tcx, args);
let hidden_ty = fold_regions(tcx, hidden_ty, |re, _dbi| match re.kind() {
ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
ty::ReErased => infcx.next_region_var(RegionVariableOrigin::Misc(span)),
_ => re,
});

View file

@ -9,7 +9,7 @@ use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, pluralize, struct_
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit};
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::infer::{self, BoundRegionConversionTime, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{
@ -311,7 +311,7 @@ fn compare_method_predicate_entailment<'tcx>(
let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars(
impl_m_span,
infer::HigherRankedType,
BoundRegionConversionTime::HigherRankedType,
tcx.fn_sig(impl_m.def_id).instantiate_identity(),
);
@ -518,7 +518,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
param_env,
infcx.instantiate_binder_with_fresh_vars(
return_span,
infer::HigherRankedType,
BoundRegionConversionTime::HigherRankedType,
tcx.fn_sig(impl_m.def_id).instantiate_identity(),
),
);

View file

@ -11,7 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{AmbigArg, ItemKind};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin, TyCtxtInferExt};
use rustc_lint_defs::builtin::SUPERTRAIT_ITEM_SHADOWING_DEFINITION;
use rustc_macros::LintDiagnostic;
use rustc_middle::mir::interpret::ErrorHandled;
@ -739,7 +739,7 @@ fn ty_known_to_outlive<'tcx>(
infcx.register_type_outlives_constraint_inner(infer::TypeOutlivesConstraint {
sub_region: region,
sup_type: ty,
origin: infer::RelateParamBound(DUMMY_SP, ty, None),
origin: SubregionOrigin::RelateParamBound(DUMMY_SP, ty, None),
});
})
}
@ -755,7 +755,11 @@ fn region_known_to_outlive<'tcx>(
region_b: ty::Region<'tcx>,
) -> bool {
test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
infcx.sub_regions(infer::RelateRegionParamBound(DUMMY_SP, None), region_b, region_a);
infcx.sub_regions(
SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None),
region_b,
region_a,
);
})
}
@ -1491,7 +1495,9 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
ty::ConstKind::Unevaluated(uv) => {
infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
}
ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(wfcx.param_env),
ty::ConstKind::Param(param_ct) => {
param_ct.find_const_ty_from_env(wfcx.param_env)
}
};
let param_ty = tcx.type_of(param.def_id).instantiate_identity();

View file

@ -10,7 +10,7 @@ use rustc_hir as hir;
use rustc_hir::ItemKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt};
use rustc_infer::infer::{self, RegionResolutionError, SubregionOrigin, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::print::PrintTraitRefExt as _;
@ -415,7 +415,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
};
let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
(&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a);
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))

View file

@ -7,7 +7,7 @@ use rustc_hir::def::{self, CtorKind, Namespace, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, HirId, LangItem};
use rustc_hir_analysis::autoderef::Autoderef;
use rustc_infer::infer;
use rustc_infer::infer::BoundRegionConversionTime;
use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
@ -219,7 +219,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let closure_sig = args.as_closure().sig();
let closure_sig = self.instantiate_binder_with_fresh_vars(
call_expr.span,
infer::FnCall,
BoundRegionConversionTime::FnCall,
closure_sig,
);
let adjustments = self.adjust_steps(autoderef);
@ -246,7 +246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let closure_args = args.as_coroutine_closure();
let coroutine_closure_sig = self.instantiate_binder_with_fresh_vars(
call_expr.span,
infer::FnCall,
BoundRegionConversionTime::FnCall,
closure_args.coroutine_closure_sig(),
);
let tupled_upvars_ty = self.next_ty_var(callee_expr.span);
@ -545,7 +545,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// renormalize the associated types at this point, since they
// previously appeared within a `Binder<>` and hence would not
// have been normalized before.
let fn_sig = self.instantiate_binder_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig);
let fn_sig = self.instantiate_binder_with_fresh_vars(
call_expr.span,
BoundRegionConversionTime::FnCall,
fn_sig,
);
let fn_sig = self.normalize(call_expr.span, fn_sig);
self.check_argument_types(

View file

@ -58,7 +58,7 @@ pub(super) fn check_fn<'a, 'tcx>(
let maybe_va_list = fn_sig.c_variadic.then(|| {
let span = body.params.last().unwrap().span;
let va_list_did = tcx.require_lang_item(LangItem::VaList, span);
let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
let region = fcx.next_region_var(RegionVariableOrigin::Misc(span));
tcx.type_of(va_list_did).instantiate(tcx, &[region.into()])
});

View file

@ -44,7 +44,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_infer::infer::relate::RelateResult;
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, InferResult, RegionVariableOrigin};
use rustc_infer::traits::{
MatchExpressionArmCause, Obligation, PredicateObligation, PredicateObligations, SelectionError,
};
@ -430,7 +430,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
} else {
if r_borrow_var.is_none() {
// create var lazily, at most once
let coercion = Coercion(span);
let coercion = RegionVariableOrigin::Coercion(span);
let r = self.next_region_var(coercion);
r_borrow_var = Some(r); // [4] above
}
@ -548,7 +548,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
(&ty::Ref(_, ty_a, mutbl_a), &ty::Ref(_, _, mutbl_b)) => {
coerce_mutbls(mutbl_a, mutbl_b)?;
let coercion = Coercion(self.cause.span);
let coercion = RegionVariableOrigin::Coercion(self.cause.span);
let r_borrow = self.next_region_var(coercion);
// We don't allow two-phase borrows here, at least for initial
@ -671,7 +671,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
return Err(TypeError::Mismatch);
}
}
Err(traits::Unimplemented) => {
Err(SelectionError::Unimplemented) => {
debug!("coerce_unsized: early return - can't prove obligation");
return Err(TypeError::Mismatch);
}

View file

@ -22,8 +22,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, HirId, QPath};
use rustc_hir_analysis::NoVariantNamed;
use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _};
use rustc_infer::infer;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin};
use rustc_infer::traits::query::NoSolution;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@ -705,7 +704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// this time with enough precision to check that the value
// whose address was taken can actually be made to live as long
// as it needs to live.
let region = self.next_region_var(infer::BorrowRegion(expr.span));
let region = self.next_region_var(RegionVariableOrigin::BorrowRegion(expr.span));
match kind {
hir::BorrowKind::Ref => Ty::new_ref(self.tcx, region, ty, mutbl),
hir::BorrowKind::Pin => Ty::new_pinned_ref(self.tcx, region, ty, mutbl),

View file

@ -11,7 +11,7 @@ use rustc_hir::{ExprKind, HirId, LangItem, Node, QPath};
use rustc_hir_analysis::check::potentially_plural_count;
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants};
use rustc_index::IndexVec;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace};
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TypeTrace};
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
@ -30,7 +30,6 @@ use crate::TupleArgumentsFlag::*;
use crate::coercion::CoerceMany;
use crate::errors::SuggestPtrNullMut;
use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
use crate::fn_ctxt::infer::FnCall;
use crate::gather_locals::Declaration;
use crate::inline_asm::InlineAsmCtxt;
use crate::method::probe::IsSuggestion;
@ -657,7 +656,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id);
let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args);
self.instantiate_binder_with_fresh_vars(call_name.span, FnCall, fn_sig);
self.instantiate_binder_with_fresh_vars(
call_name.span,
BoundRegionConversionTime::FnCall,
fn_sig,
);
}
None
};

View file

@ -15,7 +15,7 @@ use rustc_hir::{self as hir, HirId, ItemLocalMap};
use rustc_hir_analysis::hir_ty_lowering::{
HirTyLowerer, InherentAssocCandidate, RegionInferReason,
};
use rustc_infer::infer;
use rustc_infer::infer::{self, RegionVariableOrigin};
use rustc_infer::traits::{DynCompatibilityViolation, Obligation};
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::Session;
@ -244,8 +244,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
let v = match reason {
RegionInferReason::Param(def) => infer::RegionParameterDefinition(span, def.name),
_ => infer::MiscVariable(span),
RegionInferReason::Param(def) => {
RegionVariableOrigin::RegionParameterDefinition(span, def.name)
}
_ => RegionVariableOrigin::Misc(span),
};
self.next_region_var(v)
}

View file

@ -9,7 +9,9 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{
use rustc_hir_analysis::hir_ty_lowering::{
FeedConstTy, GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason,
};
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
use rustc_infer::infer::{
BoundRegionConversionTime, DefineOpaqueTypes, InferOk, RegionVariableOrigin,
};
use rustc_lint::builtin::SUPERTRAIT_ITEM_SHADOWING_USAGE;
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::adjustment::{
@ -194,7 +196,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
match pick.autoref_or_ptr_adjustment {
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
let region = self.next_region_var(infer::Autoref(self.span));
let region = self.next_region_var(RegionVariableOrigin::Autoref(self.span));
// Type we're wrapping in a reference, used later for unsizing
let base_ty = target;
@ -239,7 +241,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
}
Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => {
let region = self.next_region_var(infer::Autoref(self.span));
let region = self.next_region_var(RegionVariableOrigin::Autoref(self.span));
target = match target.kind() {
ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => {
@ -752,6 +754,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
{
self.fcx.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, value)
self.fcx.instantiate_binder_with_fresh_vars(
self.span,
BoundRegionConversionTime::FnCall,
value,
)
}
}

View file

@ -11,7 +11,7 @@ use rustc_errors::{Applicability, Diag, SubdiagMessage};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace};
use rustc_hir::def_id::DefId;
use rustc_infer::infer::{self, InferOk};
use rustc_infer::infer::{BoundRegionConversionTime, InferOk};
use rustc_infer::traits::PredicateObligations;
use rustc_middle::query::Providers;
use rustc_middle::traits::ObligationCause;
@ -400,8 +400,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// function signature so that normalization does not need to deal
// with bound regions.
let fn_sig = tcx.fn_sig(def_id).instantiate(self.tcx, args);
let fn_sig =
self.instantiate_binder_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
let fn_sig = self.instantiate_binder_with_fresh_vars(
obligation.cause.span,
BoundRegionConversionTime::FnCall,
fn_sig,
);
let InferOk { value: fn_sig, obligations: o } =
self.at(&obligation.cause, self.param_env).normalize(fn_sig);

View file

@ -12,7 +12,7 @@ use rustc_hir::HirId;
use rustc_hir::def::DefKind;
use rustc_hir_analysis::autoderef::{self, Autoderef};
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, TyCtxtInferExt};
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt};
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::middle::stability;
use rustc_middle::query::Providers;
@ -995,7 +995,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
ty::AssocKind::Fn { .. } => self.probe(|_| {
let args = self.fresh_args_for_item(self.span, method.def_id);
let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args);
let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
let fty = self.instantiate_binder_with_fresh_vars(
self.span,
BoundRegionConversionTime::FnCall,
fty,
);
self.can_eq(self.param_env, fty.output(), expected)
}),
_ => false,
@ -1756,8 +1760,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
CandidateSource::Trait(candidate.item.container_id(self.tcx))
}
TraitCandidate(trait_ref) => self.probe(|_| {
let trait_ref =
self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, trait_ref);
let trait_ref = self.instantiate_binder_with_fresh_vars(
self.span,
BoundRegionConversionTime::FnCall,
trait_ref,
);
let (xform_self_ty, _) =
self.xform_self_ty(candidate.item, trait_ref.self_ty(), trait_ref.args);
// Guide the trait selection to show impls that have methods whose type matches
@ -1873,7 +1880,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let trait_ref = self.instantiate_binder_with_fresh_vars(
self.span,
infer::FnCall,
BoundRegionConversionTime::FnCall,
poly_trait_ref,
);
let trait_ref = ocx.normalize(cause, self.param_env, trait_ref);
@ -1936,7 +1943,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => {
let trait_ref = self.instantiate_binder_with_fresh_vars(
self.span,
infer::FnCall,
BoundRegionConversionTime::FnCall,
poly_trait_ref,
);
(xform_self_ty, xform_ret_ty) =

View file

@ -22,7 +22,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{self as hir, ExprKind, HirId, Node, PathSegment, QPath};
use rustc_infer::infer::{self, RegionVariableOrigin};
use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin};
use rustc_middle::bug;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type};
use rustc_middle::ty::print::{
@ -1951,7 +1951,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if def_kind == DefKind::AssocFn {
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
let fn_sig = self.instantiate_binder_with_fresh_vars(
span,
BoundRegionConversionTime::FnCall,
fn_sig,
);
if similar_candidate.is_method() {
if let Some(args) = args
&& fn_sig.inputs()[1..].len() == args.len()
@ -2033,7 +2037,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.fn_sig(inherent_method.def_id).instantiate(self.tcx, args);
let fn_sig = self.instantiate_binder_with_fresh_vars(
item_name.span,
infer::FnCall,
BoundRegionConversionTime::FnCall,
fn_sig,
);
let name = inherent_method.name();
@ -2348,9 +2352,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !arg.is_suggestable(self.tcx, true) {
has_unsuggestable_args = true;
match arg.kind() {
GenericArgKind::Lifetime(_) => self
.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
.into(),
GenericArgKind::Lifetime(_) => {
self.next_region_var(RegionVariableOrigin::Misc(DUMMY_SP)).into()
}
GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(),
GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(),
}

View file

@ -16,7 +16,7 @@ use rustc_hir::{
PatExprKind, PatKind, expr_needs_parens,
};
use rustc_hir_analysis::autoderef::report_autoderef_recursion_limit_error;
use rustc_infer::infer;
use rustc_infer::infer::RegionVariableOrigin;
use rustc_middle::traits::PatternOriginExpr;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_middle::{bug, span_bug};
@ -2777,7 +2777,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Create a reference type with a fresh region variable.
fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
let region = self.next_region_var(infer::PatternRegion(span));
let region = self.next_region_var(RegionVariableOrigin::PatternRegion(span));
Ty::new_ref(self.tcx, region, ty, mutbl)
}

View file

@ -128,10 +128,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
CanonicalVarKind::Region(ui) => self
.next_region_var_in_universe(
RegionVariableOrigin::MiscVariable(span),
universe_map(ui),
)
.next_region_var_in_universe(RegionVariableOrigin::Misc(span), universe_map(ui))
.into(),
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, bound }) => {

View file

@ -141,7 +141,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
}
fn next_region_infer(&self) -> ty::Region<'tcx> {
self.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
self.next_region_var(RegionVariableOrigin::Misc(DUMMY_SP))
}
fn next_ty_infer(&self) -> Ty<'tcx> {

View file

@ -1,9 +1,6 @@
use std::cell::{Cell, RefCell};
use std::fmt;
pub use BoundRegionConversionTime::*;
pub use RegionVariableOrigin::*;
pub use SubregionOrigin::*;
pub use at::DefineOpaqueTypes;
use free_regions::RegionRelations;
pub use freshen::TypeFreshener;
@ -403,7 +400,7 @@ pub enum RegionVariableOrigin {
/// Region variables created for ill-categorized reasons.
///
/// They mostly indicate places in need of refactoring.
MiscVariable(Span),
Misc(Span),
/// Regions created by a `&P` or `[...]` pattern.
PatternRegion(Span),
@ -467,21 +464,19 @@ pub struct FixupError {
impl fmt::Display for FixupError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use TyOrConstInferVar::*;
match self.unresolved {
TyInt(_) => write!(
TyOrConstInferVar::TyInt(_) => write!(
f,
"cannot determine the type of this integer; \
add a suffix to specify the type explicitly"
),
TyFloat(_) => write!(
TyOrConstInferVar::TyFloat(_) => write!(
f,
"cannot determine the type of this number; \
add a suffix to specify the type explicitly"
),
Ty(_) => write!(f, "unconstrained type"),
Const(_) => write!(f, "unconstrained const value"),
TyOrConstInferVar::Ty(_) => write!(f, "unconstrained type"),
TyOrConstInferVar::Const(_) => write!(f, "unconstrained const value"),
}
}
}
@ -865,7 +860,10 @@ impl<'tcx> InferCtxt<'tcx> {
GenericParamDefKind::Lifetime => {
// Create a region inference variable for the given
// region parameter definition.
self.next_region_var(RegionParameterDefinition(span, param.name)).into()
self.next_region_var(RegionVariableOrigin::RegionParameterDefinition(
span, param.name,
))
.into()
}
GenericParamDefKind::Type { .. } => {
// Create a type inference variable for the given
@ -1172,7 +1170,7 @@ impl<'tcx> InferCtxt<'tcx> {
let arg: ty::GenericArg<'_> = match bound_var_kind {
ty::BoundVariableKind::Ty(_) => self.next_ty_var(span).into(),
ty::BoundVariableKind::Region(br) => {
self.next_region_var(BoundRegion(span, br, lbrct)).into()
self.next_region_var(RegionVariableOrigin::BoundRegion(span, br, lbrct)).into()
}
ty::BoundVariableKind::Const => self.next_const_var(span).into(),
};
@ -1472,15 +1470,15 @@ impl<'tcx> TypeTrace<'tcx> {
impl<'tcx> SubregionOrigin<'tcx> {
pub fn span(&self) -> Span {
match *self {
Subtype(ref a) => a.span(),
RelateObjectBound(a) => a,
RelateParamBound(a, ..) => a,
RelateRegionParamBound(a, _) => a,
Reborrow(a) => a,
ReferenceOutlivesReferent(_, a) => a,
CompareImplItemObligation { span, .. } => span,
AscribeUserTypeProvePredicate(span) => span,
CheckAssociatedTypeBounds { ref parent, .. } => parent.span(),
SubregionOrigin::Subtype(ref a) => a.span(),
SubregionOrigin::RelateObjectBound(a) => a,
SubregionOrigin::RelateParamBound(a, ..) => a,
SubregionOrigin::RelateRegionParamBound(a, _) => a,
SubregionOrigin::Reborrow(a) => a,
SubregionOrigin::ReferenceOutlivesReferent(_, a) => a,
SubregionOrigin::CompareImplItemObligation { span, .. } => span,
SubregionOrigin::AscribeUserTypeProvePredicate(span) => span,
SubregionOrigin::CheckAssociatedTypeBounds { ref parent, .. } => parent.span(),
}
}
@ -1528,15 +1526,15 @@ impl<'tcx> SubregionOrigin<'tcx> {
impl RegionVariableOrigin {
pub fn span(&self) -> Span {
match *self {
MiscVariable(a)
| PatternRegion(a)
| BorrowRegion(a)
| Autoref(a)
| Coercion(a)
| RegionParameterDefinition(a, ..)
| BoundRegion(a, ..)
| UpvarRegion(_, a) => a,
Nll(..) => bug!("NLL variable used with `span`"),
RegionVariableOrigin::Misc(a)
| RegionVariableOrigin::PatternRegion(a)
| RegionVariableOrigin::BorrowRegion(a)
| RegionVariableOrigin::Autoref(a)
| RegionVariableOrigin::Coercion(a)
| RegionVariableOrigin::RegionParameterDefinition(a, ..)
| RegionVariableOrigin::BoundRegion(a, ..)
| RegionVariableOrigin::UpvarRegion(_, a) => a,
RegionVariableOrigin::Nll(..) => bug!("NLL variable used with `span`"),
}
}
}

View file

@ -262,9 +262,7 @@ impl<'tcx> InferCtxt<'tcx> {
.type_of_opaque_hir_typeck(opaque_type_key.def_id)
.instantiate(self.tcx, opaque_type_key.args);
let actual = ty::fold_regions(tcx, actual, |re, _dbi| match re.kind() {
ty::ReErased => {
self.next_region_var(RegionVariableOrigin::MiscVariable(span))
}
ty::ReErased => self.next_region_var(RegionVariableOrigin::Misc(span)),
_ => re,
});
actual

View file

@ -141,7 +141,7 @@ impl<'tcx> InferCtxt<'tcx> {
debug!(?sup_type, ?sub_region, ?cause);
let origin = SubregionOrigin::from_obligation_cause(cause, || {
infer::RelateParamBound(
SubregionOrigin::RelateParamBound(
cause.span,
sup_type,
match cause.code().peel_derives() {

View file

@ -14,7 +14,7 @@ use tracing::{debug, instrument};
use self::CombineMapType::*;
use self::UndoLog::*;
use super::{MiscVariable, RegionVariableOrigin, Rollback, SubregionOrigin};
use super::{RegionVariableOrigin, Rollback, SubregionOrigin};
use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot};
use crate::infer::unify_key::{RegionVariableValue, RegionVidKey};
@ -580,7 +580,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
let a_universe = self.universe(a);
let b_universe = self.universe(b);
let c_universe = cmp::max(a_universe, b_universe);
let c = self.new_region_var(c_universe, MiscVariable(origin.span()));
let c = self.new_region_var(c_universe, RegionVariableOrigin::Misc(origin.span()));
self.combine_map(t).insert(vars, c);
self.undo_log.push(AddCombination(t, vars));
let new_r = ty::Region::new_var(tcx, c);

View file

@ -603,10 +603,9 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
}
}
Ok(self.infcx.next_region_var_in_universe(
RegionVariableOrigin::MiscVariable(self.span),
self.for_universe,
))
Ok(self
.infcx
.next_region_var_in_universe(RegionVariableOrigin::Misc(self.span), self.for_universe))
}
#[instrument(level = "debug", skip(self, c2), ret)]

View file

@ -5,6 +5,7 @@ use rustc_middle::ty::{
};
use super::{FixupError, FixupResult, InferCtxt};
use crate::infer::TyOrConstInferVar;
///////////////////////////////////////////////////////////////////////////
// OPPORTUNISTIC VAR RESOLVER
@ -144,13 +145,17 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
if !t.has_infer() {
Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
use super::TyOrConstInferVar::*;
let t = self.infcx.shallow_resolve(t);
match *t.kind() {
ty::Infer(ty::TyVar(vid)) => Err(FixupError { unresolved: Ty(vid) }),
ty::Infer(ty::IntVar(vid)) => Err(FixupError { unresolved: TyInt(vid) }),
ty::Infer(ty::FloatVar(vid)) => Err(FixupError { unresolved: TyFloat(vid) }),
ty::Infer(ty::TyVar(vid)) => {
Err(FixupError { unresolved: TyOrConstInferVar::Ty(vid) })
}
ty::Infer(ty::IntVar(vid)) => {
Err(FixupError { unresolved: TyOrConstInferVar::TyInt(vid) })
}
ty::Infer(ty::FloatVar(vid)) => {
Err(FixupError { unresolved: TyOrConstInferVar::TyFloat(vid) })
}
ty::Infer(_) => {
bug!("Unexpected type in full type resolver: {:?}", t);
}

View file

@ -19,7 +19,8 @@ pub enum ScrubbedTraitError<'tcx> {
TrueError,
/// An ambiguity. This goal may hold if further inference is done.
Ambiguity,
/// An old-solver-style cycle error, which will fatal.
/// An old-solver-style cycle error, which will fatal. This is not
/// returned by the new solver.
Cycle(PredicateObligations<'tcx>),
}

View file

@ -20,8 +20,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
use rustc_span::Span;
use thin_vec::ThinVec;
pub use self::ImplSource::*;
pub use self::SelectionError::*;
pub use self::engine::{FromSolverError, ScrubbedTraitError, TraitEngine};
pub(crate) use self::project::UndoLog;
pub use self::project::{

View file

@ -977,9 +977,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
};
match it.kind {
hir::ItemKind::Fn { generics, .. } => {
if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name)
.map(|at| at.span())
.or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
if let Some(attr_span) =
find_attr!(attrs, AttributeKind::ExportName {span, ..} => *span)
.or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
{
check_no_mangle_on_generic_fn(attr_span, None, generics, it.span);
}
@ -1010,9 +1010,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
for it in *items {
if let hir::AssocItemKind::Fn { .. } = it.kind {
let attrs = cx.tcx.hir_attrs(it.id.hir_id());
if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name)
.map(|at| at.span())
.or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
if let Some(attr_span) =
find_attr!(attrs, AttributeKind::ExportName {span, ..} => *span)
.or_else(
|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span),
)
{
check_no_mangle_on_generic_fn(
attr_span,

View file

@ -78,6 +78,11 @@ middle_erroneous_constant = erroneous constant encountered
middle_failed_writing_file =
failed to write file {$path}: {$error}"
# Note: We only mention patterns here since the error can only occur with references, and those
# are forbidden in const generics.
middle_invalid_const_in_valtree = constant {$global_const_id} cannot be used as pattern
.note = constants that reference mutable or external memory cannot be used as pattern
middle_layout_cycle =
a cycle occurred during layout computation
@ -95,6 +100,8 @@ middle_layout_too_generic = the type `{$ty}` does not have a fixed layout
middle_layout_unknown =
the type `{$ty}` has an unknown layout
middle_max_num_nodes_in_valtree = maximum number of nodes exceeded in constant {$global_const_id}
middle_opaque_hidden_type_mismatch =
concrete type differs from previous defining opaque type use
.label = expected `{$self_ty}`, got `{$other_ty}`

View file

@ -170,3 +170,20 @@ pub(crate) struct TypeLengthLimit {
pub path: PathBuf,
pub type_length: usize,
}
#[derive(Diagnostic)]
#[diag(middle_max_num_nodes_in_valtree)]
pub(crate) struct MaxNumNodesInValtree {
#[primary_span]
pub span: Span,
pub global_const_id: String,
}
#[derive(Diagnostic)]
#[diag(middle_invalid_const_in_valtree)]
#[note]
pub(crate) struct InvalidConstInValtree {
#[primary_span]
pub span: Span,
pub global_const_id: String,
}

View file

@ -35,7 +35,7 @@ impl From<ReportedErrorInfo> for ErrorHandled {
}
impl ErrorHandled {
pub fn with_span(self, span: Span) -> Self {
pub(crate) fn with_span(self, span: Span) -> Self {
match self {
ErrorHandled::Reported(err, _span) => ErrorHandled::Reported(err, span),
ErrorHandled::TooGeneric(_span) => ErrorHandled::TooGeneric(span),
@ -94,14 +94,51 @@ impl From<ReportedErrorInfo> for ErrorGuaranteed {
}
}
/// An error type for the `const_to_valtree` query. Some error should be reported with a "use-site span",
/// which means the query cannot emit the error, so those errors are represented as dedicated variants here.
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
pub enum ValTreeCreationError<'tcx> {
/// The constant is too big to be valtree'd.
NodesOverflow,
/// The constant references mutable or external memory, so it cannot be valtree'd.
InvalidConst,
/// Values of this type, or this particular value, are not supported as valtrees.
NonSupportedType(Ty<'tcx>),
/// The error has already been handled by const evaluation.
ErrorHandled(ErrorHandled),
}
impl<'tcx> From<ErrorHandled> for ValTreeCreationError<'tcx> {
fn from(err: ErrorHandled) -> Self {
ValTreeCreationError::ErrorHandled(err)
}
}
impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> {
fn from(err: InterpErrorInfo<'tcx>) -> Self {
// An error ocurred outside the const-eval query, as part of constructing the valtree. We
// don't currently preserve the details of this error, since `InterpErrorInfo` cannot be put
// into a query result and it can only be access of some mutable or external memory.
let (_kind, backtrace) = err.into_parts();
backtrace.print_backtrace();
ValTreeCreationError::InvalidConst
}
}
impl<'tcx> ValTreeCreationError<'tcx> {
pub(crate) fn with_span(self, span: Span) -> Self {
use ValTreeCreationError::*;
match self {
ErrorHandled(handled) => ErrorHandled(handled.with_span(span)),
other => other,
}
}
}
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>;
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
/// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed
/// because the value contains something of type `ty` that is not valtree-compatible.
/// The caller can then show an appropriate error; the query does not have the
/// necessary context to give good user-facing errors for this case.
pub type EvalToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>;
pub type EvalToValTreeResult<'tcx> = Result<ValTree<'tcx>, ValTreeCreationError<'tcx>>;
#[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8);
@ -450,10 +487,9 @@ pub enum ValidationErrorKind<'tcx> {
ptr_kind: PointerKind,
ty: Ty<'tcx>,
},
ConstRefToMutable,
ConstRefToExtern,
MutableRefToImmutable,
UnsafeCellInImmutable,
MutableRefInConst,
NullFnPtr,
NeverVal,
NullablePtrOutOfRange {

View file

@ -38,8 +38,8 @@ pub use self::error::{
EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind,
InterpErrorInfo, InterpErrorKind, InterpResult, InvalidMetaKind, InvalidProgramInfo,
MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo,
ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
ValidationErrorKind, interp_ok,
ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValTreeCreationError,
ValidationErrorInfo, ValidationErrorKind, interp_ok,
};
pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance};
pub use self::value::Scalar;

View file

@ -5,11 +5,11 @@ use rustc_span::{DUMMY_SP, Span};
use tracing::{debug, instrument};
use super::{
ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId,
ReportedErrorInfo,
ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, GlobalId, ReportedErrorInfo,
};
use crate::mir;
use crate::ty::{self, GenericArgs, TyCtxt, TypeVisitableExt};
use crate::mir::interpret::ValTreeCreationError;
use crate::ty::{self, ConstToValTreeResult, GenericArgs, TyCtxt, TypeVisitableExt};
use crate::{error, mir};
impl<'tcx> TyCtxt<'tcx> {
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
@ -92,7 +92,7 @@ impl<'tcx> TyCtxt<'tcx> {
typing_env: ty::TypingEnv<'tcx>,
ct: ty::UnevaluatedConst<'tcx>,
span: Span,
) -> EvalToValTreeResult<'tcx> {
) -> ConstToValTreeResult<'tcx> {
// Cannot resolve `Unevaluated` constants that contain inference
// variables. We reject those here since `resolve`
// would fail otherwise.
@ -103,47 +103,54 @@ impl<'tcx> TyCtxt<'tcx> {
bug!("did not expect inference variables here");
}
match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted: None };
self.const_eval_global_id_for_typeck(typing_env, cid, span).inspect(|_| {
// We are emitting the lint here instead of in `is_const_evaluatable`
// as we normalize obligations before checking them, and normalization
// uses this function to evaluate this constant.
//
// @lcnr believes that successfully evaluating even though there are
// used generic parameters is a bug of evaluation, so checking for it
// here does feel somewhat sensible.
if !self.features().generic_const_exprs()
&& ct.args.has_non_region_param()
// We only FCW for anon consts as repeat expr counts with anon consts are the only place
// that we have a back compat hack for. We don't need to check this is a const argument
// as only anon consts as const args should get evaluated "for the type system".
//
// If we don't *only* FCW anon consts we can wind up incorrectly FCW'ing uses of assoc
// consts in pattern positions. #140447
&& self.def_kind(instance.def_id()) == DefKind::AnonConst
{
let mir_body = self.mir_for_ctfe(instance.def_id());
if mir_body.is_polymorphic {
let Some(local_def_id) = ct.def.as_local() else { return };
self.node_span_lint(
lint::builtin::CONST_EVALUATABLE_UNCHECKED,
self.local_def_id_to_hir_id(local_def_id),
self.def_span(ct.def),
|lint| { lint.primary_message("cannot use constants which depend on generic parameters in types"); },
)
}
}
})
}
let cid = match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) {
Ok(Some(instance)) => GlobalId { instance, promoted: None },
// For errors during resolution, we deliberately do not point at the usage site of the constant,
// since for these errors the place the constant is used shouldn't matter.
Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
Ok(None) => return Err(ErrorHandled::TooGeneric(DUMMY_SP).into()),
Err(err) => {
Err(ErrorHandled::Reported(ReportedErrorInfo::non_const_eval_error(err), DUMMY_SP))
return Err(ErrorHandled::Reported(
ReportedErrorInfo::non_const_eval_error(err),
DUMMY_SP,
)
.into());
}
}
};
self.const_eval_global_id_for_typeck(typing_env, cid, span).inspect(|_| {
// We are emitting the lint here instead of in `is_const_evaluatable`
// as we normalize obligations before checking them, and normalization
// uses this function to evaluate this constant.
//
// @lcnr believes that successfully evaluating even though there are
// used generic parameters is a bug of evaluation, so checking for it
// here does feel somewhat sensible.
if !self.features().generic_const_exprs()
&& ct.args.has_non_region_param()
// We only FCW for anon consts as repeat expr counts with anon consts are the only place
// that we have a back compat hack for. We don't need to check this is a const argument
// as only anon consts as const args should get evaluated "for the type system".
//
// If we don't *only* FCW anon consts we can wind up incorrectly FCW'ing uses of assoc
// consts in pattern positions. #140447
&& self.def_kind(cid.instance.def_id()) == DefKind::AnonConst
{
let mir_body = self.mir_for_ctfe(cid.instance.def_id());
if mir_body.is_polymorphic {
let Some(local_def_id) = ct.def.as_local() else { return };
self.node_span_lint(
lint::builtin::CONST_EVALUATABLE_UNCHECKED,
self.local_def_id_to_hir_id(local_def_id),
self.def_span(ct.def),
|lint| {
lint.primary_message(
"cannot use constants which depend on generic parameters in types",
);
},
)
}
}
})
}
pub fn const_eval_instance(
@ -182,17 +189,42 @@ impl<'tcx> TyCtxt<'tcx> {
typing_env: ty::TypingEnv<'tcx>,
cid: GlobalId<'tcx>,
span: Span,
) -> EvalToValTreeResult<'tcx> {
) -> ConstToValTreeResult<'tcx> {
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
// improve caching of queries.
let inputs =
self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid));
debug!(?inputs);
if !span.is_dummy() {
let res = if !span.is_dummy() {
// The query doesn't know where it is being invoked, so we need to fix the span.
self.at(span).eval_to_valtree(inputs).map_err(|e| e.with_span(span))
} else {
self.eval_to_valtree(inputs)
};
match res {
Ok(valtree) => Ok(Ok(valtree)),
Err(err) => {
match err {
// Let the caller decide how to handle this.
ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)),
// Report the others.
ValTreeCreationError::NodesOverflow => {
let handled = self.dcx().emit_err(error::MaxNumNodesInValtree {
span,
global_const_id: cid.display(self),
});
Err(ReportedErrorInfo::allowed_in_infallible(handled).into())
}
ValTreeCreationError::InvalidConst => {
let handled = self.dcx().emit_err(error::InvalidConstInValtree {
span,
global_const_id: cid.display(self),
});
Err(ReportedErrorInfo::allowed_in_infallible(handled).into())
}
ValTreeCreationError::ErrorHandled(handled) => Err(handled),
}
}
}
}
}

View file

@ -4,6 +4,7 @@ use std::mem::MaybeUninit;
use rustc_span::ErrorGuaranteed;
use crate::mir::interpret::EvalToValTreeResult;
use crate::query::CyclePlaceholder;
use crate::ty::adjustment::CoerceUnsizedInfo;
use crate::ty::{self, Ty, TyCtxt};
@ -156,10 +157,8 @@ impl EraseType for Result<mir::ConstValue<'_>, mir::interpret::ErrorHandled> {
type Result = [u8; size_of::<Result<mir::ConstValue<'static>, mir::interpret::ErrorHandled>>()];
}
impl EraseType for Result<Result<ty::ValTree<'_>, Ty<'_>>, mir::interpret::ErrorHandled> {
type Result = [u8; size_of::<
Result<Result<ty::ValTree<'static>, Ty<'static>>, mir::interpret::ErrorHandled>,
>()];
impl EraseType for EvalToValTreeResult<'_> {
type Result = [u8; size_of::<EvalToValTreeResult<'static>>()];
}
impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {

View file

@ -5,7 +5,7 @@ use rustc_data_structures::intern::Interned;
use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use super::ScalarInt;
use crate::mir::interpret::Scalar;
use crate::mir::interpret::{ErrorHandled, Scalar};
use crate::ty::{self, Ty, TyCtxt};
/// This datastructure is used to represent the value of constants used in the type system.
@ -124,6 +124,12 @@ impl fmt::Debug for ValTree<'_> {
}
}
/// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed
/// because the value contains something of type `ty` that is not valtree-compatible.
/// The caller can then show an appropriate error; the query does not have the
/// necessary context to give good user-facing errors for this case.
pub type ConstToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>;
/// A type-level constant value.
///
/// Represents a typed, fully evaluated constant.

View file

@ -698,14 +698,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.unsizing_params_for_adt(adt_def_id)
}
fn find_const_ty_from_env(
self,
param_env: ty::ParamEnv<'tcx>,
placeholder: Self::PlaceholderConst,
) -> Ty<'tcx> {
placeholder.find_const_ty_from_env(param_env)
}
fn anonymize_bound_vars<T: TypeFoldable<TyCtxt<'tcx>>>(
self,
binder: ty::Binder<'tcx, T>,

View file

@ -75,8 +75,8 @@ pub use self::closure::{
place_to_string_for_capture,
};
pub use self::consts::{
AnonConstKind, AtomicOrdering, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt,
UnevaluatedConst, ValTree, ValTreeKind, Value,
AnonConstKind, AtomicOrdering, Const, ConstInt, ConstKind, ConstToValTreeResult, Expr,
ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind, Value,
};
pub use self::context::{
CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,
@ -907,30 +907,6 @@ pub struct Placeholder<T> {
pub universe: UniverseIndex,
pub bound: T,
}
impl Placeholder<BoundVar> {
pub fn find_const_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> {
let mut candidates = env.caller_bounds().iter().filter_map(|clause| {
// `ConstArgHasType` are never desugared to be higher ranked.
match clause.kind().skip_binder() {
ty::ClauseKind::ConstArgHasType(placeholder_ct, ty) => {
assert!(!(placeholder_ct, ty).has_escaping_bound_vars());
match placeholder_ct.kind() {
ty::ConstKind::Placeholder(placeholder_ct) if placeholder_ct == self => {
Some(ty)
}
_ => None,
}
}
_ => None,
}
});
let ty = candidates.next().unwrap();
assert!(candidates.next().is_none());
ty
}
}
pub type PlaceholderRegion = Placeholder<BoundRegion>;

View file

@ -346,7 +346,7 @@ impl ParamConst {
}
#[instrument(level = "debug")]
pub fn find_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> {
pub fn find_const_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> {
let mut candidates = env.caller_bounds().iter().filter_map(|clause| {
// `ConstArgHasType` are never desugared to be higher ranked.
match clause.kind().skip_binder() {
@ -362,8 +362,19 @@ impl ParamConst {
}
});
let ty = candidates.next().unwrap();
assert!(candidates.next().is_none());
// N.B. it may be tempting to fix ICEs by making this function return
// `Option<Ty<'tcx>>` instead of `Ty<'tcx>`; however, this is generally
// considered to be a bandaid solution, since it hides more important
// underlying issues with how we construct generics and predicates of
// items. It's advised to fix the underlying issue rather than trying
// to modify this function.
let ty = candidates.next().unwrap_or_else(|| {
bug!("cannot find `{self:?}` in param-env: {env:#?}");
});
assert!(
candidates.next().is_none(),
"did not expect duplicate `ConstParamHasTy` for `{self:?}` in param-env: {env:#?}"
);
ty
}
}

View file

@ -326,11 +326,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Intern
let kind_ty = args.kind_ty();
let sig = args.coroutine_closure_sig().skip_binder();
// FIXME: let_chains
let kind = kind_ty.to_opt_closure_kind();
let coroutine_ty = if kind.is_some() && !args.tupled_upvars_ty().is_ty_var() {
let closure_kind = kind.unwrap();
if !closure_kind.extends(goal_kind) {
let coroutine_ty = if let Some(kind) = kind_ty.to_opt_closure_kind()
&& !args.tupled_upvars_ty().is_ty_var()
{
if !kind.extends(goal_kind) {
return Err(NoSolution);
}
@ -435,10 +434,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I:
let sig = args.coroutine_closure_sig().skip_binder();
let mut nested = vec![];
// FIXME: let_chains
let kind = kind_ty.to_opt_closure_kind();
let coroutine_ty = if kind.is_some() && !args.tupled_upvars_ty().is_ty_var() {
if !kind.unwrap().extends(goal_kind) {
let coroutine_ty = if let Some(kind) = kind_ty.to_opt_closure_kind()
&& !args.tupled_upvars_ty().is_ty_var()
{
if !kind.extends(goal_kind) {
return Err(NoSolution);
}

View file

@ -211,7 +211,7 @@ where
ty::ConstKind::Bound(_, _) => panic!("escaping bound vars in {:?}", ct),
ty::ConstKind::Value(cv) => cv.ty(),
ty::ConstKind::Placeholder(placeholder) => {
self.cx().find_const_ty_from_env(goal.param_env, placeholder)
placeholder.find_const_ty_from_env(goal.param_env)
}
};

View file

@ -486,6 +486,11 @@ passes_missing_panic_handler =
passes_missing_stability_attr =
{$descr} has missing stability attribute
passes_mixed_export_name_and_no_mangle = `{$no_mangle_attr}` attribute may not be used in combination with `{$export_name_attr}`
.label = `{$no_mangle_attr}` is ignored
.note = `{$export_name_attr}` takes precedence
.suggestion = remove the `{$no_mangle_attr}` attribute
passes_multiple_rustc_main =
multiple functions with a `#[rustc_main]` attribute
.first = first `#[rustc_main]` function

View file

@ -30,11 +30,13 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, TyCtxt, TypingMode};
use rustc_middle::{bug, span_bug};
use rustc_session::config::CrateType;
use rustc_session::lint;
use rustc_session::lint::builtin::{
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
};
use rustc_session::parse::feature_err;
use rustc_span::edition::Edition;
use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
@ -169,6 +171,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
Attribute::Parsed(AttributeKind::Cold(attr_span)) => {
self.check_cold(hir_id, *attr_span, span, target)
}
Attribute::Parsed(AttributeKind::ExportName { span: attr_span, .. }) => {
self.check_export_name(hir_id, *attr_span, span, target)
}
Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => {
self.check_align(span, target, *align, *repr_span)
}
@ -223,7 +228,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
&mut doc_aliases,
),
[sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
[sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target),
[sym::rustc_layout_scalar_valid_range_start, ..]
| [sym::rustc_layout_scalar_valid_range_end, ..] => {
self.check_rustc_layout_scalar_valid_range(attr, span, target)
@ -401,6 +405,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.check_repr(attrs, span, target, item, hir_id);
self.check_used(attrs, target, span);
self.check_rustc_force_inline(hir_id, attrs, span, target);
self.check_mix_no_mangle_export(hir_id, attrs);
}
fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) {
@ -1653,7 +1658,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
/// Checks if `#[export_name]` is applied to a function or static.
fn check_export_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
fn check_export_name(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
match target {
Target::Static | Target::Fn => {}
Target::Method(..) if self.is_impl_item(hir_id) => {}
@ -1662,10 +1667,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
// erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "export_name");
self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "export_name");
}
_ => {
self.dcx().emit_err(errors::ExportName { attr_span: attr.span(), span });
self.dcx().emit_err(errors::ExportName { attr_span, span });
}
}
}
@ -2626,6 +2631,36 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
fn check_mix_no_mangle_export(&self, hir_id: HirId, attrs: &[Attribute]) {
if let Some(export_name_span) = find_attr!(attrs, AttributeKind::ExportName { span: export_name_span, .. } => *export_name_span)
&& let Some(no_mangle_span) =
find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span)
{
let no_mangle_attr = if no_mangle_span.edition() >= Edition::Edition2024 {
"#[unsafe(no_mangle)]"
} else {
"#[no_mangle]"
};
let export_name_attr = if export_name_span.edition() >= Edition::Edition2024 {
"#[unsafe(export_name)]"
} else {
"#[export_name]"
};
self.tcx.emit_node_span_lint(
lint::builtin::UNUSED_ATTRIBUTES,
hir_id,
no_mangle_span,
errors::MixedExportNameAndNoMangle {
no_mangle_span,
export_name_span,
no_mangle_attr,
export_name_attr,
},
);
}
}
/// Checks if `#[autodiff]` is applied to an item other than a function item.
fn check_autodiff(&self, _hir_id: HirId, _attr: &Attribute, span: Span, target: Target) {
debug!("check_autodiff");

View file

@ -49,6 +49,18 @@ pub(crate) struct ConstContinueAttr {
pub node_span: Span,
}
#[derive(LintDiagnostic)]
#[diag(passes_mixed_export_name_and_no_mangle)]
pub(crate) struct MixedExportNameAndNoMangle {
#[label]
#[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
pub no_mangle_span: Span,
#[note]
pub export_name_span: Span,
pub no_mangle_attr: &'static str,
pub export_name_attr: &'static str,
}
#[derive(LintDiagnostic)]
#[diag(passes_outer_crate_level_attr)]
pub(crate) struct OuterCrateLevelAttr;

View file

@ -1617,6 +1617,7 @@ symbols! {
pie,
pin,
pin_ergonomics,
pin_macro,
platform_intrinsics,
plugin,
plugin_registrar,

View file

@ -909,11 +909,11 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
}
}
(GenericArgKind::Const(inner_ct), TermKind::Const(target_ct)) => {
use ty::InferConst::*;
match (inner_ct.kind(), target_ct.kind()) {
(ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => {
self.tecx.root_const_var(a_vid) == self.tecx.root_const_var(b_vid)
}
(
ty::ConstKind::Infer(ty::InferConst::Var(a_vid)),
ty::ConstKind::Infer(ty::InferConst::Var(b_vid)),
) => self.tecx.root_const_var(a_vid) == self.tecx.root_const_var(b_vid),
_ => false,
}
}

View file

@ -5,7 +5,6 @@ use rustc_span::Span;
use crate::error_reporting::TypeErrCtxt;
use crate::infer::RegionResolutionError;
use crate::infer::RegionResolutionError::*;
mod different_lifetimes;
pub mod find_anon_type;
@ -83,8 +82,10 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
pub(super) fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
match (&self.error, self.regions) {
(Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), *sub, *sup)),
(Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {
(Some(RegionResolutionError::ConcreteFailure(origin, sub, sup)), None) => {
Some((origin.span(), *sub, *sup))
}
(Some(RegionResolutionError::SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {
Some((origin.span(), *sub, *sup))
}
(None, Some((span, sub, sup))) => Some((span, sub, sup)),

View file

@ -5,6 +5,7 @@ use rustc_hir::def::{Namespace, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{Visitor, walk_ty};
use rustc_hir::{self as hir, AmbigArg};
use rustc_infer::infer::SubregionOrigin;
use rustc_middle::hir::nested_filter;
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::ExpectedFound;
@ -16,7 +17,7 @@ use tracing::debug;
use crate::error_reporting::infer::nice_region_error::NiceRegionError;
use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted;
use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
use crate::infer::{RegionResolutionError, Subtype, ValuePairs};
use crate::infer::{RegionResolutionError, ValuePairs};
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
@ -32,7 +33,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
_sup,
_,
) = error.clone()
&& let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
&& let (SubregionOrigin::Subtype(sup_trace), SubregionOrigin::Subtype(sub_trace)) =
(&sup_origin, &sub_origin)
&& let &ObligationCauseCode::CompareImplItem { trait_item_def_id, .. } =
sub_trace.cause.code()
&& sub_trace.values == sup_trace.values

View file

@ -27,7 +27,10 @@ use crate::errors::{
};
use crate::fluent_generated as fluent;
use crate::infer::region_constraints::GenericKind;
use crate::infer::{self, InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin};
use crate::infer::{
BoundRegionConversionTime, InferCtxt, RegionResolutionError, RegionVariableOrigin,
SubregionOrigin,
};
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
pub fn report_region_errors(
@ -219,21 +222,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) {
match *origin {
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
SubregionOrigin::Subtype(ref trace) => RegionOriginNote::WithRequirement {
span: trace.cause.span,
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
expected_found: self.values_str(trace.values, &trace.cause, err.long_ty_path()),
}
.add_to_diag(err),
infer::Reborrow(span) => {
SubregionOrigin::Reborrow(span) => {
RegionOriginNote::Plain { span, msg: fluent::trait_selection_reborrow }
.add_to_diag(err)
}
infer::RelateObjectBound(span) => {
SubregionOrigin::RelateObjectBound(span) => {
RegionOriginNote::Plain { span, msg: fluent::trait_selection_relate_object_bound }
.add_to_diag(err);
}
infer::ReferenceOutlivesReferent(ty, span) => {
SubregionOrigin::ReferenceOutlivesReferent(ty, span) => {
RegionOriginNote::WithName {
span,
msg: fluent::trait_selection_reference_outlives_referent,
@ -242,7 +245,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
.add_to_diag(err);
}
infer::RelateParamBound(span, ty, opt_span) => {
SubregionOrigin::RelateParamBound(span, ty, opt_span) => {
RegionOriginNote::WithName {
span,
msg: fluent::trait_selection_relate_param_bound,
@ -258,24 +261,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
.add_to_diag(err);
}
}
infer::RelateRegionParamBound(span, _) => {
SubregionOrigin::RelateRegionParamBound(span, _) => {
RegionOriginNote::Plain {
span,
msg: fluent::trait_selection_relate_region_param_bound,
}
.add_to_diag(err);
}
infer::CompareImplItemObligation { span, .. } => {
SubregionOrigin::CompareImplItemObligation { span, .. } => {
RegionOriginNote::Plain {
span,
msg: fluent::trait_selection_compare_impl_item_obligation,
}
.add_to_diag(err);
}
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
SubregionOrigin::CheckAssociatedTypeBounds { ref parent, .. } => {
self.note_region_origin(err, parent);
}
infer::AscribeUserTypeProvePredicate(span) => {
SubregionOrigin::AscribeUserTypeProvePredicate(span) => {
RegionOriginNote::Plain {
span,
msg: fluent::trait_selection_ascribe_user_type_prove_predicate,
@ -293,7 +296,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
sup: Region<'tcx>,
) -> Diag<'a> {
let mut err = match origin {
infer::Subtype(box trace) => {
SubregionOrigin::Subtype(box trace) => {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
let mut err = self.report_and_explain_type_error(
trace,
@ -347,7 +350,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
err
}
infer::Reborrow(span) => {
SubregionOrigin::Reborrow(span) => {
let reference_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
@ -369,7 +372,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
notes: reference_valid.into_iter().chain(content_valid).collect(),
})
}
infer::RelateObjectBound(span) => {
SubregionOrigin::RelateObjectBound(span) => {
let object_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
@ -391,7 +394,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
notes: object_valid.into_iter().chain(pointer_valid).collect(),
})
}
infer::RelateParamBound(span, ty, opt_span) => {
SubregionOrigin::RelateParamBound(span, ty, opt_span) => {
let prefix = match sub.kind() {
ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy,
_ => note_and_explain::PrefixKind::TypeOutlive,
@ -415,7 +418,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
note,
})
}
infer::RelateRegionParamBound(span, ty) => {
SubregionOrigin::RelateRegionParamBound(span, ty) => {
let param_instantiated = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
@ -457,7 +460,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
})
}
infer::ReferenceOutlivesReferent(ty, span) => {
SubregionOrigin::ReferenceOutlivesReferent(ty, span) => {
let pointer_valid = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
@ -480,7 +483,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
notes: pointer_valid.into_iter().chain(data_valid).collect(),
})
}
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
SubregionOrigin::CompareImplItemObligation {
span,
impl_item_def_id,
trait_item_def_id,
} => {
let mut err = self.report_extra_impl_obligation(
span,
impl_item_def_id,
@ -499,7 +506,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
err
}
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
SubregionOrigin::CheckAssociatedTypeBounds {
impl_item_def_id,
trait_item_def_id,
parent,
} => {
let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup);
// Don't mention the item name if it's an RPITIT, since that'll just confuse
@ -520,7 +531,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
);
err
}
infer::AscribeUserTypeProvePredicate(span) => {
SubregionOrigin::AscribeUserTypeProvePredicate(span) => {
let instantiated = note_and_explain::RegionExplanation::new(
self.tcx,
generic_param_scope,
@ -618,7 +629,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// I can't think how to do better than this right now. -nikomatsakis
debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
match placeholder_origin {
infer::Subtype(box ref trace)
SubregionOrigin::Subtype(box ref trace)
if matches!(
&trace.cause.code().peel_derives(),
ObligationCauseCode::WhereClause(..)
@ -648,7 +659,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
)
}
}
infer::Subtype(box trace) => {
SubregionOrigin::Subtype(box trace) => {
let terr = TypeError::RegionsPlaceholderMismatch;
return self.report_and_explain_type_error(
trace,
@ -945,8 +956,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
if let infer::Subtype(ref sup_trace) = sup_origin
&& let infer::Subtype(ref sub_trace) = sub_origin
if let SubregionOrigin::Subtype(ref sup_trace) = sup_origin
&& let SubregionOrigin::Subtype(ref sub_trace) = sub_origin
&& let Some((sup_expected, sup_found)) =
self.values_str(sup_trace.values, &sup_trace.cause, err.long_ty_path())
&& let Some((sub_expected, sub_found)) =
@ -1004,30 +1015,38 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
s
};
let var_description = match var_origin {
infer::MiscVariable(_) => String::new(),
infer::PatternRegion(_) => " for pattern".to_string(),
infer::BorrowRegion(_) => " for borrow expression".to_string(),
infer::Autoref(_) => " for autoref".to_string(),
infer::Coercion(_) => " for automatic coercion".to_string(),
infer::BoundRegion(_, br, infer::FnCall) => {
RegionVariableOrigin::Misc(_) => String::new(),
RegionVariableOrigin::PatternRegion(_) => " for pattern".to_string(),
RegionVariableOrigin::BorrowRegion(_) => " for borrow expression".to_string(),
RegionVariableOrigin::Autoref(_) => " for autoref".to_string(),
RegionVariableOrigin::Coercion(_) => " for automatic coercion".to_string(),
RegionVariableOrigin::BoundRegion(_, br, BoundRegionConversionTime::FnCall) => {
format!(" for lifetime parameter {}in function call", br_string(br))
}
infer::BoundRegion(_, br, infer::HigherRankedType) => {
RegionVariableOrigin::BoundRegion(
_,
br,
BoundRegionConversionTime::HigherRankedType,
) => {
format!(" for lifetime parameter {}in generic type", br_string(br))
}
infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
RegionVariableOrigin::BoundRegion(
_,
br,
BoundRegionConversionTime::AssocTypeProjection(def_id),
) => format!(
" for lifetime parameter {}in trait containing associated type `{}`",
br_string(br),
self.tcx.associated_item(def_id).name()
),
infer::RegionParameterDefinition(_, name) => {
RegionVariableOrigin::RegionParameterDefinition(_, name) => {
format!(" for lifetime parameter `{name}`")
}
infer::UpvarRegion(ref upvar_id, _) => {
RegionVariableOrigin::UpvarRegion(ref upvar_id, _) => {
let var_name = self.tcx.hir_name(upvar_id.var_path.hir_id);
format!(" for capture of `{var_name}` by closure")
}
infer::Nll(..) => bug!("NLL variable found in lexical phase"),
RegionVariableOrigin::Nll(..) => bug!("NLL variable found in lexical phase"),
};
struct_span_code_err!(

View file

@ -47,8 +47,8 @@ use crate::infer::{self, InferCtxt, InferCtxtExt as _};
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::{
MismatchedProjectionTypes, NormalizeExt, Obligation, ObligationCause, ObligationCauseCode,
ObligationCtxt, Overflow, PredicateObligation, SelectionContext, SelectionError,
SignatureMismatch, TraitDynIncompatible, elaborate, specialization_graph,
ObligationCtxt, PredicateObligation, SelectionContext, SelectionError, elaborate,
specialization_graph,
};
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
@ -659,7 +659,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
}
SignatureMismatch(box SignatureMismatchData {
SelectionError::SignatureMismatch(box SignatureMismatchData {
found_trait_ref,
expected_trait_ref,
terr: terr @ TypeError::CyclicTy(_),
@ -669,7 +669,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
expected_trait_ref,
terr,
),
SignatureMismatch(box SignatureMismatchData {
SelectionError::SignatureMismatch(box SignatureMismatchData {
found_trait_ref,
expected_trait_ref,
terr: _,
@ -690,7 +690,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
def_id,
),
TraitDynIncompatible(did) => {
SelectionError::TraitDynIncompatible(did) => {
let violations = self.tcx.dyn_compatibility_violations(did);
report_dyn_incompatibility(self.tcx, span, None, did, violations)
}
@ -710,12 +710,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// Already reported in the query.
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(guar)) |
// Already reported.
Overflow(OverflowError::Error(guar)) => {
SelectionError::Overflow(OverflowError::Error(guar)) => {
self.set_tainted_by_errors(guar);
return guar
},
Overflow(_) => {
SelectionError::Overflow(_) => {
bug!("overflow should be handled before the `report_selection_error` path");
}

View file

@ -154,7 +154,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
) -> ty::GenericArg<'tcx> {
match arg.kind() {
ty::GenericArgKind::Lifetime(_) => {
self.next_region_var(RegionVariableOrigin::MiscVariable(span)).into()
self.next_region_var(RegionVariableOrigin::Misc(span)).into()
}
ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(),
ty::GenericArgKind::Const(_) => self.next_const_var(span).into(),

View file

@ -37,7 +37,9 @@ pub(super) fn fulfillment_error_for_no_solution<'tcx>(
ty::ConstKind::Unevaluated(uv) => {
infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
}
ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(obligation.param_env),
ty::ConstKind::Param(param_ct) => {
param_ct.find_const_ty_from_env(obligation.param_env)
}
ty::ConstKind::Value(cv) => cv.ty,
kind => span_bug!(
obligation.cause.span,

View file

@ -356,29 +356,38 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
return IntersectionHasImpossibleObligations::Yes;
}
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
let ocx = ObligationCtxt::new(infcx);
ocx.register_obligations(obligations.iter().cloned());
let hard_errors = ocx.select_where_possible();
if !hard_errors.is_empty() {
assert!(
hard_errors.iter().all(|e| e.is_true_error()),
"should not have detected ambiguity during first pass"
);
return IntersectionHasImpossibleObligations::Yes;
}
// Make a new `ObligationCtxt` and re-prove the ambiguities with a richer
// `FulfillmentError`. This is so that we can detect overflowing obligations
// without needing to run the `BestObligation` visitor on true errors.
let ambiguities = ocx.into_pending_obligations();
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
ocx.register_obligations(ambiguities);
let errors_and_ambiguities = ocx.select_all_or_error();
// We only care about the obligations that are *definitely* true errors.
// Ambiguities do not prove the disjointness of two impls.
let (errors, ambiguities): (Vec<_>, Vec<_>) =
errors_and_ambiguities.into_iter().partition(|error| error.is_true_error());
assert!(errors.is_empty(), "should not have ambiguities during second pass");
if errors.is_empty() {
IntersectionHasImpossibleObligations::No {
overflowing_predicates: ambiguities
.into_iter()
.filter(|error| {
matches!(
error.code,
FulfillmentErrorCode::Ambiguity { overflow: Some(true) }
)
})
.map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
.collect(),
}
} else {
IntersectionHasImpossibleObligations::Yes
IntersectionHasImpossibleObligations::No {
overflowing_predicates: ambiguities
.into_iter()
.filter(|error| {
matches!(error.code, FulfillmentErrorCode::Ambiguity { overflow: Some(true) })
})
.map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
.collect(),
}
} else {
for obligation in obligations {

View file

@ -20,7 +20,7 @@ use super::project::{self, ProjectAndUnifyResult};
use super::select::SelectionContext;
use super::{
EvaluationResult, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
ScrubbedTraitError, Unimplemented, const_evaluatable, wf,
ScrubbedTraitError, const_evaluatable, wf,
};
use crate::error_reporting::InferCtxtErrorExt;
use crate::infer::{InferCtxt, TyOrConstInferVar};
@ -456,7 +456,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
ty::PredicateKind::DynCompatible(trait_def_id) => {
if !self.selcx.tcx().is_dyn_compatible(trait_def_id) {
ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented))
ProcessResult::Error(FulfillmentErrorCode::Select(
SelectionError::Unimplemented,
))
} else {
ProcessResult::Changed(Default::default())
}
@ -507,7 +509,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
}
ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
ty::ConstKind::Param(param_ct) => {
param_ct.find_ty_from_env(obligation.param_env)
param_ct.find_const_ty_from_env(obligation.param_env)
}
};

View file

@ -36,8 +36,8 @@ use rustc_middle::ty::{
self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Upcast,
};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use rustc_span::{DUMMY_SP, Span};
use tracing::{debug, instrument};
pub use self::coherence::{
@ -644,7 +644,9 @@ pub fn try_evaluate_const<'tcx>(
let erased_uv = tcx.erase_regions(uv);
use rustc_middle::mir::interpret::ErrorHandled;
match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) {
// FIXME: `def_span` will point at the definition of this const; ideally, we'd point at
// where it gets used as a const generic.
match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, tcx.def_span(uv.def)) {
Ok(Ok(val)) => Ok(ty::Const::new_value(
tcx,
val,

View file

@ -84,9 +84,6 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
// was discarded -- this could be because of ambiguity, or because
// a higher-priority candidate is already there.
fn push_candidate(&mut self, candidate: ProjectionCandidate<'tcx>) -> bool {
use self::ProjectionCandidate::*;
use self::ProjectionCandidateSet::*;
// This wacky variable is just used to try and
// make code readable and avoid confusing paths.
// It is assigned a "value" of `()` only on those
@ -98,12 +95,12 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
let convert_to_ambiguous;
match self {
None => {
*self = Single(candidate);
ProjectionCandidateSet::None => {
*self = ProjectionCandidateSet::Single(candidate);
return true;
}
Single(current) => {
ProjectionCandidateSet::Single(current) => {
// Duplicates can happen inside ParamEnv. In the case, we
// perform a lazy deduplication.
if current == &candidate {
@ -118,16 +115,18 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
// clauses are the safer choice. See the comment on
// `select::SelectionCandidate` and #21974 for more details.
match (current, candidate) {
(ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (),
(ParamEnv(..), _) => return false,
(_, ParamEnv(..)) => bug!(
(ProjectionCandidate::ParamEnv(..), ProjectionCandidate::ParamEnv(..)) => {
convert_to_ambiguous = ()
}
(ProjectionCandidate::ParamEnv(..), _) => return false,
(_, ProjectionCandidate::ParamEnv(..)) => bug!(
"should never prefer non-param-env candidates over param-env candidates"
),
(_, _) => convert_to_ambiguous = (),
}
}
Ambiguous | Error(..) => {
ProjectionCandidateSet::Ambiguous | ProjectionCandidateSet::Error(..) => {
return false;
}
}
@ -135,7 +134,7 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
// We only ever get here when we moved from a single candidate
// to ambiguous.
let () = convert_to_ambiguous;
*self = Ambiguous;
*self = ProjectionCandidateSet::Ambiguous;
false
}
}

View file

@ -11,7 +11,7 @@ use std::ops::ControlFlow;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
use rustc_middle::ty::{
@ -28,8 +28,7 @@ use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::util::{self, closure_trait_ref_and_return_type};
use crate::traits::{
ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause,
PolyTraitObligation, PredicateObligation, Selection, SelectionError, SignatureMismatch,
TraitDynIncompatible, TraitObligation, Unimplemented,
PolyTraitObligation, PredicateObligation, Selection, SelectionError, TraitObligation,
};
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
@ -176,7 +175,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let candidate = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span,
HigherRankedType,
BoundRegionConversionTime::HigherRankedType,
candidate,
);
let mut obligations = PredicateObligations::new();
@ -194,7 +193,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.at(&obligation.cause, obligation.param_env)
.eq(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented)?,
.map_err(|_| SelectionError::Unimplemented)?,
);
// FIXME(compiler-errors): I don't think this is needed.
@ -374,7 +373,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
}
let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else {
return Err(Unimplemented);
return Err(SelectionError::Unimplemented);
};
let dst = predicate.trait_ref.args.type_at(0);
@ -386,7 +385,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
transmute_env.is_transmutable(rustc_transmute::Types { dst, src }, assume);
let fully_flattened = match maybe_transmutable {
Answer::No(_) => Err(Unimplemented)?,
Answer::No(_) => Err(SelectionError::Unimplemented)?,
Answer::If(cond) => flatten_answer_tree(self.tcx(), obligation, cond, assume),
Answer::Yes => PredicateObligations::new(),
};
@ -500,7 +499,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
});
let object_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span,
HigherRankedType,
BoundRegionConversionTime::HigherRankedType,
object_trait_ref,
);
let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty);
@ -513,7 +512,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let upcast_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span,
HigherRankedType,
BoundRegionConversionTime::HigherRankedType,
unnormalized_upcast_trait_ref,
);
let upcast_trait_ref = normalize_with_depth_to(
@ -530,7 +529,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.at(&obligation.cause, obligation.param_env)
.eq(DefineOpaqueTypes::No, trait_predicate.trait_ref, upcast_trait_ref)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented)?,
.map_err(|_| SelectionError::Unimplemented)?,
);
// Check supertraits hold. This is so that their associated type bounds
@ -962,7 +961,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let found_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span,
HigherRankedType,
BoundRegionConversionTime::HigherRankedType,
found_trait_ref,
);
// Normalize the obligation and expected trait refs together, because why not
@ -986,7 +985,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligations
})
.map_err(|terr| {
SignatureMismatch(Box::new(SignatureMismatchData {
SelectionError::SignatureMismatch(Box::new(SignatureMismatchData {
expected_trait_ref: obligation_trait_ref,
found_trait_ref,
terr,
@ -1090,7 +1089,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.infcx
.at(&obligation.cause, obligation.param_env)
.sup(DefineOpaqueTypes::Yes, target, source_trait)
.map_err(|_| Unimplemented)?;
.map_err(|_| SelectionError::Unimplemented)?;
// Register one obligation for 'a: 'b.
let outlives = ty::OutlivesPredicate(r_a, r_b);
@ -1109,7 +1108,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
(_, &ty::Dynamic(data, r, ty::Dyn)) => {
let mut object_dids = data.auto_traits().chain(data.principal_def_id());
if let Some(did) = object_dids.find(|did| !tcx.is_dyn_compatible(*did)) {
return Err(TraitDynIncompatible(did));
return Err(SelectionError::TraitDynIncompatible(did));
}
let predicate_to_obligation = |predicate| {
@ -1189,7 +1188,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.infcx
.at(&obligation.cause, obligation.param_env)
.eq(DefineOpaqueTypes::Yes, b, a)
.map_err(|_| Unimplemented)?;
.map_err(|_| SelectionError::Unimplemented)?;
ImplSource::Builtin(BuiltinImplSource::Misc, obligations)
}
@ -1198,7 +1197,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
(&ty::Adt(def, args_a), &ty::Adt(_, args_b)) => {
let unsizing_params = tcx.unsizing_params_for_adt(def.did());
if unsizing_params.is_empty() {
return Err(Unimplemented);
return Err(SelectionError::Unimplemented);
}
let tail_field = def.non_enum_variant().tail();
@ -1237,7 +1236,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.infcx
.at(&obligation.cause, obligation.param_env)
.eq(DefineOpaqueTypes::Yes, target, new_struct)
.map_err(|_| Unimplemented)?;
.map_err(|_| SelectionError::Unimplemented)?;
nested.extend(obligations);
// Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate.

View file

@ -39,7 +39,7 @@ use super::coherence::{self, Conflict};
use super::project::ProjectionTermObligation;
use super::util::closure_trait_ref_and_return_type;
use super::{
ImplDerivedCause, Normalized, Obligation, ObligationCause, ObligationCauseCode, Overflow,
ImplDerivedCause, Normalized, Obligation, ObligationCause, ObligationCauseCode,
PolyTraitObligation, PredicateObligation, Selection, SelectionError, SelectionResult,
TraitQueryMode, const_evaluatable, project, util, wf,
};
@ -48,9 +48,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener};
use crate::solve::InferCtxtSelectExt as _;
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
use crate::traits::{
EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects, sizedness_fast_path,
};
use crate::traits::{EvaluateConstErr, ProjectionCacheKey, effects, sizedness_fast_path};
mod _match;
mod candidate_assembly;
@ -454,8 +452,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
}
Ok(_) => Ok(None),
Err(OverflowError::Canonical) => Err(Overflow(OverflowError::Canonical)),
Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))),
Err(OverflowError::Canonical) => {
Err(SelectionError::Overflow(OverflowError::Canonical))
}
Err(OverflowError::Error(e)) => {
Err(SelectionError::Overflow(OverflowError::Error(e)))
}
})
.flat_map(Result::transpose)
.collect::<Result<Vec<_>, _>>()?;
@ -479,7 +481,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?stack.obligation.predicate, "found error type in predicate, treating as ambiguous");
Ok(None)
} else {
Err(Unimplemented)
Err(SelectionError::Unimplemented)
}
} else {
let has_non_region_infer = stack.obligation.predicate.has_non_region_infer();
@ -979,7 +981,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
ty::ConstKind::Param(param_ct) => {
param_ct.find_ty_from_env(obligation.param_env)
param_ct.find_const_ty_from_env(obligation.param_env)
}
};
@ -1222,7 +1224,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match self.candidate_from_obligation(stack) {
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
Ok(None) => Ok(EvaluatedToAmbig),
Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
Err(SelectionError::Overflow(OverflowError::Canonical)) => {
Err(OverflowError::Canonical)
}
Err(..) => Ok(EvaluatedToErr),
}
}
@ -1536,7 +1540,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return Some(res);
} else if cfg!(debug_assertions) {
match infcx.selection_cache.get(&(param_env, pred), tcx) {
None | Some(Err(Overflow(OverflowError::Canonical))) => {}
None | Some(Err(SelectionError::Overflow(OverflowError::Canonical))) => {}
res => bug!("unexpected local cache result: {res:?}"),
}
}
@ -1592,7 +1596,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
if self.can_use_global_caches(param_env, cache_fresh_trait_pred) {
if let Err(Overflow(OverflowError::Canonical)) = candidate {
if let Err(SelectionError::Overflow(OverflowError::Canonical)) = candidate {
// Don't cache overflow globally; we only produce this in certain modes.
} else {
debug!(?pred, ?candidate, "insert_candidate_cache global");

View file

@ -273,8 +273,6 @@ impl<'tcx> Graph {
// Descend the specialization tree, where `parent` is the current parent node.
loop {
use self::Inserted::*;
let insert_result = self.children.entry(parent).or_default().insert(
tcx,
impl_def_id,
@ -283,11 +281,11 @@ impl<'tcx> Graph {
)?;
match insert_result {
BecameNewSibling(opt_lint) => {
Inserted::BecameNewSibling(opt_lint) => {
last_lint = opt_lint;
break;
}
ReplaceChildren(grand_children_to_be) => {
Inserted::ReplaceChildren(grand_children_to_be) => {
// We currently have
//
// P
@ -326,7 +324,7 @@ impl<'tcx> Graph {
}
break;
}
ShouldRecurseOn(new_parent) => {
Inserted::ShouldRecurseOn(new_parent) => {
parent = new_parent;
}
}

View file

@ -10,7 +10,7 @@ use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt, Upc
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::traits::{
ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext,
Unimplemented, sizedness_fast_path,
SelectionError, sizedness_fast_path,
};
use tracing::debug;
@ -47,7 +47,7 @@ pub(crate) fn codegen_select_candidate<'tcx>(
let selection = match selcx.select(&obligation) {
Ok(Some(selection)) => selection,
Ok(None) => return Err(CodegenObligationError::Ambiguity),
Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
Err(SelectionError::Unimplemented) => return Err(CodegenObligationError::Unimplemented),
Err(e) => {
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
}

View file

@ -12,7 +12,7 @@ use crate::elaborate::Elaboratable;
use crate::fold::{TypeFoldable, TypeSuperFoldable};
use crate::relate::Relate;
use crate::solve::{AdtDestructorKind, SizedTraitKind};
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
use crate::{self as ty, CollectAndApply, Interner, UpcastFrom};
pub trait Ty<I: Interner<Ty = Self>>:
@ -538,6 +538,45 @@ pub trait PlaceholderLike<I: Interner>: Copy + Debug + Hash + Eq {
fn with_updated_universe(self, ui: ty::UniverseIndex) -> Self;
}
pub trait PlaceholderConst<I: Interner>: PlaceholderLike<I, Bound = I::BoundConst> {
fn find_const_ty_from_env(self, env: I::ParamEnv) -> I::Ty;
}
impl<I: Interner> PlaceholderConst<I> for I::PlaceholderConst {
fn find_const_ty_from_env(self, env: I::ParamEnv) -> I::Ty {
let mut candidates = env.caller_bounds().iter().filter_map(|clause| {
// `ConstArgHasType` are never desugared to be higher ranked.
match clause.kind().skip_binder() {
ty::ClauseKind::ConstArgHasType(placeholder_ct, ty) => {
assert!(!(placeholder_ct, ty).has_escaping_bound_vars());
match placeholder_ct.kind() {
ty::ConstKind::Placeholder(placeholder_ct) if placeholder_ct == self => {
Some(ty)
}
_ => None,
}
}
_ => None,
}
});
// N.B. it may be tempting to fix ICEs by making this function return
// `Option<Ty<'tcx>>` instead of `Ty<'tcx>`; however, this is generally
// considered to be a bandaid solution, since it hides more important
// underlying issues with how we construct generics and predicates of
// items. It's advised to fix the underlying issue rather than trying
// to modify this function.
let ty = candidates.next().unwrap_or_else(|| {
panic!("cannot find `{self:?}` in param-env: {env:#?}");
});
assert!(
candidates.next().is_none(),
"did not expect duplicate `ConstParamHasTy` for `{self:?}` in param-env: {env:#?}"
);
ty
}
}
pub trait IntoKind {
type Kind;

View file

@ -133,7 +133,7 @@ pub trait Interner:
type Const: Const<Self>;
type ParamConst: Copy + Debug + Hash + Eq + ParamLike;
type BoundConst: BoundVarLike<Self>;
type PlaceholderConst: PlaceholderLike<Self, Bound = Self::BoundConst>;
type PlaceholderConst: PlaceholderConst<Self>;
type ValueConst: ValueConst<Self>;
type ExprConst: ExprConst<Self>;
type ValTree: Copy + Debug + Hash + Eq;
@ -348,12 +348,6 @@ pub trait Interner:
type UnsizingParams: Deref<Target = DenseBitSet<u32>>;
fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams;
fn find_const_ty_from_env(
self,
param_env: Self::ParamEnv,
placeholder: Self::PlaceholderConst,
) -> Self::Ty;
fn anonymize_bound_vars<T: TypeFoldable<Self>>(
self,
binder: ty::Binder<Self, T>,

View file

@ -3004,7 +3004,6 @@ pub struct Weak<
// `Weak::new` sets this to `usize::MAX` so that it doesnt need
// to allocate space on the heap. That's not a value a real pointer
// will ever have because RcInner has alignment at least 2.
// This is only possible when `T: Sized`; unsized `T` never dangle.
ptr: NonNull<RcInner<T>>,
alloc: A,
}

View file

@ -342,7 +342,6 @@ pub struct Weak<
// `Weak::new` sets this to `usize::MAX` so that it doesnt need
// to allocate space on the heap. That's not a value a real pointer
// will ever have because RcInner has alignment at least 2.
// This is only possible when `T: Sized`; unsized `T` never dangle.
ptr: NonNull<ArcInner<T>>,
alloc: A,
}

View file

@ -255,6 +255,7 @@ use crate::fmt::{self, Debug, Display};
use crate::marker::{PhantomData, PointerLike, Unsize};
use crate::mem;
use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
use crate::panic::const_panic;
use crate::pin::PinCoerceUnsized;
use crate::ptr::{self, NonNull};
@ -781,16 +782,24 @@ impl Display for BorrowMutError {
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[track_caller]
#[cold]
fn panic_already_borrowed(err: BorrowMutError) -> ! {
panic!("{err}")
const fn panic_already_borrowed(err: BorrowMutError) -> ! {
const_panic!(
"RefCell already borrowed",
"{err}",
err: BorrowMutError = err,
)
}
// This ensures the panicking code is outlined from `borrow` for `RefCell`.
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[track_caller]
#[cold]
fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
panic!("{err}")
const fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
const_panic!(
"RefCell already mutably borrowed",
"{err}",
err: BorrowError = err,
)
}
// Positive values represent the number of `Ref` active. Negative values
@ -810,12 +819,12 @@ type BorrowCounter = isize;
const UNUSED: BorrowCounter = 0;
#[inline(always)]
fn is_writing(x: BorrowCounter) -> bool {
const fn is_writing(x: BorrowCounter) -> bool {
x < UNUSED
}
#[inline(always)]
fn is_reading(x: BorrowCounter) -> bool {
const fn is_reading(x: BorrowCounter) -> bool {
x > UNUSED
}
@ -884,8 +893,9 @@ impl<T> RefCell<T> {
#[stable(feature = "refcell_replace", since = "1.24.0")]
#[track_caller]
#[rustc_confusables("swap")]
pub fn replace(&self, t: T) -> T {
mem::replace(&mut *self.borrow_mut(), t)
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const fn replace(&self, t: T) -> T {
mem::replace(&mut self.borrow_mut(), t)
}
/// Replaces the wrapped value with a new one computed from `f`, returning
@ -935,7 +945,8 @@ impl<T> RefCell<T> {
/// ```
#[inline]
#[stable(feature = "refcell_swap", since = "1.24.0")]
pub fn swap(&self, other: &Self) {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const fn swap(&self, other: &Self) {
mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
}
}
@ -975,7 +986,8 @@ impl<T: ?Sized> RefCell<T> {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[track_caller]
pub fn borrow(&self) -> Ref<'_, T> {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const fn borrow(&self) -> Ref<'_, T> {
match self.try_borrow() {
Ok(b) => b,
Err(err) => panic_already_mutably_borrowed(err),
@ -1010,14 +1022,15 @@ impl<T: ?Sized> RefCell<T> {
#[stable(feature = "try_borrow", since = "1.13.0")]
#[inline]
#[cfg_attr(feature = "debug_refcell", track_caller)]
pub fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError> {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError> {
match BorrowRef::new(&self.borrow) {
Some(b) => {
#[cfg(feature = "debug_refcell")]
{
// `borrowed_at` is always the *first* active borrow
if b.borrow.get() == 1 {
self.borrowed_at.set(Some(crate::panic::Location::caller()));
self.borrowed_at.replace(Some(crate::panic::Location::caller()));
}
}
@ -1071,7 +1084,8 @@ impl<T: ?Sized> RefCell<T> {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[track_caller]
pub fn borrow_mut(&self) -> RefMut<'_, T> {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const fn borrow_mut(&self) -> RefMut<'_, T> {
match self.try_borrow_mut() {
Ok(b) => b,
Err(err) => panic_already_borrowed(err),
@ -1103,12 +1117,13 @@ impl<T: ?Sized> RefCell<T> {
#[stable(feature = "try_borrow", since = "1.13.0")]
#[inline]
#[cfg_attr(feature = "debug_refcell", track_caller)]
pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
match BorrowRefMut::new(&self.borrow) {
Some(b) => {
#[cfg(feature = "debug_refcell")]
{
self.borrowed_at.set(Some(crate::panic::Location::caller()));
self.borrowed_at.replace(Some(crate::panic::Location::caller()));
}
// SAFETY: `BorrowRefMut` guarantees unique access.
@ -1139,7 +1154,8 @@ impl<T: ?Sized> RefCell<T> {
#[stable(feature = "cell_as_ptr", since = "1.12.0")]
#[rustc_as_ptr]
#[rustc_never_returns_null_ptr]
pub fn as_ptr(&self) -> *mut T {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const fn as_ptr(&self) -> *mut T {
self.value.get()
}
@ -1176,7 +1192,8 @@ impl<T: ?Sized> RefCell<T> {
/// ```
#[inline]
#[stable(feature = "cell_get_mut", since = "1.11.0")]
pub fn get_mut(&mut self) -> &mut T {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const fn get_mut(&mut self) -> &mut T {
self.value.get_mut()
}
@ -1202,7 +1219,8 @@ impl<T: ?Sized> RefCell<T> {
/// assert!(c.try_borrow().is_ok());
/// ```
#[unstable(feature = "cell_leak", issue = "69099")]
pub fn undo_leak(&mut self) -> &mut T {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const fn undo_leak(&mut self) -> &mut T {
*self.borrow.get_mut() = UNUSED;
self.get_mut()
}
@ -1236,7 +1254,8 @@ impl<T: ?Sized> RefCell<T> {
/// ```
#[stable(feature = "borrow_state", since = "1.37.0")]
#[inline]
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
if !is_writing(self.borrow.get()) {
// SAFETY: We check that nobody is actively writing now, but it is
// the caller's responsibility to ensure that nobody writes until
@ -1400,7 +1419,7 @@ struct BorrowRef<'b> {
impl<'b> BorrowRef<'b> {
#[inline]
fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRef<'b>> {
const fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRef<'b>> {
let b = borrow.get().wrapping_add(1);
if !is_reading(b) {
// Incrementing borrow can result in a non-reading value (<= 0) in these cases:
@ -1417,22 +1436,24 @@ impl<'b> BorrowRef<'b> {
// 1. It was = 0, i.e. it wasn't borrowed, and we are taking the first read borrow
// 2. It was > 0 and < isize::MAX, i.e. there were read borrows, and isize
// is large enough to represent having one more read borrow
borrow.set(b);
borrow.replace(b);
Some(BorrowRef { borrow })
}
}
}
impl Drop for BorrowRef<'_> {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
impl const Drop for BorrowRef<'_> {
#[inline]
fn drop(&mut self) {
let borrow = self.borrow.get();
debug_assert!(is_reading(borrow));
self.borrow.set(borrow - 1);
self.borrow.replace(borrow - 1);
}
}
impl Clone for BorrowRef<'_> {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
impl const Clone for BorrowRef<'_> {
#[inline]
fn clone(&self) -> Self {
// Since this Ref exists, we know the borrow flag
@ -1442,7 +1463,7 @@ impl Clone for BorrowRef<'_> {
// Prevent the borrow counter from overflowing into
// a writing borrow.
assert!(borrow != BorrowCounter::MAX);
self.borrow.set(borrow + 1);
self.borrow.replace(borrow + 1);
BorrowRef { borrow: self.borrow }
}
}
@ -1463,7 +1484,8 @@ pub struct Ref<'b, T: ?Sized + 'b> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Deref for Ref<'_, T> {
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
impl<T: ?Sized> const Deref for Ref<'_, T> {
type Target = T;
#[inline]
@ -1488,7 +1510,8 @@ impl<'b, T: ?Sized> Ref<'b, T> {
#[stable(feature = "cell_extras", since = "1.15.0")]
#[must_use]
#[inline]
pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
Ref { value: orig.value, borrow: orig.borrow.clone() }
}
@ -1610,7 +1633,8 @@ impl<'b, T: ?Sized> Ref<'b, T> {
/// assert!(cell.try_borrow_mut().is_err());
/// ```
#[unstable(feature = "cell_leak", issue = "69099")]
pub fn leak(orig: Ref<'b, T>) -> &'b T {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const fn leak(orig: Ref<'b, T>) -> &'b T {
// By forgetting this Ref we ensure that the borrow counter in the RefCell can't go back to
// UNUSED within the lifetime `'b`. Resetting the reference tracking state would require a
// unique reference to the borrowed RefCell. No further mutable references can be created
@ -1776,7 +1800,8 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
/// assert!(cell.try_borrow_mut().is_err());
/// ```
#[unstable(feature = "cell_leak", issue = "69099")]
pub fn leak(mut orig: RefMut<'b, T>) -> &'b mut T {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
pub const fn leak(mut orig: RefMut<'b, T>) -> &'b mut T {
// By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell can't
// go back to UNUSED within the lifetime `'b`. Resetting the reference tracking state would
// require a unique reference to the borrowed RefCell. No further references can be created
@ -1792,25 +1817,26 @@ struct BorrowRefMut<'b> {
borrow: &'b Cell<BorrowCounter>,
}
impl Drop for BorrowRefMut<'_> {
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
impl const Drop for BorrowRefMut<'_> {
#[inline]
fn drop(&mut self) {
let borrow = self.borrow.get();
debug_assert!(is_writing(borrow));
self.borrow.set(borrow + 1);
self.borrow.replace(borrow + 1);
}
}
impl<'b> BorrowRefMut<'b> {
#[inline]
fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRefMut<'b>> {
const fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRefMut<'b>> {
// NOTE: Unlike BorrowRefMut::clone, new is called to create the initial
// mutable reference, and so there must currently be no existing
// references. Thus, while clone increments the mutable refcount, here
// we explicitly only allow going from UNUSED to UNUSED - 1.
match borrow.get() {
UNUSED => {
borrow.set(UNUSED - 1);
borrow.replace(UNUSED - 1);
Some(BorrowRefMut { borrow })
}
_ => None,
@ -1849,7 +1875,8 @@ pub struct RefMut<'b, T: ?Sized + 'b> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Deref for RefMut<'_, T> {
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
impl<T: ?Sized> const Deref for RefMut<'_, T> {
type Target = T;
#[inline]
@ -1860,7 +1887,8 @@ impl<T: ?Sized> Deref for RefMut<'_, T> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> DerefMut for RefMut<'_, T> {
#[rustc_const_unstable(feature = "const_deref", issue = "88955")]
impl<T: ?Sized> const DerefMut for RefMut<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
// SAFETY: the value is accessible as long as we hold our borrow.

View file

@ -223,7 +223,16 @@ where
{
let mut accum = init;
let first = if started { next_item.take() } else { iter.next() };
let first = if started {
next_item.take()
} else {
let n = iter.next();
// skip invoking fold() for empty iterators
if n.is_none() {
return accum;
}
n
};
if let Some(x) = first {
accum = f(accum, x);
}

View file

@ -420,7 +420,7 @@ pub use self::adapters::{Intersperse, IntersperseWith};
issue = "42168"
)]
pub use self::range::Step;
#[unstable(feature = "iter_macro", issue = "none", reason = "generators are unstable")]
#[unstable(feature = "iter_macro", issue = "142269", reason = "generators are unstable")]
pub use self::sources::iter;
#[stable(feature = "iter_empty", since = "1.2.0")]
pub use self::sources::{Empty, empty};

View file

@ -19,7 +19,7 @@ pub use self::empty::{Empty, empty};
pub use self::from_coroutine::{FromCoroutine, from_coroutine};
#[stable(feature = "iter_from_fn", since = "1.34.0")]
pub use self::from_fn::{FromFn, from_fn};
#[unstable(feature = "iter_macro", issue = "none", reason = "generators are unstable")]
#[unstable(feature = "iter_macro", issue = "142269", reason = "generators are unstable")]
pub use self::generator::iter;
#[stable(feature = "iter_once", since = "1.2.0")]
pub use self::once::{Once, once};

View file

@ -18,7 +18,7 @@
/// let v: Vec<_> = it.collect();
/// assert_eq!(v, [1, 2, 3]);
/// ```
#[unstable(feature = "iter_macro", issue = "none", reason = "generators are unstable")]
#[unstable(feature = "iter_macro", issue = "142269", reason = "generators are unstable")]
#[allow_internal_unstable(coroutines, iter_from_coroutine)]
#[rustc_builtin_macro]
pub macro iter($($t:tt)*) {

View file

@ -1935,6 +1935,7 @@ unsafe impl<T: ?Sized> PinCoerceUnsized for *mut T {}
#[stable(feature = "pin_macro", since = "1.68.0")]
#[rustc_macro_transparency = "semitransparent"]
#[allow_internal_unstable(super_let)]
#[rustc_diagnostic_item = "pin_macro"]
// `super` gets removed by rustfmt
#[rustfmt::skip]
pub macro pin($value:expr $(,)?) {

View file

@ -1,4 +1,5 @@
use core::cell::*;
use core::mem::forget;
#[test]
fn smoketest_unsafe_cell() {
@ -477,3 +478,74 @@ fn const_cells() {
const _: i32 = CELL.into_inner();
*/
}
#[test]
fn refcell_borrow() {
// Check that `borrow` is usable at compile-time
const {
let a = RefCell::new(0);
assert!(a.try_borrow().is_ok());
assert!(a.try_borrow_mut().is_ok());
let a_ref = a.borrow();
assert!(*a_ref == 0);
assert!(a.try_borrow().is_ok());
assert!(a.try_borrow_mut().is_err());
}
}
#[test]
fn refcell_borrow_mut() {
// Check that `borrow_mut` is usable at compile-time
const {
let mut a = RefCell::new(0);
{
assert!(a.try_borrow().is_ok());
assert!(a.try_borrow_mut().is_ok());
let mut a_ref = a.borrow_mut();
assert!(*a_ref == 0);
*a_ref = 10;
assert!(*a_ref == 10);
assert!(a.try_borrow().is_err());
assert!(a.try_borrow_mut().is_err());
}
assert!(*a.get_mut() == 10);
};
}
struct NeverDrop;
impl Drop for NeverDrop {
fn drop(&mut self) {
panic!("should never be called");
}
}
#[test]
fn refcell_replace() {
// Check that `replace` is usable at compile-time
const {
let a = RefCell::new(0);
assert!(a.replace(10) == 0);
let a = a.into_inner();
assert!(a == 10);
let b = RefCell::new(NeverDrop);
forget(b.replace(NeverDrop));
forget(b)
};
}
#[test]
fn refcell_swap() {
// Check that `swap` is usable at compile-time
const {
let (a, b) = (RefCell::new(31), RefCell::new(41));
a.swap(&b);
let (a, b) = (a.into_inner(), b.into_inner());
assert!(a == 41);
assert!(b == 31);
let c = RefCell::new(NeverDrop);
let d = RefCell::new(NeverDrop);
c.swap(&d);
forget((c, d));
};
}

View file

@ -15,8 +15,11 @@
#![feature(cfg_target_has_reliable_f16_f128)]
#![feature(char_max_len)]
#![feature(clone_to_uninit)]
#![feature(const_deref)]
#![feature(const_destruct)]
#![feature(const_eval_select)]
#![feature(const_float_round_methods)]
#![feature(const_ref_cell)]
#![feature(const_trait_impl)]
#![feature(core_float_math)]
#![feature(core_intrinsics)]

View file

@ -481,7 +481,7 @@ impl<T: ?Sized> RwLock<T> {
/// in the returned error.
///
/// This function will return the [`WouldBlock`] error if the `RwLock` could
/// not be acquired because it was already locked exclusively.
/// not be acquired because it was already locked.
///
/// [`Poisoned`]: TryLockError::Poisoned
/// [`WouldBlock`]: TryLockError::WouldBlock

View file

@ -272,7 +272,7 @@ fn rustup_installed(builder: &Builder<'_>) -> bool {
let mut rustup = command("rustup");
rustup.arg("--version");
rustup.allow_failure().run_always().run_capture_stdout(builder).is_success()
rustup.allow_failure().run_in_dry_run().run_capture_stdout(builder).is_success()
}
fn stage_dir_exists(stage_path: &str) -> bool {

View file

@ -809,7 +809,7 @@ impl Config {
config.initial_sysroot = t!(PathBuf::from_str(
command(&config.initial_rustc)
.args(["--print", "sysroot"])
.run_always()
.run_in_dry_run()
.run_capture_stdout(&config)
.stdout()
.trim()
@ -1391,11 +1391,11 @@ impl Config {
// all the git commands below are actually executed, because some follow-up code
// in bootstrap might depend on the submodules being checked out. Furthermore, not all
// the command executions below work with an empty output (produced during dry run).
// Therefore, all commands below are marked with `run_always()`, so that they also run in
// Therefore, all commands below are marked with `run_in_dry_run()`, so that they also run in
// dry run mode.
let submodule_git = || {
let mut cmd = helpers::git(Some(&absolute_path));
cmd.run_always();
cmd.run_in_dry_run();
cmd
};
@ -1405,7 +1405,7 @@ impl Config {
let checked_out_hash = checked_out_hash.trim_end();
// Determine commit that the submodule *should* have.
let recorded = helpers::git(Some(&self.src))
.run_always()
.run_in_dry_run()
.args(["ls-tree", "HEAD"])
.arg(relative_path)
.run_capture_stdout(self)
@ -1425,7 +1425,7 @@ impl Config {
helpers::git(Some(&self.src))
.allow_failure()
.run_always()
.run_in_dry_run()
.args(["submodule", "-q", "sync"])
.arg(relative_path)
.run(self);
@ -1436,12 +1436,12 @@ impl Config {
// even though that has no relation to the upstream for the submodule.
let current_branch = helpers::git(Some(&self.src))
.allow_failure()
.run_always()
.run_in_dry_run()
.args(["symbolic-ref", "--short", "HEAD"])
.run_capture(self);
let mut git = helpers::git(Some(&self.src)).allow_failure();
git.run_always();
git.run_in_dry_run();
if current_branch.is_success() {
// If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name.
// This syntax isn't accepted by `branch.{branch}`. Strip it.

View file

@ -88,7 +88,7 @@ fn workspace_members(build: &Build) -> Vec<Package> {
.arg("--no-deps")
.arg("--manifest-path")
.arg(build.src.join(manifest_path));
let metadata_output = cargo.run_always().run_capture_stdout(build).stdout();
let metadata_output = cargo.run_in_dry_run().run_capture_stdout(build).stdout();
let Output { packages, .. } = t!(serde_json::from_str(&metadata_output));
packages
};

View file

@ -202,7 +202,7 @@ than building it.
let stage0_supported_target_list: HashSet<String> = command(&build.config.initial_rustc)
.args(["--print", "target-list"])
.run_always()
.run_in_dry_run()
.run_capture_stdout(&build)
.stdout()
.lines()
@ -366,7 +366,7 @@ than building it.
// Cygwin. The Cygwin build does not have generators for Visual
// Studio, so detect that here and error.
let out =
command("cmake").arg("--help").run_always().run_capture_stdout(&build).stdout();
command("cmake").arg("--help").run_in_dry_run().run_capture_stdout(&build).stdout();
if !out.contains("Visual Studio") {
panic!(
"

View file

@ -383,7 +383,7 @@ impl Build {
let in_tree_gcc_info = config.in_tree_gcc_info.clone();
let initial_target_libdir = command(&config.initial_rustc)
.run_always()
.run_in_dry_run()
.args(["--print", "target-libdir"])
.run_capture_stdout(&config)
.stdout()
@ -490,7 +490,7 @@ impl Build {
// If local-rust is the same major.minor as the current version, then force a
// local-rebuild
let local_version_verbose = command(&build.initial_rustc)
.run_always()
.run_in_dry_run()
.args(["--version", "--verbose"])
.run_capture_stdout(&build)
.stdout();
@ -949,7 +949,7 @@ impl Build {
static SYSROOT_CACHE: OnceLock<PathBuf> = OnceLock::new();
SYSROOT_CACHE.get_or_init(|| {
command(&self.initial_rustc)
.run_always()
.run_in_dry_run()
.args(["--print", "sysroot"])
.run_capture_stdout(self)
.stdout()
@ -1512,7 +1512,7 @@ impl Build {
"refs/remotes/origin/{}..HEAD",
self.config.stage0_metadata.config.nightly_branch
))
.run_always()
.run_in_dry_run()
.run_capture(self)
.stdout()
});

View file

@ -66,19 +66,22 @@ impl GitInfo {
.arg("-1")
.arg("--date=short")
.arg("--pretty=format:%cd")
.run_always()
.run_in_dry_run()
.start_capture_stdout(&exec_ctx);
let mut git_hash_cmd = helpers::git(Some(dir));
let ver_hash =
git_hash_cmd.arg("rev-parse").arg("HEAD").run_always().start_capture_stdout(&exec_ctx);
let ver_hash = git_hash_cmd
.arg("rev-parse")
.arg("HEAD")
.run_in_dry_run()
.start_capture_stdout(&exec_ctx);
let mut git_short_hash_cmd = helpers::git(Some(dir));
let short_ver_hash = git_short_hash_cmd
.arg("rev-parse")
.arg("--short=9")
.arg("HEAD")
.run_always()
.run_in_dry_run()
.start_capture_stdout(&exec_ctx);
GitInfo::Present(Some(Info {

View file

@ -66,7 +66,7 @@ pub struct BootstrapCommand {
command: Command,
pub failure_behavior: BehaviorOnFailure,
// Run the command even during dry run
pub run_always: bool,
pub run_in_dry_run: bool,
// This field makes sure that each command is executed (or disarmed) before it is dropped,
// to avoid forgetting to execute a command.
drop_bomb: DropBomb,
@ -138,8 +138,8 @@ impl<'a> BootstrapCommand {
Self { failure_behavior: BehaviorOnFailure::Ignore, ..self }
}
pub fn run_always(&mut self) -> &mut Self {
self.run_always = true;
pub fn run_in_dry_run(&mut self) -> &mut Self {
self.run_in_dry_run = true;
self
}
@ -228,7 +228,7 @@ impl From<Command> for BootstrapCommand {
Self {
command,
failure_behavior: BehaviorOnFailure::Exit,
run_always: false,
run_in_dry_run: false,
drop_bomb: DropBomb::arm(program),
}
}

View file

@ -93,7 +93,7 @@ impl ExecutionContext {
let created_at = command.get_created_location();
let executed_at = std::panic::Location::caller();
if self.dry_run() && !command.run_always {
if self.dry_run() && !command.run_in_dry_run {
return DeferredCommand { process: None, stdout, stderr, command, executed_at };
}

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