mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 00:03:43 +00:00
Auto merge of #133152 - jhpratt:rollup-wkqs5ud, r=jhpratt
Rollup of 7 pull requests Successful merges: - #132795 (Check `use<..>` in RPITIT for refinement) - #132944 (add parentheses when unboxing suggestion needed) - #132993 (Make rustc consider itself a stable compiler when `RUSTC_BOOTSTRAP=-1`) - #133130 (`suggest_borrow_generic_arg`: instantiate clauses properly) - #133133 (rustdoc-search: add standalone trailing `::` test) - #133143 (Diagnostics for let mut in item context) - #133147 (Fixup some test directives) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
bf6adec108
@ -27,7 +27,7 @@ use rustc_middle::mir::{
|
|||||||
};
|
};
|
||||||
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, ClauseKind, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
|
self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
|
||||||
suggest_constraining_type_params,
|
suggest_constraining_type_params,
|
||||||
};
|
};
|
||||||
use rustc_middle::util::CallKind;
|
use rustc_middle::util::CallKind;
|
||||||
@ -649,11 +649,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||||||
) -> Option<ty::Mutability> {
|
) -> Option<ty::Mutability> {
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();
|
let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();
|
||||||
let clauses = tcx.predicates_of(callee_did).instantiate_identity(self.infcx.tcx).predicates;
|
let clauses = tcx.predicates_of(callee_did);
|
||||||
|
|
||||||
// First, is there at least one method on one of `param`'s trait bounds?
|
// First, is there at least one method on one of `param`'s trait bounds?
|
||||||
// This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.
|
// This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.
|
||||||
if !clauses.iter().any(|clause| {
|
if !clauses.instantiate_identity(tcx).predicates.iter().any(|clause| {
|
||||||
clause.as_trait_clause().is_some_and(|tc| {
|
clause.as_trait_clause().is_some_and(|tc| {
|
||||||
tc.self_ty().skip_binder().is_param(param.index)
|
tc.self_ty().skip_binder().is_param(param.index)
|
||||||
&& tc.polarity() == ty::PredicatePolarity::Positive
|
&& tc.polarity() == ty::PredicatePolarity::Positive
|
||||||
@ -700,23 +700,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test the callee's predicates, substituting a reference in for the self ty
|
// Test the callee's predicates, substituting in `ref_ty` for the moved argument type.
|
||||||
// in bounds on `param`.
|
clauses.instantiate(tcx, new_args).predicates.iter().all(|&(mut clause)| {
|
||||||
clauses.iter().all(|&clause| {
|
// Normalize before testing to see through type aliases and projections.
|
||||||
let clause_for_ref = clause.kind().map_bound(|kind| match kind {
|
if let Ok(normalized) = tcx.try_normalize_erasing_regions(self.param_env, clause) {
|
||||||
ClauseKind::Trait(c) if c.self_ty().is_param(param.index) => {
|
clause = normalized;
|
||||||
ClauseKind::Trait(c.with_self_ty(tcx, ref_ty))
|
}
|
||||||
}
|
|
||||||
ClauseKind::Projection(c) if c.self_ty().is_param(param.index) => {
|
|
||||||
ClauseKind::Projection(c.with_self_ty(tcx, ref_ty))
|
|
||||||
}
|
|
||||||
_ => kind,
|
|
||||||
});
|
|
||||||
self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(
|
self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(
|
||||||
tcx,
|
tcx,
|
||||||
ObligationCause::dummy(),
|
ObligationCause::dummy(),
|
||||||
self.param_env,
|
self.param_env,
|
||||||
ty::EarlyBinder::bind(clause_for_ref).instantiate(tcx, generic_args),
|
clause,
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}) {
|
}) {
|
||||||
|
@ -74,14 +74,19 @@ impl UnstableFeatures {
|
|||||||
// Returns whether `krate` should be counted as unstable
|
// Returns whether `krate` should be counted as unstable
|
||||||
let is_unstable_crate =
|
let is_unstable_crate =
|
||||||
|var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name));
|
|var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name));
|
||||||
// `true` if we should enable unstable features for bootstrapping.
|
|
||||||
let bootstrap =
|
let bootstrap = std::env::var("RUSTC_BOOTSTRAP").ok();
|
||||||
std::env::var("RUSTC_BOOTSTRAP").is_ok_and(|var| var == "1" || is_unstable_crate(&var));
|
if let Some(val) = bootstrap.as_deref() {
|
||||||
match (disable_unstable_features, bootstrap) {
|
match val {
|
||||||
(_, true) => UnstableFeatures::Cheat,
|
val if val == "1" || is_unstable_crate(val) => return UnstableFeatures::Cheat,
|
||||||
(true, _) => UnstableFeatures::Disallow,
|
// Hypnotize ourselves so that we think we are a stable compiler and thus don't
|
||||||
(false, _) => UnstableFeatures::Allow,
|
// allow any unstable features.
|
||||||
|
"-1" => return UnstableFeatures::Disallow,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if disable_unstable_features { UnstableFeatures::Disallow } else { UnstableFeatures::Allow }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_nightly_build(&self) -> bool {
|
pub fn is_nightly_build(&self) -> bool {
|
||||||
|
@ -18,6 +18,16 @@ fn rustc_bootstrap_parsing() {
|
|||||||
assert!(!is_bootstrap("x,y,z", Some("a")));
|
assert!(!is_bootstrap("x,y,z", Some("a")));
|
||||||
assert!(!is_bootstrap("x,y,z", None));
|
assert!(!is_bootstrap("x,y,z", None));
|
||||||
|
|
||||||
// this is technically a breaking change, but there are no stability guarantees for RUSTC_BOOTSTRAP
|
// `RUSTC_BOOTSTRAP=0` is not recognized.
|
||||||
assert!(!is_bootstrap("0", None));
|
assert!(!is_bootstrap("0", None));
|
||||||
|
|
||||||
|
// `RUSTC_BOOTSTRAP=-1` is force-stable, no unstable features allowed.
|
||||||
|
let is_force_stable = |krate| {
|
||||||
|
std::env::set_var("RUSTC_BOOTSTRAP", "-1");
|
||||||
|
matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Disallow)
|
||||||
|
};
|
||||||
|
assert!(is_force_stable(None));
|
||||||
|
// Does not support specifying any crate.
|
||||||
|
assert!(is_force_stable(Some("x")));
|
||||||
|
assert!(is_force_stable(Some("x,y,z")));
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ pub struct EnabledLangFeature {
|
|||||||
pub stable_since: Option<Symbol>,
|
pub stable_since: Option<Symbol>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information abhout an enabled library feature.
|
/// Information about an enabled library feature.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct EnabledLibFeature {
|
pub struct EnabledLibFeature {
|
||||||
pub gate_name: Symbol,
|
pub gate_name: Symbol,
|
||||||
|
@ -448,6 +448,11 @@ hir_analysis_rpitit_refined = impl trait in impl method signature does not match
|
|||||||
.note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
|
.note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
|
||||||
.feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
|
.feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
|
||||||
|
|
||||||
|
hir_analysis_rpitit_refined_lifetimes = impl trait in impl method captures fewer lifetimes than in trait
|
||||||
|
.suggestion = modify the `use<..>` bound to capture the same lifetimes that the trait does
|
||||||
|
.note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
|
||||||
|
.feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
|
||||||
|
|
||||||
hir_analysis_self_in_impl_self =
|
hir_analysis_self_in_impl_self =
|
||||||
`Self` is not valid in the self type of an impl block
|
`Self` is not valid in the self type of an impl block
|
||||||
.note = replace `Self` with a different type
|
.note = replace `Self` with a different type
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
use itertools::Itertools as _;
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||||
use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE};
|
use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE};
|
||||||
@ -75,6 +76,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
|
|||||||
let mut trait_bounds = vec![];
|
let mut trait_bounds = vec![];
|
||||||
// Bounds that we find on the RPITITs in the impl signature.
|
// Bounds that we find on the RPITITs in the impl signature.
|
||||||
let mut impl_bounds = vec![];
|
let mut impl_bounds = vec![];
|
||||||
|
// Pairs of trait and impl opaques.
|
||||||
|
let mut pairs = vec![];
|
||||||
|
|
||||||
for trait_projection in collector.types.into_iter().rev() {
|
for trait_projection in collector.types.into_iter().rev() {
|
||||||
let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args);
|
let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args);
|
||||||
@ -121,6 +124,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
|
|||||||
tcx.explicit_item_bounds(impl_opaque.def_id)
|
tcx.explicit_item_bounds(impl_opaque.def_id)
|
||||||
.iter_instantiated_copied(tcx, impl_opaque.args),
|
.iter_instantiated_copied(tcx, impl_opaque.args),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
pairs.push((trait_projection, impl_opaque));
|
||||||
}
|
}
|
||||||
|
|
||||||
let hybrid_preds = tcx
|
let hybrid_preds = tcx
|
||||||
@ -212,6 +217,39 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure that the RPITIT doesn't capture fewer regions than
|
||||||
|
// the trait definition. We hard-error if it captures *more*, since that
|
||||||
|
// is literally unrepresentable in the type system; however, we may be
|
||||||
|
// promising stronger outlives guarantees if we capture *fewer* regions.
|
||||||
|
for (trait_projection, impl_opaque) in pairs {
|
||||||
|
let impl_variances = tcx.variances_of(impl_opaque.def_id);
|
||||||
|
let impl_captures: FxIndexSet<_> = impl_opaque
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.zip_eq(impl_variances)
|
||||||
|
.filter(|(_, v)| **v == ty::Invariant)
|
||||||
|
.map(|(arg, _)| arg)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let trait_variances = tcx.variances_of(trait_projection.def_id);
|
||||||
|
let mut trait_captures = FxIndexSet::default();
|
||||||
|
for (arg, variance) in trait_projection.args.iter().zip_eq(trait_variances) {
|
||||||
|
if *variance != ty::Invariant {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
arg.visit_with(&mut CollectParams { params: &mut trait_captures });
|
||||||
|
}
|
||||||
|
|
||||||
|
if !trait_captures.iter().all(|arg| impl_captures.contains(arg)) {
|
||||||
|
report_mismatched_rpitit_captures(
|
||||||
|
tcx,
|
||||||
|
impl_opaque.def_id.expect_local(),
|
||||||
|
trait_captures,
|
||||||
|
is_internal,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ImplTraitInTraitCollector<'tcx> {
|
struct ImplTraitInTraitCollector<'tcx> {
|
||||||
@ -342,3 +380,65 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Anonymize<'tcx> {
|
|||||||
self.tcx.anonymize_bound_vars(t)
|
self.tcx.anonymize_bound_vars(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CollectParams<'a, 'tcx> {
|
||||||
|
params: &'a mut FxIndexSet<ty::GenericArg<'tcx>>,
|
||||||
|
}
|
||||||
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CollectParams<'_, 'tcx> {
|
||||||
|
fn visit_ty(&mut self, ty: Ty<'tcx>) {
|
||||||
|
if let ty::Param(_) = ty.kind() {
|
||||||
|
self.params.insert(ty.into());
|
||||||
|
} else {
|
||||||
|
ty.super_visit_with(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_region(&mut self, r: ty::Region<'tcx>) {
|
||||||
|
match r.kind() {
|
||||||
|
ty::ReEarlyParam(_) | ty::ReLateParam(_) => {
|
||||||
|
self.params.insert(r.into());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_const(&mut self, ct: ty::Const<'tcx>) {
|
||||||
|
if let ty::ConstKind::Param(_) = ct.kind() {
|
||||||
|
self.params.insert(ct.into());
|
||||||
|
} else {
|
||||||
|
ct.super_visit_with(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_mismatched_rpitit_captures<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
impl_opaque_def_id: LocalDefId,
|
||||||
|
mut trait_captured_args: FxIndexSet<ty::GenericArg<'tcx>>,
|
||||||
|
is_internal: bool,
|
||||||
|
) {
|
||||||
|
let Some(use_bound_span) =
|
||||||
|
tcx.hir_node_by_def_id(impl_opaque_def_id).expect_opaque_ty().bounds.iter().find_map(
|
||||||
|
|bound| match *bound {
|
||||||
|
rustc_hir::GenericBound::Use(_, span) => Some(span),
|
||||||
|
hir::GenericBound::Trait(_) | hir::GenericBound::Outlives(_) => None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else {
|
||||||
|
// I have no idea when you would ever undercapture without a `use<..>`.
|
||||||
|
tcx.dcx().delayed_bug("expected use<..> to undercapture in an impl opaque");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
trait_captured_args
|
||||||
|
.sort_by_cached_key(|arg| !matches!(arg.unpack(), ty::GenericArgKind::Lifetime(_)));
|
||||||
|
let suggestion = format!("use<{}>", trait_captured_args.iter().join(", "));
|
||||||
|
|
||||||
|
tcx.emit_node_span_lint(
|
||||||
|
if is_internal { REFINING_IMPL_TRAIT_INTERNAL } else { REFINING_IMPL_TRAIT_REACHABLE },
|
||||||
|
tcx.local_def_id_to_hir_id(impl_opaque_def_id),
|
||||||
|
use_bound_span,
|
||||||
|
crate::errors::ReturnPositionImplTraitInTraitRefinedLifetimes {
|
||||||
|
suggestion_span: use_bound_span,
|
||||||
|
suggestion,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -1153,6 +1153,16 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> {
|
|||||||
pub return_ty: Ty<'tcx>,
|
pub return_ty: Ty<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(hir_analysis_rpitit_refined_lifetimes)]
|
||||||
|
#[note]
|
||||||
|
#[note(hir_analysis_feedback_note)]
|
||||||
|
pub(crate) struct ReturnPositionImplTraitInTraitRefinedLifetimes {
|
||||||
|
#[suggestion(applicability = "maybe-incorrect", code = "{suggestion}")]
|
||||||
|
pub suggestion_span: Span,
|
||||||
|
pub suggestion: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis_inherent_ty_outside, code = E0390)]
|
#[diag(hir_analysis_inherent_ty_outside, code = E0390)]
|
||||||
#[help]
|
#[help]
|
||||||
|
@ -2648,15 +2648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| {
|
let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| {
|
||||||
let needs_parens = match expr.kind {
|
if self.needs_parentheses(expr) {
|
||||||
// parenthesize if needed (Issue #46756)
|
|
||||||
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
|
|
||||||
// parenthesize borrows of range literals (Issue #54505)
|
|
||||||
_ if is_range_literal(expr) => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if needs_parens {
|
|
||||||
(
|
(
|
||||||
vec![
|
vec![
|
||||||
(span.shrink_to_lo(), format!("{prefix}{sugg}(")),
|
(span.shrink_to_lo(), format!("{prefix}{sugg}(")),
|
||||||
@ -2869,6 +2861,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.needs_parentheses(expr) {
|
||||||
|
return Some((
|
||||||
|
vec![
|
||||||
|
(span, format!("{suggestion}(")),
|
||||||
|
(expr.span.shrink_to_hi(), ")".to_string()),
|
||||||
|
],
|
||||||
|
message,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
return Some((
|
return Some((
|
||||||
vec![(span, suggestion)],
|
vec![(span, suggestion)],
|
||||||
message,
|
message,
|
||||||
@ -2897,6 +2902,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn needs_parentheses(&self, expr: &hir::Expr<'_>) -> bool {
|
||||||
|
match expr.kind {
|
||||||
|
// parenthesize if needed (Issue #46756)
|
||||||
|
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
|
||||||
|
// parenthesize borrows of range literals (Issue #54505)
|
||||||
|
_ if is_range_literal(expr) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn suggest_cast(
|
pub(crate) fn suggest_cast(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
|
@ -77,18 +77,35 @@ impl<'a> Parser<'a> {
|
|||||||
if !self.eat(term) {
|
if !self.eat(term) {
|
||||||
let token_str = super::token_descr(&self.token);
|
let token_str = super::token_descr(&self.token);
|
||||||
if !self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {
|
if !self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {
|
||||||
|
let is_let = self.token.is_keyword(kw::Let);
|
||||||
|
let is_let_mut = is_let && self.look_ahead(1, |t| t.is_keyword(kw::Mut));
|
||||||
|
let let_has_ident = is_let && !is_let_mut && self.is_kw_followed_by_ident(kw::Let);
|
||||||
|
|
||||||
let msg = format!("expected item, found {token_str}");
|
let msg = format!("expected item, found {token_str}");
|
||||||
let mut err = self.dcx().struct_span_err(self.token.span, msg);
|
let mut err = self.dcx().struct_span_err(self.token.span, msg);
|
||||||
let span = self.token.span;
|
|
||||||
if self.is_kw_followed_by_ident(kw::Let) {
|
let label = if is_let {
|
||||||
err.span_label(
|
"`let` cannot be used for global variables"
|
||||||
span,
|
|
||||||
"consider using `const` or `static` instead of `let` for global variables",
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
err.span_label(span, "expected item")
|
"expected item"
|
||||||
.note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>");
|
|
||||||
};
|
};
|
||||||
|
err.span_label(self.token.span, label);
|
||||||
|
|
||||||
|
if is_let {
|
||||||
|
if is_let_mut {
|
||||||
|
err.help("consider using `static` and a `Mutex` instead of `let mut`");
|
||||||
|
} else if let_has_ident {
|
||||||
|
err.span_suggestion_short(
|
||||||
|
self.token.span,
|
||||||
|
"consider using `static` or `const` instead of `let`",
|
||||||
|
"static",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
err.help("consider using `static` or `const` instead of `let`");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err.note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>");
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// This causes hygiene information to be saved to the incr cache.
|
// This causes hygiene information to be saved to the incr cache.
|
||||||
// 2. One function is the foreign crate is modified. This causes the
|
// 2. One function is the foreign crate is modified. This causes the
|
||||||
// optimized mir for an unmodified function to be loaded from the
|
// optimized mir for an unmodified function to be loaded from the
|
||||||
//@ incremental cache and written out to the crate metadata.
|
// incremental cache and written out to the crate metadata.
|
||||||
// 3. In the process of loading and writing out this function's MIR,
|
// 3. In the process of loading and writing out this function's MIR,
|
||||||
// we load hygiene information from the incremental cache and
|
// we load hygiene information from the incremental cache and
|
||||||
// write it to our metadata.
|
// write it to our metadata.
|
||||||
|
7
tests/rustdoc-js/trailing.js
Normal file
7
tests/rustdoc-js/trailing.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// exact-check
|
||||||
|
const EXPECTED = {
|
||||||
|
'query': 'inner::',
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'trailing::inner', 'name': 'function' },
|
||||||
|
],
|
||||||
|
}
|
3
tests/rustdoc-js/trailing.rs
Normal file
3
tests/rustdoc-js/trailing.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod inner {
|
||||||
|
pub fn function() {}
|
||||||
|
}
|
10
tests/ui/bootstrap/rustc_bootstap.force_stable.stderr
Normal file
10
tests/ui/bootstrap/rustc_bootstap.force_stable.stderr
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
error: the option `Z` is only accepted on the nightly compiler
|
||||||
|
|
||||||
|
help: consider switching to a nightly toolchain: `rustup default nightly`
|
||||||
|
|
||||||
|
note: selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>
|
||||||
|
|
||||||
|
note: for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>
|
||||||
|
|
||||||
|
error: 1 nightly option were parsed
|
||||||
|
|
47
tests/ui/bootstrap/rustc_bootstap.rs
Normal file
47
tests/ui/bootstrap/rustc_bootstap.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
//! Check `RUSTC_BOOTSTRAP`'s behavior in relation to feature stability and what rustc considers
|
||||||
|
//! itself to be (stable vs non-stable ).
|
||||||
|
//!
|
||||||
|
//! `RUSTC_BOOTSTRAP` accepts:
|
||||||
|
//!
|
||||||
|
//! - `1`: cheat, allow usage of unstable features even if rustc thinks it is a stable compiler.
|
||||||
|
//! - `x,y,z`: comma-delimited list of crates.
|
||||||
|
//! - `-1`: force rustc to think it is a stable compiler.
|
||||||
|
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
|
//@ revisions: default_nightly cheat cheat_single_crate cheat_multi_crate force_stable invalid_zero invalid_junk
|
||||||
|
//@ only-nightly
|
||||||
|
|
||||||
|
//@[default_nightly] unset-rustc-env:RUSTC_BOOTSTRAP
|
||||||
|
//@[default_nightly] check-pass
|
||||||
|
|
||||||
|
// For a nightly compiler, this is same as `default_nightly` as if `RUSTC_BOOTSTRAP` was unset.
|
||||||
|
//@[invalid_zero] rustc-env:RUSTC_BOOTSTRAP=0
|
||||||
|
//@[invalid_zero] check-pass
|
||||||
|
|
||||||
|
// Invalid values are silently discarded, same as `default_nightly`, i.e. as if `RUSTC_BOOTSTRAP`
|
||||||
|
// was unset.
|
||||||
|
//@[invalid_junk] rustc-env:RUSTC_BOOTSTRAP=*
|
||||||
|
//@[invalid_junk] check-pass
|
||||||
|
|
||||||
|
//@[cheat] rustc-env:RUSTC_BOOTSTRAP=1
|
||||||
|
//@[cheat] check-pass
|
||||||
|
|
||||||
|
//@[cheat_single_crate] rustc-env:RUSTC_BOOTSTRAP=x
|
||||||
|
//@[cheat_single_crate] check-pass
|
||||||
|
|
||||||
|
//@[cheat_multi_crate] rustc-env:RUSTC_BOOTSTRAP=x,y,z
|
||||||
|
//@[cheat_multi_crate] check-pass
|
||||||
|
|
||||||
|
// Note: compiletest passes some `-Z` flags to the compiler for ui testing purposes, so here we
|
||||||
|
// instead abuse the fact that `-Z unstable-options` is also part of rustc's stability story and is
|
||||||
|
// also affected by `RUSTC_BOOTSTRAP`.
|
||||||
|
//@[force_stable] rustc-env:RUSTC_BOOTSTRAP=-1
|
||||||
|
//@[force_stable] compile-flags: -Z unstable-options
|
||||||
|
//@[force_stable] regex-error-pattern: error: the option `Z` is only accepted on the nightly compiler
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
// Note: `rustc_attrs` is a perma-unstable internal feature that is unlikely to change, which is
|
||||||
|
// used as a proxy to check `RUSTC_BOOTSTRAP` versus stability checking logic.
|
||||||
|
#![feature(rustc_attrs)]
|
@ -0,0 +1,18 @@
|
|||||||
|
//@ check-fail
|
||||||
|
fn main() {
|
||||||
|
let x = Box::new(Some(1));
|
||||||
|
|
||||||
|
let test: Option<i32> = x;
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
let x = Box::new(Some(1));
|
||||||
|
let test: Option<i32> = { x as Box<Option<i32>> };
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
|
||||||
|
let x = Box::new(Some(1));
|
||||||
|
let test: Option<i32> = if true { x as Box<Option<i32>> } else { None };
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
|
||||||
|
let x = std::rc::Rc::new(Some(1));
|
||||||
|
let test: Option<i32> = x as std::rc::Rc<Option<i32>>;
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/unboxing-needing-parenthases-issue-132924.rs:5:29
|
||||||
|
|
|
||||||
|
LL | let test: Option<i32> = x;
|
||||||
|
| ----------- ^ expected `Option<i32>`, found `Box<Option<{integer}>>`
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<i32>`
|
||||||
|
found struct `Box<Option<{integer}>>`
|
||||||
|
help: consider unboxing the value
|
||||||
|
|
|
||||||
|
LL | let test: Option<i32> = *x;
|
||||||
|
| +
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/unboxing-needing-parenthases-issue-132924.rs:8:31
|
||||||
|
|
|
||||||
|
LL | let test: Option<i32> = { x as Box<Option<i32>> };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ expected `Option<i32>`, found `Box<Option<i32>>`
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<_>`
|
||||||
|
found struct `Box<Option<_>>`
|
||||||
|
help: consider unboxing the value
|
||||||
|
|
|
||||||
|
LL | let test: Option<i32> = { *(x as Box<Option<i32>>) };
|
||||||
|
| ++ +
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/unboxing-needing-parenthases-issue-132924.rs:12:39
|
||||||
|
|
|
||||||
|
LL | let test: Option<i32> = if true { x as Box<Option<i32>> } else { None };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ expected `Option<i32>`, found `Box<Option<i32>>`
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<_>`
|
||||||
|
found struct `Box<Option<_>>`
|
||||||
|
help: consider unboxing the value
|
||||||
|
|
|
||||||
|
LL | let test: Option<i32> = if true { *(x as Box<Option<i32>>) } else { None };
|
||||||
|
| ++ +
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/unboxing-needing-parenthases-issue-132924.rs:16:29
|
||||||
|
|
|
||||||
|
LL | let test: Option<i32> = x as std::rc::Rc<Option<i32>>;
|
||||||
|
| ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Option<i32>`, found `Rc<Option<i32>>`
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<_>`
|
||||||
|
found struct `Rc<Option<_>>`
|
||||||
|
help: consider dereferencing the type
|
||||||
|
|
|
||||||
|
LL | let test: Option<i32> = *(x as std::rc::Rc<Option<i32>>);
|
||||||
|
| ++ +
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
36
tests/ui/impl-trait/in-trait/refine-captures.rs
Normal file
36
tests/ui/impl-trait/in-trait/refine-captures.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#![feature(precise_capturing_in_traits)]
|
||||||
|
|
||||||
|
trait LifetimeParam<'a> {
|
||||||
|
fn test() -> impl Sized;
|
||||||
|
}
|
||||||
|
// Refining via capturing fewer lifetimes than the trait definition.
|
||||||
|
impl<'a> LifetimeParam<'a> for i32 {
|
||||||
|
fn test() -> impl Sized + use<> {}
|
||||||
|
//~^ WARN impl trait in impl method captures fewer lifetimes than in trait
|
||||||
|
}
|
||||||
|
// If the lifetime is substituted, then we don't refine anything.
|
||||||
|
impl LifetimeParam<'static> for u32 {
|
||||||
|
fn test() -> impl Sized + use<> {}
|
||||||
|
// Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
trait TypeParam<T> {
|
||||||
|
fn test() -> impl Sized;
|
||||||
|
}
|
||||||
|
// Indirectly capturing a lifetime param through a type param substitution.
|
||||||
|
impl<'a> TypeParam<&'a ()> for i32 {
|
||||||
|
fn test() -> impl Sized + use<> {}
|
||||||
|
//~^ WARN impl trait in impl method captures fewer lifetimes than in trait
|
||||||
|
}
|
||||||
|
// Two of them, but only one is captured...
|
||||||
|
impl<'a, 'b> TypeParam<(&'a (), &'b ())> for u32 {
|
||||||
|
fn test() -> impl Sized + use<'b> {}
|
||||||
|
//~^ WARN impl trait in impl method captures fewer lifetimes than in trait
|
||||||
|
}
|
||||||
|
// What if we don't capture a type param? That should be an error otherwise.
|
||||||
|
impl<T> TypeParam<T> for u64 {
|
||||||
|
fn test() -> impl Sized + use<> {}
|
||||||
|
//~^ ERROR `impl Trait` must mention all type parameters in scope in `use<...>`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
52
tests/ui/impl-trait/in-trait/refine-captures.stderr
Normal file
52
tests/ui/impl-trait/in-trait/refine-captures.stderr
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
warning: impl trait in impl method captures fewer lifetimes than in trait
|
||||||
|
--> $DIR/refine-captures.rs:8:31
|
||||||
|
|
|
||||||
|
LL | fn test() -> impl Sized + use<> {}
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
|
||||||
|
= note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
|
||||||
|
= note: `#[warn(refining_impl_trait_internal)]` on by default
|
||||||
|
help: modify the `use<..>` bound to capture the same lifetimes that the trait does
|
||||||
|
|
|
||||||
|
LL | fn test() -> impl Sized + use<'a> {}
|
||||||
|
| ~~~~~~~
|
||||||
|
|
||||||
|
warning: impl trait in impl method captures fewer lifetimes than in trait
|
||||||
|
--> $DIR/refine-captures.rs:22:31
|
||||||
|
|
|
||||||
|
LL | fn test() -> impl Sized + use<> {}
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
|
||||||
|
= note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
|
||||||
|
help: modify the `use<..>` bound to capture the same lifetimes that the trait does
|
||||||
|
|
|
||||||
|
LL | fn test() -> impl Sized + use<'a> {}
|
||||||
|
| ~~~~~~~
|
||||||
|
|
||||||
|
warning: impl trait in impl method captures fewer lifetimes than in trait
|
||||||
|
--> $DIR/refine-captures.rs:27:31
|
||||||
|
|
|
||||||
|
LL | fn test() -> impl Sized + use<'b> {}
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
= note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
|
||||||
|
= note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
|
||||||
|
help: modify the `use<..>` bound to capture the same lifetimes that the trait does
|
||||||
|
|
|
||||||
|
LL | fn test() -> impl Sized + use<'a, 'b> {}
|
||||||
|
| ~~~~~~~~~~~
|
||||||
|
|
||||||
|
error: `impl Trait` must mention all type parameters in scope in `use<...>`
|
||||||
|
--> $DIR/refine-captures.rs:32:18
|
||||||
|
|
|
||||||
|
LL | impl<T> TypeParam<T> for u64 {
|
||||||
|
| - type parameter is implicitly captured by this `impl Trait`
|
||||||
|
LL | fn test() -> impl Sized + use<> {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: currently, all type parameters are required to be mentioned in the precise captures list
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error; 3 warnings emitted
|
||||||
|
|
@ -18,8 +18,8 @@ impl AsMut<Bar> for Bar {
|
|||||||
|
|
||||||
fn foo<T: AsRef<Bar>>(_: T) {}
|
fn foo<T: AsRef<Bar>>(_: T) {}
|
||||||
fn qux<T: AsMut<Bar>>(_: T) {}
|
fn qux<T: AsMut<Bar>>(_: T) {}
|
||||||
fn bat<T: Borrow<T>>(_: T) {}
|
fn bat<T: Borrow<Bar>>(_: T) {}
|
||||||
fn baz<T: BorrowMut<T>>(_: T) {}
|
fn baz<T: BorrowMut<Bar>>(_: T) {}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let bar = Bar;
|
let bar = Bar;
|
||||||
|
@ -18,8 +18,8 @@ impl AsMut<Bar> for Bar {
|
|||||||
|
|
||||||
fn foo<T: AsRef<Bar>>(_: T) {}
|
fn foo<T: AsRef<Bar>>(_: T) {}
|
||||||
fn qux<T: AsMut<Bar>>(_: T) {}
|
fn qux<T: AsMut<Bar>>(_: T) {}
|
||||||
fn bat<T: Borrow<T>>(_: T) {}
|
fn bat<T: Borrow<Bar>>(_: T) {}
|
||||||
fn baz<T: BorrowMut<T>>(_: T) {}
|
fn baz<T: BorrowMut<Bar>>(_: T) {}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let bar = Bar;
|
let bar = Bar;
|
||||||
|
25
tests/ui/moves/region-var-in-moved-ty-issue-133118.rs
Normal file
25
tests/ui/moves/region-var-in-moved-ty-issue-133118.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//! regression test for #133118
|
||||||
|
|
||||||
|
pub trait Alpha {
|
||||||
|
fn y(self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Beta {
|
||||||
|
type Gamma;
|
||||||
|
fn gamma(&self) -> Self::Gamma;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn a<T: Alpha>(_x: T) -> usize {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn x<B>(beta: &B) -> usize
|
||||||
|
where
|
||||||
|
for<'a> &'a B: Beta,
|
||||||
|
for<'a> <&'a B as Beta>::Gamma: Alpha,
|
||||||
|
{
|
||||||
|
let g1 = beta.gamma();
|
||||||
|
a(g1) + a(g1) //~ ERROR use of moved value: `g1` [E0382]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {}
|
21
tests/ui/moves/region-var-in-moved-ty-issue-133118.stderr
Normal file
21
tests/ui/moves/region-var-in-moved-ty-issue-133118.stderr
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
error[E0382]: use of moved value: `g1`
|
||||||
|
--> $DIR/region-var-in-moved-ty-issue-133118.rs:22:15
|
||||||
|
|
|
||||||
|
LL | let g1 = beta.gamma();
|
||||||
|
| -- move occurs because `g1` has type `<&B as Beta>::Gamma`, which does not implement the `Copy` trait
|
||||||
|
LL | a(g1) + a(g1)
|
||||||
|
| -- ^^ value used here after move
|
||||||
|
| |
|
||||||
|
| value moved here
|
||||||
|
|
|
||||||
|
note: consider changing this parameter type in function `a` to borrow instead if owning the value isn't necessary
|
||||||
|
--> $DIR/region-var-in-moved-ty-issue-133118.rs:12:24
|
||||||
|
|
|
||||||
|
LL | pub fn a<T: Alpha>(_x: T) -> usize {
|
||||||
|
| - ^ this parameter takes ownership of the value
|
||||||
|
| |
|
||||||
|
| in this function
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0382`.
|
@ -2,7 +2,12 @@ error: expected item, found keyword `let`
|
|||||||
--> $DIR/suggest-const-for-global-var.rs:1:1
|
--> $DIR/suggest-const-for-global-var.rs:1:1
|
||||||
|
|
|
|
||||||
LL | let X: i32 = 12;
|
LL | let X: i32 = 12;
|
||||||
| ^^^ consider using `const` or `static` instead of `let` for global variables
|
| ^^^
|
||||||
|
| |
|
||||||
|
| `let` cannot be used for global variables
|
||||||
|
| help: consider using `static` or `const` instead of `let`
|
||||||
|
|
|
||||||
|
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
5
tests/ui/parser/suggest-static-for-global-var-mut.rs
Normal file
5
tests/ui/parser/suggest-static-for-global-var-mut.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
let mut _data = vec![1,2,3];
|
||||||
|
//~^ ERROR expected item, found keyword `let`
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
11
tests/ui/parser/suggest-static-for-global-var-mut.stderr
Normal file
11
tests/ui/parser/suggest-static-for-global-var-mut.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error: expected item, found keyword `let`
|
||||||
|
--> $DIR/suggest-static-for-global-var-mut.rs:1:1
|
||||||
|
|
|
||||||
|
LL | let mut _data = vec![1,2,3];
|
||||||
|
| ^^^ `let` cannot be used for global variables
|
||||||
|
|
|
||||||
|
= help: consider using `static` and a `Mutex` instead of `let mut`
|
||||||
|
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
//@ build-fail
|
//@ build-fail
|
||||||
//@ revisions: legacy v0
|
//@ revisions: legacy v0
|
||||||
//@[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
|
//@[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
|
||||||
//@[v0]compile-flags: -C symbol-mangling-version=v0
|
//@[v0]compile-flags: -C symbol-mangling-version=v0
|
||||||
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//@ build-fail
|
//@ build-fail
|
||||||
//@ revisions: legacy v0
|
//@ revisions: legacy v0
|
||||||
//@[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
|
//@[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
|
||||||
//@[v0]compile-flags: -C symbol-mangling-version=v0
|
//@[v0]compile-flags: -C symbol-mangling-version=v0
|
||||||
//@[legacy]normalize-stderr-test: "h[\w]{16}E?\)" -> "<SYMBOL_HASH>)"
|
//@[legacy]normalize-stderr-test: "h[\w]{16}E?\)" -> "<SYMBOL_HASH>)"
|
||||||
|
|
||||||
#![feature(auto_traits, rustc_attrs)]
|
#![feature(auto_traits, rustc_attrs)]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//@ build-fail
|
//@ build-fail
|
||||||
//@ revisions: legacy v0
|
//@ revisions: legacy v0
|
||||||
//@[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
|
//@[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
|
||||||
//@[v0]compile-flags: -C symbol-mangling-version=v0
|
//@[v0]compile-flags: -C symbol-mangling-version=v0
|
||||||
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user