Auto merge of #66879 - RalfJung:rollup-nprxpzi, r=RalfJung
Rollup of 11 pull requests Successful merges: - #66379 (Rephrase docs in for ptr) - #66589 (Draw vertical lines correctly in compiler error messages) - #66613 (Allow customising ty::TraitRef's printing behavior) - #66766 (Panic machinery comments and tweaks) - #66791 (Handle GlobalCtxt directly from librustc_interface query system) - #66793 (Record temporary static references in generator witnesses) - #66808 (Cleanup error code) - #66826 (Clarifies how to tag users for assigning PRs) - #66837 (Clarify `{f32,f64}::EPSILON` docs) - #66844 (Miri: do not consider memory allocated by caller_location leaked) - #66872 (Minor documentation fix) Failed merges: r? @ghost
This commit is contained in:
commit
9081929d45
@ -150,13 +150,13 @@ All pull requests are reviewed by another person. We have a bot,
|
||||
request.
|
||||
|
||||
If you want to request that a specific person reviews your pull request,
|
||||
you can add an `r?` to the message. For example, [Steve][steveklabnik] usually reviews
|
||||
you can add an `r?` to the pull request description. For example, [Steve][steveklabnik] usually reviews
|
||||
documentation changes. So if you were to make a documentation change, add
|
||||
|
||||
r? @steveklabnik
|
||||
|
||||
to the end of the message, and @rust-highfive will assign [@steveklabnik][steveklabnik] instead
|
||||
of a random person. This is entirely optional.
|
||||
to the end of the pull request description, and [@rust-highfive][rust-highfive] will assign
|
||||
[@steveklabnik][steveklabnik] instead of a random person. This is entirely optional.
|
||||
|
||||
After someone has reviewed your pull request, they will leave an annotation
|
||||
on the pull request with an `r+`. It will look something like this:
|
||||
|
@ -68,7 +68,7 @@ use crate::intrinsics;
|
||||
// Any trait
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A type to emulate dynamic typing.
|
||||
/// A trait to emulate dynamic typing.
|
||||
///
|
||||
/// Most types implement `Any`. However, any type which contains a non-`'static` reference does not.
|
||||
/// See the [module-level documentation][mod] for more details.
|
||||
|
@ -26,7 +26,7 @@ pub const DIGITS: u32 = 6;
|
||||
|
||||
/// [Machine epsilon] value for `f32`.
|
||||
///
|
||||
/// This is the difference between `1.0` and the next largest representable number.
|
||||
/// This is the difference between `1.0` and the next larger representable number.
|
||||
///
|
||||
/// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -26,7 +26,7 @@ pub const DIGITS: u32 = 15;
|
||||
|
||||
/// [Machine epsilon] value for `f64`.
|
||||
///
|
||||
/// This is the difference between `1.0` and the next largest representable number.
|
||||
/// This is the difference between `1.0` and the next larger representable number.
|
||||
///
|
||||
/// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -266,6 +266,16 @@ impl fmt::Display for Location<'_> {
|
||||
#[unstable(feature = "std_internals", issue = "0")]
|
||||
#[doc(hidden)]
|
||||
pub unsafe trait BoxMeUp {
|
||||
fn box_me_up(&mut self) -> *mut (dyn Any + Send);
|
||||
/// Take full ownership of the contents.
|
||||
/// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in libcore.
|
||||
///
|
||||
/// After this method got called, only some dummy default value is left in `self`.
|
||||
/// Calling this method twice, or calling `get` after calling this method, is an error.
|
||||
///
|
||||
/// The argument is borrowed because the panic runtime (`__rust_start_panic`) only
|
||||
/// gets a borrowed `dyn BoxMeUp`.
|
||||
fn take_box(&mut self) -> *mut (dyn Any + Send);
|
||||
|
||||
/// Just borrow the contents.
|
||||
fn get(&mut self) -> &(dyn Any + Send);
|
||||
}
|
||||
|
@ -11,13 +11,13 @@
|
||||
//! ```
|
||||
//!
|
||||
//! This definition allows for panicking with any general message, but it does not
|
||||
//! allow for failing with a `Box<Any>` value. The reason for this is that libcore
|
||||
//! is not allowed to allocate.
|
||||
//! allow for failing with a `Box<Any>` value. (`PanicInfo` just contains a `&(dyn Any + Send)`,
|
||||
//! for which we fill in a dummy value in `PanicInfo::internal_constructor`.)
|
||||
//! The reason for this is that libcore is not allowed to allocate.
|
||||
//!
|
||||
//! This module contains a few other panicking functions, but these are just the
|
||||
//! necessary lang items for the compiler. All panics are funneled through this
|
||||
//! one function. Currently, the actual symbol is declared in the standard
|
||||
//! library, but the location of this may change over time.
|
||||
//! one function. The actual symbol is declared through the `#[panic_handler]` attribute.
|
||||
|
||||
// ignore-tidy-undocumented-unsafe
|
||||
|
||||
@ -72,6 +72,7 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>, location: &Location<'_>) -> ! {
|
||||
}
|
||||
|
||||
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
|
||||
// that gets resolved to the `#[panic_handler]` function.
|
||||
extern "Rust" {
|
||||
#[lang = "panic_impl"]
|
||||
fn panic_impl(pi: &PanicInfo<'_>) -> !;
|
||||
|
@ -1074,17 +1074,22 @@ impl<T: ?Sized> *const T {
|
||||
/// operation because the returned value could be pointing to invalid
|
||||
/// memory.
|
||||
///
|
||||
/// When calling this method, you have to ensure that if the pointer is
|
||||
/// non-NULL, then it is properly aligned, dereferencable (for the whole
|
||||
/// size of `T`) and points to an initialized instance of `T`. This applies
|
||||
/// even if the result of this method is unused!
|
||||
/// When calling this method, you have to ensure that *either* the pointer is NULL *or*
|
||||
/// all of the following is true:
|
||||
/// - it is properly aligned
|
||||
/// - it must point to an initialized instance of T; in particular, the pointer must be
|
||||
/// "dereferencable" in the sense defined [here].
|
||||
///
|
||||
/// This applies even if the result of this method is unused!
|
||||
/// (The part about being initialized is not yet fully decided, but until
|
||||
/// it is, the only safe approach is to ensure that they are indeed initialized.)
|
||||
///
|
||||
/// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
|
||||
/// not necessarily reflect the actual lifetime of the data. It is up to the
|
||||
/// caller to ensure that for the duration of this lifetime, the memory this
|
||||
/// pointer points to does not get written to outside of `UnsafeCell<U>`.
|
||||
/// not necessarily reflect the actual lifetime of the data. *You* must enforce
|
||||
/// Rust's aliasing rules. In particular, for the duration of this lifetime,
|
||||
/// the memory the pointer points to must not get mutated (except inside `UnsafeCell`).
|
||||
///
|
||||
/// [here]: crate::ptr#safety
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -1929,18 +1934,23 @@ impl<T: ?Sized> *mut T {
|
||||
/// of the returned pointer, nor can it ensure that the lifetime `'a`
|
||||
/// returned is indeed a valid lifetime for the contained data.
|
||||
///
|
||||
/// When calling this method, you have to ensure that if the pointer is
|
||||
/// non-NULL, then it is properly aligned, dereferencable (for the whole
|
||||
/// size of `T`) and points to an initialized instance of `T`. This applies
|
||||
/// even if the result of this method is unused!
|
||||
/// When calling this method, you have to ensure that *either* the pointer is NULL *or*
|
||||
/// all of the following is true:
|
||||
/// - it is properly aligned
|
||||
/// - it must point to an initialized instance of T; in particular, the pointer must be
|
||||
/// "dereferencable" in the sense defined [here].
|
||||
///
|
||||
/// This applies even if the result of this method is unused!
|
||||
/// (The part about being initialized is not yet fully decided, but until
|
||||
/// it is the only safe approach is to ensure that they are indeed initialized.)
|
||||
///
|
||||
/// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
|
||||
/// not necessarily reflect the actual lifetime of the data. It is up to the
|
||||
/// caller to ensure that for the duration of this lifetime, the memory this
|
||||
/// pointer points to does not get accessed through any other pointer.
|
||||
/// not necessarily reflect the actual lifetime of the data. *You* must enforce
|
||||
/// Rust's aliasing rules. In particular, for the duration of this lifetime,
|
||||
/// the memory this pointer points to must not get accessed (read or written)
|
||||
/// through any other pointer.
|
||||
///
|
||||
/// [here]: crate::ptr#safety
|
||||
/// [`as_ref`]: #method.as_ref
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -94,5 +94,5 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8),
|
||||
#[unwind(allowed)]
|
||||
pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 {
|
||||
let payload = payload as *mut &mut dyn BoxMeUp;
|
||||
imp::panic(Box::from_raw((*payload).box_me_up()))
|
||||
imp::panic(Box::from_raw((*payload).take_box()))
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ macro_rules! arena_types {
|
||||
rustc::hir::def_id::CrateNum
|
||||
>
|
||||
>,
|
||||
[few] hir_forest: rustc::hir::map::Forest,
|
||||
[few] diagnostic_items: rustc_data_structures::fx::FxHashMap<
|
||||
syntax::symbol::Symbol,
|
||||
rustc::hir::def_id::DefId,
|
||||
|
@ -200,7 +200,7 @@ pub struct Map<'hir> {
|
||||
|
||||
map: HirEntryMap<'hir>,
|
||||
|
||||
definitions: &'hir Definitions,
|
||||
definitions: Definitions,
|
||||
|
||||
/// The reverse mapping of `node_to_hir_id`.
|
||||
hir_to_node_id: FxHashMap<HirId, NodeId>,
|
||||
@ -267,8 +267,8 @@ impl<'hir> Map<'hir> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn definitions(&self) -> &'hir Definitions {
|
||||
self.definitions
|
||||
pub fn definitions(&self) -> &Definitions {
|
||||
&self.definitions
|
||||
}
|
||||
|
||||
pub fn def_key(&self, def_id: DefId) -> DefKey {
|
||||
@ -1251,7 +1251,7 @@ impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } }
|
||||
pub fn map_crate<'hir>(sess: &crate::session::Session,
|
||||
cstore: &CrateStoreDyn,
|
||||
forest: &'hir Forest,
|
||||
definitions: &'hir Definitions)
|
||||
definitions: Definitions)
|
||||
-> Map<'hir> {
|
||||
let _prof_timer = sess.prof.generic_activity("build_hir_map");
|
||||
|
||||
@ -1260,7 +1260,7 @@ pub fn map_crate<'hir>(sess: &crate::session::Session,
|
||||
.map(|(node_id, &hir_id)| (hir_id, node_id)).collect();
|
||||
|
||||
let (map, crate_hash) = {
|
||||
let hcx = crate::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore);
|
||||
let hcx = crate::ich::StableHashingContext::new(sess, &forest.krate, &definitions, cstore);
|
||||
|
||||
let mut collector = NodeCollector::root(sess,
|
||||
&forest.krate,
|
||||
|
@ -1545,8 +1545,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found),
|
||||
infer::Regions(ref exp_found) => self.expected_found_str(exp_found),
|
||||
infer::Consts(ref exp_found) => self.expected_found_str(exp_found),
|
||||
infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
|
||||
infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found),
|
||||
infer::TraitRefs(ref exp_found) => {
|
||||
let pretty_exp_found = ty::error::ExpectedFound {
|
||||
expected: exp_found.expected.print_only_trait_path(),
|
||||
found: exp_found.found.print_only_trait_path()
|
||||
};
|
||||
self.expected_found_str(&pretty_exp_found)
|
||||
},
|
||||
infer::PolyTraitRefs(ref exp_found) => {
|
||||
let pretty_exp_found = ty::error::ExpectedFound {
|
||||
expected: exp_found.expected.print_only_trait_path(),
|
||||
found: exp_found.found.print_only_trait_path()
|
||||
};
|
||||
self.expected_found_str(&pretty_exp_found)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -401,7 +401,7 @@ impl NiceRegionError<'me, 'tcx> {
|
||||
format!(
|
||||
"{}`{}` would have to be implemented for the type `{}`",
|
||||
if leading_ellipsis { "..." } else { "" },
|
||||
expected_trait_ref,
|
||||
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
|
||||
expected_trait_ref.map(|tr| tr.self_ty()),
|
||||
)
|
||||
} else {
|
||||
@ -409,7 +409,7 @@ impl NiceRegionError<'me, 'tcx> {
|
||||
"{}`{}` must implement `{}`",
|
||||
if leading_ellipsis { "..." } else { "" },
|
||||
expected_trait_ref.map(|tr| tr.self_ty()),
|
||||
expected_trait_ref,
|
||||
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
|
||||
)
|
||||
};
|
||||
|
||||
@ -449,14 +449,14 @@ impl NiceRegionError<'me, 'tcx> {
|
||||
let mut note = if passive_voice {
|
||||
format!(
|
||||
"...but `{}` is actually implemented for the type `{}`",
|
||||
actual_trait_ref,
|
||||
actual_trait_ref.map(|tr| tr.print_only_trait_path()),
|
||||
actual_trait_ref.map(|tr| tr.self_ty()),
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"...but `{}` actually implements `{}`",
|
||||
actual_trait_ref.map(|tr| tr.self_ty()),
|
||||
actual_trait_ref,
|
||||
actual_trait_ref.map(|tr| tr.print_only_trait_path()),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -1292,7 +1292,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String {
|
||||
self.resolve_vars_if_possible(t).to_string()
|
||||
self.resolve_vars_if_possible(t).print_only_trait_path().to_string()
|
||||
}
|
||||
|
||||
/// If `TyVar(vid)` resolves to a type, return that type. Else, return the
|
||||
|
@ -800,8 +800,13 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
|
||||
// This shouldn't ever be needed, but just in case:
|
||||
path.push(match trait_ref {
|
||||
Some(trait_ref) => {
|
||||
Symbol::intern(&format!("<impl {} for {}>", trait_ref,
|
||||
self_ty))
|
||||
Symbol::intern(
|
||||
&format!(
|
||||
"<impl {} for {}>",
|
||||
trait_ref.print_only_trait_path(),
|
||||
self_ty
|
||||
)
|
||||
)
|
||||
},
|
||||
None => Symbol::intern(&format!("<impl {}>", self_ty)),
|
||||
});
|
||||
|
@ -737,7 +737,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let is_try = self.tcx.sess.source_map().span_to_snippet(span)
|
||||
.map(|s| &s == "?")
|
||||
.unwrap_or(false);
|
||||
let is_from = format!("{}", trait_ref).starts_with("std::convert::From<");
|
||||
let is_from =
|
||||
format!("{}", trait_ref.print_only_trait_path())
|
||||
.starts_with("std::convert::From<");
|
||||
let (message, note) = if is_try && is_from {
|
||||
(Some(format!(
|
||||
"`?` couldn't convert the error to `{}`",
|
||||
@ -768,7 +770,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
format!(
|
||||
"{}the trait `{}` is not implemented for `{}`",
|
||||
pre_message,
|
||||
trait_ref,
|
||||
trait_ref.print_only_trait_path(),
|
||||
trait_ref.self_ty(),
|
||||
)
|
||||
};
|
||||
@ -1189,7 +1191,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
if param_ty => {
|
||||
// Missing generic type parameter bound.
|
||||
let param_name = self_ty.to_string();
|
||||
let constraint = trait_ref.to_string();
|
||||
let constraint = trait_ref.print_only_trait_path().to_string();
|
||||
if suggest_constraining_type_param(
|
||||
generics,
|
||||
&mut err,
|
||||
@ -1416,7 +1418,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let msg = format!(
|
||||
"the trait bound `{}: {}` is not satisfied",
|
||||
found,
|
||||
obligation.parent_trait_ref.skip_binder(),
|
||||
obligation.parent_trait_ref.skip_binder().print_only_trait_path(),
|
||||
);
|
||||
if has_custom_message {
|
||||
err.note(&msg);
|
||||
@ -1430,7 +1432,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
err.span_label(span, &format!(
|
||||
"expected an implementor of trait `{}`",
|
||||
obligation.parent_trait_ref.skip_binder(),
|
||||
obligation.parent_trait_ref.skip_binder().print_only_trait_path(),
|
||||
));
|
||||
err.span_suggestion(
|
||||
span,
|
||||
@ -1562,7 +1564,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
} else {
|
||||
err.note(&format!(
|
||||
"`{}` is implemented for `{:?}`, but not for `{:?}`",
|
||||
trait_ref,
|
||||
trait_ref.print_only_trait_path(),
|
||||
trait_type,
|
||||
trait_ref.skip_binder().self_ty(),
|
||||
));
|
||||
@ -2226,7 +2228,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
|
||||
err.span_note(span, &format!(
|
||||
"future does not implement `{}` as this value is used across an await",
|
||||
trait_ref,
|
||||
trait_ref.print_only_trait_path(),
|
||||
));
|
||||
|
||||
// Add a note for the item obligation that remains - normally a note pointing to the
|
||||
@ -2409,7 +2411,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
|
||||
err.note(
|
||||
&format!("required because of the requirements on the impl of `{}` for `{}`",
|
||||
parent_trait_ref,
|
||||
parent_trait_ref.print_only_trait_path(),
|
||||
parent_trait_ref.skip_binder().self_ty()));
|
||||
let parent_predicate = parent_trait_ref.to_predicate();
|
||||
self.note_obligation_cause_code(err,
|
||||
|
@ -1044,7 +1044,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let cause = IntercrateAmbiguityCause::DownstreamCrate {
|
||||
trait_desc: trait_ref.to_string(),
|
||||
trait_desc: trait_ref.print_only_trait_path().to_string(),
|
||||
self_desc: if self_ty.has_concrete_skeleton() {
|
||||
Some(self_ty.to_string())
|
||||
} else {
|
||||
@ -1386,7 +1386,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
if !candidate_set.ambiguous && no_candidates_apply {
|
||||
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let trait_desc = trait_ref.to_string();
|
||||
let trait_desc = trait_ref.print_only_trait_path().to_string();
|
||||
let self_desc = if self_ty.has_concrete_skeleton() {
|
||||
Some(self_ty.to_string())
|
||||
} else {
|
||||
|
@ -417,7 +417,7 @@ fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String>
|
||||
w.push('>');
|
||||
}
|
||||
|
||||
write!(w, " {} for {}", trait_ref, tcx.type_of(impl_def_id)).unwrap();
|
||||
write!(w, " {} for {}", trait_ref.print_only_trait_path(), tcx.type_of(impl_def_id)).unwrap();
|
||||
|
||||
// The predicates will contain default bounds like `T: Sized`. We need to
|
||||
// remove these bounds, and add `T: ?Sized` to any untouched type parameters.
|
||||
|
@ -146,7 +146,7 @@ impl<'tcx> Children {
|
||||
let self_ty = trait_ref.self_ty();
|
||||
OverlapError {
|
||||
with_impl: possible_sibling,
|
||||
trait_desc: trait_ref.to_string(),
|
||||
trait_desc: trait_ref.print_only_trait_path().to_string(),
|
||||
// Only report the `Self` type if it has at least
|
||||
// some outer concrete shell; otherwise, it's
|
||||
// not adding much information.
|
||||
|
@ -995,7 +995,7 @@ impl<'tcx> Deref for TyCtxt<'tcx> {
|
||||
}
|
||||
|
||||
pub struct GlobalCtxt<'tcx> {
|
||||
pub arena: WorkerLocal<Arena<'tcx>>,
|
||||
pub arena: &'tcx WorkerLocal<Arena<'tcx>>,
|
||||
|
||||
interners: CtxtInterners<'tcx>,
|
||||
|
||||
@ -1170,6 +1170,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
local_providers: ty::query::Providers<'tcx>,
|
||||
extern_providers: ty::query::Providers<'tcx>,
|
||||
arenas: &'tcx AllArenas,
|
||||
arena: &'tcx WorkerLocal<Arena<'tcx>>,
|
||||
resolutions: ty::ResolverOutputs,
|
||||
hir: hir_map::Map<'tcx>,
|
||||
on_disk_query_result_cache: query::OnDiskCache<'tcx>,
|
||||
@ -1225,7 +1226,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
sess: s,
|
||||
lint_store,
|
||||
cstore,
|
||||
arena: WorkerLocal::new(|_| Arena::default()),
|
||||
arena,
|
||||
interners,
|
||||
dep_graph,
|
||||
prof: s.prof.clone(),
|
||||
|
@ -449,7 +449,7 @@ pub trait PrettyPrinter<'tcx>:
|
||||
|
||||
p!(print(self_ty));
|
||||
if let Some(trait_ref) = trait_ref {
|
||||
p!(write(" as "), print(trait_ref));
|
||||
p!(write(" as "), print(trait_ref.print_only_trait_path()));
|
||||
}
|
||||
Ok(cx)
|
||||
})
|
||||
@ -468,7 +468,7 @@ pub trait PrettyPrinter<'tcx>:
|
||||
|
||||
p!(write("impl "));
|
||||
if let Some(trait_ref) = trait_ref {
|
||||
p!(print(trait_ref), write(" for "));
|
||||
p!(print(trait_ref.print_only_trait_path()), write(" for "));
|
||||
}
|
||||
p!(print(self_ty));
|
||||
|
||||
@ -619,7 +619,7 @@ pub trait PrettyPrinter<'tcx>:
|
||||
|
||||
p!(
|
||||
write("{}", if first { " " } else { "+" }),
|
||||
print(trait_ref));
|
||||
print(trait_ref.print_only_trait_path()));
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
@ -1696,6 +1696,30 @@ impl fmt::Display for ty::RegionKind {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
|
||||
/// the trait path. That is, it will print `Trait<U>` instead of
|
||||
/// `<T as Trait<U>>`.
|
||||
#[derive(Copy, Clone, TypeFoldable, Lift)]
|
||||
pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>);
|
||||
|
||||
impl fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ty::TraitRef<'tcx> {
|
||||
pub fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> {
|
||||
TraitRefPrintOnlyTraitPath(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ty::Binder<ty::TraitRef<'tcx>> {
|
||||
pub fn print_only_trait_path(self) -> ty::Binder<TraitRefPrintOnlyTraitPath<'tcx>> {
|
||||
self.map_bound(|tr| tr.print_only_trait_path())
|
||||
}
|
||||
}
|
||||
|
||||
forward_display_to_print! {
|
||||
Ty<'tcx>,
|
||||
&'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
|
||||
@ -1705,6 +1729,7 @@ forward_display_to_print! {
|
||||
// because `for<'tcx>` isn't possible yet.
|
||||
ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>,
|
||||
ty::Binder<ty::TraitRef<'tcx>>,
|
||||
ty::Binder<TraitRefPrintOnlyTraitPath<'tcx>>,
|
||||
ty::Binder<ty::FnSig<'tcx>>,
|
||||
ty::Binder<ty::TraitPredicate<'tcx>>,
|
||||
ty::Binder<ty::SubtypePredicate<'tcx>>,
|
||||
@ -1739,7 +1764,7 @@ define_print_and_forward_display! {
|
||||
// Use a type that can't appear in defaults of type parameters.
|
||||
let dummy_self = cx.tcx().mk_ty_infer(ty::FreshTy(0));
|
||||
let trait_ref = self.with_self_ty(cx.tcx(), dummy_self);
|
||||
p!(print(trait_ref))
|
||||
p!(print(trait_ref.print_only_trait_path()))
|
||||
}
|
||||
|
||||
ty::ExistentialProjection<'tcx> {
|
||||
@ -1783,7 +1808,11 @@ define_print_and_forward_display! {
|
||||
}
|
||||
|
||||
ty::TraitRef<'tcx> {
|
||||
p!(print_def_path(self.def_id, self.substs));
|
||||
p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
|
||||
}
|
||||
|
||||
TraitRefPrintOnlyTraitPath<'tcx> {
|
||||
p!(print_def_path(self.0.def_id, self.0.substs));
|
||||
}
|
||||
|
||||
ty::ParamTy {
|
||||
@ -1799,7 +1828,8 @@ define_print_and_forward_display! {
|
||||
}
|
||||
|
||||
ty::TraitPredicate<'tcx> {
|
||||
p!(print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref))
|
||||
p!(print(self.trait_ref.self_ty()), write(": "),
|
||||
print(self.trait_ref.print_only_trait_path()))
|
||||
}
|
||||
|
||||
ty::ProjectionPredicate<'tcx> {
|
||||
|
@ -223,10 +223,7 @@ impl fmt::Debug for ty::FloatVarValue {
|
||||
|
||||
impl fmt::Debug for ty::TraitRef<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// FIXME(#59188) this is used across the compiler to print
|
||||
// a `TraitRef` qualified (with the Self type explicit),
|
||||
// instead of having a different way to make that choice.
|
||||
write!(f, "<{} as {}>", self.self_ty(), self)
|
||||
fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -682,6 +682,23 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
self.static_mutability(def_id) == Some(hir::Mutability::Mutable)
|
||||
}
|
||||
|
||||
/// Get the type of the pointer to the static that we use in MIR.
|
||||
pub fn static_ptr_ty(&self, def_id: DefId) -> Ty<'tcx> {
|
||||
// Make sure that any constants in the static's type are evaluated.
|
||||
let static_ty = self.normalize_erasing_regions(
|
||||
ty::ParamEnv::empty(),
|
||||
self.type_of(def_id),
|
||||
);
|
||||
|
||||
if self.is_mutable_static(def_id) {
|
||||
self.mk_mut_ptr(static_ty)
|
||||
} else if self.is_foreign_item(def_id) {
|
||||
self.mk_imm_ptr(static_ty)
|
||||
} else {
|
||||
self.mk_imm_ref(self.lifetimes.re_erased, static_ty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Expands the given impl trait type, stopping if the type is recursive.
|
||||
pub fn try_expand_impl_trait_type(
|
||||
self,
|
||||
|
@ -283,121 +283,128 @@ pub fn run_compiler(
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
compiler.parse()?;
|
||||
let linker = compiler.enter(|queries| {
|
||||
let early_exit = || sess.compile_status().map(|_| None);
|
||||
queries.parse()?;
|
||||
|
||||
if let Some(ppm) = &sess.opts.pretty {
|
||||
if ppm.needs_ast_map() {
|
||||
compiler.global_ctxt()?.peek_mut().enter(|tcx| {
|
||||
let expanded_crate = compiler.expansion()?.take().0;
|
||||
pretty::print_after_hir_lowering(
|
||||
tcx,
|
||||
compiler.input(),
|
||||
&expanded_crate,
|
||||
if let Some(ppm) = &sess.opts.pretty {
|
||||
if ppm.needs_ast_map() {
|
||||
queries.global_ctxt()?.peek_mut().enter(|tcx| {
|
||||
let expanded_crate = queries.expansion()?.take().0;
|
||||
pretty::print_after_hir_lowering(
|
||||
tcx,
|
||||
compiler.input(),
|
||||
&expanded_crate,
|
||||
*ppm,
|
||||
compiler.output_file().as_ref().map(|p| &**p),
|
||||
);
|
||||
Ok(())
|
||||
})?;
|
||||
} else {
|
||||
let krate = queries.parse()?.take();
|
||||
pretty::print_after_parsing(
|
||||
sess,
|
||||
&compiler.input(),
|
||||
&krate,
|
||||
*ppm,
|
||||
compiler.output_file().as_ref().map(|p| &**p),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
if callbacks.after_parsing(compiler) == Compilation::Stop {
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
if sess.opts.debugging_opts.parse_only ||
|
||||
sess.opts.debugging_opts.show_span.is_some() ||
|
||||
sess.opts.debugging_opts.ast_json_noexpand {
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
{
|
||||
let (_, lint_store) = &*queries.register_plugins()?.peek();
|
||||
|
||||
// Lint plugins are registered; now we can process command line flags.
|
||||
if sess.opts.describe_lints {
|
||||
describe_lints(&sess, &lint_store, true);
|
||||
return early_exit();
|
||||
}
|
||||
}
|
||||
|
||||
queries.expansion()?;
|
||||
if callbacks.after_expansion(compiler) == Compilation::Stop {
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
queries.prepare_outputs()?;
|
||||
|
||||
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
|
||||
&& sess.opts.output_types.len() == 1
|
||||
{
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
queries.global_ctxt()?;
|
||||
|
||||
if sess.opts.debugging_opts.no_analysis ||
|
||||
sess.opts.debugging_opts.ast_json {
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
if sess.opts.debugging_opts.save_analysis {
|
||||
let expanded_crate = &queries.expansion()?.peek().0;
|
||||
let crate_name = queries.crate_name()?.peek().clone();
|
||||
queries.global_ctxt()?.peek_mut().enter(|tcx| {
|
||||
let result = tcx.analysis(LOCAL_CRATE);
|
||||
|
||||
time(sess, "save analysis", || {
|
||||
save::process_crate(
|
||||
tcx,
|
||||
&expanded_crate,
|
||||
&crate_name,
|
||||
&compiler.input(),
|
||||
None,
|
||||
DumpHandler::new(
|
||||
compiler.output_dir().as_ref().map(|p| &**p), &crate_name
|
||||
)
|
||||
)
|
||||
});
|
||||
|
||||
result
|
||||
// AST will be dropped *after* the `after_analysis` callback
|
||||
// (needed by the RLS)
|
||||
})?;
|
||||
} else {
|
||||
let krate = compiler.parse()?.take();
|
||||
pretty::print_after_parsing(
|
||||
sess,
|
||||
&compiler.input(),
|
||||
&krate,
|
||||
*ppm,
|
||||
compiler.output_file().as_ref().map(|p| &**p),
|
||||
);
|
||||
// Drop AST after creating GlobalCtxt to free memory
|
||||
mem::drop(queries.expansion()?.take());
|
||||
}
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
if callbacks.after_parsing(compiler) == Compilation::Stop {
|
||||
return sess.compile_status();
|
||||
}
|
||||
queries.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?;
|
||||
|
||||
if sess.opts.debugging_opts.parse_only ||
|
||||
sess.opts.debugging_opts.show_span.is_some() ||
|
||||
sess.opts.debugging_opts.ast_json_noexpand {
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
{
|
||||
let (_, lint_store) = &*compiler.register_plugins()?.peek();
|
||||
|
||||
// Lint plugins are registered; now we can process command line flags.
|
||||
if sess.opts.describe_lints {
|
||||
describe_lints(&sess, &lint_store, true);
|
||||
return sess.compile_status();
|
||||
if callbacks.after_analysis(compiler) == Compilation::Stop {
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
if sess.opts.debugging_opts.save_analysis {
|
||||
mem::drop(queries.expansion()?.take());
|
||||
}
|
||||
|
||||
queries.ongoing_codegen()?;
|
||||
|
||||
if sess.opts.debugging_opts.print_type_sizes {
|
||||
sess.code_stats.print_type_sizes();
|
||||
}
|
||||
|
||||
let linker = queries.linker()?;
|
||||
Ok(Some(linker))
|
||||
})?;
|
||||
|
||||
if let Some(linker) = linker {
|
||||
linker.link()?
|
||||
}
|
||||
|
||||
compiler.expansion()?;
|
||||
if callbacks.after_expansion(compiler) == Compilation::Stop {
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
compiler.prepare_outputs()?;
|
||||
|
||||
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
|
||||
&& sess.opts.output_types.len() == 1
|
||||
{
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
compiler.global_ctxt()?;
|
||||
|
||||
if sess.opts.debugging_opts.no_analysis ||
|
||||
sess.opts.debugging_opts.ast_json {
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
if sess.opts.debugging_opts.save_analysis {
|
||||
let expanded_crate = &compiler.expansion()?.peek().0;
|
||||
let crate_name = compiler.crate_name()?.peek().clone();
|
||||
compiler.global_ctxt()?.peek_mut().enter(|tcx| {
|
||||
let result = tcx.analysis(LOCAL_CRATE);
|
||||
|
||||
time(sess, "save analysis", || {
|
||||
save::process_crate(
|
||||
tcx,
|
||||
&expanded_crate,
|
||||
&crate_name,
|
||||
&compiler.input(),
|
||||
None,
|
||||
DumpHandler::new(compiler.output_dir().as_ref().map(|p| &**p), &crate_name)
|
||||
)
|
||||
});
|
||||
|
||||
result
|
||||
// AST will be dropped *after* the `after_analysis` callback
|
||||
// (needed by the RLS)
|
||||
})?;
|
||||
} else {
|
||||
// Drop AST after creating GlobalCtxt to free memory
|
||||
mem::drop(compiler.expansion()?.take());
|
||||
}
|
||||
|
||||
compiler.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?;
|
||||
|
||||
if callbacks.after_analysis(compiler) == Compilation::Stop {
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
if sess.opts.debugging_opts.save_analysis {
|
||||
mem::drop(compiler.expansion()?.take());
|
||||
}
|
||||
|
||||
compiler.ongoing_codegen()?;
|
||||
|
||||
// Drop GlobalCtxt after starting codegen to free memory
|
||||
mem::drop(compiler.global_ctxt()?.take());
|
||||
|
||||
if sess.opts.debugging_opts.print_type_sizes {
|
||||
sess.code_stats.print_type_sizes();
|
||||
}
|
||||
|
||||
compiler.link()?;
|
||||
|
||||
if sess.opts.debugging_opts.perf_stats {
|
||||
sess.print_perf_stats();
|
||||
}
|
||||
|
@ -1,14 +1,18 @@
|
||||
This error indicates that the compiler was unable to sensibly evaluate a
|
||||
constant expression that had to be evaluated. Attempting to divide by 0
|
||||
or causing integer overflow are two ways to induce this error. For example:
|
||||
A constant value failed to get evaluated.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0080
|
||||
enum Enum {
|
||||
X = (1 << 500),
|
||||
Y = (1 / 0)
|
||||
Y = (1 / 0),
|
||||
}
|
||||
```
|
||||
|
||||
This error indicates that the compiler was unable to sensibly evaluate a
|
||||
constant expression that had to be evaluated. Attempting to divide by 0
|
||||
or causing an integer overflow are two ways to induce this error.
|
||||
|
||||
Ensure that the expressions given can be evaluated as the desired integer type.
|
||||
See the FFI section of the Reference for more information about using a custom
|
||||
integer type:
|
||||
|
@ -1,21 +1,23 @@
|
||||
Enum discriminants are used to differentiate enum variants stored in memory.
|
||||
This error indicates that the same value was used for two or more variants,
|
||||
making them impossible to tell apart.
|
||||
A discrimant value is present more than once.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0081
|
||||
// Bad.
|
||||
enum Enum {
|
||||
P = 3,
|
||||
X = 3,
|
||||
X = 3, // error!
|
||||
Y = 5,
|
||||
}
|
||||
```
|
||||
|
||||
Enum discriminants are used to differentiate enum variants stored in memory.
|
||||
This error indicates that the same value was used for two or more variants,
|
||||
making it impossible to distinguish them.
|
||||
|
||||
```
|
||||
// Good.
|
||||
enum Enum {
|
||||
P,
|
||||
X = 3,
|
||||
X = 3, // ok!
|
||||
Y = 5,
|
||||
}
|
||||
```
|
||||
@ -27,7 +29,7 @@ variants.
|
||||
```compile_fail,E0081
|
||||
enum Bad {
|
||||
X,
|
||||
Y = 0
|
||||
Y = 0, // error!
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
You gave an unnecessary type or const parameter in a type alias. Erroneous
|
||||
code example:
|
||||
An unnecessary type or const parameter was given in a type alias.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0091
|
||||
type Foo<T> = u32; // error: type parameter `T` is unused
|
||||
|
@ -835,7 +835,7 @@ impl EmitterWriter {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
// Write the colunmn separator.
|
||||
// Write the column separator.
|
||||
//
|
||||
// After this we will have:
|
||||
//
|
||||
@ -906,7 +906,7 @@ impl EmitterWriter {
|
||||
// | __________
|
||||
// | | |
|
||||
// | |
|
||||
// 3 |
|
||||
// 3 | |
|
||||
// 4 | | }
|
||||
// | |_
|
||||
for &(pos, annotation) in &annotations_position {
|
||||
@ -920,7 +920,7 @@ impl EmitterWriter {
|
||||
if pos > 1 && (annotation.has_label() || annotation.takes_space()) {
|
||||
for p in line_offset + 1..=line_offset + pos {
|
||||
buffer.putc(p,
|
||||
code_offset + annotation.start_col - margin.computed_left,
|
||||
(code_offset + annotation.start_col).saturating_sub(left),
|
||||
'|',
|
||||
style);
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
use crate::queries::Queries;
|
||||
use crate::util;
|
||||
pub use crate::passes::BoxedResolver;
|
||||
|
||||
@ -36,7 +35,6 @@ pub struct Compiler {
|
||||
pub(crate) input_path: Option<PathBuf>,
|
||||
pub(crate) output_dir: Option<PathBuf>,
|
||||
pub(crate) output_file: Option<PathBuf>,
|
||||
pub(crate) queries: Queries,
|
||||
pub(crate) crate_name: Option<String>,
|
||||
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut lint::LintStore) + Send + Sync>>,
|
||||
pub(crate) override_queries:
|
||||
@ -169,7 +167,6 @@ pub fn run_compiler_in_existing_thread_pool<R>(
|
||||
input_path: config.input_path,
|
||||
output_dir: config.output_dir,
|
||||
output_file: config.output_file,
|
||||
queries: Default::default(),
|
||||
crate_name: config.crate_name,
|
||||
register_lints: config.register_lints,
|
||||
override_queries: config.override_queries,
|
||||
|
@ -3,6 +3,7 @@ use crate::util;
|
||||
use crate::proc_macro_decls;
|
||||
|
||||
use log::{info, warn, log_enabled};
|
||||
use rustc::arena::Arena;
|
||||
use rustc::dep_graph::DepGraph;
|
||||
use rustc::hir;
|
||||
use rustc::hir::lowering::lower_crate;
|
||||
@ -22,7 +23,7 @@ use rustc_codegen_ssa::back::link::emit_metadata;
|
||||
use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
||||
use rustc_codegen_utils::link::filename_for_metadata;
|
||||
use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
|
||||
use rustc_data_structures::sync::{Lrc, ParallelIterator, par_iter};
|
||||
use rustc_data_structures::sync::{Lrc, Once, ParallelIterator, par_iter, WorkerLocal};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_incremental;
|
||||
use rustc_mir as mir;
|
||||
@ -739,93 +740,77 @@ pub fn default_provide_extern(providers: &mut ty::query::Providers<'_>) {
|
||||
rustc_codegen_ssa::provide_extern(providers);
|
||||
}
|
||||
|
||||
declare_box_region_type!(
|
||||
pub BoxedGlobalCtxt,
|
||||
for('tcx),
|
||||
(&'tcx GlobalCtxt<'tcx>) -> ((), ())
|
||||
);
|
||||
pub struct QueryContext<'tcx>(&'tcx GlobalCtxt<'tcx>);
|
||||
|
||||
impl BoxedGlobalCtxt {
|
||||
impl<'tcx> QueryContext<'tcx> {
|
||||
pub fn enter<F, R>(&mut self, f: F) -> R
|
||||
where
|
||||
F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
|
||||
F: FnOnce(TyCtxt<'tcx>) -> R,
|
||||
{
|
||||
self.access(|gcx| ty::tls::enter_global(gcx, |tcx| f(tcx)))
|
||||
ty::tls::enter_global(self.0, |tcx| f(tcx))
|
||||
}
|
||||
|
||||
pub fn print_stats(&self) {
|
||||
self.0.queries.print_stats()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_global_ctxt(
|
||||
compiler: &Compiler,
|
||||
pub fn create_global_ctxt<'tcx>(
|
||||
compiler: &'tcx Compiler,
|
||||
lint_store: Lrc<lint::LintStore>,
|
||||
mut hir_forest: hir::map::Forest,
|
||||
hir_forest: &'tcx hir::map::Forest,
|
||||
mut resolver_outputs: ResolverOutputs,
|
||||
outputs: OutputFilenames,
|
||||
crate_name: &str,
|
||||
) -> BoxedGlobalCtxt {
|
||||
let sess = compiler.session().clone();
|
||||
let codegen_backend = compiler.codegen_backend().clone();
|
||||
let crate_name = crate_name.to_string();
|
||||
global_ctxt: &'tcx Once<GlobalCtxt<'tcx>>,
|
||||
all_arenas: &'tcx AllArenas,
|
||||
arena: &'tcx WorkerLocal<Arena<'tcx>>,
|
||||
) -> QueryContext<'tcx> {
|
||||
let sess = &compiler.session();
|
||||
let defs = mem::take(&mut resolver_outputs.definitions);
|
||||
let override_queries = compiler.override_queries;
|
||||
|
||||
let ((), result) = BoxedGlobalCtxt::new(static move || {
|
||||
let sess = &*sess;
|
||||
|
||||
let global_ctxt: Option<GlobalCtxt<'_>>;
|
||||
let arenas = AllArenas::new();
|
||||
|
||||
// Construct the HIR map.
|
||||
let hir_map = time(sess, "indexing HIR", || {
|
||||
hir::map::map_crate(sess, &*resolver_outputs.cstore, &mut hir_forest, &defs)
|
||||
});
|
||||
|
||||
let query_result_on_disk_cache = time(sess, "load query result cache", || {
|
||||
rustc_incremental::load_query_result_cache(sess)
|
||||
});
|
||||
|
||||
let mut local_providers = ty::query::Providers::default();
|
||||
default_provide(&mut local_providers);
|
||||
codegen_backend.provide(&mut local_providers);
|
||||
|
||||
let mut extern_providers = local_providers;
|
||||
default_provide_extern(&mut extern_providers);
|
||||
codegen_backend.provide_extern(&mut extern_providers);
|
||||
|
||||
if let Some(callback) = override_queries {
|
||||
callback(sess, &mut local_providers, &mut extern_providers);
|
||||
}
|
||||
|
||||
let gcx = TyCtxt::create_global_ctxt(
|
||||
sess,
|
||||
lint_store,
|
||||
local_providers,
|
||||
extern_providers,
|
||||
&arenas,
|
||||
resolver_outputs,
|
||||
hir_map,
|
||||
query_result_on_disk_cache,
|
||||
&crate_name,
|
||||
&outputs
|
||||
);
|
||||
|
||||
global_ctxt = Some(gcx);
|
||||
let gcx = global_ctxt.as_ref().unwrap();
|
||||
|
||||
ty::tls::enter_global(gcx, |tcx| {
|
||||
// Do some initialization of the DepGraph that can only be done with the
|
||||
// tcx available.
|
||||
time(tcx.sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx));
|
||||
});
|
||||
|
||||
yield BoxedGlobalCtxt::initial_yield(());
|
||||
box_region_allow_access!(for('tcx), (&'tcx GlobalCtxt<'tcx>), (gcx));
|
||||
|
||||
if sess.opts.debugging_opts.query_stats {
|
||||
gcx.queries.print_stats();
|
||||
}
|
||||
// Construct the HIR map.
|
||||
let hir_map = time(sess, "indexing HIR", || {
|
||||
hir::map::map_crate(sess, &*resolver_outputs.cstore, &hir_forest, defs)
|
||||
});
|
||||
|
||||
result
|
||||
let query_result_on_disk_cache = time(sess, "load query result cache", || {
|
||||
rustc_incremental::load_query_result_cache(sess)
|
||||
});
|
||||
|
||||
let codegen_backend = compiler.codegen_backend();
|
||||
let mut local_providers = ty::query::Providers::default();
|
||||
default_provide(&mut local_providers);
|
||||
codegen_backend.provide(&mut local_providers);
|
||||
|
||||
let mut extern_providers = local_providers;
|
||||
default_provide_extern(&mut extern_providers);
|
||||
codegen_backend.provide_extern(&mut extern_providers);
|
||||
|
||||
if let Some(callback) = compiler.override_queries {
|
||||
callback(sess, &mut local_providers, &mut extern_providers);
|
||||
}
|
||||
|
||||
let gcx = global_ctxt.init_locking(|| TyCtxt::create_global_ctxt(
|
||||
sess,
|
||||
lint_store,
|
||||
local_providers,
|
||||
extern_providers,
|
||||
&all_arenas,
|
||||
arena,
|
||||
resolver_outputs,
|
||||
hir_map,
|
||||
query_result_on_disk_cache,
|
||||
&crate_name,
|
||||
&outputs
|
||||
));
|
||||
|
||||
// Do some initialization of the DepGraph that can only be done with the tcx available.
|
||||
ty::tls::enter_global(&gcx, |tcx| {
|
||||
time(tcx.sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx));
|
||||
});
|
||||
|
||||
QueryContext(gcx)
|
||||
}
|
||||
|
||||
/// Runs the resolution, type-checking, region checking and other
|
||||
|
@ -1,17 +1,19 @@
|
||||
use crate::interface::{Compiler, Result};
|
||||
use crate::passes::{self, BoxedResolver, BoxedGlobalCtxt};
|
||||
use crate::passes::{self, BoxedResolver, QueryContext};
|
||||
|
||||
use rustc_incremental::DepGraphFuture;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::sync::{Lrc, Once, WorkerLocal};
|
||||
use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
||||
use rustc::session::config::{OutputFilenames, OutputType};
|
||||
use rustc::util::common::{time, ErrorReported};
|
||||
use rustc::arena::Arena;
|
||||
use rustc::hir;
|
||||
use rustc::lint;
|
||||
use rustc::session::Session;
|
||||
use rustc::lint::LintStore;
|
||||
use rustc::hir::def_id::LOCAL_CRATE;
|
||||
use rustc::ty::steal::Steal;
|
||||
use rustc::ty::ResolverOutputs;
|
||||
use rustc::ty::{AllArenas, ResolverOutputs, GlobalCtxt};
|
||||
use rustc::dep_graph::DepGraph;
|
||||
use std::cell::{Ref, RefMut, RefCell};
|
||||
use std::rc::Rc;
|
||||
@ -44,13 +46,6 @@ impl<T> Query<T> {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Returns a stolen query result. Panics if there's already a result.
|
||||
pub fn give(&self, value: T) {
|
||||
let mut result = self.result.borrow_mut();
|
||||
assert!(result.is_none(), "a result already exists");
|
||||
*result = Some(Ok(value));
|
||||
}
|
||||
|
||||
/// Borrows the query result using the RefCell. Panics if the result is stolen.
|
||||
pub fn peek(&self) -> Ref<'_, T> {
|
||||
Ref::map(self.result.borrow(), |r| {
|
||||
@ -74,24 +69,54 @@ impl<T> Default for Query<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Queries {
|
||||
pub struct Queries<'tcx> {
|
||||
compiler: &'tcx Compiler,
|
||||
gcx: Once<GlobalCtxt<'tcx>>,
|
||||
|
||||
all_arenas: AllArenas,
|
||||
arena: WorkerLocal<Arena<'tcx>>,
|
||||
|
||||
dep_graph_future: Query<Option<DepGraphFuture>>,
|
||||
parse: Query<ast::Crate>,
|
||||
crate_name: Query<String>,
|
||||
register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
|
||||
expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>,
|
||||
dep_graph: Query<DepGraph>,
|
||||
lower_to_hir: Query<(Steal<hir::map::Forest>, Steal<ResolverOutputs>)>,
|
||||
lower_to_hir: Query<(&'tcx hir::map::Forest, Steal<ResolverOutputs>)>,
|
||||
prepare_outputs: Query<OutputFilenames>,
|
||||
global_ctxt: Query<BoxedGlobalCtxt>,
|
||||
global_ctxt: Query<QueryContext<'tcx>>,
|
||||
ongoing_codegen: Query<Box<dyn Any>>,
|
||||
link: Query<()>,
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
impl<'tcx> Queries<'tcx> {
|
||||
pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> {
|
||||
Queries {
|
||||
compiler,
|
||||
gcx: Once::new(),
|
||||
all_arenas: AllArenas::new(),
|
||||
arena: WorkerLocal::new(|_| Arena::default()),
|
||||
dep_graph_future: Default::default(),
|
||||
parse: Default::default(),
|
||||
crate_name: Default::default(),
|
||||
register_plugins: Default::default(),
|
||||
expansion: Default::default(),
|
||||
dep_graph: Default::default(),
|
||||
lower_to_hir: Default::default(),
|
||||
prepare_outputs: Default::default(),
|
||||
global_ctxt: Default::default(),
|
||||
ongoing_codegen: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn session(&self) -> &Lrc<Session> {
|
||||
&self.compiler.sess
|
||||
}
|
||||
fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
|
||||
&self.compiler.codegen_backend()
|
||||
}
|
||||
|
||||
pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
|
||||
self.queries.dep_graph_future.compute(|| {
|
||||
self.dep_graph_future.compute(|| {
|
||||
Ok(if self.session().opts.build_dep_graph() {
|
||||
Some(rustc_incremental::load_dep_graph(self.session()))
|
||||
} else {
|
||||
@ -101,8 +126,8 @@ impl Compiler {
|
||||
}
|
||||
|
||||
pub fn parse(&self) -> Result<&Query<ast::Crate>> {
|
||||
self.queries.parse.compute(|| {
|
||||
passes::parse(self.session(), &self.input).map_err(
|
||||
self.parse.compute(|| {
|
||||
passes::parse(self.session(), &self.compiler.input).map_err(
|
||||
|mut parse_error| {
|
||||
parse_error.emit();
|
||||
ErrorReported
|
||||
@ -112,7 +137,7 @@ impl Compiler {
|
||||
}
|
||||
|
||||
pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
|
||||
self.queries.register_plugins.compute(|| {
|
||||
self.register_plugins.compute(|| {
|
||||
let crate_name = self.crate_name()?.peek().clone();
|
||||
let krate = self.parse()?.take();
|
||||
|
||||
@ -120,7 +145,7 @@ impl Compiler {
|
||||
let result = passes::register_plugins(
|
||||
self.session(),
|
||||
&*self.codegen_backend().metadata_loader(),
|
||||
self.register_lints
|
||||
self.compiler.register_lints
|
||||
.as_ref()
|
||||
.map(|p| &**p)
|
||||
.unwrap_or_else(|| empty),
|
||||
@ -140,8 +165,8 @@ impl Compiler {
|
||||
}
|
||||
|
||||
pub fn crate_name(&self) -> Result<&Query<String>> {
|
||||
self.queries.crate_name.compute(|| {
|
||||
Ok(match self.crate_name {
|
||||
self.crate_name.compute(|| {
|
||||
Ok(match self.compiler.crate_name {
|
||||
Some(ref crate_name) => crate_name.clone(),
|
||||
None => {
|
||||
let parse_result = self.parse()?;
|
||||
@ -149,7 +174,7 @@ impl Compiler {
|
||||
rustc_codegen_utils::link::find_crate_name(
|
||||
Some(self.session()),
|
||||
&krate.attrs,
|
||||
&self.input
|
||||
&self.compiler.input
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -159,11 +184,11 @@ impl Compiler {
|
||||
pub fn expansion(
|
||||
&self
|
||||
) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
|
||||
self.queries.expansion.compute(|| {
|
||||
self.expansion.compute(|| {
|
||||
let crate_name = self.crate_name()?.peek().clone();
|
||||
let (krate, lint_store) = self.register_plugins()?.take();
|
||||
passes::configure_and_expand(
|
||||
self.sess.clone(),
|
||||
self.session().clone(),
|
||||
lint_store.clone(),
|
||||
self.codegen_backend().metadata_loader(),
|
||||
krate,
|
||||
@ -175,7 +200,7 @@ impl Compiler {
|
||||
}
|
||||
|
||||
pub fn dep_graph(&self) -> Result<&Query<DepGraph>> {
|
||||
self.queries.dep_graph.compute(|| {
|
||||
self.dep_graph.compute(|| {
|
||||
Ok(match self.dep_graph_future()?.take() {
|
||||
None => DepGraph::new_disabled(),
|
||||
Some(future) => {
|
||||
@ -192,15 +217,15 @@ impl Compiler {
|
||||
}
|
||||
|
||||
pub fn lower_to_hir(
|
||||
&self,
|
||||
) -> Result<&Query<(Steal<hir::map::Forest>, Steal<ResolverOutputs>)>> {
|
||||
self.queries.lower_to_hir.compute(|| {
|
||||
&'tcx self,
|
||||
) -> Result<&Query<(&'tcx hir::map::Forest, Steal<ResolverOutputs>)>> {
|
||||
self.lower_to_hir.compute(|| {
|
||||
let expansion_result = self.expansion()?;
|
||||
let peeked = expansion_result.peek();
|
||||
let krate = &peeked.0;
|
||||
let resolver = peeked.1.steal();
|
||||
let lint_store = &peeked.2;
|
||||
let hir = Steal::new(resolver.borrow_mut().access(|resolver| {
|
||||
let hir = resolver.borrow_mut().access(|resolver| {
|
||||
passes::lower_to_hir(
|
||||
self.session(),
|
||||
lint_store,
|
||||
@ -208,41 +233,47 @@ impl Compiler {
|
||||
&*self.dep_graph()?.peek(),
|
||||
&krate
|
||||
)
|
||||
})?);
|
||||
})?;
|
||||
let hir = self.arena.alloc(hir);
|
||||
Ok((hir, Steal::new(BoxedResolver::to_resolver_outputs(resolver))))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
|
||||
self.queries.prepare_outputs.compute(|| {
|
||||
self.prepare_outputs.compute(|| {
|
||||
let expansion_result = self.expansion()?;
|
||||
let (krate, boxed_resolver, _) = &*expansion_result.peek();
|
||||
let crate_name = self.crate_name()?;
|
||||
let crate_name = crate_name.peek();
|
||||
passes::prepare_outputs(self.session(), self, &krate, &boxed_resolver, &crate_name)
|
||||
passes::prepare_outputs(
|
||||
self.session(), self.compiler, &krate, &boxed_resolver, &crate_name
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn global_ctxt(&self) -> Result<&Query<BoxedGlobalCtxt>> {
|
||||
self.queries.global_ctxt.compute(|| {
|
||||
pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> {
|
||||
self.global_ctxt.compute(|| {
|
||||
let crate_name = self.crate_name()?.peek().clone();
|
||||
let outputs = self.prepare_outputs()?.peek().clone();
|
||||
let lint_store = self.expansion()?.peek().2.clone();
|
||||
let hir = self.lower_to_hir()?;
|
||||
let hir = hir.peek();
|
||||
let (hir_forest, resolver_outputs) = &*hir;
|
||||
let hir = self.lower_to_hir()?.peek();
|
||||
let (ref hir_forest, ref resolver_outputs) = &*hir;
|
||||
Ok(passes::create_global_ctxt(
|
||||
self,
|
||||
self.compiler,
|
||||
lint_store,
|
||||
hir_forest.steal(),
|
||||
hir_forest,
|
||||
resolver_outputs.steal(),
|
||||
outputs,
|
||||
&crate_name))
|
||||
&crate_name,
|
||||
&self.gcx,
|
||||
&self.all_arenas,
|
||||
&self.arena,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ongoing_codegen(&self) -> Result<&Query<Box<dyn Any>>> {
|
||||
self.queries.ongoing_codegen.compute(|| {
|
||||
pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
|
||||
self.ongoing_codegen.compute(|| {
|
||||
let outputs = self.prepare_outputs()?;
|
||||
self.global_ctxt()?.peek_mut().enter(|tcx| {
|
||||
tcx.analysis(LOCAL_CRATE).ok();
|
||||
@ -259,22 +290,58 @@ impl Compiler {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn link(&self) -> Result<&Query<()>> {
|
||||
self.queries.link.compute(|| {
|
||||
let sess = self.session();
|
||||
pub fn linker(&'tcx self) -> Result<Linker> {
|
||||
let dep_graph = self.dep_graph()?;
|
||||
let prepare_outputs = self.prepare_outputs()?;
|
||||
let ongoing_codegen = self.ongoing_codegen()?;
|
||||
|
||||
let ongoing_codegen = self.ongoing_codegen()?.take();
|
||||
let sess = self.session().clone();
|
||||
let codegen_backend = self.codegen_backend().clone();
|
||||
|
||||
self.codegen_backend().join_codegen_and_link(
|
||||
ongoing_codegen,
|
||||
sess,
|
||||
&*self.dep_graph()?.peek(),
|
||||
&*self.prepare_outputs()?.peek(),
|
||||
).map_err(|_| ErrorReported)?;
|
||||
|
||||
Ok(())
|
||||
Ok(Linker {
|
||||
sess,
|
||||
dep_graph: dep_graph.peek().clone(),
|
||||
prepare_outputs: prepare_outputs.take(),
|
||||
ongoing_codegen: ongoing_codegen.take(),
|
||||
codegen_backend,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Linker {
|
||||
sess: Lrc<Session>,
|
||||
dep_graph: DepGraph,
|
||||
prepare_outputs: OutputFilenames,
|
||||
ongoing_codegen: Box<dyn Any>,
|
||||
codegen_backend: Lrc<Box<dyn CodegenBackend>>,
|
||||
}
|
||||
|
||||
impl Linker {
|
||||
pub fn link(self) -> Result<()> {
|
||||
self.codegen_backend.join_codegen_and_link(
|
||||
self.ongoing_codegen,
|
||||
&self.sess,
|
||||
&self.dep_graph,
|
||||
&self.prepare_outputs,
|
||||
).map_err(|_| ErrorReported)
|
||||
}
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
pub fn enter<F, T>(&self, f: F) -> T
|
||||
where F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T
|
||||
{
|
||||
let queries = Queries::new(&self);
|
||||
let ret = f(&queries);
|
||||
|
||||
if self.session().opts.debugging_opts.query_stats {
|
||||
if let Ok(gcx) = queries.global_ctxt() {
|
||||
gcx.peek().print_stats();
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
// This method is different to all the other methods in `Compiler` because
|
||||
// it lacks a `Queries` entry. It's also not currently used. It does serve
|
||||
@ -282,24 +349,30 @@ impl Compiler {
|
||||
// between some passes. And see `rustc_driver::run_compiler` for a more
|
||||
// complex example.
|
||||
pub fn compile(&self) -> Result<()> {
|
||||
self.prepare_outputs()?;
|
||||
let linker = self.enter(|queries| {
|
||||
queries.prepare_outputs()?;
|
||||
|
||||
if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
|
||||
&& self.session().opts.output_types.len() == 1
|
||||
{
|
||||
return Ok(())
|
||||
if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
|
||||
&& self.session().opts.output_types.len() == 1
|
||||
{
|
||||
return Ok(None)
|
||||
}
|
||||
|
||||
queries.global_ctxt()?;
|
||||
|
||||
// Drop AST after creating GlobalCtxt to free memory.
|
||||
mem::drop(queries.expansion()?.take());
|
||||
|
||||
queries.ongoing_codegen()?;
|
||||
|
||||
let linker = queries.linker()?;
|
||||
Ok(Some(linker))
|
||||
})?;
|
||||
|
||||
if let Some(linker) = linker {
|
||||
linker.link()?
|
||||
}
|
||||
|
||||
self.global_ctxt()?;
|
||||
|
||||
// Drop AST after creating GlobalCtxt to free memory.
|
||||
mem::drop(self.expansion()?.take());
|
||||
|
||||
self.ongoing_codegen()?;
|
||||
|
||||
// Drop GlobalCtxt after starting codegen to free memory.
|
||||
mem::drop(self.global_ctxt()?.take());
|
||||
|
||||
self.link().map(|_| ())
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -933,14 +933,7 @@ fn convert_path_expr<'a, 'tcx>(
|
||||
// We encode uses of statics as a `*&STATIC` where the `&STATIC` part is
|
||||
// a constant reference (or constant raw pointer for `static mut`) in MIR
|
||||
Res::Def(DefKind::Static, id) => {
|
||||
let ty = cx.tcx.type_of(id);
|
||||
let ty = if cx.tcx.is_mutable_static(id) {
|
||||
cx.tcx.mk_mut_ptr(ty)
|
||||
} else if cx.tcx.is_foreign_item(id) {
|
||||
cx.tcx.mk_imm_ptr(ty)
|
||||
} else {
|
||||
cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_static, ty)
|
||||
};
|
||||
let ty = cx.tcx.static_ptr_ty(id);
|
||||
let ptr = cx.tcx.alloc_map.lock().create_static_alloc(id);
|
||||
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
||||
ExprKind::Deref { arg: Expr {
|
||||
|
@ -100,7 +100,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
|
||||
// This match is just a canary for future changes to `MemoryKind`, which most likely need
|
||||
// changes in this function.
|
||||
match kind {
|
||||
MemoryKind::Stack | MemoryKind::Vtable => {},
|
||||
MemoryKind::Stack | MemoryKind::Vtable | MemoryKind::CallerLocation => {},
|
||||
}
|
||||
// Set allocation mutability as appropriate. This is used by LLVM to put things into
|
||||
// read-only memory, and also by Miri when evluating other constants/statics that
|
||||
|
@ -28,7 +28,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let file = Scalar::Ptr(self.tag_static_base_pointer(file_ptr));
|
||||
let file_len = Scalar::from_uint(filename.as_str().len() as u128, ptr_size);
|
||||
|
||||
let location = self.allocate(loc_layout, MemoryKind::Stack);
|
||||
let location = self.allocate(loc_layout, MemoryKind::CallerLocation);
|
||||
|
||||
let file_out = self.mplace_field(location, 0)?;
|
||||
let file_ptr_out = self.force_ptr(self.mplace_field(file_out, 0)?.ptr)?;
|
||||
|
@ -24,11 +24,13 @@ use super::{
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub enum MemoryKind<T> {
|
||||
/// Error if deallocated except during a stack pop
|
||||
/// Stack memory. Error if deallocated except during a stack pop.
|
||||
Stack,
|
||||
/// Error if ever deallocated
|
||||
/// Memory backing vtables. Error if ever deallocated.
|
||||
Vtable,
|
||||
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
|
||||
/// Memory allocated by `caller_location` intrinsic. Error if ever deallocated.
|
||||
CallerLocation,
|
||||
/// Additional memory kinds a machine wishes to distinguish from the builtin ones.
|
||||
Machine(T),
|
||||
}
|
||||
|
||||
@ -38,6 +40,7 @@ impl<T: MayLeak> MayLeak for MemoryKind<T> {
|
||||
match self {
|
||||
MemoryKind::Stack => false,
|
||||
MemoryKind::Vtable => true,
|
||||
MemoryKind::CallerLocation => true,
|
||||
MemoryKind::Machine(k) => k.may_leak()
|
||||
}
|
||||
}
|
||||
@ -719,6 +722,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
||||
let extra = match kind {
|
||||
MemoryKind::Stack => " (stack)".to_owned(),
|
||||
MemoryKind::Vtable => " (vtable)".to_owned(),
|
||||
MemoryKind::CallerLocation => " (caller_location)".to_owned(),
|
||||
MemoryKind::Machine(m) => format!(" ({:?})", m),
|
||||
};
|
||||
self.dump_alloc_helper(
|
||||
|
@ -84,7 +84,7 @@ where
|
||||
{
|
||||
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
|
||||
let TraitRef { def_id, substs } = trait_ref;
|
||||
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) ||
|
||||
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path()) ||
|
||||
(!self.def_id_visitor.shallow() && substs.visit_with(self))
|
||||
}
|
||||
|
||||
|
@ -1149,8 +1149,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
let candidates = traits::supertraits(tcx, trait_ref).filter(|r| {
|
||||
self.trait_defines_associated_type_named(r.def_id(), binding.item_name)
|
||||
});
|
||||
self.one_bound_for_assoc_type(candidates, &trait_ref.to_string(),
|
||||
binding.item_name, binding.span)
|
||||
self.one_bound_for_assoc_type(
|
||||
candidates,
|
||||
&trait_ref.print_only_trait_path().to_string(),
|
||||
binding.item_name,
|
||||
binding.span
|
||||
)
|
||||
}?;
|
||||
|
||||
let (assoc_ident, def_scope) =
|
||||
@ -1589,12 +1593,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
if let Some(span) = bound_span {
|
||||
err.span_label(span, format!("ambiguous `{}` from `{}`",
|
||||
assoc_name,
|
||||
bound));
|
||||
bound.print_only_trait_path()));
|
||||
} else {
|
||||
span_note!(&mut err, span,
|
||||
"associated type `{}` could derive from `{}`",
|
||||
ty_param_name,
|
||||
bound);
|
||||
bound.print_only_trait_path());
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
|
@ -185,6 +185,8 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr) {
|
||||
let scope = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
||||
|
||||
match &expr.kind {
|
||||
ExprKind::Call(callee, args) => match &callee.kind {
|
||||
ExprKind::Path(qpath) => {
|
||||
@ -210,13 +212,20 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
|
||||
}
|
||||
_ => intravisit::walk_expr(self, expr),
|
||||
}
|
||||
ExprKind::Path(qpath) => {
|
||||
let res = self.fcx.tables.borrow().qpath_res(qpath, expr.hir_id);
|
||||
if let Res::Def(DefKind::Static, def_id) = res {
|
||||
// Statics are lowered to temporary references or
|
||||
// pointers in MIR, so record that type.
|
||||
let ptr_ty = self.fcx.tcx.static_ptr_ty(def_id);
|
||||
self.record(ptr_ty, scope, Some(expr), expr.span);
|
||||
}
|
||||
}
|
||||
_ => intravisit::walk_expr(self, expr),
|
||||
}
|
||||
|
||||
self.expr_count += 1;
|
||||
|
||||
let scope = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
||||
|
||||
// If there are adjustments, then record the final type --
|
||||
// this is the actual value that is being produced.
|
||||
if let Some(adjusted_ty) = self.fcx.tables.borrow().expr_ty_adjusted_opt(expr) {
|
||||
|
@ -502,7 +502,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
if !unsatisfied_predicates.is_empty() {
|
||||
let mut bound_list = unsatisfied_predicates.iter()
|
||||
.map(|p| format!("`{} : {}`", p.self_ty(), p))
|
||||
.map(|p| format!("`{} : {}`", p.self_ty(), p.print_only_trait_path()))
|
||||
.collect::<Vec<_>>();
|
||||
bound_list.sort();
|
||||
bound_list.dedup(); // #35677
|
||||
|
@ -2002,7 +2002,7 @@ fn check_impl_items_against_trait<'tcx>(
|
||||
"item `{}` is an associated const, \
|
||||
which doesn't match its trait `{}`",
|
||||
ty_impl_item.ident,
|
||||
impl_trait_ref);
|
||||
impl_trait_ref.print_only_trait_path());
|
||||
err.span_label(impl_item.span, "does not match trait");
|
||||
// We can only get the spans from local trait definition
|
||||
// Same for E0324 and E0325
|
||||
@ -2026,7 +2026,7 @@ fn check_impl_items_against_trait<'tcx>(
|
||||
"item `{}` is an associated method, \
|
||||
which doesn't match its trait `{}`",
|
||||
ty_impl_item.ident,
|
||||
impl_trait_ref);
|
||||
impl_trait_ref.print_only_trait_path());
|
||||
err.span_label(impl_item.span, "does not match trait");
|
||||
if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) {
|
||||
err.span_label(trait_span, "item in trait");
|
||||
@ -2045,7 +2045,7 @@ fn check_impl_items_against_trait<'tcx>(
|
||||
"item `{}` is an associated type, \
|
||||
which doesn't match its trait `{}`",
|
||||
ty_impl_item.ident,
|
||||
impl_trait_ref);
|
||||
impl_trait_ref.print_only_trait_path());
|
||||
err.span_label(impl_item.span, "does not match trait");
|
||||
if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) {
|
||||
err.span_label(trait_span, "item in trait");
|
||||
|
@ -35,7 +35,7 @@ impl UnsafetyChecker<'tcx> {
|
||||
item.span,
|
||||
E0199,
|
||||
"implementing the trait `{}` is not unsafe",
|
||||
trait_ref);
|
||||
trait_ref.print_only_trait_path());
|
||||
}
|
||||
|
||||
(Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
|
||||
@ -43,7 +43,7 @@ impl UnsafetyChecker<'tcx> {
|
||||
item.span,
|
||||
E0200,
|
||||
"the trait `{}` requires an `unsafe impl` declaration",
|
||||
trait_ref);
|
||||
trait_ref.print_only_trait_path());
|
||||
}
|
||||
|
||||
(Unsafety::Normal, Some(attr_name), Unsafety::Normal,
|
||||
|
@ -343,14 +343,14 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||
registry: rustc_driver::diagnostics_registry(),
|
||||
};
|
||||
|
||||
interface::run_compiler_in_existing_thread_pool(config, |compiler| {
|
||||
interface::run_compiler_in_existing_thread_pool(config, |compiler| compiler.enter(|queries| {
|
||||
let sess = compiler.session();
|
||||
|
||||
// We need to hold on to the complete resolver, so we cause everything to be
|
||||
// cloned for the analysis passes to use. Suboptimal, but necessary in the
|
||||
// current architecture.
|
||||
let resolver = {
|
||||
let parts = abort_on_err(compiler.expansion(), sess).peek();
|
||||
let parts = abort_on_err(queries.expansion(), sess).peek();
|
||||
let resolver = parts.1.borrow();
|
||||
|
||||
// Before we actually clone it, let's force all the extern'd crates to
|
||||
@ -358,10 +358,11 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||
// intra-doc-links
|
||||
resolver.borrow_mut().access(|resolver| {
|
||||
for extern_name in &extern_names {
|
||||
resolver.resolve_str_path_error(DUMMY_SP, extern_name, TypeNS, CRATE_NODE_ID)
|
||||
.unwrap_or_else(
|
||||
|()| panic!("Unable to resolve external crate {}", extern_name)
|
||||
);
|
||||
resolver.resolve_str_path_error(
|
||||
DUMMY_SP, extern_name, TypeNS, CRATE_NODE_ID
|
||||
).unwrap_or_else(
|
||||
|()| panic!("Unable to resolve external crate {}", extern_name)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@ -373,7 +374,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||
sess.fatal("Compilation failed, aborting rustdoc");
|
||||
}
|
||||
|
||||
let mut global_ctxt = abort_on_err(compiler.global_ctxt(), sess).take();
|
||||
let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take();
|
||||
|
||||
global_ctxt.enter(|tcx| {
|
||||
tcx.analysis(LOCAL_CRATE).ok();
|
||||
@ -447,8 +448,8 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||
},
|
||||
sym::plugins => {
|
||||
report_deprecated_attr("plugins = \"...\"", diag);
|
||||
eprintln!("WARNING: `#![doc(plugins = \"...\")]` no longer functions; \
|
||||
see CVE-2018-1000622");
|
||||
eprintln!("WARNING: `#![doc(plugins = \"...\")]` \
|
||||
no longer functions; see CVE-2018-1000622");
|
||||
continue
|
||||
},
|
||||
_ => continue,
|
||||
@ -486,7 +487,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||
|
||||
(krate, ctxt.renderinfo.into_inner(), render_options)
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter
|
||||
|
@ -85,14 +85,14 @@ pub fn run(options: Options) -> i32 {
|
||||
let mut test_args = options.test_args.clone();
|
||||
let display_warnings = options.display_warnings;
|
||||
|
||||
let tests = interface::run_compiler(config, |compiler| -> Result<_, ErrorReported> {
|
||||
let lower_to_hir = compiler.lower_to_hir()?;
|
||||
let tests = interface::run_compiler(config, |compiler| compiler.enter(|queries| {
|
||||
let lower_to_hir = queries.lower_to_hir()?;
|
||||
|
||||
let mut opts = scrape_test_config(lower_to_hir.peek().0.borrow().krate());
|
||||
let mut opts = scrape_test_config(lower_to_hir.peek().0.krate());
|
||||
opts.display_warnings |= options.display_warnings;
|
||||
let enable_per_target_ignores = options.enable_per_target_ignores;
|
||||
let mut collector = Collector::new(
|
||||
compiler.crate_name()?.peek().to_string(),
|
||||
queries.crate_name()?.peek().to_string(),
|
||||
options,
|
||||
false,
|
||||
opts,
|
||||
@ -101,7 +101,8 @@ pub fn run(options: Options) -> i32 {
|
||||
enable_per_target_ignores,
|
||||
);
|
||||
|
||||
let mut global_ctxt = compiler.global_ctxt()?.take();
|
||||
let mut global_ctxt = queries.global_ctxt()?.take();
|
||||
|
||||
global_ctxt.enter(|tcx| {
|
||||
let krate = tcx.hir().krate();
|
||||
let mut hir_collector = HirCollector {
|
||||
@ -116,8 +117,9 @@ pub fn run(options: Options) -> i32 {
|
||||
});
|
||||
});
|
||||
|
||||
Ok(collector.tests)
|
||||
}).expect("compiler aborted in rustdoc!");
|
||||
let ret : Result<_, ErrorReported> = Ok(collector.tests);
|
||||
ret
|
||||
})).expect("compiler aborted in rustdoc!");
|
||||
|
||||
test_args.insert(0, "rustdoctest".to_string());
|
||||
|
||||
|
@ -425,5 +425,5 @@ pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||
/// ```
|
||||
#[stable(feature = "resume_unwind", since = "1.9.0")]
|
||||
pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
|
||||
panicking::update_count_then_panic(payload)
|
||||
panicking::rust_panic_without_hook(payload)
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ use crate::sys_common::rwlock::RWLock;
|
||||
use crate::sys_common::{thread_info, util};
|
||||
use crate::sys_common::backtrace::{self, RustBacktrace};
|
||||
use crate::thread;
|
||||
use crate::process;
|
||||
|
||||
#[cfg(not(test))]
|
||||
use crate::io::set_panic;
|
||||
@ -46,6 +47,8 @@ extern {
|
||||
vtable_ptr: *mut usize) -> u32;
|
||||
|
||||
/// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings.
|
||||
/// It cannot be `Box<dyn BoxMeUp>` because the other end of this call does not depend
|
||||
/// on liballoc, and thus cannot use `Box`.
|
||||
#[unwind(allowed)]
|
||||
fn __rust_start_panic(payload: usize) -> u32;
|
||||
}
|
||||
@ -296,14 +299,6 @@ pub fn panicking() -> bool {
|
||||
update_panic_count(0) != 0
|
||||
}
|
||||
|
||||
/// Entry point of panic from the libcore crate (`panic_impl` lang item).
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
#[unwind(allowed)]
|
||||
pub fn rust_begin_panic(info: &PanicInfo<'_>) -> ! {
|
||||
continue_panic_fmt(&info)
|
||||
}
|
||||
|
||||
/// The entry point for panicking with a formatted message.
|
||||
///
|
||||
/// This is designed to reduce the amount of code required at the call
|
||||
@ -324,13 +319,17 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>,
|
||||
unsafe { intrinsics::abort() }
|
||||
}
|
||||
|
||||
// Just package everything into a `PanicInfo` and continue like libcore panics.
|
||||
let (file, line, col) = *file_line_col;
|
||||
let location = Location::internal_constructor(file, line, col);
|
||||
let info = PanicInfo::internal_constructor(Some(msg), &location);
|
||||
continue_panic_fmt(&info)
|
||||
begin_panic_handler(&info)
|
||||
}
|
||||
|
||||
fn continue_panic_fmt(info: &PanicInfo<'_>) -> ! {
|
||||
/// Entry point of panics from the libcore crate (`panic_impl` lang item).
|
||||
#[cfg_attr(not(test), panic_handler)]
|
||||
#[unwind(allowed)]
|
||||
pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
|
||||
struct PanicPayload<'a> {
|
||||
inner: &'a fmt::Arguments<'a>,
|
||||
string: Option<String>,
|
||||
@ -345,6 +344,7 @@ fn continue_panic_fmt(info: &PanicInfo<'_>) -> ! {
|
||||
use crate::fmt::Write;
|
||||
|
||||
let inner = self.inner;
|
||||
// Lazily, the first time this gets called, run the actual string formatting.
|
||||
self.string.get_or_insert_with(|| {
|
||||
let mut s = String::new();
|
||||
drop(s.write_fmt(*inner));
|
||||
@ -354,7 +354,7 @@ fn continue_panic_fmt(info: &PanicInfo<'_>) -> ! {
|
||||
}
|
||||
|
||||
unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
|
||||
fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
|
||||
fn take_box(&mut self) -> *mut (dyn Any + Send) {
|
||||
let contents = mem::take(self.fill());
|
||||
Box::into_raw(Box::new(contents))
|
||||
}
|
||||
@ -378,7 +378,9 @@ fn continue_panic_fmt(info: &PanicInfo<'_>) -> ! {
|
||||
&file_line_col);
|
||||
}
|
||||
|
||||
/// This is the entry point of panicking for panic!() and assert!().
|
||||
/// This is the entry point of panicking for the non-format-string variants of
|
||||
/// panic!() and assert!(). In particular, this is the only entry point that supports
|
||||
/// arbitrary payloads, not just format strings.
|
||||
#[unstable(feature = "libstd_sys_internals",
|
||||
reason = "used by the panic! macro",
|
||||
issue = "0")]
|
||||
@ -412,10 +414,10 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3
|
||||
}
|
||||
|
||||
unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
|
||||
fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
|
||||
fn take_box(&mut self) -> *mut (dyn Any + Send) {
|
||||
let data = match self.inner.take() {
|
||||
Some(a) => Box::new(a) as Box<dyn Any + Send>,
|
||||
None => Box::new(()),
|
||||
None => process::abort(),
|
||||
};
|
||||
Box::into_raw(data)
|
||||
}
|
||||
@ -423,7 +425,7 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3
|
||||
fn get(&mut self) -> &(dyn Any + Send) {
|
||||
match self.inner {
|
||||
Some(ref a) => a,
|
||||
None => &(),
|
||||
None => process::abort(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -457,9 +459,12 @@ fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
|
||||
let mut info = PanicInfo::internal_constructor(message, &location);
|
||||
HOOK_LOCK.read();
|
||||
match HOOK {
|
||||
// Some platforms know that printing to stderr won't ever actually
|
||||
// Some platforms (like wasm) know that printing to stderr won't ever actually
|
||||
// print anything, and if that's the case we can skip the default
|
||||
// hook.
|
||||
// hook. Since string formatting happens lazily when calling `payload`
|
||||
// methods, this means we avoid formatting the string at all!
|
||||
// (The panic runtime might still call `payload.take_box()` though and trigger
|
||||
// formatting.)
|
||||
Hook::Default if panic_output().is_none() => {}
|
||||
Hook::Default => {
|
||||
info.set_payload(payload.get());
|
||||
@ -486,14 +491,15 @@ fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
|
||||
rust_panic(payload)
|
||||
}
|
||||
|
||||
/// Shim around rust_panic. Called by resume_unwind.
|
||||
pub fn update_count_then_panic(msg: Box<dyn Any + Send>) -> ! {
|
||||
/// This is the entry point for `resume_unwind`.
|
||||
/// It just forwards the payload to the panic runtime.
|
||||
pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
|
||||
update_panic_count(1);
|
||||
|
||||
struct RewrapBox(Box<dyn Any + Send>);
|
||||
|
||||
unsafe impl BoxMeUp for RewrapBox {
|
||||
fn box_me_up(&mut self) -> *mut (dyn Any + Send) {
|
||||
fn take_box(&mut self) -> *mut (dyn Any + Send) {
|
||||
Box::into_raw(mem::replace(&mut self.0, Box::new(())))
|
||||
}
|
||||
|
||||
@ -502,7 +508,7 @@ pub fn update_count_then_panic(msg: Box<dyn Any + Send>) -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
rust_panic(&mut RewrapBox(msg))
|
||||
rust_panic(&mut RewrapBox(payload))
|
||||
}
|
||||
|
||||
/// An unmangled function (through `rustc_std_internal_symbol`) on which to slap
|
||||
|
@ -66,6 +66,11 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
|
||||
|
||||
interface::run_compiler(config, |compiler| {
|
||||
// This runs all the passes prior to linking, too.
|
||||
compiler.link().ok();
|
||||
let linker = compiler.enter(|queries| {
|
||||
queries.linker()
|
||||
});
|
||||
if let Ok(linker) = linker {
|
||||
linker.link();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
24
src/test/ui/async-await/issues/issue-66695-static-refs.rs
Normal file
24
src/test/ui/async-await/issues/issue-66695-static-refs.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// build-pass
|
||||
// edition:2018
|
||||
|
||||
static A: [i32; 5] = [1, 2, 3, 4, 5];
|
||||
|
||||
async fn fun() {
|
||||
let u = A[async { 1 }.await];
|
||||
match A {
|
||||
i if async { true }.await => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
async {
|
||||
let u = A[async { 1 }.await];
|
||||
};
|
||||
async {
|
||||
match A {
|
||||
i if async { true }.await => (),
|
||||
_ => (),
|
||||
}
|
||||
};
|
||||
}
|
16
src/test/ui/generator/static-reference-across-yield.rs
Normal file
16
src/test/ui/generator/static-reference-across-yield.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// build-pass
|
||||
#![feature(generators)]
|
||||
|
||||
static A: [i32; 5] = [1, 2, 3, 4, 5];
|
||||
|
||||
fn main() {
|
||||
static || {
|
||||
let u = A[{yield; 1}];
|
||||
};
|
||||
static || {
|
||||
match A {
|
||||
i if { yield; true } => (),
|
||||
_ => (),
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
// ignore-tidy-linelength
|
||||
|
||||
fn main() {
|
||||
let unicode_is_fun = "‱ஹ௸௵꧄.ဪ꧅⸻𒈙𒐫﷽𒌄𒈟𒍼𒁎𒀱𒌧𒅃 𒈓𒍙𒊎𒄡𒅌𒁏𒀰𒐪𒐩𒈙𒐫𪚥";
|
||||
let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
|
||||
//~^ ERROR binary operation `+` cannot be applied to type `&str`
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
error[E0369]: binary operation `+` cannot be applied to type `&str`
|
||||
--> $DIR/non-1-width-unicode-multiline-label.rs:5:260
|
||||
|
|
||||
LL | ...ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇...࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
|
||||
| -------------- ^ -------------- &str
|
||||
| | |
|
||||
| | `+` cannot be used to concatenate two `&str` strings
|
||||
| &str
|
||||
|
|
||||
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
|
||||
|
|
||||
LL | let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!";
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0369`.
|
@ -3,7 +3,7 @@ error[E0308]: mismatched types
|
||||
|
|
||||
LL | ...♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄...
|
||||
| -- ^^ expected `()`, found integer
|
||||
| |
|
||||
| |
|
||||
| expected due to this
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
x
Reference in New Issue
Block a user