Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 4 pull requests #61519

Closed
wants to merge 13 commits into from
10 changes: 7 additions & 3 deletions src/librustc/infer/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<V>(
&self,
value: &V,
Expand Down
4 changes: 3 additions & 1 deletion src/librustc/traits/query/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 12 additions & 1 deletion src/librustc_mir/dataflow/impls/borrowed_locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
12 changes: 11 additions & 1 deletion src/librustc_mir/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rustc::mir::interpret::{
};

use super::{
Machine, PlaceTy, OpTy, InterpretCx,
Machine, PlaceTy, OpTy, InterpretCx, Immediate,
};

mod type_name;
Expand Down Expand Up @@ -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"
Expand Down
17 changes: 12 additions & 5 deletions src/librustc_mir/interpret/intrinsics/type_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
18 changes: 11 additions & 7 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
})
}
}
}
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
37 changes: 37 additions & 0 deletions src/test/run-pass/ctfe/const-fn-type-name.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// run-pass

#![feature(core_intrinsics)]
#![feature(const_fn)]
#![allow(dead_code)]

const fn type_name_wrapper<T>(_: &T) -> &'static str {
unsafe { core::intrinsics::type_name::<T>() }
}

struct Struct<TA, TB, TC> {
a: TA,
b: TB,
c: TC,
}

type StructInstantiation = Struct<i8, f64, bool>;

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);
}
15 changes: 15 additions & 0 deletions src/test/ui/issues/issue-61475.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// run-pass
#![allow(dead_code)]

enum E {
A, B
}

fn main() {
match &&E::A {
&&E::A => {
}
&&E::B => {
}
};
}
11 changes: 11 additions & 0 deletions src/test/ui/nll/empty-type-predicate.rs
Original file line number Diff line number Diff line change
@@ -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() {}
34 changes: 34 additions & 0 deletions src/test/ui/nll/issue-61311-normalize.rs
Original file line number Diff line number Diff line change
@@ -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<T> HasProj for T {
type Proj = Unit;
}

trait HasProjFn {
type Proj;
fn the_fn(_: Self::Proj);
}

impl HasProjFn for Unit
where
Box<dyn Obj + 'static>: HasProj,
<Box<dyn Obj + 'static> as HasProj>::Proj: Bound,
{
type Proj = Unit;
fn the_fn(_: Self::Proj) {}
}

fn main() {}
Loading