Auto merge of #123497 - GuillaumeGomez:rollup-usqb4q9, r=GuillaumeGomez

Rollup of 8 pull requests

Successful merges:

 - #122334 (Vendor rustc_codegen_gcc)
 - #122894 (Move check for error in impl header outside of reporting)
 - #123149 (Port argument-non-c-like-enum to Rust)
 - #123311 (Match ergonomics: implement "`&`pat everywhere")
 - #123350 (Actually use the inferred `ClosureKind` from signature inference in coroutine-closures)
 - #123474 (Port `run-make/issue-7349` to a codegen test)
 - #123489 (handle rustc args properly in bootstrap)
 - #123496 (ping on wf changes, remove fixme)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-04-05 15:20:50 +00:00
commit 1921968cc5
42 changed files with 910 additions and 167 deletions

View File

@ -79,16 +79,18 @@ dependencies = [
[[package]]
name = "gccjit"
version = "1.0.0"
source = "git+https://github.com/antoyo/gccjit.rs#9f8f67edc006d543b17529a001803ffece48349e"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecaa4c3da2d74c1a991b4faff75d49ab1d0522d9a99d8e2614b3b04d226417ce"
dependencies = [
"gccjit_sys",
]
[[package]]
name = "gccjit_sys"
version = "0.0.1"
source = "git+https://github.com/antoyo/gccjit.rs#9f8f67edc006d543b17529a001803ffece48349e"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "406a66fba005f1a02661f2f9443e5693dd3a667b7c58e70aa4ccc4c8b50b4758"
dependencies = [
"libc",
]

View File

@ -22,7 +22,7 @@ master = ["gccjit/master"]
default = ["master"]
[dependencies]
gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
gccjit = "2.0"
# Local copy.
#gccjit = { path = "../gccjit.rs" }

View File

@ -567,6 +567,8 @@ declare_features! (
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
(unstable, raw_ref_op, "1.41.0", Some(64490)),
/// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
(incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
/// Allows using the `#[register_tool]` attribute.
(unstable, register_tool, "1.41.0", Some(66079)),
/// Allows the `#[repr(i128)]` attribute for enums.

View File

@ -227,11 +227,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
});
let closure_kind_ty = self.next_ty_var(TypeVariableOrigin {
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
});
let closure_kind_ty = match expected_kind {
Some(kind) => Ty::from_closure_kind(tcx, kind),
// Create a type variable (for now) to represent the closure kind.
// It will be unified during the upvar inference phase (`upvar.rs`)
None => self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
}),
};
let coroutine_captures_by_ref_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
@ -262,10 +269,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
);
let coroutine_kind_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
});
let coroutine_kind_ty = match expected_kind {
Some(kind) => Ty::from_coroutine_closure_kind(tcx, kind),
// Create a type variable (for now) to represent the closure kind.
// It will be unified during the upvar inference phase (`upvar.rs`)
None => self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
}),
};
let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,

View File

@ -130,7 +130,14 @@ enum AdjustMode {
/// Peel off all immediate reference types.
Peel,
/// Reset binding mode to the initial mode.
/// Used for destructuring assignment, where we don't want any match ergonomics.
Reset,
/// Produced by ref patterns.
/// Reset the binding mode to the initial mode,
/// and if the old biding mode was by-reference
/// with mutability matching the pattern,
/// mark the pattern as having consumed this reference.
ResetAndConsumeRef(Mutability),
/// Pass on the input binding mode and expected type.
Pass,
}
@ -174,7 +181,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => None,
};
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
let (expected, def_bm, ref_pattern_already_consumed) =
self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
let pat_info = PatInfo {
binding_mode: def_bm,
top_info: ti,
@ -211,7 +219,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
PatKind::Ref(inner, mutbl) => self.check_pat_ref(
pat,
inner,
mutbl,
expected,
pat_info,
ref_pattern_already_consumed,
),
PatKind::Slice(before, slice, after) => {
self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
}
@ -264,17 +279,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Compute the new expected type and default binding mode from the old ones
/// as well as the pattern form we are currently checking.
///
/// Last entry is only relevant for ref patterns (`&` and `&mut`);
/// if `true`, then the ref pattern consumed a match ergonomics inserted reference
/// and so does no need to match against a reference in the scrutinee type.
fn calc_default_binding_mode(
&self,
pat: &'tcx Pat<'tcx>,
expected: Ty<'tcx>,
def_bm: BindingAnnotation,
adjust_mode: AdjustMode,
) -> (Ty<'tcx>, BindingAnnotation) {
) -> (Ty<'tcx>, BindingAnnotation, bool) {
match adjust_mode {
AdjustMode::Pass => (expected, def_bm),
AdjustMode::Reset => (expected, INITIAL_BM),
AdjustMode::Peel => self.peel_off_references(pat, expected, def_bm),
AdjustMode::Pass => (expected, def_bm, false),
AdjustMode::Reset => (expected, INITIAL_BM, false),
AdjustMode::ResetAndConsumeRef(mutbl) => {
(expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl))
}
AdjustMode::Peel => {
let peeled = self.peel_off_references(pat, expected, def_bm);
(peeled.0, peeled.1, false)
}
}
}
@ -329,7 +354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// ```
//
// See issue #46688.
PatKind::Ref(..) => AdjustMode::Reset,
PatKind::Ref(_, mutbl) => AdjustMode::ResetAndConsumeRef(*mutbl),
// A `_` pattern works with any expected type, so there's no need to do anything.
PatKind::Wild
// A malformed pattern doesn't have an expected type, so let's just accept any type.
@ -840,8 +865,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let Some(mt) = self.shallow_resolve(expected).builtin_deref(true)
&& let ty::Dynamic(..) = mt.ty.kind()
{
// This is "x = SomeTrait" being reduced from
// "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
// This is "x = dyn SomeTrait" being reduced from
// "let &x = &dyn SomeTrait" or "let box x = Box<dyn SomeTrait>", an error.
let type_str = self.ty_to_string(expected);
let mut err = struct_span_code_err!(
self.dcx(),
@ -2036,6 +2061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mutbl: Mutability,
expected: Ty<'tcx>,
pat_info: PatInfo<'tcx, '_>,
consumed_inherited_ref: bool,
) -> Ty<'tcx> {
let tcx = self.tcx;
let expected = self.shallow_resolve(expected);
@ -2051,26 +2077,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match *expected.kind() {
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
_ => {
let inner_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span: inner.span,
});
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
let err = self.demand_eqtype_pat_diag(
pat.span,
expected,
ref_ty,
pat_info.top_info,
);
if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
// We already matched against a match-ergonmics inserted reference,
// so we don't need to match against a reference from the original type.
// Save this infor for use in lowering later
self.typeck_results
.borrow_mut()
.skipped_ref_pats_mut()
.insert(pat.hir_id);
(expected, expected)
} else {
let inner_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span: inner.span,
});
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
let err = self.demand_eqtype_pat_diag(
pat.span,
expected,
ref_ty,
pat_info.top_info,
);
// Look for a case like `fn foo(&foo: u32)` and suggest
// `fn foo(foo: &u32)`
if let Some(mut err) = err {
self.borrow_pat_suggestion(&mut err, pat);
err.emit();
// Look for a case like `fn foo(&foo: u32)` and suggest
// `fn foo(foo: &u32)`
if let Some(mut err) = err {
self.borrow_pat_suggestion(&mut err, pat);
err.emit();
}
(ref_ty, inner_ty)
}
(ref_ty, inner_ty)
}
}
}

View File

@ -166,7 +166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
body_id: hir::BodyId,
body: &'tcx hir::Body<'tcx>,
capture_clause: hir::CaptureBy,
mut capture_clause: hir::CaptureBy,
) {
// Extract the type of the closure.
let ty = self.node_ty(closure_hir_id);
@ -259,6 +259,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
.consume_body(body);
// If a coroutine is comes from a coroutine-closure that is `move`, but
// the coroutine-closure was inferred to be `FnOnce` during signature
// inference, then it's still possible that we try to borrow upvars from
// the coroutine-closure because they are not used by the coroutine body
// in a way that forces a move.
//
// This would lead to an impossible to satisfy situation, since `AsyncFnOnce`
// coroutine bodies can't borrow from their parent closure. To fix this,
// we force the inner coroutine to also be `move`. This only matters for
// coroutine-closures that are `move` since otherwise they themselves will
// be borrowing from the outer environment, so there's no self-borrows occuring.
if let UpvarArgs::Coroutine(..) = args
&& let hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) =
self.tcx.coroutine_kind(closure_def_id).expect("coroutine should have kind")
&& let parent_hir_id =
self.tcx.local_def_id_to_hir_id(self.tcx.local_parent(closure_def_id))
&& let parent_ty = self.node_ty(parent_hir_id)
&& let Some(ty::ClosureKind::FnOnce) = self.closure_kind(parent_ty)
{
capture_clause = self.tcx.hir_node(parent_hir_id).expect_closure().capture_clause;
}
debug!(
"For closure={:?}, capture_information={:#?}",
closure_def_id, delegate.capture_information
@ -399,16 +421,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
// Additionally, we can now constrain the coroutine's kind type.
let ty::Coroutine(_, coroutine_args) =
*self.typeck_results.borrow().expr_ty(body.value).kind()
else {
bug!();
};
self.demand_eqtype(
span,
coroutine_args.as_coroutine().kind_ty(),
Ty::from_coroutine_closure_kind(self.tcx, closure_kind),
);
//
// We only do this if `infer_kind`, because if we have constrained
// the kind from closure signature inference, the kind inferred
// for the inner coroutine may actually be more restrictive.
if infer_kind {
let ty::Coroutine(_, coroutine_args) =
*self.typeck_results.borrow().expr_ty(body.value).kind()
else {
bug!();
};
self.demand_eqtype(
span,
coroutine_args.as_coroutine().kind_ty(),
Ty::from_coroutine_closure_kind(self.tcx, closure_kind),
);
}
}
self.log_closure_min_capture_info(closure_def_id, span);

View File

@ -345,6 +345,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
_ => {}
};
self.visit_skipped_ref_pats(p.hir_id);
self.visit_pat_adjustments(p.span, p.hir_id);
self.visit_node_id(p.span, p.hir_id);
@ -674,6 +675,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
}
}
#[instrument(skip(self), level = "debug")]
fn visit_skipped_ref_pats(&mut self, hir_id: hir::HirId) {
if self.fcx.typeck_results.borrow_mut().skipped_ref_pats_mut().remove(hir_id) {
debug!("node is a skipped ref pat");
self.typeck_results.skipped_ref_pats_mut().insert(hir_id);
}
}
fn visit_liberated_fn_sigs(&mut self) {
let fcx_typeck_results = self.fcx.typeck_results.borrow();
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);

View File

@ -96,6 +96,10 @@ pub struct TypeckResults<'tcx> {
/// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
/// Set of reference patterns that match against a match-ergonomics inserted reference
/// (as opposed to against a reference in the scrutinee type).
skipped_ref_pats: ItemLocalSet,
/// Records the reasons that we picked the kind of each closure;
/// not all closures are present in the map.
closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
@ -228,6 +232,7 @@ impl<'tcx> TypeckResults<'tcx> {
adjustments: Default::default(),
pat_binding_modes: Default::default(),
pat_adjustments: Default::default(),
skipped_ref_pats: Default::default(),
closure_kind_origins: Default::default(),
liberated_fn_sigs: Default::default(),
fru_field_types: Default::default(),
@ -435,6 +440,14 @@ impl<'tcx> TypeckResults<'tcx> {
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
}
pub fn skipped_ref_pats(&self) -> LocalSetInContext<'_> {
LocalSetInContext { hir_owner: self.hir_owner, data: &self.skipped_ref_pats }
}
pub fn skipped_ref_pats_mut(&mut self) -> LocalSetInContextMut<'_> {
LocalSetInContextMut { hir_owner: self.hir_owner, data: &mut self.skipped_ref_pats }
}
/// Does the pattern recursively contain a `ref mut` binding in it?
///
/// This is used to determined whether a `deref` pattern should emit a `Deref`
@ -629,6 +642,49 @@ impl<'a, V> LocalTableInContextMut<'a, V> {
}
}
#[derive(Clone, Copy, Debug)]
pub struct LocalSetInContext<'a> {
hir_owner: OwnerId,
data: &'a ItemLocalSet,
}
impl<'a> LocalSetInContext<'a> {
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn contains(&self, id: hir::HirId) -> bool {
validate_hir_id_for_typeck_results(self.hir_owner, id);
self.data.contains(&id.local_id)
}
}
#[derive(Debug)]
pub struct LocalSetInContextMut<'a> {
hir_owner: OwnerId,
data: &'a mut ItemLocalSet,
}
impl<'a> LocalSetInContextMut<'a> {
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn contains(&self, id: hir::HirId) -> bool {
validate_hir_id_for_typeck_results(self.hir_owner, id);
self.data.contains(&id.local_id)
}
pub fn insert(&mut self, id: hir::HirId) -> bool {
validate_hir_id_for_typeck_results(self.hir_owner, id);
self.data.insert(id.local_id)
}
pub fn remove(&mut self, id: hir::HirId) -> bool {
validate_hir_id_for_typeck_results(self.hir_owner, id);
self.data.remove(&id.local_id)
}
}
rustc_index::newtype_index! {
#[derive(HashStable)]
#[encodable]

View File

@ -65,7 +65,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the
// adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
// gets the least-dereferenced type).
let unadjusted_pat = self.lower_pattern_unadjusted(pat);
let unadjusted_pat = match pat.kind {
hir::PatKind::Ref(inner, _)
if self.typeck_results.skipped_ref_pats().contains(pat.hir_id) =>
{
self.lower_pattern_unadjusted(inner)
}
_ => self.lower_pattern_unadjusted(pat),
};
self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
unadjusted_pat,
|pat: Box<_>, ref_ty| {

View File

@ -91,15 +91,17 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
return;
}
let ty::Coroutine(_, coroutine_args) = *coroutine_ty.kind() else { bug!("{body:#?}") };
// We don't need to generate a by-move coroutine if the kind of the coroutine is
// already `FnOnce` -- that means that any upvars that the closure consumes have
// already been taken by-value.
let coroutine_kind = coroutine_args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap();
if coroutine_kind == ty::ClosureKind::FnOnce {
// We don't need to generate a by-move coroutine if the coroutine body was
// produced by the `CoroutineKindShim`, since it's already by-move.
if matches!(body.source.instance, ty::InstanceDef::CoroutineKindShim { .. }) {
return;
}
let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!("{body:#?}") };
let args = args.as_coroutine();
let coroutine_kind = args.kind_ty().to_opt_closure_kind().unwrap();
let parent_def_id = tcx.local_parent(coroutine_def_id);
let ty::CoroutineClosure(_, parent_args) =
*tcx.type_of(parent_def_id).instantiate_identity().kind()
@ -128,6 +130,12 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
// the outer closure body -- we need to change the coroutine to take the
// upvar by value.
if coroutine_capture.is_by_ref() && !parent_capture.is_by_ref() {
assert_ne!(
coroutine_kind,
ty::ClosureKind::FnOnce,
"`FnOnce` coroutine-closures return coroutines that capture from \
their body; it will always result in a borrowck error!"
);
by_ref_fields.insert(FieldIdx::from_usize(num_args + idx));
}

View File

@ -1456,6 +1456,7 @@ symbols! {
receiver,
recursion_limit,
reexport_test_harness_main,
ref_pat_everywhere,
ref_unwind_safe_trait,
reference,
reflect,

View File

@ -407,10 +407,6 @@ fn report_conflicting_impls<'tcx>(
impl_span: Span,
err: &mut Diag<'_, G>,
) {
if (overlap.trait_ref, overlap.self_ty).references_error() {
err.downgrade_to_delayed_bug();
}
match tcx.span_of_impl(overlap.with_impl) {
Ok(span) => {
err.span_label(span, "first implementation here");
@ -463,6 +459,11 @@ fn report_conflicting_impls<'tcx>(
)
});
// Don't report overlap errors if the header references error
if let Err(err) = (overlap.trait_ref, overlap.self_ty).error_reported() {
return Err(err);
}
match used_to_be_allowed {
None => {
let reported = if overlap.with_impl.is_local()

View File

@ -714,8 +714,6 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
// perfect and there may be ways to abuse the fact that we
// ignore requirements with escaping bound vars. That's a
// more general issue however.
//
// FIXME(eddyb) add the type to `walker` instead of recursing.
let fn_sig = tcx.fn_sig(did).instantiate(tcx, args);
fn_sig.output().skip_binder().visit_with(self);

View File

@ -1038,6 +1038,7 @@ class RustBuild(object):
sync_dirs = "--sync ./src/tools/cargo/Cargo.toml " \
"--sync ./src/tools/rust-analyzer/Cargo.toml " \
"--sync ./compiler/rustc_codegen_cranelift/Cargo.toml " \
"--sync ./compiler/rustc_codegen_gcc/Cargo.toml " \
"--sync ./src/bootstrap/Cargo.toml "
eprint('ERROR: vendoring required, but vendor directory does not exist.')
eprint(' Run `cargo vendor {}` to initialize the '

View File

@ -1011,6 +1011,8 @@ impl Step for PlainSourceTarball {
.arg("--sync")
.arg(builder.src.join("./compiler/rustc_codegen_cranelift/Cargo.toml"))
.arg("--sync")
.arg(builder.src.join("./compiler/rustc_codegen_gcc/Cargo.toml"))
.arg("--sync")
.arg(builder.src.join("./src/bootstrap/Cargo.toml"))
// Will read the libstd Cargo.toml
// which uses the unstable `public-dependency` feature.

View File

@ -2102,12 +2102,10 @@ impl<'a> Builder<'a> {
rustdocflags.arg("--cfg=parallel_compiler");
}
// set rustc args passed from command line
let rustc_args =
self.config.cmd.rustc_args().iter().map(|s| s.to_string()).collect::<Vec<_>>();
if !rustc_args.is_empty() {
cargo.env("RUSTFLAGS", &rustc_args.join(" "));
}
// Pass the value of `--rustc-args` from test command. If it's not a test command, this won't set anything.
self.config.cmd.rustc_args().iter().for_each(|v| {
rustflags.arg(v);
});
Cargo {
command: cargo,

View File

@ -3926,11 +3926,17 @@ impl<'test> TestCx<'test> {
cmd.env("IS_MSVC", "1")
.env("IS_WINDOWS", "1")
.env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
.env("CC", format!("'{}' {}", self.config.cc, cflags))
.env("CXX", format!("'{}' {}", &self.config.cxx, cxxflags));
// Note: we diverge from legacy run_make and don't lump `CC` the compiler and
// default flags together.
.env("CC_DEFAULT_FLAGS", &cflags)
.env("CC", &self.config.cc)
.env("CXX_DEFAULT_FLAGS", &cxxflags)
.env("CXX", &self.config.cxx);
} else {
cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
.env("CXX", format!("{} {}", self.config.cxx, self.config.cxxflags))
cmd.env("CC_DEFAULT_FLAGS", &self.config.cflags)
.env("CC", &self.config.cc)
.env("CXX_DEFAULT_FLAGS", &self.config.cxxflags)
.env("CXX", &self.config.cxx)
.env("AR", &self.config.ar);
if self.config.target.contains("windows") {

View File

@ -88,4 +88,38 @@ async fn async_main() {
};
call_once(c).await;
}
fn force_fnonce<T>(f: impl async FnOnce() -> T) -> impl async FnOnce() -> T {
f
}
// Capture something with `move`, but infer to `AsyncFnOnce`
{
let x = Hello(6);
let c = force_fnonce(async move || {
println!("{x:?}");
});
call_once(c).await;
let x = &Hello(7);
let c = force_fnonce(async move || {
println!("{x:?}");
});
call_once(c).await;
}
// Capture something by-ref, but infer to `AsyncFnOnce`
{
let x = Hello(8);
let c = force_fnonce(async || {
println!("{x:?}");
});
call_once(c).await;
let x = &Hello(9);
let c = force_fnonce(async || {
println!("{x:?}");
});
call_once(c).await;
}
}

View File

@ -8,3 +8,7 @@ Hello(3)
Hello(4)
Hello(4)
Hello(5)
Hello(6)
Hello(7)
Hello(8)
Hello(9)

View File

@ -0,0 +1,202 @@
use std::env;
use std::path::Path;
use std::process::{Command, Output};
use crate::{bin_name, cygpath_windows, handle_failed_output, is_msvc, is_windows, tmp_dir, uname};
/// Construct a new platform-specific C compiler invocation.
///
/// WARNING: This means that what flags are accepted by the underlying C compiler is
/// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`.
pub fn cc() -> Cc {
Cc::new()
}
/// A platform-specific C compiler invocation builder. The specific C compiler used is
/// passed down from compiletest.
#[derive(Debug)]
pub struct Cc {
cmd: Command,
}
impl Cc {
/// Construct a new platform-specific C compiler invocation.
///
/// WARNING: This means that what flags are accepted by the underlying C compile is
/// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`.
pub fn new() -> Self {
let compiler = env::var("CC").unwrap();
let mut cmd = Command::new(compiler);
let default_cflags = env::var("CC_DEFAULT_FLAGS").unwrap();
for flag in default_cflags.split(char::is_whitespace) {
cmd.arg(flag);
}
Self { cmd }
}
/// Specify path of the input file.
pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
self.cmd.arg(path.as_ref());
self
}
/// Add a *platform-and-compiler-specific* argument. Please consult the docs for the various
/// possible C compilers on the various platforms to check which arguments are legal for
/// which compiler.
pub fn arg(&mut self, flag: &str) -> &mut Self {
self.cmd.arg(flag);
self
}
/// Add multiple *platform-and-compiler-specific* arguments. Please consult the docs for the
/// various possible C compilers on the various platforms to check which arguments are legal
/// for which compiler.
pub fn args(&mut self, args: &[&str]) -> &mut Self {
self.cmd.args(args);
self
}
/// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler. This assumes that the executable
/// is under `$TMPDIR`.
pub fn out_exe(&mut self, name: &str) -> &mut Self {
// Ref: tools.mk (irrelevant lines omitted):
//
// ```makefile
// ifdef IS_MSVC
// OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
// -Fo:`cygpath -w $(TMPDIR)/$(1).obj`
// else
// OUT_EXE=-o $(TMPDIR)/$(1)
// endif
// ```
if is_msvc() {
let fe_path = cygpath_windows(tmp_dir().join(bin_name(name)));
let fo_path = cygpath_windows(tmp_dir().join(format!("{name}.obj")));
self.cmd.arg(format!("-Fe:{fe_path}"));
self.cmd.arg(format!("-Fo:{fo_path}"));
} else {
self.cmd.arg("-o");
self.cmd.arg(tmp_dir().join(name));
}
self
}
/// Run the constructed C invocation command and assert that it is successfully run.
#[track_caller]
pub fn run(&mut self) -> Output {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();
let output = self.cmd.output().unwrap();
if !output.status.success() {
handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
}
output
}
/// Inspect what the underlying [`Command`] is up to the current construction.
pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self {
f(&self.cmd);
self
}
}
/// `EXTRACFLAGS`
pub fn extra_c_flags() -> Vec<&'static str> {
// Adapted from tools.mk (trimmed):
//
// ```makefile
// ifdef IS_WINDOWS
// ifdef IS_MSVC
// EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib
// else
// EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization
// endif
// else
// ifeq ($(UNAME),Darwin)
// EXTRACFLAGS := -lresolv
// else
// ifeq ($(UNAME),FreeBSD)
// EXTRACFLAGS := -lm -lpthread -lgcc_s
// else
// ifeq ($(UNAME),SunOS)
// EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv
// else
// ifeq ($(UNAME),OpenBSD)
// EXTRACFLAGS := -lm -lpthread -lc++abi
// else
// EXTRACFLAGS := -lm -lrt -ldl -lpthread
// endif
// endif
// endif
// endif
// endif
// ```
if is_windows() {
if is_msvc() {
vec![
"ws2_32.lib",
"userenv.lib",
"advapi32.lib",
"bcrypt.lib",
"ntdll.lib",
"synchronization.lib",
]
} else {
vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"]
}
} else {
match uname() {
n if n.contains("Darwin") => vec!["-lresolv"],
n if n.contains("FreeBSD") => vec!["-lm", "-lpthread", "-lgcc_s"],
n if n.contains("SunOS") => {
vec!["-lm", "-lpthread", "-lposix4", "-lsocket", "-lresolv"]
}
n if n.contains("OpenBSD") => vec!["-lm", "-lpthread", "-lc++abi"],
_ => vec!["-lm", "-lrt", "-ldl", "-lpthread"],
}
}
}
/// `EXTRACXXFLAGS`
pub fn extra_cxx_flags() -> Vec<&'static str> {
// Adapted from tools.mk (trimmed):
//
// ```makefile
// ifdef IS_WINDOWS
// ifdef IS_MSVC
// else
// EXTRACXXFLAGS := -lstdc++
// endif
// else
// ifeq ($(UNAME),Darwin)
// EXTRACXXFLAGS := -lc++
// else
// ifeq ($(UNAME),FreeBSD)
// else
// ifeq ($(UNAME),SunOS)
// else
// ifeq ($(UNAME),OpenBSD)
// else
// EXTRACXXFLAGS := -lstdc++
// endif
// endif
// endif
// endif
// endif
// ```
if is_windows() {
if is_msvc() { vec![] } else { vec!["-lstdc++"] }
} else {
match uname() {
n if n.contains("Darwin") => vec!["-lc++"],
_ => vec!["-lstdc++"],
}
}
}

View File

@ -1,14 +1,16 @@
pub mod cc;
pub mod run;
pub mod rustc;
pub mod rustdoc;
use std::env;
use std::path::PathBuf;
use std::process::Output;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
pub use object;
pub use wasmparser;
pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc};
pub use run::{run, run_fail};
pub use rustc::{aux_build, rustc, Rustc};
pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
@ -18,6 +20,89 @@ pub fn tmp_dir() -> PathBuf {
env::var_os("TMPDIR").unwrap().into()
}
/// `TARGET`
pub fn target() -> String {
env::var("TARGET").unwrap()
}
/// Check if target is windows-like.
pub fn is_windows() -> bool {
env::var_os("IS_WINDOWS").is_some()
}
/// Check if target uses msvc.
pub fn is_msvc() -> bool {
env::var_os("IS_MSVC").is_some()
}
/// Construct a path to a static library under `$TMPDIR` given the library name. This will return a
/// path with `$TMPDIR` joined with platform-and-compiler-specific library name.
pub fn static_lib(name: &str) -> PathBuf {
tmp_dir().join(static_lib_name(name))
}
/// Construct the static library name based on the platform.
pub fn static_lib_name(name: &str) -> String {
// See tools.mk (irrelevant lines omitted):
//
// ```makefile
// ifeq ($(UNAME),Darwin)
// STATICLIB = $(TMPDIR)/lib$(1).a
// else
// ifdef IS_WINDOWS
// ifdef IS_MSVC
// STATICLIB = $(TMPDIR)/$(1).lib
// else
// STATICLIB = $(TMPDIR)/lib$(1).a
// endif
// else
// STATICLIB = $(TMPDIR)/lib$(1).a
// endif
// endif
// ```
assert!(!name.contains(char::is_whitespace), "name cannot contain whitespace");
if target().contains("msvc") { format!("{name}.lib") } else { format!("lib{name}.a") }
}
/// Construct the binary name based on platform.
pub fn bin_name(name: &str) -> String {
if is_windows() { format!("{name}.exe") } else { name.to_string() }
}
/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
/// available on the platform!
#[track_caller]
pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();
let mut cygpath = Command::new("cygpath");
cygpath.arg("-w");
cygpath.arg(path.as_ref());
let output = cygpath.output().unwrap();
if !output.status.success() {
handle_failed_output(&format!("{:#?}", cygpath), output, caller_line_number);
}
let s = String::from_utf8(output.stdout).unwrap();
// cygpath -w can attach a newline
s.trim().to_string()
}
/// Run `uname`. This assumes that `uname` is available on the platform!
#[track_caller]
pub fn uname() -> String {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();
let mut uname = Command::new("uname");
let output = uname.output().unwrap();
if !output.status.success() {
handle_failed_output(&format!("{:#?}", uname), output, caller_line_number);
}
String::from_utf8(output.stdout).unwrap()
}
fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! {
if output.status.success() {
eprintln!("command incorrectly succeeded at line {caller_line_number}");

View File

@ -2,17 +2,14 @@ use std::env;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use super::handle_failed_output;
use crate::is_windows;
fn run_common(bin_name: &str) -> (Command, Output) {
let target = env::var("TARGET").unwrap();
let bin_name =
if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() };
use super::{bin_name, handle_failed_output};
fn run_common(name: &str) -> (Command, Output) {
let mut bin_path = PathBuf::new();
bin_path.push(env::var("TMPDIR").unwrap());
bin_path.push(&bin_name);
bin_path.push(&bin_name(name));
let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap();
let mut cmd = Command::new(bin_path);
cmd.env(&ld_lib_path_envvar, {
@ -27,7 +24,7 @@ fn run_common(bin_name: &str) -> (Command, Output) {
env::join_paths(paths.iter()).unwrap()
});
if target.contains("windows") {
if is_windows() {
let mut paths = vec![];
for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) {
paths.push(p.to_path_buf());
@ -42,11 +39,11 @@ fn run_common(bin_name: &str) -> (Command, Output) {
/// Run a built binary and make sure it succeeds.
#[track_caller]
pub fn run(bin_name: &str) -> Output {
pub fn run(name: &str) -> Output {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();
let (cmd, output) = run_common(bin_name);
let (cmd, output) = run_common(name);
if !output.status.success() {
handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
}
@ -55,11 +52,11 @@ pub fn run(bin_name: &str) -> Output {
/// Run a built binary and make sure it fails.
#[track_caller]
pub fn run_fail(bin_name: &str) -> Output {
pub fn run_fail(name: &str) -> Output {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();
let (cmd, output) = run_common(bin_name);
let (cmd, output) = run_common(name);
if output.status.success() {
handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
}

View File

@ -5,7 +5,6 @@ run-make/allocator-shim-circular-deps/Makefile
run-make/allow-non-lint-warnings-cmdline/Makefile
run-make/allow-warnings-cmdline-stability/Makefile
run-make/archive-duplicate-names/Makefile
run-make/arguments-non-c-like-enum/Makefile
run-make/atomic-lock-free/Makefile
run-make/bare-outfile/Makefile
run-make/branch-protection-check-IBT/Makefile
@ -131,7 +130,6 @@ run-make/issue-53964/Makefile
run-make/issue-64153/Makefile
run-make/issue-68794-textrel-on-minimal-lib/Makefile
run-make/issue-69368/Makefile
run-make/issue-7349/Makefile
run-make/issue-83045/Makefile
run-make/issue-83112-incr-test-moved-file/Makefile
run-make/issue-84395-lto-embed-bitcode/Makefile

View File

@ -56,7 +56,7 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>)
Some((&["rustc_codegen_cranelift"], PERMITTED_CRANELIFT_DEPENDENCIES)),
),
// tidy-alphabetical-start
//("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None), // FIXME uncomment once all deps are vendored
("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None),
//("library/backtrace", &[], None), // FIXME uncomment once rust-lang/backtrace#562 has been synced back to the rust repo
//("library/portable-simd", &[], None), // FIXME uncomment once rust-lang/portable-simd#363 has been synced back to the rust repo
//("library/stdarch", EXCEPTIONS_STDARCH, None), // FIXME uncomment once rust-lang/stdarch#1462 has been synced back to the rust repo
@ -164,15 +164,12 @@ const EXCEPTIONS_CRANELIFT: ExceptionList = &[
// tidy-alphabetical-end
];
// FIXME uncomment once all deps are vendored
/*
const EXCEPTIONS_GCC: ExceptionList = &[
// tidy-alphabetical-start
("gccjit", "GPL-3.0"),
("gccjit_sys", "GPL-3.0"),
// tidy-alphabetical-end
];
*/
const EXCEPTIONS_BOOTSTRAP: ExceptionList = &[
("ryu", "Apache-2.0 OR BSL-1.0"), // through serde. BSL is not acceptble, but we use it under Apache-2.0

View File

@ -0,0 +1,33 @@
// Test to make sure that inner functions within a polymorphic outer function
// don't get re-codegened when the outer function is monomorphized. The test
// code monomorphizes the outer functions several times, but the magic constants
// used in the inner functions should each appear only once in the generated IR.
// issue: rust-lang/rust#7349
//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0
// CHECK-COUNT-1: ret i32 8675309
// CHECK-COUNT-1: ret i32 11235813
fn outer<T>() {
#[allow(dead_code)]
fn inner() -> u32 {
8675309
}
inner();
}
extern "C" fn outer_foreign<T>() {
#[allow(dead_code)]
fn inner() -> u32 {
11235813
}
inner();
}
fn main() {
outer::<isize>();
outer::<usize>();
outer_foreign::<isize>();
outer_foreign::<usize>();
}

View File

@ -1,8 +0,0 @@
# ignore-cross-compile
include ../tools.mk
all:
$(RUSTC) --crate-type=staticlib nonclike.rs
$(CC) test.c $(call STATICLIB,nonclike) $(call OUT_EXE,test) \
$(EXTRACFLAGS) $(EXTRACXXFLAGS)
$(call RUN,test)

View File

@ -0,0 +1,20 @@
//! Check that non-trivial `repr(C)` enum in Rust has valid C layout.
//@ ignore-cross-compile
extern crate run_make_support;
use run_make_support::{cc, extra_c_flags, extra_cxx_flags, run, rustc, static_lib};
pub fn main() {
use std::path::Path;
rustc().input("nonclike.rs").crate_type("staticlib").run();
cc().input("test.c")
.input(static_lib("nonclike"))
.out_exe("test")
.args(&extra_c_flags())
.args(&extra_cxx_flags())
.inspect(|cmd| eprintln!("{cmd:?}"))
.run();
run("test");
}

View File

@ -1,11 +0,0 @@
include ../tools.mk
# Test to make sure that inner functions within a polymorphic outer function
# don't get re-codegened when the outer function is monomorphized. The test
# code monomorphizes the outer functions several times, but the magic constants
# used in the inner functions should each appear only once in the generated IR.
all:
$(RUSTC) foo.rs --emit=llvm-ir
[ "$$(grep -c 'ret i32 8675309' "$(TMPDIR)/foo.ll")" -eq "1" ]
[ "$$(grep -c 'ret i32 11235813' "$(TMPDIR)/foo.ll")" -eq "1" ]

View File

@ -1,22 +0,0 @@
fn outer<T>() {
#[allow(dead_code)]
fn inner() -> u32 {
8675309
}
inner();
}
extern "C" fn outer_foreign<T>() {
#[allow(dead_code)]
fn inner() -> u32 {
11235813
}
inner();
}
fn main() {
outer::<isize>();
outer::<usize>();
outer_foreign::<isize>();
outer_foreign::<usize>();
}

View File

@ -79,4 +79,38 @@ async fn async_main() {
};
call_once(c).await;
}
fn force_fnonce<T>(f: impl async FnOnce() -> T) -> impl async FnOnce() -> T {
f
}
// Capture something with `move`, but infer to `AsyncFnOnce`
{
let x = Hello(6);
let c = force_fnonce(async move || {
println!("{x:?}");
});
call_once(c).await;
let x = &Hello(7);
let c = force_fnonce(async move || {
println!("{x:?}");
});
call_once(c).await;
}
// Capture something by-ref, but infer to `AsyncFnOnce`
{
let x = Hello(8);
let c = force_fnonce(async || {
println!("{x:?}");
});
call_once(c).await;
let x = &Hello(9);
let c = force_fnonce(async || {
println!("{x:?}");
});
call_once(c).await;
}
}

View File

@ -8,3 +8,7 @@ Hello(3)
Hello(4)
Hello(4)
Hello(5)
Hello(6)
Hello(7)
Hello(8)
Hello(9)

View File

@ -2,18 +2,22 @@
#![feature(async_closure)]
fn main() {
fn needs_async_fn(_: impl async Fn()) {}
fn needs_async_fn(_: impl async Fn()) {}
fn a() {
let mut x = 1;
needs_async_fn(async || {
//~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut`
//~^ ERROR cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
x += 1;
});
}
fn b() {
let x = String::new();
needs_async_fn(move || async move {
//~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce`
println!("{x}");
});
}
fn main() {}

View File

@ -1,26 +1,5 @@
error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut`
--> $DIR/wrong-fn-kind.rs:9:20
|
LL | needs_async_fn(async || {
| -------------- -^^^^^^^
| | |
| _____|______________this closure implements `async FnMut`, not `async Fn`
| | |
| | required by a bound introduced by this call
LL | |
LL | | x += 1;
| | - closure is `async FnMut` because it mutates the variable `x` here
LL | | });
| |_____- the requirement to implement `async Fn` derives from here
|
note: required by a bound in `needs_async_fn`
--> $DIR/wrong-fn-kind.rs:6:31
|
LL | fn needs_async_fn(_: impl async Fn()) {}
| ^^^^^^^^^^ required by this bound in `needs_async_fn`
error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce`
--> $DIR/wrong-fn-kind.rs:15:20
--> $DIR/wrong-fn-kind.rs:17:20
|
LL | needs_async_fn(move || async move {
| -------------- -^^^^^^
@ -35,11 +14,29 @@ LL | | });
| |_____- the requirement to implement `async Fn` derives from here
|
note: required by a bound in `needs_async_fn`
--> $DIR/wrong-fn-kind.rs:6:31
--> $DIR/wrong-fn-kind.rs:5:27
|
LL | fn needs_async_fn(_: impl async Fn()) {}
| ^^^^^^^^^^ required by this bound in `needs_async_fn`
LL | fn needs_async_fn(_: impl async Fn()) {}
| ^^^^^^^^^^ required by this bound in `needs_async_fn`
error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
--> $DIR/wrong-fn-kind.rs:9:29
|
LL | fn needs_async_fn(_: impl async Fn()) {}
| --------------- change this to accept `FnMut` instead of `Fn`
...
LL | needs_async_fn(async || {
| _____--------------_--------_^
| | | |
| | | in this closure
| | expects `Fn` instead of `FnMut`
LL | |
LL | | x += 1;
| | - mutable borrow occurs due to use of `x` in closure
LL | | });
| |_____^ cannot borrow as mutable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0525`.
Some errors have detailed explanations: E0525, E0596.
For more information about an error, try `rustc --explain E0525`.

View File

@ -0,0 +1,27 @@
error[E0726]: implicit elided lifetime not allowed here
--> $DIR/skip-reporting-if-references-err.rs:10:9
|
LL | impl<T> ToUnit for T {}
| ^^^^^^ expected lifetime parameter
|
help: indicate the anonymous lifetime
|
LL | impl<T> ToUnit<'_> for T {}
| ++++
error[E0277]: the trait bound `for<'a> (): ToUnit<'a>` is not satisfied
--> $DIR/skip-reporting-if-references-err.rs:15:29
|
LL | impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `()`
error[E0277]: the trait bound `for<'a> (): ToUnit<'a>` is not satisfied
--> $DIR/skip-reporting-if-references-err.rs:15:18
|
LL | impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `()`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0277, E0726.
For more information about an error, try `rustc --explain E0277`.

View File

@ -0,0 +1,14 @@
error[E0726]: implicit elided lifetime not allowed here
--> $DIR/skip-reporting-if-references-err.rs:10:9
|
LL | impl<T> ToUnit for T {}
| ^^^^^^ expected lifetime parameter
|
help: indicate the anonymous lifetime
|
LL | impl<T> ToUnit<'_> for T {}
| ++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0726`.

View File

@ -0,0 +1,19 @@
// Regression test for #121006.
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
trait ToUnit<'a> {
type Unit;
}
impl<T> ToUnit for T {}
//~^ ERROR implicit elided lifetime not allowed here
trait Overlap {}
impl<U> Overlap for fn(U) {}
impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {}
//[current]~^ ERROR the trait bound `for<'a> (): ToUnit<'a>` is not satisfied
//[current]~| ERROR the trait bound `for<'a> (): ToUnit<'a>` is not satisfied
fn main() {}

View File

@ -0,0 +1,14 @@
pub fn main() {
if let Some(Some(&x)) = &Some(&Some(0)) {
//~^ ERROR: mismatched types [E0308]
let _: u32 = x;
}
if let Some(&Some(x)) = &Some(Some(0)) {
//~^ ERROR: mismatched types [E0308]
let _: u32 = x;
}
if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
//~^ ERROR: mismatched types [E0308]
let _: u32 = x;
}
}

View File

@ -0,0 +1,49 @@
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_everywhere.rs:2:22
|
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(Some(x)) = &Some(&Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_everywhere.rs:6:17
|
LL | if let Some(&Some(x)) = &Some(Some(0)) {
| ^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>`
| |
| expected `Option<{integer}>`, found `&_`
|
= note: expected enum `Option<{integer}>`
found reference `&_`
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_everywhere.rs:10:22
|
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
| ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/feature-gate-ref_pat_everywhere.rs:10:22
|
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
| ^^^^^^
help: consider removing `&mut` from the pattern
|
LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) {
| ~
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,16 @@
#![allow(incomplete_features)]
#![feature(ref_pat_everywhere)]
pub fn main() {
if let Some(&x) = Some(0) {
//~^ ERROR: mismatched types [E0308]
let _: u32 = x;
}
if let &Some(x) = &mut Some(0) {
//~^ ERROR: mismatched types [E0308]
let _: u32 = x;
}
if let Some(&x) = &mut Some(0) {
//~^ ERROR: mismatched types [E0308]
let _: u32 = x;
}
}

View File

@ -0,0 +1,44 @@
error[E0308]: mismatched types
--> $DIR/ref_pat_everywhere-mutability-mismatch.rs:4:17
|
LL | if let Some(&x) = Some(0) {
| ^^ ------- this expression has type `Option<{integer}>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(x) = Some(0) {
| ~
error[E0308]: mismatched types
--> $DIR/ref_pat_everywhere-mutability-mismatch.rs:8:12
|
LL | if let &Some(x) = &mut Some(0) {
| ^^^^^^^^ ------------ this expression has type `&mut Option<{integer}>`
| |
| types differ in mutability
|
= note: expected mutable reference `&mut Option<{integer}>`
found reference `&_`
error[E0308]: mismatched types
--> $DIR/ref_pat_everywhere-mutability-mismatch.rs:12:17
|
LL | if let Some(&x) = &mut Some(0) {
| ^^ ------------ this expression has type `&mut Option<{integer}>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(x) = &mut Some(0) {
| ~
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,18 @@
//@ run-pass
#![allow(incomplete_features)]
#![feature(ref_pat_everywhere)]
pub fn main() {
if let Some(Some(&x)) = &Some(&Some(0)) {
let _: u32 = x;
}
if let Some(&Some(x)) = &Some(Some(0)) {
let _: u32 = x;
}
if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(&mut Some(0)) {
let _: u32 = x;
}
}

View File

@ -469,11 +469,11 @@ message = "Some changes occurred in need_type_info.rs"
cc = ["@lcnr"]
[mentions."compiler/rustc_middle/src/ty/relate.rs"]
message = "Type relation code was changed"
message = "changes to the core type system"
cc = ["@compiler-errors", "@lcnr"]
[mentions."compiler/rustc_infer/src/infer/relate"]
message = "Type relation code was changed"
message = "changes to the core type system"
cc = ["@compiler-errors", "@lcnr"]
[mentions."compiler/rustc_middle/src/mir/interpret"]
@ -484,6 +484,10 @@ cc = ["@rust-lang/miri"]
message = "Some changes occurred to MIR optimizations"
cc = ["@rust-lang/wg-mir-opt"]
[mentions."compiler/rustc_trait_selection/src/traits/wf.rs"]
message = "changes to the core type system"
cc = ["@compiler-errors", "@lcnr"]
[mentions."compiler/rustc_trait_selection/src/traits/const_evaluatable.rs"]
message = "Some changes occurred in `const_evaluatable.rs`"
cc = ["@BoxyUwU"]