diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 0e9dbcac5cd64..ae4bfcaa90373 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -115,13 +115,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// A hacky variant of `canonicalize_query` that does not /// canonicalize `'static`. Unfortunately, the existing leak - /// check treaks `'static` differently in some cases (see also + /// check treats `'static` differently in some cases (see also /// #33684), so if we are performing an operation that may need to /// prove "leak-check" related things, we leave `'static` /// alone. + /// + /// `'static` is also special cased when winnowing candidates when + /// selecting implementation candidates, so we also have to leave `'static` + /// alone for queries that do selection. // - // FIXME(#48536): once we have universes, we can remove this and just use - // `canonicalize_query`. + // FIXME(#48536): once the above issues are resolved, we can remove this + // and just use `canonicalize_query`. pub fn canonicalize_hr_query_hack( &self, value: &V, diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index d09a9c107869b..0b20ec884fc4d 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -145,7 +145,9 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx let gcx = self.infcx.tcx.global_tcx(); let mut orig_values = OriginalQueryValues::default(); - let c_data = self.infcx.canonicalize_query( + // HACK(matthewjasper) `'static` is special-cased in selection, + // so we cannot canonicalize it. + let c_data = self.infcx.canonicalize_hr_query_hack( &self.param_env.and(*data), &mut orig_values); debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs index 3b663ef6dad61..361353f8df4c8 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs @@ -334,6 +334,13 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> { match outlives_bound { OutlivesBound::RegionSubRegion(r1, r2) => { + // `where Type:` is lowered to `where Type: 'empty` so that + // we check `Type` is well formed, but there's no use for + // this bound here. + if let ty::ReEmpty = r1 { + return; + } + // The bound says that `r1 <= r2`; we store `r2: r1`. let r1 = self.universal_regions.to_region_vid(r1); let r2 = self.universal_regions.to_region_vid(r2); diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs index 47af10a1c5023..55ec46566a487 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -56,9 +56,20 @@ impl<'a, 'tcx> BitDenotation<'tcx> for HaveBeenBorrowedLocals<'a, 'tcx> { fn terminator_effect(&self, sets: &mut BlockSets<'_, Local>, loc: Location) { + let terminator = self.mir[loc.block].terminator(); BorrowedLocalsVisitor { sets, - }.visit_terminator(self.mir[loc.block].terminator(), loc); + }.visit_terminator(terminator, loc); + match &terminator.kind { + // Drop terminators borrows the location + TerminatorKind::Drop { location, .. } | + TerminatorKind::DropAndReplace { location, .. } => { + if let Some(local) = find_local(location) { + sets.gen(local); + } + } + _ => (), + } } fn propagate_call_return( diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 34e9b4972a16d..61375d3bab594 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -11,7 +11,7 @@ use rustc::mir::interpret::{ }; use super::{ - Machine, PlaceTy, OpTy, InterpretCx, + Machine, PlaceTy, OpTy, InterpretCx, Immediate, }; mod type_name; @@ -78,6 +78,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> let id_val = Scalar::from_uint(type_id, dest.layout.size); self.write_scalar(id_val, dest)?; } + + "type_name" => { + let alloc = alloc_type_name(self.tcx.tcx, substs.type_at(0)); + let name_id = self.tcx.alloc_map.lock().create_memory_alloc(alloc); + let id_ptr = self.memory.tag_static_base_pointer(name_id.into()); + let alloc_len = alloc.bytes.len() as u64; + let name_val = Immediate::new_slice(Scalar::Ptr(id_ptr), alloc_len, self); + self.write_immediate(name_val, dest)?; + } + | "ctpop" | "cttz" | "cttz_nonzero" diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs index 456fc70fc0d1d..1270b35ebb955 100644 --- a/src/librustc_mir/interpret/intrinsics/type_name.rs +++ b/src/librustc_mir/interpret/intrinsics/type_name.rs @@ -213,16 +213,23 @@ impl Write for AbsolutePathPrinter<'_, '_> { /// Produces an absolute path representation of the given type. See also the documentation on /// `std::any::type_name` pub fn type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> { - let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path; - let len = path.len(); - let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes()); - let alloc = tcx.intern_const_alloc(alloc); + let alloc = alloc_type_name(tcx, ty); tcx.mk_const(ty::Const { val: ConstValue::Slice { data: alloc, start: 0, - end: len, + end: alloc.bytes.len(), }, ty: tcx.mk_static_str(), }) } + +/// Directly returns an `Allocation` containing an absolute path representation of the given type. +pub(super) fn alloc_type_name<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: Ty<'tcx> +) -> &'tcx Allocation { + let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path; + let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes()); + tcx.intern_const_alloc(alloc) +} diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ae1e5116c676e..dafa4d5c3ecca 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -628,10 +628,10 @@ impl<'a> Parser<'a> { } _ => { Err(if self.prev_token_kind == PrevTokenKind::DocComment { - self.span_fatal_err(self.prev_span, Error::UselessDocComment) - } else { - self.expected_ident_found() - }) + self.span_fatal_err(self.prev_span, Error::UselessDocComment) + } else { + self.expected_ident_found() + }) } } } @@ -1657,8 +1657,8 @@ impl<'a> Parser<'a> { path = self.parse_path(PathStyle::Type)?; path_span = path_lo.to(self.prev_span); } else { - path = ast::Path { segments: Vec::new(), span: DUMMY_SP }; path_span = self.span.to(self.span); + path = ast::Path { segments: Vec::new(), span: path_span }; } // See doc comment for `unmatched_angle_bracket_count`. @@ -2844,7 +2844,11 @@ impl<'a> Parser<'a> { // want to keep their span info to improve diagnostics in these cases in a later stage. (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3` (true, Some(AssocOp::Subtract)) | // `{ 42 } -5` - (true, Some(AssocOp::Add)) => { // `{ 42 } + 42 + (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) + (true, Some(AssocOp::Add)) // `{ 42 } + 42 + // If the next token is a keyword, then the tokens above *are* unambiguously incorrect: + // `if x { a } else { b } && if y { c } else { d }` + if !self.look_ahead(1, |t| t.is_reserved_ident()) => { // These cases are ambiguous and can't be identified in the parser alone let sp = self.sess.source_map().start_point(self.span); self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span); @@ -5298,7 +5302,7 @@ impl<'a> Parser<'a> { let mut where_clause = WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), - span: DUMMY_SP, + span: self.prev_span.to(self.prev_span), }; if !self.eat_keyword(kw::Where) { diff --git a/src/test/run-pass/ctfe/const-fn-type-name.rs b/src/test/run-pass/ctfe/const-fn-type-name.rs new file mode 100644 index 0000000000000..2ee6415aa68b7 --- /dev/null +++ b/src/test/run-pass/ctfe/const-fn-type-name.rs @@ -0,0 +1,37 @@ +// run-pass + +#![feature(core_intrinsics)] +#![feature(const_fn)] +#![allow(dead_code)] + +const fn type_name_wrapper(_: &T) -> &'static str { + unsafe { core::intrinsics::type_name::() } +} + +struct Struct { + a: TA, + b: TB, + c: TC, +} + +type StructInstantiation = Struct; + +const CONST_STRUCT: StructInstantiation = StructInstantiation { + a: 12, + b: 13.7, + c: false, +}; + +const CONST_STRUCT_NAME: &'static str = type_name_wrapper(&CONST_STRUCT); + +fn main() { + let non_const_struct = StructInstantiation { + a: 87, + b: 65.99, + c: true, + }; + + let non_const_struct_name = type_name_wrapper(&non_const_struct); + + assert_eq!(CONST_STRUCT_NAME, non_const_struct_name); +} diff --git a/src/test/ui/issues/issue-61475.rs b/src/test/ui/issues/issue-61475.rs new file mode 100644 index 0000000000000..680449c9ef3e6 --- /dev/null +++ b/src/test/ui/issues/issue-61475.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(dead_code)] + +enum E { + A, B +} + +fn main() { + match &&E::A { + &&E::A => { + } + &&E::B => { + } + }; +} diff --git a/src/test/ui/nll/empty-type-predicate.rs b/src/test/ui/nll/empty-type-predicate.rs new file mode 100644 index 0000000000000..75431d40ce542 --- /dev/null +++ b/src/test/ui/nll/empty-type-predicate.rs @@ -0,0 +1,11 @@ +// Regression test for #61315 +// +// `dyn T:` is lowered to `dyn T: ReEmpty` - check that we don't ICE in NLL for +// the unexpected region. + +// compile-pass + +trait T {} +fn f() where dyn T: {} + +fn main() {} diff --git a/src/test/ui/nll/issue-61311-normalize.rs b/src/test/ui/nll/issue-61311-normalize.rs new file mode 100644 index 0000000000000..1164e9ef2d62f --- /dev/null +++ b/src/test/ui/nll/issue-61311-normalize.rs @@ -0,0 +1,34 @@ +// Regression test for #61311 +// We would ICE after failing to normalize `Self::Proj` in the `impl` below. + +// compile-pass + +pub struct Unit; +trait Obj {} + +trait Bound {} +impl Bound for Unit {} + +pub trait HasProj { + type Proj; +} + +impl HasProj for T { + type Proj = Unit; +} + +trait HasProjFn { + type Proj; + fn the_fn(_: Self::Proj); +} + +impl HasProjFn for Unit +where + Box: HasProj, + as HasProj>::Proj: Bound, +{ + type Proj = Unit; + fn the_fn(_: Self::Proj) {} +} + +fn main() {} diff --git a/src/test/ui/nll/issue-61320-normalize.rs b/src/test/ui/nll/issue-61320-normalize.rs new file mode 100644 index 0000000000000..a36ccd36113b5 --- /dev/null +++ b/src/test/ui/nll/issue-61320-normalize.rs @@ -0,0 +1,160 @@ +// Regression test for #61320 +// This is the same issue as #61311, just a larger test case. + +// compile-pass + +pub struct AndThen +where + A: Future, + B: IntoFuture, +{ + state: (A, B::Future, F), +} + +pub struct FutureResult { + inner: Option>, +} + +impl Future for FutureResult { + type Item = T; + type Error = E; + + fn poll(&mut self) -> Poll { + unimplemented!() + } +} + +pub type Poll = Result; + +impl Future for AndThen +where + A: Future, + B: IntoFuture, + F: FnOnce(A::Item) -> B, +{ + type Item = B::Item; + type Error = B::Error; + + fn poll(&mut self) -> Poll { + unimplemented!() + } +} + +pub trait Future { + type Item; + + type Error; + + fn poll(&mut self) -> Poll; + + fn and_then(self, f: F) -> AndThen + where + F: FnOnce(Self::Item) -> B, + B: IntoFuture, + Self: Sized, + { + unimplemented!() + } +} + +pub trait IntoFuture { + /// The future that this type can be converted into. + type Future: Future; + + /// The item that the future may resolve with. + type Item; + /// The error that the future may resolve with. + type Error; + + /// Consumes this object and produces a future. + fn into_future(self) -> Self::Future; +} + +impl IntoFuture for F { + type Future = F; + type Item = F::Item; + type Error = F::Error; + + fn into_future(self) -> F { + self + } +} + +impl Future for ::std::boxed::Box { + type Item = F::Item; + type Error = F::Error; + + fn poll(&mut self) -> Poll { + (**self).poll() + } +} + +impl IntoFuture for Result { + type Future = FutureResult; + type Item = T; + type Error = E; + + fn into_future(self) -> FutureResult { + unimplemented!() + } +} + +struct Request(T); + +trait RequestContext {} +impl RequestContext for T {} +struct NoContext; +impl AsRef for NoContext { + fn as_ref(&self) -> &Self { + &NoContext + } +} + +type BoxedError = Box; +type DefaultFuture = Box + Send>; + +trait Guard: Sized { + type Result: IntoFuture; + fn from_request(request: &Request<()>) -> Self::Result; +} + +trait FromRequest: Sized { + type Context; + type Future: Future + Send; + fn from_request(request: Request<()>) -> Self::Future; +} + +struct MyGuard; +impl Guard for MyGuard { + type Result = Result; + fn from_request(_request: &Request<()>) -> Self::Result { + Ok(MyGuard) + } +} + +struct Generic { + _inner: I, +} + +impl FromRequest for Generic +where + MyGuard: Guard, + ::Result: IntoFuture, + <::Result as IntoFuture>::Future: Send, + I: FromRequest, +{ + type Future = DefaultFuture; + type Context = NoContext; + fn from_request(headers: Request<()>) -> DefaultFuture { + let _future = ::from_request(&headers) + .into_future() + .and_then(move |_| { + ::from_request(headers) + .into_future() + .and_then(move |fld_inner| Ok(Generic { _inner: fld_inner }).into_future()) + }); + panic!(); + } +} + +fn main() {}