Auto merge of #140324 - matthiaskrgr:rollup-jlzvdre, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #139865 (Stabilize proc_macro::Span::{start,end,line,column}.)
 - #140086 (If creating a temporary directory fails with permission denied then retry with backoff)
 - #140216 (Document that "extern blocks must be unsafe" in Rust 2024)
 - #140253 (Add XtensaAsmPrinter)
 - #140272 (Improve error message for `||` (or) in let chains)
 - #140305 (Track per-obligation recursion depth only if there is inference in the new solver)
 - #140306 (handle specialization in the new trait solver)
 - #140308 (stall generator witness obligations: add regression test)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-04-26 05:18:22 +00:00
commit 5ae50d3b21
45 changed files with 526 additions and 139 deletions

View file

@ -3700,6 +3700,9 @@ dependencies = [
[[package]]
name = "rustc_fs_util"
version = "0.0.0"
dependencies = [
"tempfile",
]
[[package]]
name = "rustc_graphviz"
@ -4012,7 +4015,6 @@ dependencies = [
"rustc_session",
"rustc_span",
"rustc_target",
"tempfile",
"tracing",
]

View file

@ -13,9 +13,9 @@ use object::read::archive::ArchiveFile;
use object::read::macho::FatArch;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::memmap::Mmap;
use rustc_fs_util::TempDirBuilder;
use rustc_session::Session;
use rustc_span::Symbol;
use tempfile::Builder as TempFileBuilder;
use tracing::trace;
use super::metadata::search_for_section;
@ -501,7 +501,7 @@ impl<'a> ArArchiveBuilder<'a> {
// it creates. We need it to be the default mode for back compat reasons however. (See
// #107495) To handle this we are telling tempfile to create a temporary directory instead
// and then inside this directory create a file using File::create.
let archive_tmpdir = TempFileBuilder::new()
let archive_tmpdir = TempDirBuilder::new()
.suffix(".temp-archive")
.tempdir_in(output.parent().unwrap_or_else(|| Path::new("")))
.map_err(|err| {

View file

@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
use rustc_fs_util::{TempDirBuilder, fix_windows_verbatim_for_gcc, try_canonicalize};
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_macros::LintDiagnostic;
use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
@ -48,7 +48,6 @@ use rustc_target::spec::{
LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel,
SanitizerSet, SplitDebuginfo,
};
use tempfile::Builder as TempFileBuilder;
use tracing::{debug, info, warn};
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
@ -100,7 +99,7 @@ pub fn link_binary(
});
if outputs.outputs.should_link() {
let tmpdir = TempFileBuilder::new()
let tmpdir = TempDirBuilder::new()
.prefix("rustc")
.tempdir()
.unwrap_or_else(|error| sess.dcx().emit_fatal(errors::CreateTempDir { error }));

View file

@ -5,4 +5,5 @@ edition = "2024"
[dependencies]
# tidy-alphabetical-start
tempfile = "3.7.1"
# tidy-alphabetical-end

View file

@ -1,6 +1,8 @@
use std::ffi::CString;
use std::ffi::{CString, OsStr};
use std::path::{Path, PathBuf, absolute};
use std::{fs, io};
use std::{env, fs, io};
use tempfile::TempDir;
// Unfortunately, on windows, it looks like msvcrt.dll is silently translating
// verbatim paths under the hood to non-verbatim paths! This manifests itself as
@ -102,3 +104,43 @@ pub fn path_to_c_string(p: &Path) -> CString {
pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
fs::canonicalize(&path).or_else(|_| absolute(&path))
}
pub struct TempDirBuilder<'a, 'b> {
builder: tempfile::Builder<'a, 'b>,
}
impl<'a, 'b> TempDirBuilder<'a, 'b> {
pub fn new() -> Self {
Self { builder: tempfile::Builder::new() }
}
pub fn prefix<S: AsRef<OsStr> + ?Sized>(&mut self, prefix: &'a S) -> &mut Self {
self.builder.prefix(prefix);
self
}
pub fn suffix<S: AsRef<OsStr> + ?Sized>(&mut self, suffix: &'b S) -> &mut Self {
self.builder.suffix(suffix);
self
}
pub fn tempdir_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<TempDir> {
let dir = dir.as_ref();
// On Windows in CI, we had been getting fairly frequent "Access is denied"
// errors when creating temporary directories.
// So this implements a simple retry with backoff loop.
#[cfg(windows)]
for wait in 1..11 {
match self.builder.tempdir_in(dir) {
Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {}
t => return t,
}
std::thread::sleep(std::time::Duration::from_millis(1 << wait));
}
self.builder.tempdir_in(dir)
}
pub fn tempdir(&self) -> io::Result<TempDir> {
self.tempdir_in(env::temp_dir())
}
}

View file

@ -229,6 +229,7 @@ pub fn initialize_available_targets() {
LLVMInitializeXtensaTargetInfo,
LLVMInitializeXtensaTarget,
LLVMInitializeXtensaTargetMC,
LLVMInitializeXtensaAsmPrinter,
LLVMInitializeXtensaAsmParser
);
init_target!(

View file

@ -26,7 +26,6 @@ rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
tempfile = "3.2"
tracing = "0.1"
# tidy-alphabetical-end

View file

@ -2,11 +2,11 @@ use std::path::{Path, PathBuf};
use std::{fs, io};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_fs_util::TempDirBuilder;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{CrateType, OutFileName, OutputType};
use rustc_session::output::filename_for_metadata;
use rustc_session::{MetadataKind, Session};
use tempfile::Builder as TempFileBuilder;
use crate::errors::{
BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile,
@ -45,7 +45,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
// final destination, with an `fs::rename` call. In order for the rename to
// always succeed, the temporary file needs to be on the same filesystem,
// which is why we create it inside the output directory specifically.
let metadata_tmpdir = TempFileBuilder::new()
let metadata_tmpdir = TempDirBuilder::new()
.prefix("rmeta")
.tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new("")))
.unwrap_or_else(|err| tcx.dcx().emit_fatal(FailedCreateTempdir { err }));

View file

@ -590,6 +590,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.defaultness(def_id).has_value()
}
fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool {
self.specializes((impl_def_id, victim_def_id))
}
fn impl_is_default(self, impl_def_id: DefId) -> bool {
self.defaultness(impl_def_id).is_default()
}

View file

@ -10,6 +10,7 @@ use rustc_type_ir::{
};
use tracing::{debug, instrument};
use super::has_only_region_constraints;
use super::trait_goals::TraitGoalProvenVia;
use crate::delegate::SolverDelegate;
use crate::solve::inspect::ProbeKind;
@ -771,6 +772,69 @@ where
}
})
}
}
pub(super) enum AllowInferenceConstraints {
Yes,
No,
}
impl<D, I> EvalCtxt<'_, D>
where
D: SolverDelegate<Interner = I>,
I: Interner,
{
/// Check whether we can ignore impl candidates due to specialization.
///
/// This is only necessary for `feature(specialization)` and seems quite ugly.
pub(super) fn filter_specialized_impls(
&mut self,
allow_inference_constraints: AllowInferenceConstraints,
candidates: &mut Vec<Candidate<I>>,
) {
match self.typing_mode() {
TypingMode::Coherence => return,
TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. }
| TypingMode::PostAnalysis => {}
}
let mut i = 0;
'outer: while i < candidates.len() {
let CandidateSource::Impl(victim_def_id) = candidates[i].source else {
i += 1;
continue;
};
for (j, c) in candidates.iter().enumerate() {
if i == j {
continue;
}
let CandidateSource::Impl(other_def_id) = c.source else {
continue;
};
// See if we can toss out `victim` based on specialization.
//
// While this requires us to know *for sure* that the `lhs` impl applies
// we still use modulo regions here. This is fine as specialization currently
// assumes that specializing impls have to be always applicable, meaning that
// the only allowed region constraints may be constraints also present on the default impl.
if matches!(allow_inference_constraints, AllowInferenceConstraints::Yes)
|| has_only_region_constraints(c.result)
{
if self.cx().impl_specializes(other_def_id, victim_def_id) {
candidates.remove(i);
continue 'outer;
}
}
}
i += 1;
}
}
/// Assemble and merge candidates for goals which are related to an underlying trait
/// goal. Right now, this is normalizes-to and host effect goals.
@ -857,7 +921,7 @@ where
}
}
TraitGoalProvenVia::Misc => {
let candidates =
let mut candidates =
self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
// Prefer "orphaned" param-env normalization predicates, which are used
@ -871,6 +935,13 @@ where
return Ok(response);
}
// We drop specialized impls to allow normalization via a final impl here. In case
// the specializing impl has different inference constraints from the specialized
// impl, proving the trait goal is already ambiguous, so we never get here. This
// means we can just ignore inference constraints and don't have to special-case
// constraining the normalized-to `term`.
self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates);
let responses: Vec<_> = candidates.iter().map(|c| c.result).collect();
if let Some(response) = self.try_merge_responses(&responses) {
Ok(response)

View file

@ -16,6 +16,7 @@ use rustc_type_ir::{
};
use tracing::{instrument, trace};
use super::has_only_region_constraints;
use crate::coherence;
use crate::delegate::SolverDelegate;
use crate::solve::inspect::{self, ProofTreeBuilder};
@ -476,13 +477,8 @@ where
Ok(response) => response,
};
let has_changed = if !response.value.var_values.is_identity_modulo_regions()
|| !response.value.external_constraints.opaque_types.is_empty()
{
HasChanged::Yes
} else {
HasChanged::No
};
let has_changed =
if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No };
let (normalization_nested_goals, certainty) =
self.instantiate_and_apply_query_response(goal.param_env, orig_values, response);

View file

@ -70,6 +70,17 @@ fn has_no_inference_or_external_constraints<I: Interner>(
&& normalization_nested_goals.is_empty()
}
fn has_only_region_constraints<I: Interner>(response: ty::Canonical<I, Response<I>>) -> bool {
let ExternalConstraintsData {
region_constraints: _,
ref opaque_types,
ref normalization_nested_goals,
} = *response.value.external_constraints;
response.value.var_values.is_identity_modulo_regions()
&& opaque_types.is_empty()
&& normalization_nested_goals.is_empty()
}
impl<'a, D, I> EvalCtxt<'a, D>
where
D: SolverDelegate<Interner = I>,

View file

@ -213,9 +213,6 @@ where
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
};
// In case the associated item is hidden due to specialization, we have to
// return ambiguity this would otherwise be incomplete, resulting in
// unsoundness during coherence (#105782).
let target_item_def_id = match ecx.fetch_eligible_assoc_item(
goal_trait_ref,
goal.predicate.def_id(),
@ -223,8 +220,28 @@ where
) {
Ok(Some(target_item_def_id)) => target_item_def_id,
Ok(None) => {
return ecx
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
match ecx.typing_mode() {
// In case the associated item is hidden due to specialization, we have to
// return ambiguity this would otherwise be incomplete, resulting in
// unsoundness during coherence (#105782).
ty::TypingMode::Coherence => {
return ecx.evaluate_added_goals_and_make_canonical_response(
Certainty::AMBIGUOUS,
);
}
// Outside of coherence, we treat the associated item as rigid instead.
ty::TypingMode::Analysis { .. }
| ty::TypingMode::Borrowck { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. }
| ty::TypingMode::PostAnalysis => {
ecx.structurally_instantiate_normalizes_to_term(
goal,
goal.predicate.alias,
);
return ecx
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
}
};
}
Err(guar) => return error_response(ecx, guar),
};

View file

@ -13,7 +13,7 @@ use tracing::{instrument, trace};
use crate::delegate::SolverDelegate;
use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
use crate::solve::assembly::{self, AssembleCandidatesFrom, Candidate};
use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidatesFrom, Candidate};
use crate::solve::inspect::ProbeKind;
use crate::solve::{
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
@ -1338,6 +1338,8 @@ where
};
}
self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
// If there are *only* global where bounds, then make sure to return that this
// is still reported as being proven-via the param-env so that rigid projections
// operate correctly. Otherwise, drop all global where-bounds before merging the

View file

@ -675,6 +675,8 @@ parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns ar
parse_nul_in_c_str = null characters in C string literals are not supported
parse_or_in_let_chain = `||` operators are not supported in let chain conditions
parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
parse_out_of_range_hex_escape = out of range hex escape

View file

@ -478,6 +478,13 @@ pub(crate) struct ExpectedExpressionFoundLet {
pub comparison: Option<MaybeComparison>,
}
#[derive(Diagnostic)]
#[diag(parse_or_in_let_chain)]
pub(crate) struct OrInLetChain {
#[primary_span]
pub span: Span,
}
#[derive(Subdiagnostic, Clone, Copy)]
#[multipart_suggestion(
parse_maybe_missing_let,

View file

@ -4073,14 +4073,18 @@ impl MutVisitor for CondChecker<'_> {
match e.kind {
ExprKind::Let(_, _, _, ref mut recovered @ Recovered::No) => {
if let Some(reason) = self.forbid_let_reason {
*recovered = Recovered::Yes(self.parser.dcx().emit_err(
errors::ExpectedExpressionFoundLet {
let error = match reason {
NotSupportedOr(or_span) => {
self.parser.dcx().emit_err(errors::OrInLetChain { span: or_span })
}
_ => self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet {
span,
reason,
missing_let: self.missing_let,
comparison: self.comparison,
},
));
}),
};
*recovered = Recovered::Yes(error);
} else if self.depth > 1 {
// Top level `let` is always allowed; only gate chains
match self.let_chains_policy {

View file

@ -163,15 +163,15 @@ where
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
let mut errors = Vec::new();
for i in 0.. {
if !infcx.tcx.recursion_limit().value_within_limit(i) {
self.obligations.on_fulfillment_overflow(infcx);
// Only return true errors that we have accumulated while processing.
return errors;
}
loop {
let mut has_changed = false;
for obligation in self.obligations.drain_pending(|_| true) {
for mut obligation in self.obligations.drain_pending(|_| true) {
if !infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) {
self.obligations.on_fulfillment_overflow(infcx);
// Only return true errors that we have accumulated while processing.
return errors;
}
let goal = obligation.as_goal();
let result = <&SolverDelegate<'tcx>>::from(infcx)
.evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span)
@ -189,6 +189,13 @@ where
};
if changed == HasChanged::Yes {
// We increment the recursion depth here to track the number of times
// this goal has resulted in inference progress. This doesn't precisely
// model the way that we track recursion depth in the old solver due
// to the fact that we only process root obligations, but it is a good
// approximation and should only result in fulfillment overflow in
// pathological cases.
obligation.recursion_depth += 1;
has_changed = true;
}

View file

@ -286,6 +286,8 @@ pub trait Interner:
fn has_item_definition(self, def_id: Self::DefId) -> bool;
fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool;
fn impl_is_default(self, impl_def_id: Self::DefId) -> bool;
fn impl_trait_ref(self, impl_def_id: Self::DefId) -> ty::EarlyBinder<Self, ty::TraitRef<Self>>;

View file

@ -513,13 +513,13 @@ impl Span {
}
/// Creates an empty span pointing to directly before this span.
#[unstable(feature = "proc_macro_span", issue = "54725")]
#[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")]
pub fn start(&self) -> Span {
Span(self.0.start())
}
/// Creates an empty span pointing to directly after this span.
#[unstable(feature = "proc_macro_span", issue = "54725")]
#[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")]
pub fn end(&self) -> Span {
Span(self.0.end())
}
@ -527,7 +527,7 @@ impl Span {
/// The one-indexed line of the source file where the span starts.
///
/// To obtain the line of the span's end, use `span.end().line()`.
#[unstable(feature = "proc_macro_span", issue = "54725")]
#[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")]
pub fn line(&self) -> usize {
self.0.line()
}
@ -535,7 +535,7 @@ impl Span {
/// The one-indexed column of the source file where the span starts.
///
/// To obtain the column of the span's end, use `span.end().column()`.
#[unstable(feature = "proc_macro_span", issue = "54725")]
#[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")]
pub fn column(&self) -> usize {
self.0.column()
}

View file

@ -388,11 +388,15 @@ mod enum_keyword {}
/// lazy_static;`. The other use is in foreign function interfaces (FFI).
///
/// `extern` is used in two different contexts within FFI. The first is in the form of external
/// blocks, for declaring function interfaces that Rust code can call foreign code by.
/// blocks, for declaring function interfaces that Rust code can call foreign code by. This use
/// of `extern` is unsafe, since we are asserting to the compiler that all function declarations
/// are correct. If they are not, using these items may lead to undefined behavior.
///
/// ```rust ignore
/// // SAFETY: The function declarations given below are in
/// // line with the header files of `my_c_library`.
/// #[link(name = "my_c_library")]
/// extern "C" {
/// unsafe extern "C" {
/// fn my_c_function(x: i32) -> bool;
/// }
/// ```

View file

@ -0,0 +1,25 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@ check-pass
//@ edition: 2024
// This test previously used the `is_copy_raw` query during
// HIR typeck, dropping the list of generators from the current
// body. This then caused a query cycle.
struct W<T>(*const T);
impl<T: Send> Clone for W<T> {
fn clone(&self) -> Self { W(self.0) }
}
impl<T: Send> Copy for W<T> {}
fn main() {
let coro = async {};
let x = W(&raw const coro);
let c = || {
let x = x;
};
}

View file

@ -0,0 +1,28 @@
error: `||` operators are not supported in let chain conditions
--> $DIR/or-in-let-chain.rs:6:24
|
LL | if let true = true || false {}
| ^^
error: expected expression, found `let` statement
--> $DIR/or-in-let-chain.rs:9:9
|
LL | if (let true = true) || false {}
| ^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
error: `||` operators are not supported in let chain conditions
--> $DIR/or-in-let-chain.rs:12:24
|
LL | if let true = true || false || true {}
| ^^
error: `||` operators are not supported in let chain conditions
--> $DIR/or-in-let-chain.rs:15:33
|
LL | if let true = true && false || true {}
| ^^
error: aborting due to 4 previous errors

View file

@ -0,0 +1,28 @@
error: `||` operators are not supported in let chain conditions
--> $DIR/or-in-let-chain.rs:6:24
|
LL | if let true = true || false {}
| ^^
error: expected expression, found `let` statement
--> $DIR/or-in-let-chain.rs:9:9
|
LL | if (let true = true) || false {}
| ^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
error: `||` operators are not supported in let chain conditions
--> $DIR/or-in-let-chain.rs:12:24
|
LL | if let true = true || false || true {}
| ^^
error: `||` operators are not supported in let chain conditions
--> $DIR/or-in-let-chain.rs:15:33
|
LL | if let true = true && false || true {}
| ^^
error: aborting due to 4 previous errors

View file

@ -0,0 +1,17 @@
//@ revisions: edition2021 edition2024
//@ [edition2021] edition: 2021
//@ [edition2024] edition: 2024
fn main() {
if let true = true || false {}
//~^ ERROR `||` operators are not supported in let chain conditions
// With parentheses
if (let true = true) || false {}
//~^ ERROR expected expression, found `let` statement
// Multiple || operators
if let true = true || false || true {}
//~^ ERROR `||` operators are not supported in let chain conditions
// Mixed operators (should still show error for ||)
if let true = true && false || true {}
//~^ ERROR `||` operators are not supported in let chain conditions
}

View file

@ -3,7 +3,7 @@
fn let_or_guard(x: Result<Option<i32>, ()>) {
match x {
Ok(opt) if let Some(4) = opt || false => {}
//~^ ERROR expected expression, found `let` statement
//~^ ERROR `||` operators are not supported in let chain conditions
_ => {}
}
}

View file

@ -1,11 +1,4 @@
error: expected expression, found `let` statement
--> $DIR/ast-validate-guards.rs:5:20
|
LL | Ok(opt) if let Some(4) = opt || false => {}
| ^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
error: `||` operators are not supported in let chain conditions
--> $DIR/ast-validate-guards.rs:5:38
|
LL | Ok(opt) if let Some(4) = opt || false => {}

View file

@ -272,14 +272,7 @@ LL | if (let 0 = 0)? {}
|
= note: only supported directly in conditions of `if` and `while` expressions
error: expected expression, found `let` statement
--> $DIR/disallowed-positions.rs:121:16
|
LL | if true || let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
error: `||` operators are not supported in let chain conditions
--> $DIR/disallowed-positions.rs:121:13
|
LL | if true || let 0 = 0 {}
@ -485,14 +478,7 @@ LL | while (let 0 = 0)? {}
|
= note: only supported directly in conditions of `if` and `while` expressions
error: expected expression, found `let` statement
--> $DIR/disallowed-positions.rs:212:19
|
LL | while true || let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
error: `||` operators are not supported in let chain conditions
--> $DIR/disallowed-positions.rs:212:16
|
LL | while true || let 0 = 0 {}

View file

@ -272,14 +272,7 @@ LL | if (let 0 = 0)? {}
|
= note: only supported directly in conditions of `if` and `while` expressions
error: expected expression, found `let` statement
--> $DIR/disallowed-positions.rs:121:16
|
LL | if true || let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
error: `||` operators are not supported in let chain conditions
--> $DIR/disallowed-positions.rs:121:13
|
LL | if true || let 0 = 0 {}
@ -485,14 +478,7 @@ LL | while (let 0 = 0)? {}
|
= note: only supported directly in conditions of `if` and `while` expressions
error: expected expression, found `let` statement
--> $DIR/disallowed-positions.rs:212:19
|
LL | while true || let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
error: `||` operators are not supported in let chain conditions
--> $DIR/disallowed-positions.rs:212:16
|
LL | while true || let 0 = 0 {}

View file

@ -272,14 +272,7 @@ LL | if (let 0 = 0)? {}
|
= note: only supported directly in conditions of `if` and `while` expressions
error: expected expression, found `let` statement
--> $DIR/disallowed-positions.rs:121:16
|
LL | if true || let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
error: `||` operators are not supported in let chain conditions
--> $DIR/disallowed-positions.rs:121:13
|
LL | if true || let 0 = 0 {}
@ -485,14 +478,7 @@ LL | while (let 0 = 0)? {}
|
= note: only supported directly in conditions of `if` and `while` expressions
error: expected expression, found `let` statement
--> $DIR/disallowed-positions.rs:212:19
|
LL | while true || let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
error: `||` operators are not supported in let chain conditions
--> $DIR/disallowed-positions.rs:212:16
|
LL | while true || let 0 = 0 {}

View file

@ -119,7 +119,7 @@ fn nested_within_if_expr() {
//~^ ERROR expected expression, found `let` statement
if true || let 0 = 0 {}
//~^ ERROR expected expression, found `let` statement
//~^ ERROR `||` operators are not supported in let chain conditions
if (true || let 0 = 0) {}
//~^ ERROR expected expression, found `let` statement
if true && (true || let 0 = 0) {}
@ -210,7 +210,7 @@ fn nested_within_while_expr() {
//~^ ERROR expected expression, found `let` statement
while true || let 0 = 0 {}
//~^ ERROR expected expression, found `let` statement
//~^ ERROR `||` operators are not supported in let chain conditions
while (true || let 0 = 0) {}
//~^ ERROR expected expression, found `let` statement
while true && (true || let 0 = 0) {}

View file

@ -0,0 +1,12 @@
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/prefer-specializing-impl-over-default.rs:5:12
|
LL | #![feature(specialization)]
| ^^^^^^^^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: consider using `min_specialization` instead, which is more stable and complete
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

View file

@ -0,0 +1,12 @@
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/prefer-specializing-impl-over-default.rs:5:12
|
LL | #![feature(specialization)]
| ^^^^^^^^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: consider using `min_specialization` instead, which is more stable and complete
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

View file

@ -0,0 +1,29 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@ check-pass
#![feature(specialization)]
//~^ WARN the feature `specialization` is incomplete
trait WithAssoc: 'static {
type Assoc;
}
impl<T: 'static> WithAssoc for (T,) {
type Assoc = ();
}
struct GenericArray<U: WithAssoc>(U::Assoc);
trait AbiExample {
fn example();
}
impl<U: WithAssoc> AbiExample for GenericArray<U> {
fn example() {}
}
impl<T> AbiExample for T {
default fn example() {}
}
fn main() {
let _ = GenericArray::<((),)>::example();
}

View file

@ -1,5 +1,5 @@
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/specialization-default-projection.rs:1:12
--> $DIR/specialization-default-projection.rs:5:12
|
LL | #![feature(specialization)]
| ^^^^^^^^^^^^^^
@ -9,7 +9,7 @@ LL | #![feature(specialization)]
= note: `#[warn(incomplete_features)]` on by default
error[E0308]: mismatched types
--> $DIR/specialization-default-projection.rs:21:5
--> $DIR/specialization-default-projection.rs:25:5
|
LL | fn generic<T>() -> <T as Foo>::Assoc {
| ----------------- expected `<T as Foo>::Assoc` because of return type
@ -23,7 +23,7 @@ LL | ()
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0308]: mismatched types
--> $DIR/specialization-default-projection.rs:28:5
--> $DIR/specialization-default-projection.rs:32:5
|
LL | fn monomorphic() -> () {
| -- expected `()` because of return type

View file

@ -0,0 +1,43 @@
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/specialization-default-projection.rs:5:12
|
LL | #![feature(specialization)]
| ^^^^^^^^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: consider using `min_specialization` instead, which is more stable and complete
= note: `#[warn(incomplete_features)]` on by default
error[E0308]: mismatched types
--> $DIR/specialization-default-projection.rs:25:5
|
LL | fn generic<T>() -> <T as Foo>::Assoc {
| ----------------- expected `<T as Foo>::Assoc` because of return type
...
LL | ()
| ^^ types differ
|
= note: expected associated type `<T as Foo>::Assoc`
found unit type `()`
= help: consider constraining the associated type `<T as Foo>::Assoc` to `()` or calling a method that returns `<T as Foo>::Assoc`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0308]: mismatched types
--> $DIR/specialization-default-projection.rs:32:5
|
LL | fn monomorphic() -> () {
| -- expected `()` because of return type
...
LL | generic::<()>()
| ^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
| |
| types differ
|
= note: expected unit type `()`
found associated type `<() as Foo>::Assoc`
= help: consider constraining the associated type `<() as Foo>::Assoc` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0308`.

View file

@ -1,3 +1,7 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
// Make sure we can't project defaulted associated types

View file

@ -1,5 +1,5 @@
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/specialization-default-types.rs:5:12
--> $DIR/specialization-default-types.rs:9:12
|
LL | #![feature(specialization)]
| ^^^^^^^^^^^^^^
@ -9,7 +9,7 @@ LL | #![feature(specialization)]
= note: `#[warn(incomplete_features)]` on by default
error[E0308]: mismatched types
--> $DIR/specialization-default-types.rs:15:9
--> $DIR/specialization-default-types.rs:19:9
|
LL | default type Output = Box<T>;
| ----------------------------- associated type is `default` and may be overridden
@ -22,7 +22,7 @@ LL | Box::new(self)
found struct `Box<T>`
error[E0308]: mismatched types
--> $DIR/specialization-default-types.rs:25:5
--> $DIR/specialization-default-types.rs:29:5
|
LL | fn trouble<T>(t: T) -> Box<T> {
| ------ expected `Box<T>` because of return type

View file

@ -0,0 +1,39 @@
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/specialization-default-types.rs:9:12
|
LL | #![feature(specialization)]
| ^^^^^^^^^^^^^^
|
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
= help: consider using `min_specialization` instead, which is more stable and complete
= note: `#[warn(incomplete_features)]` on by default
error[E0308]: mismatched types
--> $DIR/specialization-default-types.rs:19:9
|
LL | default type Output = Box<T>;
| ----------------------------- associated type is `default` and may be overridden
LL | default fn generate(self) -> Self::Output {
| ------------ expected `<T as Example>::Output` because of return type
LL | Box::new(self)
| ^^^^^^^^^^^^^^ types differ
|
= note: expected associated type `<T as Example>::Output`
found struct `Box<T>`
error[E0308]: mismatched types
--> $DIR/specialization-default-types.rs:29:5
|
LL | fn trouble<T>(t: T) -> Box<T> {
| ------ expected `Box<T>` because of return type
LL | Example::generate(t)
| ^^^^^^^^^^^^^^^^^^^^ types differ
|
= note: expected struct `Box<T>`
found associated type `<T as Example>::Output`
= help: consider constraining the associated type `<T as Example>::Output` to `Box<T>`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0308`.

View file

@ -1,3 +1,7 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
// It should not be possible to use the concrete value of a defaulted
// associated type in the impl defining it -- otherwise, what happens
// if it's overridden?

View file

@ -0,0 +1,31 @@
//@ check-pass
//@ compile-flags: -Znext-solver
// Ensure that a stack of coerce predicates doesn't end up overflowing when they get procesed
// in *reverse* order, which may require O(N) iterations of the fulfillment loop.
#![recursion_limit = "16"]
fn main() {
match 0 {
0 => None,
1 => None,
2 => None,
3 => None,
4 => None,
5 => None,
6 => None,
7 => None,
8 => None,
9 => None,
10 => None,
11 => None,
12 => None,
13 => None,
14 => None,
15 => None,
16 => None,
17 => None,
_ => Some(1u32),
};
}

View file

@ -10,11 +10,8 @@ trait Default {
impl<T> Default for T {
default type Id = T;
// This will be fixed by #111994
fn intu(&self) -> &Self::Id {
//~^ ERROR type annotations needed
//~| ERROR cannot normalize `<T as Default>::Id: '_`
self //~ ERROR cannot satisfy
self //~ ERROR mismatched types
}
}
@ -25,6 +22,7 @@ fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U {
use std::num::NonZero;
fn main() {
let s = transmute::<u8, Option<NonZero<u8>>>(0); //~ ERROR cannot satisfy
let s = transmute::<u8, Option<NonZero<u8>>>(0);
//~^ ERROR type mismatch resolving `<u8 as Default>::Id == Option<NonZero<u8>>`
assert_eq!(s, None);
}

View file

@ -8,37 +8,32 @@ LL | #![feature(specialization)]
= help: consider using `min_specialization` instead, which is more stable and complete
= note: `#[warn(incomplete_features)]` on by default
error: cannot normalize `<T as Default>::Id: '_`
--> $DIR/specialization-transmute.rs:14:5
error[E0308]: mismatched types
--> $DIR/specialization-transmute.rs:14:9
|
LL | fn intu(&self) -> &Self::Id {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0282]: type annotations needed
--> $DIR/specialization-transmute.rs:14:23
|
LL | fn intu(&self) -> &Self::Id {
| ^^^^^^^^^ cannot infer type for reference `&<T as Default>::Id`
error[E0284]: type annotations needed: cannot satisfy `<T as Default>::Id normalizes-to T`
--> $DIR/specialization-transmute.rs:17:9
|
| --------- expected `&<T as Default>::Id` because of return type
LL | self
| ^^^^ cannot satisfy `<T as Default>::Id normalizes-to T`
| ^^^^ types differ
|
= note: expected reference `&<T as Default>::Id`
found reference `&T`
error[E0284]: type annotations needed: cannot satisfy `<u8 as Default>::Id normalizes-to Option<NonZero<u8>>`
--> $DIR/specialization-transmute.rs:28:13
error[E0271]: type mismatch resolving `<u8 as Default>::Id == Option<NonZero<u8>>`
--> $DIR/specialization-transmute.rs:25:50
|
LL | let s = transmute::<u8, Option<NonZero<u8>>>(0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `<u8 as Default>::Id normalizes-to Option<NonZero<u8>>`
| ------------------------------------ ^ types differ
| |
| required by a bound introduced by this call
|
note: required by a bound in `transmute`
--> $DIR/specialization-transmute.rs:21:25
--> $DIR/specialization-transmute.rs:18:25
|
LL | fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U {
| ^^^^^^ required by this bound in `transmute`
error: aborting due to 4 previous errors; 1 warning emitted
error: aborting due to 2 previous errors; 1 warning emitted
Some errors have detailed explanations: E0282, E0284.
For more information about an error, try `rustc --explain E0282`.
Some errors have detailed explanations: E0271, E0308.
For more information about an error, try `rustc --explain E0271`.

View file

@ -18,5 +18,5 @@ fn test<T: Default<Id = U>, U>() {}
fn main() {
test::<u32, ()>();
//~^ ERROR cannot satisfy `<u32 as Default>::Id normalizes-to ()`
//~^ ERROR type mismatch resolving `<u32 as Default>::Id == ()`
}

View file

@ -8,11 +8,11 @@ LL | #![feature(specialization)]
= help: consider using `min_specialization` instead, which is more stable and complete
= note: `#[warn(incomplete_features)]` on by default
error[E0284]: type annotations needed: cannot satisfy `<u32 as Default>::Id normalizes-to ()`
--> $DIR/specialization-unconstrained.rs:20:5
error[E0271]: type mismatch resolving `<u32 as Default>::Id == ()`
--> $DIR/specialization-unconstrained.rs:20:12
|
LL | test::<u32, ()>();
| ^^^^^^^^^^^^^^^^^ cannot satisfy `<u32 as Default>::Id normalizes-to ()`
| ^^^ types differ
|
note: required by a bound in `test`
--> $DIR/specialization-unconstrained.rs:17:20
@ -22,4 +22,4 @@ LL | fn test<T: Default<Id = U>, U>() {}
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0284`.
For more information about this error, try `rustc --explain E0271`.