use hir;
use hir::print as pprust;
+use lint;
use hir::def::Def;
use hir::def_id::DefId;
use infer::{self, TypeOrigin};
let (fn_decl, generics) = rebuilder.rebuild();
self.give_expl_lifetime_param(err, &fn_decl, unsafety, constness, name, &generics, span);
}
+
+ pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) {
+ for issue32330 in issue32330s {
+ match *issue32330 {
+ ty::Issue32330::WontChange => { }
+ ty::Issue32330::WillChange { fn_def_id, region_name } => {
+ self.tcx.sess.add_lint(
+ lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
+ ast::CRATE_NODE_ID,
+ span,
+ format!("lifetime parameter `{0}` declared on fn `{1}` \
+ appears only in the return type, \
+ but here is required to be higher-ranked, \
+ which means that `{0}` must appear in both \
+ argument and return types",
+ region_name,
+ self.tcx.item_path_str(fn_def_id)));
+ }
+ }
+ }
+ }
}
struct RebuildPathInfo<'a> {
span: codemap::DUMMY_SP,
name: name }
}
+
use super::{CombinedSnapshot,
InferCtxt,
+ LateBoundRegion,
HigherRankedType,
SubregionOrigin,
SkolemizationMap};
debug!("leak_check: skol_map={:?}",
skol_map);
+ // ## Issue #32330 warnings
+ //
+ // When Issue #32330 is fixed, a certain number of late-bound
+ // regions (LBR) will become early-bound. We wish to issue
+ // warnings when the result of `leak_check` relies on such LBR, as
+ // that means that compilation will likely start to fail.
+ //
+ // Recall that when we do a "HR subtype" check, we replace all
+ // late-bound regions (LBR) in the subtype with fresh variables,
+ // and skolemize the late-bound regions in the supertype. If those
+ // skolemized regions from the supertype wind up being
+ // super-regions (directly or indirectly) of either
+ //
+ // - another skolemized region; or,
+ // - some region that pre-exists the HR subtype check
+ // - e.g., a region variable that is not one of those created
+ // to represent bound regions in the subtype
+ //
+ // then leak-check (and hence the subtype check) fails.
+ //
+ // What will change when we fix #32330 is that some of the LBR in the
+ // subtype may become early-bound. In that case, they would no longer be in
+ // the "permitted set" of variables that can be related to a skolemized
+ // type.
+ //
+ // So the foundation for this warning is to collect variables that we found
+ // to be related to a skolemized type. For each of them, we have a
+ // `BoundRegion` which carries a `Issue32330` flag. We check whether any of
+ // those flags indicate that this variable was created from a lifetime
+ // that will change from late- to early-bound. If so, we issue a warning
+ // indicating that the results of compilation may change.
+ //
+ // This is imperfect, since there are other kinds of code that will not
+ // compile once #32330 is fixed. However, it fixes the errors observed in
+ // practice on crater runs.
+ let mut warnings = vec![];
+
let new_vars = self.region_vars_confined_to_snapshot(snapshot);
for (&skol_br, &skol) in skol_map {
// The inputs to a skolemized variable can only
// or new variables:
match tainted_region {
ty::ReVar(vid) => {
- if new_vars.iter().any(|&x| x == vid) { continue; }
+ if new_vars.contains(&vid) {
+ warnings.extend(
+ match self.region_vars.var_origin(vid) {
+ LateBoundRegion(_,
+ ty::BrNamed(_, _, wc),
+ _) => Some(wc),
+ _ => None,
+ });
+ continue;
+ }
}
_ => {
if tainted_region == skol { continue; }
}
}
+ self.issue_32330_warnings(span, &warnings);
+
for (_, &skol) in skol_map {
// The outputs from a skolemized variable must all be
// equatable with `'static`.
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(unboxed_closures)]
+#![feature(rustc_attrs)]
+
+// Test for projection cache. We should be able to project distinct
+// lifetimes from `foo` as we reinstantiate it multiple times, but not
+// if we do it just once. In this variant, the region `'a` is used in
+// an contravariant position, which affects the results.
+
+// revisions: ok oneuse transmute krisskross
+
+#![allow(dead_code, unused_variables)]
+
+fn foo<'a>() -> &'a u32 { loop { } }
+
+fn bar<T>(t: T, x: T::Output) -> T::Output
+ where T: FnOnce<()>
+{
+ t()
+}
+
+#[cfg(ok)] // two instantiations: OK
+fn baz<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
+ let a = bar(foo, x);
+ let b = bar(foo, y);
+ (a, b)
+}
+
+#[cfg(oneuse)] // one instantiation: OK (surprisingly)
+fn baz<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
+ let f /* : fn() -> &'static u32 */ = foo; // <-- inferred type annotated
+ let a = bar(f, x); // this is considered ok because fn args are contravariant...
+ let b = bar(f, y); // ...and hence we infer T to distinct values in each call.
+ (a, b)
+}
+
+// FIXME(#32330)
+//#[cfg(transmute)] // one instantiations: BAD
+//fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
+// bar(foo, x) //[transmute] ERROR E0495
+//}
+
+// FIXME(#32330)
+//#[cfg(krisskross)] // two instantiations, mixing and matching: BAD
+//fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
+// let a = bar(foo, y); //[krisskross] ERROR E0495
+// let b = bar(foo, x); //[krisskross] ERROR E0495
+// (a, b)
+//}
+
+#[rustc_error]
+fn main() { }
+//[ok]~^ ERROR compilation successful
+//[oneuse]~^^ ERROR compilation successful
+//[transmute]~^^^ ERROR compilation successful
+//[krisskross]~^^^^ ERROR compilation successful
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(unboxed_closures)]
+#![feature(rustc_attrs)]
+
+// Test for projection cache. We should be able to project distinct
+// lifetimes from `foo` as we reinstantiate it multiple times, but not
+// if we do it just once. In this variant, the region `'a` is used in
+// an invariant position, which affects the results.
+
+// revisions: ok oneuse transmute krisskross
+
+#![allow(dead_code, unused_variables)]
+
+use std::marker::PhantomData;
+
+struct Type<'a> {
+ // Invariant
+ data: PhantomData<fn(&'a u32) -> &'a u32>
+}
+
+fn foo<'a>() -> Type<'a> { loop { } }
+
+fn bar<T>(t: T, x: T::Output) -> T::Output
+ where T: FnOnce<()>
+{
+ t()
+}
+
+#[cfg(ok)] // two instantiations: OK
+fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+ let a = bar(foo, x);
+ let b = bar(foo, y);
+ (a, b)
+}
+
+// FIXME(#32330)
+//#[cfg(oneuse)] // one instantiation: BAD
+//fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+// let f = foo; // <-- No consistent type can be inferred for `f` here.
+// let a = bar(f, x); //[oneuse] ERROR E0495
+// let b = bar(f, y);
+// (a, b)
+//}
+
+// FIXME(#32330)
+//#[cfg(transmute)] // one instantiations: BAD
+//fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
+// // Cannot instantiate `foo` with any lifetime other than `'a`,
+// // since it is provided as input.
+//
+// bar(foo, x) //[transmute] ERROR E0495
+//}
+
+// FIXME(#32330)
+//#[cfg(krisskross)] // two instantiations, mixing and matching: BAD
+//fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+// let a = bar(foo, y); //[krisskross] ERROR E0495
+// let b = bar(foo, x); //[krisskross] ERROR E0495
+// (a, b)
+//}
+
+#[rustc_error]
+fn main() { }
+//[ok]~^ ERROR compilation successful
+//[oneuse]~^^ ERROR compilation successful
+//[transmute]~^^^ ERROR compilation successful
+//[krisskross]~^^^^ ERROR compilation successful
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test was derived from the wasm and parsell crates. They
+// stopped compiling when #32330 is fixed.
+
+#![allow(dead_code, unused_variables)]
+#![deny(hr_lifetime_in_assoc_type)]
+#![feature(unboxed_closures)]
+
+use std::str::Chars;
+
+pub trait HasOutput<Ch, Str> {
+ type Output;
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Debug)]
+pub enum Token<'a> {
+ Begin(&'a str)
+}
+
+fn mk_unexpected_char_err<'a>() -> Option<&'a i32> {
+ unimplemented!()
+}
+
+fn foo<'a>(data: &mut Chars<'a>) {
+ bar(mk_unexpected_char_err)
+ //~^ ERROR lifetime parameter `'a` declared on fn `mk_unexpected_char_err`
+ //~| WARNING hard error in a future release
+}
+
+fn bar<F>(t: F)
+ // No type can satisfy this requirement, since `'a` does not
+ // appear in any of the input types:
+ where F: for<'a> Fn() -> Option<&'a i32>
+ //~^ ERROR associated type `Output` references lifetime `'a`, which does not
+ //~| WARNING hard error in a future release
+{
+}
+
+fn main() {
+}