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:
bors 2019-11-29 22:00:28 +00:00
commit 9081929d45
50 changed files with 642 additions and 399 deletions

View File

@ -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:

View File

@ -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.

View File

@ -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")]

View File

@ -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")]

View File

@ -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);
}

View File

@ -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<'_>) -> !;

View File

@ -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

View File

@ -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()))
}

View File

@ -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,

View File

@ -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,

View File

@ -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)
},
}
}

View File

@ -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()),
)
};

View File

@ -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

View File

@ -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)),
});

View File

@ -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,

View File

@ -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 {

View File

@ -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.

View File

@ -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.

View File

@ -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(),

View File

@ -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> {

View File

@ -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)
}
}

View File

@ -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,

View File

@ -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();
}

View File

@ -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:

View File

@ -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!
}
```

View File

@ -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

View File

@ -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);
}

View File

@ -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,

View File

@ -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

View File

@ -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(())
}
}

View File

@ -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 {

View File

@ -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

View File

@ -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)?;

View File

@ -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(

View File

@ -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))
}

View File

@ -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();

View File

@ -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) {

View File

@ -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

View File

@ -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");

View File

@ -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,

View File

@ -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

View File

@ -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());

View File

@ -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)
}

View File

@ -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

View File

@ -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();
}
});
}

View 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 => (),
_ => (),
}
};
}

View 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 } => (),
_ => (),
}
};
}

View File

@ -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`
}

View File

@ -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`.

View File

@ -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