Auto merge of #94134 - matthiaskrgr:rollup-b132kjz, r=matthiaskrgr
Rollup of 10 pull requests Successful merges: - #89892 (Suggest `impl Trait` return type when incorrectly using a generic return type) - #91675 (Add MemTagSanitizer Support) - #92806 (Add more information to `impl Trait` error) - #93497 (Pass `--test` flag through rustdoc to rustc so `#[test]` functions can be scraped) - #93814 (mips64-openwrt-linux-musl: correct soft-foat) - #93847 (kmc-solid: Use the filesystem thread-safety wrapper) - #93877 (asm: Allow the use of r8-r14 as clobbers on Thumb1) - #93892 (Only mark projection as ambiguous if GAT substs are constrained) - #93915 (Implement --check-cfg option (RFC 3013), take 2) - #93953 (Add the `known-bug` test directive, use it, and do some cleanup) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
1882597991
127 changed files with 1593 additions and 577 deletions
|
@ -129,13 +129,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
.operands
|
||||
.iter()
|
||||
.map(|(op, op_sp)| {
|
||||
let lower_reg = |reg| match reg {
|
||||
let lower_reg = |reg, is_clobber| match reg {
|
||||
InlineAsmRegOrRegClass::Reg(s) => {
|
||||
asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
|
||||
asm::InlineAsmReg::parse(
|
||||
asm_arch,
|
||||
&sess.target_features,
|
||||
&sess.target,
|
||||
is_clobber,
|
||||
s,
|
||||
)
|
||||
.unwrap_or_else(|e| {
|
||||
|
@ -162,24 +163,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
let op = match *op {
|
||||
InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
|
||||
reg: lower_reg(reg),
|
||||
reg: lower_reg(reg, false),
|
||||
expr: self.lower_expr_mut(expr),
|
||||
},
|
||||
InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
|
||||
reg: lower_reg(reg),
|
||||
reg: lower_reg(reg, expr.is_none()),
|
||||
late,
|
||||
expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||
},
|
||||
InlineAsmOperand::InOut { reg, late, ref expr } => {
|
||||
hir::InlineAsmOperand::InOut {
|
||||
reg: lower_reg(reg),
|
||||
reg: lower_reg(reg, false),
|
||||
late,
|
||||
expr: self.lower_expr_mut(expr),
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
|
||||
hir::InlineAsmOperand::SplitInOut {
|
||||
reg: lower_reg(reg),
|
||||
reg: lower_reg(reg, false),
|
||||
late,
|
||||
in_expr: self.lower_expr_mut(in_expr),
|
||||
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||
|
|
|
@ -97,7 +97,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let ty = l
|
||||
.ty
|
||||
.as_ref()
|
||||
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
|
||||
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
|
||||
let init = l.kind.init().map(|init| self.lower_expr(init));
|
||||
let hir_id = self.lower_node_id(l.id);
|
||||
let pat = self.lower_pat(&l.pat);
|
||||
|
@ -127,7 +127,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let ty = local
|
||||
.ty
|
||||
.as_ref()
|
||||
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
|
||||
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
|
||||
let span = self.lower_span(local.span);
|
||||
let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
|
||||
let init = self.lower_expr(init);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::{FnDeclKind, ImplTraitPosition};
|
||||
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
|
||||
|
||||
use rustc_ast::attr;
|
||||
|
@ -53,7 +55,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ParamMode::Optional,
|
||||
0,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
ImplTraitContext::disallowed(),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
));
|
||||
let args = self.lower_exprs(args);
|
||||
hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span))
|
||||
|
@ -74,12 +76,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
ExprKind::Cast(ref expr, ref ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
hir::ExprKind::Cast(expr, ty)
|
||||
}
|
||||
ExprKind::Type(ref expr, ref ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
|
||||
let ty =
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
hir::ExprKind::Type(expr, ty)
|
||||
}
|
||||
ExprKind::AddrOf(k, m, ref ohs) => {
|
||||
|
@ -203,7 +207,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
hir::ExprKind::Path(qpath)
|
||||
}
|
||||
|
@ -239,7 +243,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&se.qself,
|
||||
&se.path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
)),
|
||||
self.arena
|
||||
.alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
|
||||
|
@ -538,7 +542,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let output = match ret_ty {
|
||||
Some(ty) => hir::FnRetTy::Return(self.lower_ty(&ty, ImplTraitContext::disallowed())),
|
||||
Some(ty) => hir::FnRetTy::Return(
|
||||
self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)),
|
||||
),
|
||||
None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
|
||||
};
|
||||
|
||||
|
@ -827,7 +833,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
});
|
||||
|
||||
// Lower outside new scope to preserve `is_in_loop_condition`.
|
||||
let fn_decl = self.lower_fn_decl(decl, None, false, None);
|
||||
let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
|
||||
|
||||
hir::ExprKind::Closure(
|
||||
capture_clause,
|
||||
|
@ -919,7 +925,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// We need to lower the declaration outside the new scope, because we
|
||||
// have to conserve the state of being inside a loop condition for the
|
||||
// closure argument types.
|
||||
let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
|
||||
let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
|
||||
|
||||
hir::ExprKind::Closure(
|
||||
capture_clause,
|
||||
|
@ -1064,7 +1070,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
// Destructure like a tuple struct.
|
||||
let tuple_struct_pat =
|
||||
|
@ -1089,7 +1095,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&se.qself,
|
||||
&se.path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
let fields_omitted = match &se.rest {
|
||||
StructRest::Base(e) => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{AnonymousLifetimeMode, LoweringContext, ParamMode};
|
||||
use super::{ImplTraitContext, ImplTraitPosition};
|
||||
use crate::Arena;
|
||||
use crate::{Arena, FnDeclKind};
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
|
@ -246,7 +246,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
AnonymousLifetimeMode::PassThrough,
|
||||
|this, idty| {
|
||||
let ret_id = asyncness.opt_return_id();
|
||||
this.lower_fn_decl(&decl, Some((fn_def_id, idty)), true, ret_id)
|
||||
this.lower_fn_decl(
|
||||
&decl,
|
||||
Some((fn_def_id, idty)),
|
||||
FnDeclKind::Fn,
|
||||
ret_id,
|
||||
)
|
||||
},
|
||||
);
|
||||
let sig = hir::FnSig {
|
||||
|
@ -287,12 +292,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
capturable_lifetimes: &mut FxHashSet::default(),
|
||||
},
|
||||
);
|
||||
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
|
||||
let generics = self.lower_generics(
|
||||
generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
);
|
||||
hir::ItemKind::TyAlias(ty, generics)
|
||||
}
|
||||
ItemKind::TyAlias(box TyAlias { ref generics, ty: None, .. }) => {
|
||||
let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
|
||||
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
|
||||
let generics = self.lower_generics(
|
||||
generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
);
|
||||
hir::ItemKind::TyAlias(ty, generics)
|
||||
}
|
||||
ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
|
||||
|
@ -301,20 +312,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
enum_definition.variants.iter().map(|x| self.lower_variant(x)),
|
||||
),
|
||||
},
|
||||
self.lower_generics(generics, ImplTraitContext::disallowed()),
|
||||
self.lower_generics(
|
||||
generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
),
|
||||
),
|
||||
ItemKind::Struct(ref struct_def, ref generics) => {
|
||||
let struct_def = self.lower_variant_data(hir_id, struct_def);
|
||||
hir::ItemKind::Struct(
|
||||
struct_def,
|
||||
self.lower_generics(generics, ImplTraitContext::disallowed()),
|
||||
self.lower_generics(
|
||||
generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
),
|
||||
)
|
||||
}
|
||||
ItemKind::Union(ref vdata, ref generics) => {
|
||||
let vdata = self.lower_variant_data(hir_id, vdata);
|
||||
hir::ItemKind::Union(
|
||||
vdata,
|
||||
self.lower_generics(generics, ImplTraitContext::disallowed()),
|
||||
self.lower_generics(
|
||||
generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
),
|
||||
)
|
||||
}
|
||||
ItemKind::Impl(box Impl {
|
||||
|
@ -347,10 +367,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
AnonymousLifetimeMode::CreateParameter,
|
||||
|this, _| {
|
||||
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
||||
this.lower_trait_ref(trait_ref, ImplTraitContext::disallowed())
|
||||
this.lower_trait_ref(
|
||||
trait_ref,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
|
||||
)
|
||||
});
|
||||
|
||||
let lowered_ty = this.lower_ty(ty, ImplTraitContext::disallowed());
|
||||
let lowered_ty = this
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
|
||||
(trait_ref, lowered_ty)
|
||||
},
|
||||
|
@ -390,21 +414,33 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ref bounds,
|
||||
ref items,
|
||||
}) => {
|
||||
let bounds = self.lower_param_bounds(bounds, ImplTraitContext::disallowed());
|
||||
let bounds = self.lower_param_bounds(
|
||||
bounds,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
);
|
||||
let items = self
|
||||
.arena
|
||||
.alloc_from_iter(items.iter().map(|item| self.lower_trait_item_ref(item)));
|
||||
hir::ItemKind::Trait(
|
||||
is_auto,
|
||||
self.lower_unsafety(unsafety),
|
||||
self.lower_generics(generics, ImplTraitContext::disallowed()),
|
||||
self.lower_generics(
|
||||
generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
),
|
||||
bounds,
|
||||
items,
|
||||
)
|
||||
}
|
||||
ItemKind::TraitAlias(ref generics, ref bounds) => hir::ItemKind::TraitAlias(
|
||||
self.lower_generics(generics, ImplTraitContext::disallowed()),
|
||||
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
|
||||
self.lower_generics(
|
||||
generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
),
|
||||
self.lower_param_bounds(
|
||||
bounds,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
),
|
||||
ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => {
|
||||
let body = P(self.lower_mac_args(body));
|
||||
|
@ -423,7 +459,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
span: Span,
|
||||
body: Option<&Expr>,
|
||||
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Binding));
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
(ty, self.lower_const_body(span, body))
|
||||
}
|
||||
|
||||
|
@ -667,7 +703,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|this, _| {
|
||||
(
|
||||
// Disallow `impl Trait` in foreign items.
|
||||
this.lower_fn_decl(fdec, None, false, None),
|
||||
this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
|
||||
this.lower_fn_params_to_names(fdec),
|
||||
)
|
||||
},
|
||||
|
@ -676,7 +712,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
|
||||
}
|
||||
ForeignItemKind::Static(ref t, m, _) => {
|
||||
let ty = self.lower_ty(t, ImplTraitContext::disallowed());
|
||||
let ty =
|
||||
self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
hir::ForeignItemKind::Static(ty, m)
|
||||
}
|
||||
ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
|
||||
|
@ -744,11 +781,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
|
||||
ImplTraitContext::disallowed(),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
self.arena.alloc(t)
|
||||
} else {
|
||||
self.lower_ty(&f.ty, ImplTraitContext::disallowed())
|
||||
self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
|
||||
};
|
||||
let hir_id = self.lower_node_id(f.id);
|
||||
self.lower_attrs(hir_id, &f.attrs);
|
||||
|
@ -771,14 +808,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let (generics, kind) = match i.kind {
|
||||
AssocItemKind::Const(_, ref ty, ref default) => {
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
|
||||
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body))
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
|
||||
let names = self.lower_fn_params_to_names(&sig.decl);
|
||||
let (generics, sig) =
|
||||
self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
generics,
|
||||
sig,
|
||||
trait_item_def_id,
|
||||
FnDeclKind::Trait,
|
||||
None,
|
||||
);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
|
||||
|
@ -789,16 +831,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
generics,
|
||||
sig,
|
||||
trait_item_def_id,
|
||||
false,
|
||||
FnDeclKind::Trait,
|
||||
asyncness.opt_return_id(),
|
||||
);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
|
||||
let ty = ty.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed()));
|
||||
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
|
||||
let ty = ty.as_ref().map(|x| {
|
||||
self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
|
||||
});
|
||||
let generics = self.lower_generics(
|
||||
generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
);
|
||||
let kind = hir::TraitItemKind::Type(
|
||||
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
|
||||
self.lower_param_bounds(
|
||||
bounds,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
ty,
|
||||
);
|
||||
|
||||
|
@ -850,7 +900,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let (generics, kind) = match &i.kind {
|
||||
AssocItemKind::Const(_, ty, expr) => {
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
|
||||
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
(
|
||||
hir::Generics::empty(),
|
||||
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
|
||||
|
@ -861,19 +911,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let asyncness = sig.header.asyncness;
|
||||
let body_id =
|
||||
self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref());
|
||||
let impl_trait_return_allow = !self.is_in_trait_impl;
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
generics,
|
||||
sig,
|
||||
impl_item_def_id,
|
||||
impl_trait_return_allow,
|
||||
if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
|
||||
asyncness.opt_return_id(),
|
||||
);
|
||||
|
||||
(generics, hir::ImplItemKind::Fn(sig, body_id))
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAlias { generics, ty, .. }) => {
|
||||
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
|
||||
let generics = self.lower_generics(
|
||||
generics,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
);
|
||||
let kind = match ty {
|
||||
None => {
|
||||
let ty = self.arena.alloc(self.ty(i.span, hir::TyKind::Err));
|
||||
|
@ -1248,7 +1300,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
generics: &Generics,
|
||||
sig: &FnSig,
|
||||
fn_def_id: LocalDefId,
|
||||
impl_trait_return_allow: bool,
|
||||
kind: FnDeclKind,
|
||||
is_async: Option<NodeId>,
|
||||
) -> (hir::Generics<'hir>, hir::FnSig<'hir>) {
|
||||
let header = self.lower_fn_header(sig.header);
|
||||
|
@ -1256,14 +1308,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
generics,
|
||||
fn_def_id,
|
||||
AnonymousLifetimeMode::PassThrough,
|
||||
|this, idty| {
|
||||
this.lower_fn_decl(
|
||||
&sig.decl,
|
||||
Some((fn_def_id, idty)),
|
||||
impl_trait_return_allow,
|
||||
is_async,
|
||||
)
|
||||
},
|
||||
|this, idty| this.lower_fn_decl(&sig.decl, Some((fn_def_id, idty)), kind, is_async),
|
||||
);
|
||||
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
||||
}
|
||||
|
@ -1409,11 +1454,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
span,
|
||||
}) => self.with_in_scope_lifetime_defs(&bound_generic_params, |this| {
|
||||
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||
bound_generic_params: this
|
||||
.lower_generic_params(bound_generic_params, ImplTraitContext::disallowed()),
|
||||
bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()),
|
||||
bound_generic_params: this.lower_generic_params(
|
||||
bound_generic_params,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
),
|
||||
bounded_ty: this.lower_ty(
|
||||
bounded_ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Type),
|
||||
),
|
||||
bounds: this.arena.alloc_from_iter(bounds.iter().map(|bound| {
|
||||
this.lower_param_bound(bound, ImplTraitContext::disallowed())
|
||||
this.lower_param_bound(
|
||||
bound,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
)
|
||||
})),
|
||||
span: this.lower_span(span),
|
||||
})
|
||||
|
@ -1425,13 +1478,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}) => hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
|
||||
span: self.lower_span(span),
|
||||
lifetime: self.lower_lifetime(lifetime),
|
||||
bounds: self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
|
||||
bounds: self.lower_param_bounds(
|
||||
bounds,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
}),
|
||||
WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => {
|
||||
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
||||
hir_id: self.lower_node_id(id),
|
||||
lhs_ty: self.lower_ty(lhs_ty, ImplTraitContext::disallowed()),
|
||||
rhs_ty: self.lower_ty(rhs_ty, ImplTraitContext::disallowed()),
|
||||
lhs_ty: self
|
||||
.lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||
rhs_ty: self
|
||||
.lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||
span: self.lower_span(span),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -256,19 +256,28 @@ enum ImplTraitContext<'b, 'a> {
|
|||
/// Position in which `impl Trait` is disallowed.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
enum ImplTraitPosition {
|
||||
/// Disallowed in `let` / `const` / `static` bindings.
|
||||
Binding,
|
||||
|
||||
/// All other positions.
|
||||
Other,
|
||||
Path,
|
||||
Variable,
|
||||
Type,
|
||||
Trait,
|
||||
AsyncBlock,
|
||||
Bound,
|
||||
Generic,
|
||||
ExternFnParam,
|
||||
ClosureParam,
|
||||
PointerParam,
|
||||
FnTraitParam,
|
||||
TraitParam,
|
||||
ImplParam,
|
||||
ExternFnReturn,
|
||||
ClosureReturn,
|
||||
PointerReturn,
|
||||
FnTraitReturn,
|
||||
TraitReturn,
|
||||
ImplReturn,
|
||||
}
|
||||
|
||||
impl<'a> ImplTraitContext<'_, 'a> {
|
||||
#[inline]
|
||||
fn disallowed() -> Self {
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Other)
|
||||
}
|
||||
|
||||
fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> {
|
||||
use self::ImplTraitContext::*;
|
||||
match self {
|
||||
|
@ -284,6 +293,54 @@ impl<'a> ImplTraitContext<'_, 'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ImplTraitPosition {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let name = match self {
|
||||
ImplTraitPosition::Path => "path",
|
||||
ImplTraitPosition::Variable => "variable binding",
|
||||
ImplTraitPosition::Type => "type",
|
||||
ImplTraitPosition::Trait => "trait",
|
||||
ImplTraitPosition::AsyncBlock => "async block",
|
||||
ImplTraitPosition::Bound => "bound",
|
||||
ImplTraitPosition::Generic => "generic",
|
||||
ImplTraitPosition::ExternFnParam => "`extern fn` param",
|
||||
ImplTraitPosition::ClosureParam => "closure param",
|
||||
ImplTraitPosition::PointerParam => "`fn` pointer param",
|
||||
ImplTraitPosition::FnTraitParam => "`Fn` trait param",
|
||||
ImplTraitPosition::TraitParam => "trait method param",
|
||||
ImplTraitPosition::ImplParam => "`impl` method param",
|
||||
ImplTraitPosition::ExternFnReturn => "`extern fn` return",
|
||||
ImplTraitPosition::ClosureReturn => "closure return",
|
||||
ImplTraitPosition::PointerReturn => "`fn` pointer return",
|
||||
ImplTraitPosition::FnTraitReturn => "`Fn` trait return",
|
||||
ImplTraitPosition::TraitReturn => "trait method return",
|
||||
ImplTraitPosition::ImplReturn => "`impl` method return",
|
||||
};
|
||||
|
||||
write!(f, "{}", name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum FnDeclKind {
|
||||
Fn,
|
||||
Inherent,
|
||||
ExternFn,
|
||||
Closure,
|
||||
Pointer,
|
||||
Trait,
|
||||
Impl,
|
||||
}
|
||||
|
||||
impl FnDeclKind {
|
||||
fn impl_trait_return_allowed(&self) -> bool {
|
||||
match self {
|
||||
FnDeclKind::Fn | FnDeclKind::Inherent => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lower_crate<'a, 'hir>(
|
||||
sess: &'a Session,
|
||||
krate: &'a Crate,
|
||||
|
@ -1232,11 +1289,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
|
||||
generic_params: this.lower_generic_params(
|
||||
&f.generic_params,
|
||||
ImplTraitContext::disallowed(),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
),
|
||||
unsafety: this.lower_unsafety(f.unsafety),
|
||||
abi: this.lower_extern(f.ext),
|
||||
decl: this.lower_fn_decl(&f.decl, None, false, None),
|
||||
decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
|
||||
param_names: this.lower_fn_params_to_names(&f.decl),
|
||||
}))
|
||||
})
|
||||
|
@ -1357,13 +1414,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}),
|
||||
))
|
||||
}
|
||||
ImplTraitContext::Disallowed(_) => {
|
||||
ImplTraitContext::Disallowed(position) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.sess,
|
||||
t.span,
|
||||
E0562,
|
||||
"`impl Trait` not allowed outside of {}",
|
||||
"function and method return types",
|
||||
"`impl Trait` only allowed in function and inherent method return types, not in {}",
|
||||
position
|
||||
);
|
||||
err.emit();
|
||||
hir::TyKind::Err
|
||||
|
@ -1528,16 +1585,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
decl: &FnDecl,
|
||||
mut in_band_ty_params: Option<(LocalDefId, &mut Vec<hir::GenericParam<'hir>>)>,
|
||||
impl_trait_return_allow: bool,
|
||||
kind: FnDeclKind,
|
||||
make_ret_async: Option<NodeId>,
|
||||
) -> &'hir hir::FnDecl<'hir> {
|
||||
debug!(
|
||||
"lower_fn_decl(\
|
||||
fn_decl: {:?}, \
|
||||
in_band_ty_params: {:?}, \
|
||||
impl_trait_return_allow: {}, \
|
||||
kind: {:?}, \
|
||||
make_ret_async: {:?})",
|
||||
decl, in_band_ty_params, impl_trait_return_allow, make_ret_async,
|
||||
decl, in_band_ty_params, kind, make_ret_async,
|
||||
);
|
||||
let lt_mode = if make_ret_async.is_some() {
|
||||
// In `async fn`, argument-position elided lifetimes
|
||||
|
@ -1567,7 +1624,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ImplTraitContext::Universal(ibty, this.current_hir_id_owner),
|
||||
)
|
||||
} else {
|
||||
this.lower_ty_direct(¶m.ty, ImplTraitContext::disallowed())
|
||||
this.lower_ty_direct(
|
||||
¶m.ty,
|
||||
ImplTraitContext::Disallowed(match kind {
|
||||
FnDeclKind::Fn | FnDeclKind::Inherent => {
|
||||
unreachable!("fn should allow in-band lifetimes")
|
||||
}
|
||||
FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam,
|
||||
FnDeclKind::Closure => ImplTraitPosition::ClosureParam,
|
||||
FnDeclKind::Pointer => ImplTraitPosition::PointerParam,
|
||||
FnDeclKind::Trait => ImplTraitPosition::TraitParam,
|
||||
FnDeclKind::Impl => ImplTraitPosition::ImplParam,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}))
|
||||
});
|
||||
|
@ -1582,13 +1651,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
match decl.output {
|
||||
FnRetTy::Ty(ref ty) => {
|
||||
let context = match in_band_ty_params {
|
||||
Some((def_id, _)) if impl_trait_return_allow => {
|
||||
Some((def_id, _)) if kind.impl_trait_return_allowed() => {
|
||||
ImplTraitContext::ReturnPositionOpaqueTy {
|
||||
fn_def_id: def_id,
|
||||
origin: hir::OpaqueTyOrigin::FnReturn(def_id),
|
||||
}
|
||||
}
|
||||
_ => ImplTraitContext::disallowed(),
|
||||
_ => ImplTraitContext::Disallowed(match kind {
|
||||
FnDeclKind::Fn | FnDeclKind::Inherent => {
|
||||
unreachable!("fn should allow in-band lifetimes")
|
||||
}
|
||||
FnDeclKind::ExternFn => ImplTraitPosition::ExternFnReturn,
|
||||
FnDeclKind::Closure => ImplTraitPosition::ClosureReturn,
|
||||
FnDeclKind::Pointer => ImplTraitPosition::PointerReturn,
|
||||
FnDeclKind::Trait => ImplTraitPosition::TraitReturn,
|
||||
FnDeclKind::Impl => ImplTraitPosition::ImplReturn,
|
||||
}),
|
||||
};
|
||||
hir::FnRetTy::Return(self.lower_ty(ty, context))
|
||||
}
|
||||
|
@ -1946,7 +2024,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
GenericParamKind::Type { ref default, .. } => {
|
||||
let kind = hir::GenericParamKind::Type {
|
||||
default: default.as_ref().map(|x| {
|
||||
self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Other))
|
||||
self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
|
||||
}),
|
||||
synthetic: false,
|
||||
};
|
||||
|
@ -1954,9 +2032,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
|
||||
}
|
||||
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
|
||||
let ty = self
|
||||
.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
|
||||
this.lower_ty(&ty, ImplTraitContext::disallowed())
|
||||
let ty =
|
||||
self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
|
||||
this.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
|
||||
});
|
||||
let default = default.as_ref().map(|def| self.lower_anon_const(def));
|
||||
(
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::ImplTraitPosition;
|
||||
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode};
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
|
@ -33,7 +35,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
|
||||
break hir::PatKind::TupleStruct(qpath, pats, ddpos);
|
||||
|
@ -49,7 +51,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
break hir::PatKind::Path(qpath);
|
||||
}
|
||||
|
@ -59,7 +61,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::disallowed(),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
);
|
||||
|
||||
let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::PatField {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::ImplTraitPosition;
|
||||
|
||||
use super::{AnonymousLifetimeMode, ImplTraitContext, LoweringContext, ParamMode};
|
||||
use super::{GenericArgsCtor, ParenthesizedGenericArgs};
|
||||
|
||||
|
@ -184,7 +186,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
param_mode,
|
||||
0,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
ImplTraitContext::disallowed(),
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
)
|
||||
})),
|
||||
span: self.lower_span(p.span),
|
||||
|
@ -392,11 +394,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// we generally don't permit such things (see #51008).
|
||||
self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
|
||||
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
|
||||
let inputs = this.arena.alloc_from_iter(
|
||||
inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())),
|
||||
);
|
||||
let inputs = this.arena.alloc_from_iter(inputs.iter().map(|ty| {
|
||||
this.lower_ty_direct(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam),
|
||||
)
|
||||
}));
|
||||
let output_ty = match output {
|
||||
FnRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()),
|
||||
FnRetTy::Ty(ty) => this
|
||||
.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
|
||||
FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(*span, &[])),
|
||||
};
|
||||
let args = smallvec![GenericArg::Type(this.ty_tup(*inputs_span, inputs))];
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
//! Parsing and validation of builtin attributes
|
||||
|
||||
use rustc_ast::{self as ast, Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::node_id::CRATE_NODE_ID;
|
||||
use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||
use rustc_session::parse::{feature_err, ParseSess};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
|
@ -458,8 +461,30 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
|
|||
true
|
||||
}
|
||||
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
|
||||
let ident = cfg.ident().expect("multi-segment cfg predicate");
|
||||
sess.config.contains(&(ident.name, cfg.value_str()))
|
||||
let name = cfg.ident().expect("multi-segment cfg predicate").name;
|
||||
let value = cfg.value_str();
|
||||
if sess.check_config.names_checked && !sess.check_config.names_valid.contains(&name)
|
||||
{
|
||||
sess.buffer_lint(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
CRATE_NODE_ID,
|
||||
"unexpected `cfg` condition name",
|
||||
);
|
||||
}
|
||||
if let Some(val) = value {
|
||||
if sess.check_config.values_checked.contains(&name)
|
||||
&& !sess.check_config.values_valid.contains(&(name, val))
|
||||
{
|
||||
sess.buffer_lint(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
CRATE_NODE_ID,
|
||||
"unexpected `cfg` condition value",
|
||||
);
|
||||
}
|
||||
}
|
||||
sess.config.contains(&(name, value))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -55,6 +55,19 @@ pub fn sanitize<'ll>(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &
|
|||
if enabled.contains(SanitizerSet::HWADDRESS) {
|
||||
llvm::Attribute::SanitizeHWAddress.apply_llfn(Function, llfn);
|
||||
}
|
||||
if enabled.contains(SanitizerSet::MEMTAG) {
|
||||
// Check to make sure the mte target feature is actually enabled.
|
||||
let sess = cx.tcx.sess;
|
||||
let features = llvm_util::llvm_global_features(sess).join(",");
|
||||
let mte_feature_enabled = features.rfind("+mte");
|
||||
let mte_feature_disabled = features.rfind("-mte");
|
||||
|
||||
if mte_feature_enabled.is_none() || (mte_feature_disabled > mte_feature_enabled) {
|
||||
sess.err("`-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`");
|
||||
}
|
||||
|
||||
llvm::Attribute::SanitizeMemTag.apply_llfn(Function, llfn);
|
||||
}
|
||||
}
|
||||
|
||||
/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
|
||||
|
|
|
@ -190,6 +190,7 @@ pub enum Attribute {
|
|||
StackProtectStrong = 31,
|
||||
StackProtect = 32,
|
||||
NoUndef = 33,
|
||||
SanitizeMemTag = 34,
|
||||
}
|
||||
|
||||
/// LLVMIntPredicate
|
||||
|
|
|
@ -216,10 +216,12 @@ fn run_compiler(
|
|||
}
|
||||
|
||||
let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
|
||||
let check_cfg = interface::parse_check_cfg(matches.opt_strs("check-cfg"));
|
||||
let (odir, ofile) = make_output(&matches);
|
||||
let mut config = interface::Config {
|
||||
opts: sopts,
|
||||
crate_cfg: cfg,
|
||||
crate_check_cfg: check_cfg,
|
||||
input: Input::File(PathBuf::new()),
|
||||
input_path: None,
|
||||
output_file: ofile,
|
||||
|
|
|
@ -263,7 +263,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
|
|||
let index = self.values().push(TypeVariableData { origin });
|
||||
assert_eq!(eq_key.vid.as_u32(), index as u32);
|
||||
|
||||
debug!("new_var(index={:?}, universe={:?}, origin={:?}", eq_key.vid, universe, origin,);
|
||||
debug!("new_var(index={:?}, universe={:?}, origin={:?})", eq_key.vid, universe, origin);
|
||||
|
||||
eq_key.vid
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ pub use crate::passes::BoxedResolver;
|
|||
use crate::util;
|
||||
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::{self as ast, MetaItemKind};
|
||||
use rustc_ast::{self as ast, LitKind, MetaItemKind};
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
|
@ -13,12 +13,13 @@ use rustc_lint::LintStore;
|
|||
use rustc_middle::ty;
|
||||
use rustc_parse::maybe_new_parser_from_source_str;
|
||||
use rustc_query_impl::QueryCtxt;
|
||||
use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
|
||||
use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames};
|
||||
use rustc_session::early_error;
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::{CrateConfig, ParseSess};
|
||||
use rustc_session::{DiagnosticOutput, Session};
|
||||
use rustc_span::source_map::{FileLoader, FileName};
|
||||
use rustc_span::symbol::sym;
|
||||
use std::path::PathBuf;
|
||||
use std::result;
|
||||
|
||||
|
@ -139,6 +140,90 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
|
|||
})
|
||||
}
|
||||
|
||||
/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
|
||||
pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
|
||||
rustc_span::create_default_session_if_not_set_then(move |_| {
|
||||
let mut cfg = CheckCfg::default();
|
||||
|
||||
'specs: for s in specs {
|
||||
let sess = ParseSess::with_silent_emitter(Some(format!(
|
||||
"this error occurred on the command line: `--check-cfg={}`",
|
||||
s
|
||||
)));
|
||||
let filename = FileName::cfg_spec_source_code(&s);
|
||||
|
||||
macro_rules! error {
|
||||
($reason: expr) => {
|
||||
early_error(
|
||||
ErrorOutputType::default(),
|
||||
&format!(
|
||||
concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
|
||||
s
|
||||
),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
|
||||
Ok(mut parser) => match &mut parser.parse_meta_item() {
|
||||
Ok(meta_item) if parser.token == token::Eof => {
|
||||
if let Some(args) = meta_item.meta_item_list() {
|
||||
if meta_item.has_name(sym::names) {
|
||||
cfg.names_checked = true;
|
||||
for arg in args {
|
||||
if arg.is_word() && arg.ident().is_some() {
|
||||
let ident = arg.ident().expect("multi-segment cfg key");
|
||||
cfg.names_valid.insert(ident.name.to_string());
|
||||
} else {
|
||||
error!("`names()` arguments must be simple identifers");
|
||||
}
|
||||
}
|
||||
continue 'specs;
|
||||
} else if meta_item.has_name(sym::values) {
|
||||
if let Some((name, values)) = args.split_first() {
|
||||
if name.is_word() && name.ident().is_some() {
|
||||
let ident = name.ident().expect("multi-segment cfg key");
|
||||
cfg.values_checked.insert(ident.to_string());
|
||||
for val in values {
|
||||
if let Some(LitKind::Str(s, _)) =
|
||||
val.literal().map(|lit| &lit.kind)
|
||||
{
|
||||
cfg.values_valid
|
||||
.insert((ident.to_string(), s.to_string()));
|
||||
} else {
|
||||
error!(
|
||||
"`values()` arguments must be string literals"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
continue 'specs;
|
||||
} else {
|
||||
error!(
|
||||
"`values()` first argument must be a simple identifer"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(..) => {}
|
||||
Err(err) => err.cancel(),
|
||||
},
|
||||
Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()),
|
||||
}
|
||||
|
||||
error!(
|
||||
"expected `names(name1, name2, ... nameN)` or \
|
||||
`values(name, \"value1\", \"value2\", ... \"valueN\")`"
|
||||
);
|
||||
}
|
||||
|
||||
cfg.names_valid.extend(cfg.values_checked.iter().cloned());
|
||||
cfg
|
||||
})
|
||||
}
|
||||
|
||||
/// The compiler configuration
|
||||
pub struct Config {
|
||||
/// Command line options
|
||||
|
@ -146,6 +231,7 @@ pub struct Config {
|
|||
|
||||
/// cfg! configuration in addition to the default ones
|
||||
pub crate_cfg: FxHashSet<(String, Option<String>)>,
|
||||
pub crate_check_cfg: CheckCfg,
|
||||
|
||||
pub input: Input,
|
||||
pub input_path: Option<PathBuf>,
|
||||
|
@ -188,6 +274,7 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R
|
|||
let (mut sess, codegen_backend) = util::create_session(
|
||||
config.opts,
|
||||
config.crate_cfg,
|
||||
config.crate_check_cfg,
|
||||
config.diagnostic_output,
|
||||
config.file_loader,
|
||||
config.input_path.clone(),
|
||||
|
|
|
@ -15,6 +15,7 @@ use rustc_parse::validate_attr;
|
|||
use rustc_query_impl::QueryCtxt;
|
||||
use rustc_resolve::{self, Resolver};
|
||||
use rustc_session as session;
|
||||
use rustc_session::config::CheckCfg;
|
||||
use rustc_session::config::{self, CrateType};
|
||||
use rustc_session::config::{ErrorOutputType, Input, OutputFilenames};
|
||||
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
|
||||
|
@ -65,6 +66,7 @@ pub fn add_configuration(
|
|||
pub fn create_session(
|
||||
sopts: config::Options,
|
||||
cfg: FxHashSet<(String, Option<String>)>,
|
||||
check_cfg: CheckCfg,
|
||||
diagnostic_output: DiagnosticOutput,
|
||||
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
|
||||
input_path: Option<PathBuf>,
|
||||
|
@ -100,7 +102,13 @@ pub fn create_session(
|
|||
|
||||
let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg));
|
||||
add_configuration(&mut cfg, &mut sess, &*codegen_backend);
|
||||
|
||||
let mut check_cfg = config::to_crate_check_config(check_cfg);
|
||||
check_cfg.fill_well_known();
|
||||
check_cfg.fill_actual(&cfg);
|
||||
|
||||
sess.parse_sess.config = cfg;
|
||||
sess.parse_sess.check_config = check_cfg;
|
||||
|
||||
(Lrc::new(sess), Lrc::new(codegen_backend))
|
||||
}
|
||||
|
|
|
@ -2957,6 +2957,43 @@ declare_lint! {
|
|||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unexpected_cfgs` lint detects unexpected conditional compilation conditions.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```text
|
||||
/// rustc --check-cfg 'names()'
|
||||
/// ```
|
||||
///
|
||||
/// ```rust,ignore (needs command line option)
|
||||
/// #[cfg(widnows)]
|
||||
/// fn foo() {}
|
||||
/// ```
|
||||
///
|
||||
/// This will produce:
|
||||
///
|
||||
/// ```text
|
||||
/// warning: unknown condition name used
|
||||
/// --> lint_example.rs:1:7
|
||||
/// |
|
||||
/// 1 | #[cfg(widnows)]
|
||||
/// | ^^^^^^^
|
||||
/// |
|
||||
/// = note: `#[warn(unexpected_cfgs)]` on by default
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// This lint is only active when a `--check-cfg='names(...)'` option has been passed
|
||||
/// to the compiler and triggers whenever an unknown condition name or value is used.
|
||||
/// The known condition include names or values passed in `--check-cfg`, `--cfg`, and some
|
||||
/// well-knows names and values built into the compiler.
|
||||
pub UNEXPECTED_CFGS,
|
||||
Warn,
|
||||
"detects unexpected names and values in `#[cfg]` conditions",
|
||||
}
|
||||
|
||||
declare_lint_pass! {
|
||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||
/// that are used by other parts of the compiler.
|
||||
|
@ -3055,6 +3092,7 @@ declare_lint_pass! {
|
|||
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
|
||||
DUPLICATE_MACRO_ATTRIBUTES,
|
||||
SUSPICIOUS_AUTO_TRAIT_IMPLS,
|
||||
UNEXPECTED_CFGS,
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ enum LLVMRustAttribute {
|
|||
StackProtectStrong = 31,
|
||||
StackProtect = 32,
|
||||
NoUndef = 33,
|
||||
SanitizeMemTag = 34,
|
||||
};
|
||||
|
||||
typedef struct OpaqueRustString *RustStringRef;
|
||||
|
|
|
@ -226,6 +226,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
|
|||
return Attribute::StackProtect;
|
||||
case NoUndef:
|
||||
return Attribute::NoUndef;
|
||||
case SanitizeMemTag:
|
||||
return Attribute::SanitizeMemTag;
|
||||
}
|
||||
report_fatal_error("bad AttributeKind");
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@ use crate::infer::canonical::Canonical;
|
|||
use crate::ty::fold::ValidateBoundVars;
|
||||
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
|
||||
use crate::ty::InferTy::{self, *};
|
||||
use crate::ty::{self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable};
|
||||
use crate::ty::{
|
||||
self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitor,
|
||||
};
|
||||
use crate::ty::{DelaySpanBugEmitted, List, ParamEnv};
|
||||
use polonius_engine::Atom;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
|
@ -24,7 +26,7 @@ use std::borrow::Cow;
|
|||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Deref, Range};
|
||||
use std::ops::{ControlFlow, Deref, Range};
|
||||
use ty::util::IntTypeExt;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
|
@ -2072,6 +2074,24 @@ impl<'tcx> Ty<'tcx> {
|
|||
!matches!(self.kind(), Param(_) | Infer(_) | Error(_))
|
||||
}
|
||||
|
||||
/// Checks whether a type recursively contains another type
|
||||
///
|
||||
/// Example: `Option<()>` contains `()`
|
||||
pub fn contains(self, other: Ty<'tcx>) -> bool {
|
||||
struct ContainsTyVisitor<'tcx>(Ty<'tcx>);
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for ContainsTyVisitor<'tcx> {
|
||||
type BreakTy = ();
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if self.0 == t { ControlFlow::BREAK } else { t.super_visit_with(self) }
|
||||
}
|
||||
}
|
||||
|
||||
let cf = self.visit_with(&mut ContainsTyVisitor(other));
|
||||
cf.is_break()
|
||||
}
|
||||
|
||||
/// Returns the type and mutability of `*ty`.
|
||||
///
|
||||
/// The parameter `explicit` indicates if this is an *explicit* dereference.
|
||||
|
|
|
@ -16,7 +16,7 @@ use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, Tar
|
|||
|
||||
use rustc_serialize::json;
|
||||
|
||||
use crate::parse::CrateConfig;
|
||||
use crate::parse::{CrateCheckConfig, CrateConfig};
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
|
||||
use rustc_span::source_map::{FileName, FilePathMapping};
|
||||
|
@ -936,6 +936,7 @@ pub const fn default_lib_output() -> CrateType {
|
|||
}
|
||||
|
||||
fn default_configuration(sess: &Session) -> CrateConfig {
|
||||
// NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
|
||||
let end = &sess.target.endian;
|
||||
let arch = &sess.target.arch;
|
||||
let wordsz = sess.target.pointer_width.to_string();
|
||||
|
@ -1020,6 +1021,91 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig
|
|||
cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
|
||||
}
|
||||
|
||||
/// The parsed `--check-cfg` options
|
||||
pub struct CheckCfg<T = String> {
|
||||
/// Set if `names()` checking is enabled
|
||||
pub names_checked: bool,
|
||||
/// The union of all `names()`
|
||||
pub names_valid: FxHashSet<T>,
|
||||
/// The set of names for which `values()` was used
|
||||
pub values_checked: FxHashSet<T>,
|
||||
/// The set of all (name, value) pairs passed in `values()`
|
||||
pub values_valid: FxHashSet<(T, T)>,
|
||||
}
|
||||
|
||||
impl<T> Default for CheckCfg<T> {
|
||||
fn default() -> Self {
|
||||
CheckCfg {
|
||||
names_checked: false,
|
||||
names_valid: FxHashSet::default(),
|
||||
values_checked: FxHashSet::default(),
|
||||
values_valid: FxHashSet::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> CheckCfg<T> {
|
||||
fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
|
||||
CheckCfg {
|
||||
names_checked: self.names_checked,
|
||||
names_valid: self.names_valid.iter().map(|a| f(a)).collect(),
|
||||
values_checked: self.values_checked.iter().map(|a| f(a)).collect(),
|
||||
values_valid: self.values_valid.iter().map(|(a, b)| (f(a), f(b))).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the crate `--check-cfg` options from `String` to `Symbol`.
|
||||
/// `rustc_interface::interface::Config` accepts this in the compiler configuration,
|
||||
/// but the symbol interner is not yet set up then, so we must convert it later.
|
||||
pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
|
||||
cfg.map_data(|s| Symbol::intern(s))
|
||||
}
|
||||
|
||||
impl CrateCheckConfig {
|
||||
/// Fills a `CrateCheckConfig` with well-known configuration names.
|
||||
pub fn fill_well_known(&mut self) {
|
||||
// NOTE: This should be kept in sync with `default_configuration`
|
||||
const WELL_KNOWN_NAMES: &[Symbol] = &[
|
||||
sym::unix,
|
||||
sym::windows,
|
||||
sym::target_os,
|
||||
sym::target_family,
|
||||
sym::target_arch,
|
||||
sym::target_endian,
|
||||
sym::target_pointer_width,
|
||||
sym::target_env,
|
||||
sym::target_abi,
|
||||
sym::target_vendor,
|
||||
sym::target_thread_local,
|
||||
sym::target_has_atomic_load_store,
|
||||
sym::target_has_atomic,
|
||||
sym::target_has_atomic_equal_alignment,
|
||||
sym::panic,
|
||||
sym::sanitize,
|
||||
sym::debug_assertions,
|
||||
sym::proc_macro,
|
||||
sym::test,
|
||||
sym::doc,
|
||||
sym::doctest,
|
||||
sym::feature,
|
||||
];
|
||||
for &name in WELL_KNOWN_NAMES {
|
||||
self.names_valid.insert(name);
|
||||
}
|
||||
}
|
||||
|
||||
/// Fills a `CrateCheckConfig` with configuration names and values that are actually active.
|
||||
pub fn fill_actual(&mut self, cfg: &CrateConfig) {
|
||||
for &(k, v) in cfg {
|
||||
self.names_valid.insert(k);
|
||||
if let Some(v) = v {
|
||||
self.values_valid.insert((k, v));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
|
||||
// Combine the configuration requested by the session (command line) with
|
||||
// some default and generated configuration items.
|
||||
|
@ -1163,6 +1249,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
|
|||
vec![
|
||||
opt::flag_s("h", "help", "Display this message"),
|
||||
opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
|
||||
opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
|
||||
opt::multi_s(
|
||||
"L",
|
||||
"",
|
||||
|
|
|
@ -376,7 +376,7 @@ mod desc {
|
|||
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
|
||||
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
|
||||
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
|
||||
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory` or `thread`";
|
||||
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, or `thread`";
|
||||
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
|
||||
pub const parse_cfguard: &str =
|
||||
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
|
||||
|
@ -639,6 +639,7 @@ mod parse {
|
|||
"cfi" => SanitizerSet::CFI,
|
||||
"leak" => SanitizerSet::LEAK,
|
||||
"memory" => SanitizerSet::MEMORY,
|
||||
"memtag" => SanitizerSet::MEMTAG,
|
||||
"thread" => SanitizerSet::THREAD,
|
||||
"hwaddress" => SanitizerSet::HWADDRESS,
|
||||
_ => return false,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Contains `ParseSess` which holds state living beyond what one `Parser` might.
|
||||
//! It also serves as an input to the parser itself.
|
||||
|
||||
use crate::config::CheckCfg;
|
||||
use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId};
|
||||
use rustc_ast::node_id::NodeId;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
@ -18,6 +19,7 @@ use std::str;
|
|||
/// The set of keys (and, optionally, values) that define the compilation
|
||||
/// environment of the crate, used to drive conditional compilation.
|
||||
pub type CrateConfig = FxHashSet<(Symbol, Option<Symbol>)>;
|
||||
pub type CrateCheckConfig = CheckCfg<Symbol>;
|
||||
|
||||
/// Collected spans during parsing for places where a certain feature was
|
||||
/// used and should be feature gated accordingly in `check_crate`.
|
||||
|
@ -117,6 +119,7 @@ pub struct ParseSess {
|
|||
pub span_diagnostic: Handler,
|
||||
pub unstable_features: UnstableFeatures,
|
||||
pub config: CrateConfig,
|
||||
pub check_config: CrateCheckConfig,
|
||||
pub edition: Edition,
|
||||
pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>,
|
||||
/// Places where raw identifiers were used. This is used to avoid complaining about idents
|
||||
|
@ -162,6 +165,7 @@ impl ParseSess {
|
|||
span_diagnostic: handler,
|
||||
unstable_features: UnstableFeatures::from_environment(None),
|
||||
config: FxHashSet::default(),
|
||||
check_config: CrateCheckConfig::default(),
|
||||
edition: ExpnId::root().expn_data().edition,
|
||||
missing_fragment_specifiers: Default::default(),
|
||||
raw_identifier_spans: Lock::new(Vec::new()),
|
||||
|
|
|
@ -876,6 +876,7 @@ symbols! {
|
|||
mem_zeroed,
|
||||
member_constraints,
|
||||
memory,
|
||||
memtag,
|
||||
message,
|
||||
meta,
|
||||
metadata_type,
|
||||
|
@ -910,6 +911,7 @@ symbols! {
|
|||
naked,
|
||||
naked_functions,
|
||||
name,
|
||||
names,
|
||||
native_link_modifiers,
|
||||
native_link_modifiers_as_needed,
|
||||
native_link_modifiers_bundle,
|
||||
|
@ -1481,6 +1483,7 @@ symbols! {
|
|||
va_list,
|
||||
va_start,
|
||||
val,
|
||||
values,
|
||||
var,
|
||||
variant_count,
|
||||
vec,
|
||||
|
|
|
@ -77,6 +77,7 @@ pub fn reserved_x18(
|
|||
_arch: InlineAsmArch,
|
||||
_target_features: &FxHashSet<Symbol>,
|
||||
target: &Target,
|
||||
_is_clobber: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
if target.os == "android"
|
||||
|| target.is_like_fuchsia
|
||||
|
|
|
@ -66,10 +66,13 @@ fn frame_pointer_is_r7(target_features: &FxHashSet<Symbol>, target: &Target) ->
|
|||
}
|
||||
|
||||
fn frame_pointer_r11(
|
||||
_arch: InlineAsmArch,
|
||||
arch: InlineAsmArch,
|
||||
target_features: &FxHashSet<Symbol>,
|
||||
target: &Target,
|
||||
is_clobber: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
not_thumb1(arch, target_features, target, is_clobber)?;
|
||||
|
||||
if !frame_pointer_is_r7(target_features, target) {
|
||||
Err("the frame pointer (r11) cannot be used as an operand for inline asm")
|
||||
} else {
|
||||
|
@ -81,6 +84,7 @@ fn frame_pointer_r7(
|
|||
_arch: InlineAsmArch,
|
||||
target_features: &FxHashSet<Symbol>,
|
||||
target: &Target,
|
||||
_is_clobber: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
if frame_pointer_is_r7(target_features, target) {
|
||||
Err("the frame pointer (r7) cannot be used as an operand for inline asm")
|
||||
|
@ -93,9 +97,13 @@ fn not_thumb1(
|
|||
_arch: InlineAsmArch,
|
||||
target_features: &FxHashSet<Symbol>,
|
||||
_target: &Target,
|
||||
is_clobber: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
if target_features.contains(&sym::thumb_mode) && !target_features.contains(&sym::thumb2) {
|
||||
Err("high registers (r8+) cannot be used in Thumb-1 code")
|
||||
if !is_clobber
|
||||
&& target_features.contains(&sym::thumb_mode)
|
||||
&& !target_features.contains(&sym::thumb2)
|
||||
{
|
||||
Err("high registers (r8+) can only be used as clobbers in Thumb-1 code")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -105,8 +113,9 @@ fn reserved_r9(
|
|||
arch: InlineAsmArch,
|
||||
target_features: &FxHashSet<Symbol>,
|
||||
target: &Target,
|
||||
is_clobber: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
not_thumb1(arch, target_features, target)?;
|
||||
not_thumb1(arch, target_features, target, is_clobber)?;
|
||||
|
||||
// We detect this using the reserved-r9 feature instead of using the target
|
||||
// because the relocation model can be changed with compiler options.
|
||||
|
|
|
@ -47,6 +47,7 @@ fn only_alu32(
|
|||
_arch: InlineAsmArch,
|
||||
target_features: &FxHashSet<Symbol>,
|
||||
_target: &Target,
|
||||
_is_clobber: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
if !target_features.contains(&sym::alu32) {
|
||||
Err("register can't be used without the `alu32` target feature")
|
||||
|
|
|
@ -83,12 +83,13 @@ macro_rules! def_regs {
|
|||
_arch: super::InlineAsmArch,
|
||||
_target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
|
||||
_target: &crate::spec::Target,
|
||||
_is_clobber: bool,
|
||||
name: &str,
|
||||
) -> Result<Self, &'static str> {
|
||||
match name {
|
||||
$(
|
||||
$($alias)|* | $reg_name => {
|
||||
$($filter(_arch, _target_features, _target)?;)?
|
||||
$($filter(_arch, _target_features, _target, _is_clobber)?;)?
|
||||
Ok(Self::$reg)
|
||||
}
|
||||
)*
|
||||
|
@ -112,7 +113,7 @@ macro_rules! def_regs {
|
|||
#[allow(unused_imports)]
|
||||
use super::{InlineAsmReg, InlineAsmRegClass};
|
||||
$(
|
||||
if $($filter(_arch, _target_features, _target).is_ok() &&)? true {
|
||||
if $($filter(_arch, _target_features, _target, false).is_ok() &&)? true {
|
||||
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
|
||||
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
|
||||
}
|
||||
|
@ -298,6 +299,7 @@ impl InlineAsmReg {
|
|||
arch: InlineAsmArch,
|
||||
target_features: &FxHashSet<Symbol>,
|
||||
target: &Target,
|
||||
is_clobber: bool,
|
||||
name: Symbol,
|
||||
) -> Result<Self, &'static str> {
|
||||
// FIXME: use direct symbol comparison for register names
|
||||
|
@ -305,47 +307,79 @@ impl InlineAsmReg {
|
|||
let name = name.as_str();
|
||||
Ok(match arch {
|
||||
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
|
||||
Self::X86(X86InlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
Self::X86(X86InlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
|
||||
}
|
||||
InlineAsmArch::Arm => {
|
||||
Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
}
|
||||
InlineAsmArch::AArch64 => {
|
||||
Self::AArch64(AArch64InlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
}
|
||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
|
||||
Self::RiscV(RiscVInlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
}
|
||||
InlineAsmArch::Nvptx64 => {
|
||||
Self::Nvptx(NvptxInlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
}
|
||||
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
|
||||
Self::PowerPC(PowerPCInlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
}
|
||||
InlineAsmArch::Hexagon => {
|
||||
Self::Hexagon(HexagonInlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
}
|
||||
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
|
||||
Self::Mips(MipsInlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
}
|
||||
InlineAsmArch::S390x => {
|
||||
Self::S390x(S390xInlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
}
|
||||
InlineAsmArch::SpirV => {
|
||||
Self::SpirV(SpirVInlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
}
|
||||
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
|
||||
Self::Wasm(WasmInlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
|
||||
}
|
||||
InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse(
|
||||
arch,
|
||||
target_features,
|
||||
target,
|
||||
is_clobber,
|
||||
name,
|
||||
)?),
|
||||
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => Self::RiscV(
|
||||
RiscVInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?,
|
||||
),
|
||||
InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse(
|
||||
arch,
|
||||
target_features,
|
||||
target,
|
||||
is_clobber,
|
||||
name,
|
||||
)?),
|
||||
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => Self::PowerPC(
|
||||
PowerPCInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?,
|
||||
),
|
||||
InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(
|
||||
arch,
|
||||
target_features,
|
||||
target,
|
||||
is_clobber,
|
||||
name,
|
||||
)?),
|
||||
InlineAsmArch::Mips | InlineAsmArch::Mips64 => Self::Mips(MipsInlineAsmReg::parse(
|
||||
arch,
|
||||
target_features,
|
||||
target,
|
||||
is_clobber,
|
||||
name,
|
||||
)?),
|
||||
InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(
|
||||
arch,
|
||||
target_features,
|
||||
target,
|
||||
is_clobber,
|
||||
name,
|
||||
)?),
|
||||
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(
|
||||
arch,
|
||||
target_features,
|
||||
target,
|
||||
is_clobber,
|
||||
name,
|
||||
)?),
|
||||
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => Self::Wasm(WasmInlineAsmReg::parse(
|
||||
arch,
|
||||
target_features,
|
||||
target,
|
||||
is_clobber,
|
||||
name,
|
||||
)?),
|
||||
InlineAsmArch::Bpf => {
|
||||
Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
|
||||
}
|
||||
InlineAsmArch::Avr => {
|
||||
Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
}
|
||||
InlineAsmArch::Msp430 => {
|
||||
Self::Msp430(Msp430InlineAsmReg::parse(arch, target_features, target, name)?)
|
||||
Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?)
|
||||
}
|
||||
InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse(
|
||||
arch,
|
||||
target_features,
|
||||
target,
|
||||
is_clobber,
|
||||
name,
|
||||
)?),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -844,7 +878,7 @@ impl InlineAsmClobberAbi {
|
|||
},
|
||||
InlineAsmArch::AArch64 => match name {
|
||||
"C" | "system" | "efiapi" => {
|
||||
Ok(if aarch64::reserved_x18(arch, target_features, target).is_err() {
|
||||
Ok(if aarch64::reserved_x18(arch, target_features, target, true).is_err() {
|
||||
InlineAsmClobberAbi::AArch64NoX18
|
||||
} else {
|
||||
InlineAsmClobberAbi::AArch64
|
||||
|
|
|
@ -56,6 +56,7 @@ fn not_e(
|
|||
_arch: InlineAsmArch,
|
||||
target_features: &FxHashSet<Symbol>,
|
||||
_target: &Target,
|
||||
_is_clobber: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
if target_features.contains(&sym::e) {
|
||||
Err("register can't be used with the `e` target feature")
|
||||
|
|
|
@ -141,6 +141,7 @@ fn x86_64_only(
|
|||
arch: InlineAsmArch,
|
||||
_target_features: &FxHashSet<Symbol>,
|
||||
_target: &Target,
|
||||
_is_clobber: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
match arch {
|
||||
InlineAsmArch::X86 => Err("register is only available on x86_64"),
|
||||
|
@ -153,6 +154,7 @@ fn high_byte(
|
|||
arch: InlineAsmArch,
|
||||
_target_features: &FxHashSet<Symbol>,
|
||||
_target: &Target,
|
||||
_is_clobber: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
match arch {
|
||||
InlineAsmArch::X86_64 => Err("high byte registers cannot be used as an operand on x86_64"),
|
||||
|
@ -164,6 +166,7 @@ fn rbx_reserved(
|
|||
arch: InlineAsmArch,
|
||||
_target_features: &FxHashSet<Symbol>,
|
||||
_target: &Target,
|
||||
_is_clobber: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
match arch {
|
||||
InlineAsmArch::X86 => Ok(()),
|
||||
|
@ -178,6 +181,7 @@ fn esi_reserved(
|
|||
arch: InlineAsmArch,
|
||||
_target_features: &FxHashSet<Symbol>,
|
||||
_target: &Target,
|
||||
_is_clobber: bool,
|
||||
) -> Result<(), &'static str> {
|
||||
match arch {
|
||||
InlineAsmArch::X86 => {
|
||||
|
|
|
@ -14,7 +14,9 @@ pub fn target() -> Target {
|
|||
// As documented in https://developer.android.com/ndk/guides/cpu-features.html
|
||||
// the neon (ASIMD) and FP must exist on all android aarch64 targets.
|
||||
features: "+neon,+fp-armv8".to_string(),
|
||||
supported_sanitizers: SanitizerSet::CFI | SanitizerSet::HWADDRESS,
|
||||
supported_sanitizers: SanitizerSet::CFI
|
||||
| SanitizerSet::HWADDRESS
|
||||
| SanitizerSet::MEMTAG,
|
||||
..super::android_base::opts()
|
||||
},
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ pub fn target() -> Target {
|
|||
| SanitizerSet::CFI
|
||||
| SanitizerSet::LEAK
|
||||
| SanitizerSet::MEMORY
|
||||
| SanitizerSet::MEMTAG
|
||||
| SanitizerSet::THREAD
|
||||
| SanitizerSet::HWADDRESS,
|
||||
..super::linux_gnu_base::opts()
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::spec::{Target, TargetOptions};
|
|||
pub fn target() -> Target {
|
||||
let mut base = super::linux_musl_base::opts();
|
||||
base.cpu = "mips64r2".to_string();
|
||||
base.features = "+mips64r2".to_string();
|
||||
base.features = "+mips64r2,+soft-float".to_string();
|
||||
base.max_atomic_width = Some(64);
|
||||
base.crt_static_default = false;
|
||||
|
||||
|
|
|
@ -606,6 +606,7 @@ bitflags::bitflags! {
|
|||
const THREAD = 1 << 3;
|
||||
const HWADDRESS = 1 << 4;
|
||||
const CFI = 1 << 5;
|
||||
const MEMTAG = 1 << 6;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -619,6 +620,7 @@ impl SanitizerSet {
|
|||
SanitizerSet::CFI => "cfi",
|
||||
SanitizerSet::LEAK => "leak",
|
||||
SanitizerSet::MEMORY => "memory",
|
||||
SanitizerSet::MEMTAG => "memtag",
|
||||
SanitizerSet::THREAD => "thread",
|
||||
SanitizerSet::HWADDRESS => "hwaddress",
|
||||
_ => return None,
|
||||
|
@ -652,6 +654,7 @@ impl IntoIterator for SanitizerSet {
|
|||
SanitizerSet::CFI,
|
||||
SanitizerSet::LEAK,
|
||||
SanitizerSet::MEMORY,
|
||||
SanitizerSet::MEMTAG,
|
||||
SanitizerSet::THREAD,
|
||||
SanitizerSet::HWADDRESS,
|
||||
]
|
||||
|
@ -1883,6 +1886,7 @@ impl Target {
|
|||
Some("cfi") => SanitizerSet::CFI,
|
||||
Some("leak") => SanitizerSet::LEAK,
|
||||
Some("memory") => SanitizerSet::MEMORY,
|
||||
Some("memtag") => SanitizerSet::MEMTAG,
|
||||
Some("thread") => SanitizerSet::THREAD,
|
||||
Some("hwaddress") => SanitizerSet::HWADDRESS,
|
||||
Some(s) => return Err(format!("unknown sanitizer {}", s)),
|
||||
|
|
|
@ -19,6 +19,7 @@ use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
|
|||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||
use crate::traits::error_reporting::InferCtxtExt as _;
|
||||
use crate::traits::select::ProjectionMatchesProjection;
|
||||
use rustc_data_structures::sso::SsoHashSet;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::ErrorReported;
|
||||
|
@ -1075,16 +1076,6 @@ fn project<'cx, 'tcx>(
|
|||
return Ok(Projected::Progress(Progress::error(selcx.tcx())));
|
||||
}
|
||||
|
||||
// If the obligation contains any inference types or consts in associated
|
||||
// type substs, then we don't assemble any candidates.
|
||||
// This isn't really correct, but otherwise we can end up in a case where
|
||||
// we constrain inference variables by selecting a single predicate, when
|
||||
// we need to stay general. See issue #91762.
|
||||
let (_, predicate_own_substs) = obligation.predicate.trait_ref_and_own_substs(selcx.tcx());
|
||||
if predicate_own_substs.iter().any(|g| g.has_infer_types_or_consts()) {
|
||||
return Err(ProjectionError::TooManyCandidates);
|
||||
}
|
||||
|
||||
let mut candidates = ProjectionCandidateSet::None;
|
||||
|
||||
// Make sure that the following procedures are kept in order. ParamEnv
|
||||
|
@ -1182,7 +1173,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
|||
ProjectionCandidate::TraitDef,
|
||||
bounds.iter(),
|
||||
true,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// In the case of a trait object like
|
||||
|
@ -1247,28 +1238,35 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
|||
let bound_predicate = predicate.kind();
|
||||
if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() {
|
||||
let data = bound_predicate.rebind(data);
|
||||
let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id;
|
||||
if data.projection_def_id() != obligation.predicate.item_def_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_match = same_def_id
|
||||
&& infcx.probe(|_| {
|
||||
selcx.match_projection_projections(
|
||||
obligation,
|
||||
data,
|
||||
potentially_unnormalized_candidates,
|
||||
)
|
||||
});
|
||||
let is_match = infcx.probe(|_| {
|
||||
selcx.match_projection_projections(
|
||||
obligation,
|
||||
data,
|
||||
potentially_unnormalized_candidates,
|
||||
)
|
||||
});
|
||||
|
||||
if is_match {
|
||||
candidate_set.push_candidate(ctor(data));
|
||||
match is_match {
|
||||
ProjectionMatchesProjection::Yes => {
|
||||
candidate_set.push_candidate(ctor(data));
|
||||
|
||||
if potentially_unnormalized_candidates
|
||||
&& !obligation.predicate.has_infer_types_or_consts()
|
||||
{
|
||||
// HACK: Pick the first trait def candidate for a fully
|
||||
// inferred predicate. This is to allow duplicates that
|
||||
// differ only in normalization.
|
||||
return;
|
||||
if potentially_unnormalized_candidates
|
||||
&& !obligation.predicate.has_infer_types_or_consts()
|
||||
{
|
||||
// HACK: Pick the first trait def candidate for a fully
|
||||
// inferred predicate. This is to allow duplicates that
|
||||
// differ only in normalization.
|
||||
return;
|
||||
}
|
||||
}
|
||||
ProjectionMatchesProjection::Ambiguous => {
|
||||
candidate_set.mark_ambiguous();
|
||||
}
|
||||
ProjectionMatchesProjection::No => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1494,12 +1494,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Return `Yes` if the obligation's predicate type applies to the env_predicate, and
|
||||
/// `No` if it does not. Return `Ambiguous` in the case that the projection type is a GAT,
|
||||
/// and applying this env_predicate constrains any of the obligation's GAT substitutions.
|
||||
///
|
||||
/// This behavior is a somewhat of a hack to prevent overconstraining inference variables
|
||||
/// in cases like #91762.
|
||||
pub(super) fn match_projection_projections(
|
||||
&mut self,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
env_predicate: PolyProjectionPredicate<'tcx>,
|
||||
potentially_unnormalized_candidates: bool,
|
||||
) -> bool {
|
||||
) -> ProjectionMatchesProjection {
|
||||
let mut nested_obligations = Vec::new();
|
||||
let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
|
@ -1521,7 +1527,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
infer_predicate.projection_ty
|
||||
};
|
||||
|
||||
self.infcx
|
||||
let is_match = self
|
||||
.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(obligation.predicate, infer_projection)
|
||||
.map_or(false, |InferOk { obligations, value: () }| {
|
||||
|
@ -1530,7 +1537,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
nested_obligations.into_iter().chain(obligations),
|
||||
)
|
||||
.map_or(false, |res| res.may_apply())
|
||||
})
|
||||
});
|
||||
|
||||
if is_match {
|
||||
let generics = self.tcx().generics_of(obligation.predicate.item_def_id);
|
||||
// FIXME(generic-associated-types): Addresses aggressive inference in #92917.
|
||||
// If this type is a GAT, and of the GAT substs resolve to something new,
|
||||
// that means that we must have newly inferred something about the GAT.
|
||||
// We should give up in that case.
|
||||
if !generics.params.is_empty()
|
||||
&& obligation.predicate.substs[generics.parent_count..]
|
||||
.iter()
|
||||
.any(|&p| p.has_infer_types_or_consts() && self.infcx.shallow_resolve(p) != p)
|
||||
{
|
||||
ProjectionMatchesProjection::Ambiguous
|
||||
} else {
|
||||
ProjectionMatchesProjection::Yes
|
||||
}
|
||||
} else {
|
||||
ProjectionMatchesProjection::No
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2709,3 +2735,9 @@ impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> {
|
|||
write!(f, "TraitObligationStack({:?})", self.obligation)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ProjectionMatchesProjection {
|
||||
Yes,
|
||||
Ambiguous,
|
||||
No,
|
||||
}
|
||||
|
|
|
@ -8,8 +8,12 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{Expr, ExprKind, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind};
|
||||
use rustc_hir::{
|
||||
Expr, ExprKind, GenericBound, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind,
|
||||
WherePredicate,
|
||||
};
|
||||
use rustc_infer::infer::{self, TyCtxtInferExt};
|
||||
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, Binder, Ty};
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
|
@ -559,6 +563,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let ty = self.tcx.erase_late_bound_regions(ty);
|
||||
if self.can_coerce(expected, ty) {
|
||||
err.span_label(sp, format!("expected `{}` because of return type", expected));
|
||||
self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
|
||||
return true;
|
||||
}
|
||||
false
|
||||
|
@ -566,6 +571,115 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// check whether the return type is a generic type with a trait bound
|
||||
/// only suggest this if the generic param is not present in the arguments
|
||||
/// if this is true, hint them towards changing the return type to `impl Trait`
|
||||
/// ```
|
||||
/// fn cant_name_it<T: Fn() -> u32>() -> T {
|
||||
/// || 3
|
||||
/// }
|
||||
/// ```
|
||||
fn try_suggest_return_impl_trait(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
fn_id: hir::HirId,
|
||||
) {
|
||||
// Only apply the suggestion if:
|
||||
// - the return type is a generic parameter
|
||||
// - the generic param is not used as a fn param
|
||||
// - the generic param has at least one bound
|
||||
// - the generic param doesn't appear in any other bounds where it's not the Self type
|
||||
// Suggest:
|
||||
// - Changing the return type to be `impl <all bounds>`
|
||||
|
||||
debug!("try_suggest_return_impl_trait, expected = {:?}, found = {:?}", expected, found);
|
||||
|
||||
let ty::Param(expected_ty_as_param) = expected.kind() else { return };
|
||||
|
||||
let fn_node = self.tcx.hir().find(fn_id);
|
||||
|
||||
let Some(hir::Node::Item(hir::Item {
|
||||
kind:
|
||||
hir::ItemKind::Fn(
|
||||
hir::FnSig { decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. }, .. },
|
||||
hir::Generics { params, where_clause, .. },
|
||||
_body_id,
|
||||
),
|
||||
..
|
||||
})) = fn_node else { return };
|
||||
|
||||
let Some(expected_generic_param) = params.get(expected_ty_as_param.index as usize) else { return };
|
||||
|
||||
// get all where BoundPredicates here, because they are used in to cases below
|
||||
let where_predicates = where_clause
|
||||
.predicates
|
||||
.iter()
|
||||
.filter_map(|p| match p {
|
||||
WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||
bounds,
|
||||
bounded_ty,
|
||||
..
|
||||
}) => {
|
||||
// FIXME: Maybe these calls to `ast_ty_to_ty` can be removed (and the ones below)
|
||||
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, bounded_ty);
|
||||
Some((ty, bounds))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.map(|(ty, bounds)| match ty.kind() {
|
||||
ty::Param(param_ty) if param_ty == expected_ty_as_param => Ok(Some(bounds)),
|
||||
// check whether there is any predicate that contains our `T`, like `Option<T>: Send`
|
||||
_ => match ty.contains(expected) {
|
||||
true => Err(()),
|
||||
false => Ok(None),
|
||||
},
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>();
|
||||
|
||||
let Ok(where_predicates) = where_predicates else { return };
|
||||
|
||||
// now get all predicates in the same types as the where bounds, so we can chain them
|
||||
let predicates_from_where =
|
||||
where_predicates.iter().flatten().map(|bounds| bounds.iter()).flatten();
|
||||
|
||||
// extract all bounds from the source code using their spans
|
||||
let all_matching_bounds_strs = expected_generic_param
|
||||
.bounds
|
||||
.iter()
|
||||
.chain(predicates_from_where)
|
||||
.filter_map(|bound| match bound {
|
||||
GenericBound::Trait(_, _) => {
|
||||
self.tcx.sess.source_map().span_to_snippet(bound.span()).ok()
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
if all_matching_bounds_strs.len() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let all_bounds_str = all_matching_bounds_strs.join(" + ");
|
||||
|
||||
let ty_param_used_in_fn_params = fn_parameters.iter().any(|param| {
|
||||
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, param);
|
||||
matches!(ty.kind(), ty::Param(fn_param_ty_param) if expected_ty_as_param == fn_param_ty_param)
|
||||
});
|
||||
|
||||
if ty_param_used_in_fn_params {
|
||||
return;
|
||||
}
|
||||
|
||||
err.span_suggestion(
|
||||
fn_return.span(),
|
||||
"consider using an impl return type",
|
||||
format!("impl {}", all_bounds_str),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
pub(in super::super) fn suggest_missing_break_or_return_expr(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
|
|
|
@ -3009,6 +3009,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||
codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
|
||||
} else if item.has_name(sym::memory) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
|
||||
} else if item.has_name(sym::memtag) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
|
||||
} else if item.has_name(sym::thread) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
|
||||
} else if item.has_name(sym::hwaddress) {
|
||||
|
@ -3016,7 +3018,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||
} else {
|
||||
tcx.sess
|
||||
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
|
||||
.note("expected one of: `address`, `hwaddress`, `memory` or `thread`")
|
||||
.note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -289,7 +289,26 @@ impl OpenOptions {
|
|||
}
|
||||
|
||||
fn cstr(path: &Path) -> io::Result<CString> {
|
||||
Ok(CString::new(path.as_os_str().as_bytes())?)
|
||||
let path = path.as_os_str().as_bytes();
|
||||
|
||||
if !path.starts_with(br"\") {
|
||||
// Relative paths aren't supported
|
||||
return Err(crate::io::const_io_error!(
|
||||
crate::io::ErrorKind::Unsupported,
|
||||
"relative path is not supported on this platform",
|
||||
));
|
||||
}
|
||||
|
||||
// Apply the thread-safety wrapper
|
||||
const SAFE_PREFIX: &[u8] = br"\TS";
|
||||
let wrapped_path = [SAFE_PREFIX, &path, &[0]].concat();
|
||||
|
||||
CString::from_vec_with_nul(wrapped_path).map_err(|_| {
|
||||
crate::io::const_io_error!(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"path provided contains a nul byte",
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
impl File {
|
||||
|
|
|
@ -509,3 +509,6 @@ reverse-dependency like `examples/ex.rs` is given to rustdoc with the target
|
|||
crate being documented (`foobar`) and a path to output the calls
|
||||
(`output.calls`). Then, the generated calls file can be passed via
|
||||
`--with-examples` to the subsequent documentation of `foobar`.
|
||||
|
||||
To scrape examples from test code, e.g. functions marked `#[test]`, then
|
||||
add the `--scrape-tests` flag.
|
||||
|
|
|
@ -16,11 +16,13 @@ This feature allows for use of one of following sanitizers:
|
|||
AddressSanitizer, but based on partial hardware assistance.
|
||||
* [LeakSanitizer][clang-lsan] a run-time memory leak detector.
|
||||
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
|
||||
* [MemTagSanitizer][clang-memtag] fast memory error detector based on
|
||||
Armv8.5-A Memory Tagging Extension.
|
||||
* [ThreadSanitizer][clang-tsan] a fast data race detector.
|
||||
|
||||
To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
|
||||
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory` or
|
||||
`-Zsanitizer=thread`.
|
||||
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
|
||||
`-Zsanitizer=memtag`, or `-Zsanitizer=thread`.
|
||||
|
||||
# AddressSanitizer
|
||||
|
||||
|
@ -494,6 +496,20 @@ $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
|
|||
#0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3
|
||||
```
|
||||
|
||||
# MemTagSanitizer
|
||||
|
||||
MemTagSanitizer detects a similar class of errors as AddressSanitizer and HardwareAddressSanitizer, but with lower overhead suitable for use as hardening for production binaries.
|
||||
|
||||
MemTagSanitizer is supported on the following targets:
|
||||
|
||||
* `aarch64-linux-android`
|
||||
* `aarch64-unknown-linux-gnu`
|
||||
|
||||
MemTagSanitizer requires hardware support and the `mte` target feature.
|
||||
To enable this target feature compile with `-C target-feature="+mte"`.
|
||||
|
||||
More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html).
|
||||
|
||||
# ThreadSanitizer
|
||||
|
||||
ThreadSanitizer is a data race detection tool. It is supported on the following
|
||||
|
|
|
@ -200,6 +200,7 @@ crate fn create_config(
|
|||
lint_opts,
|
||||
describe_lints,
|
||||
lint_cap,
|
||||
scrape_examples_options,
|
||||
..
|
||||
}: RustdocOptions,
|
||||
) -> rustc_interface::Config {
|
||||
|
@ -227,6 +228,7 @@ crate fn create_config(
|
|||
|
||||
let crate_types =
|
||||
if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
|
||||
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false);
|
||||
// plays with error output here!
|
||||
let sessopts = config::Options {
|
||||
maybe_sysroot,
|
||||
|
@ -244,12 +246,14 @@ crate fn create_config(
|
|||
edition,
|
||||
describe_lints,
|
||||
crate_name,
|
||||
test,
|
||||
..Options::default()
|
||||
};
|
||||
|
||||
interface::Config {
|
||||
opts: sessopts,
|
||||
crate_cfg: interface::parse_cfgspecs(cfgs),
|
||||
crate_check_cfg: interface::parse_check_cfg(vec![]),
|
||||
input,
|
||||
input_path: cpath,
|
||||
output_file: None,
|
||||
|
|
|
@ -91,6 +91,7 @@ crate fn run(options: RustdocOptions) -> Result<(), ErrorReported> {
|
|||
let config = interface::Config {
|
||||
opts: sessopts,
|
||||
crate_cfg: interface::parse_cfgspecs(cfgs),
|
||||
crate_check_cfg: interface::parse_check_cfg(vec![]),
|
||||
input,
|
||||
input_path: None,
|
||||
output_file: None,
|
||||
|
|
|
@ -596,6 +596,9 @@ fn opts() -> Vec<RustcOptGroup> {
|
|||
"collect function call information for functions from the target crate",
|
||||
)
|
||||
}),
|
||||
unstable("scrape-tests", |o| {
|
||||
o.optflag("", "scrape-tests", "Include test code when scraping examples")
|
||||
}),
|
||||
unstable("with-examples", |o| {
|
||||
o.optmulti(
|
||||
"",
|
||||
|
|
|
@ -34,6 +34,7 @@ use std::path::PathBuf;
|
|||
crate struct ScrapeExamplesOptions {
|
||||
output_path: PathBuf,
|
||||
target_crates: Vec<String>,
|
||||
crate scrape_tests: bool,
|
||||
}
|
||||
|
||||
impl ScrapeExamplesOptions {
|
||||
|
@ -43,16 +44,22 @@ impl ScrapeExamplesOptions {
|
|||
) -> Result<Option<Self>, i32> {
|
||||
let output_path = matches.opt_str("scrape-examples-output-path");
|
||||
let target_crates = matches.opt_strs("scrape-examples-target-crate");
|
||||
match (output_path, !target_crates.is_empty()) {
|
||||
(Some(output_path), true) => Ok(Some(ScrapeExamplesOptions {
|
||||
let scrape_tests = matches.opt_present("scrape-tests");
|
||||
match (output_path, !target_crates.is_empty(), scrape_tests) {
|
||||
(Some(output_path), true, _) => Ok(Some(ScrapeExamplesOptions {
|
||||
output_path: PathBuf::from(output_path),
|
||||
target_crates,
|
||||
scrape_tests,
|
||||
})),
|
||||
(Some(_), false) | (None, true) => {
|
||||
(Some(_), false, _) | (None, true, _) => {
|
||||
diag.err("must use --scrape-examples-output-path and --scrape-examples-target-crate together");
|
||||
Err(1)
|
||||
}
|
||||
(None, false) => Ok(None),
|
||||
(None, false, true) => {
|
||||
diag.err("must use --scrape-examples-output-path and --scrape-examples-target-crate with --scrape-tests");
|
||||
Err(1)
|
||||
}
|
||||
(None, false, false) => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
12
src/test/codegen/sanitizer_memtag_attr_check.rs
Normal file
12
src/test/codegen/sanitizer_memtag_attr_check.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
// This tests that the sanitize_memtag attribute is
|
||||
// applied when enabling the memtag sanitizer.
|
||||
//
|
||||
// needs-sanitizer-memtag
|
||||
// compile-flags: -Zsanitizer=memtag -Ctarget-feature=+mte
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// CHECK: ; Function Attrs:{{.*}}sanitize_memtag
|
||||
pub fn tagged() {}
|
||||
|
||||
// CHECK: attributes #0 = {{.*}}sanitize_memtag
|
|
@ -49,6 +49,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
|
|||
let config = interface::Config {
|
||||
opts,
|
||||
crate_cfg: Default::default(),
|
||||
crate_check_cfg: Default::default(),
|
||||
input,
|
||||
input_path: None,
|
||||
output_file: Some(output),
|
||||
|
|
|
@ -7,7 +7,8 @@ $(TMPDIR)/%.calls: $(TMPDIR)/libfoobar.rmeta
|
|||
--extern foobar=$(TMPDIR)/libfoobar.rmeta \
|
||||
-Z unstable-options \
|
||||
--scrape-examples-output-path $@ \
|
||||
--scrape-examples-target-crate foobar
|
||||
--scrape-examples-target-crate foobar \
|
||||
$(extra_flags)
|
||||
|
||||
$(TMPDIR)/lib%.rmeta: src/lib.rs
|
||||
$(RUSTC) src/lib.rs --crate-name $* --crate-type lib --emit=metadata
|
||||
|
|
6
src/test/run-make/rustdoc-scrape-examples-test/Makefile
Normal file
6
src/test/run-make/rustdoc-scrape-examples-test/Makefile
Normal file
|
@ -0,0 +1,6 @@
|
|||
extra_flags := --scrape-tests
|
||||
deps := ex
|
||||
|
||||
-include ../rustdoc-scrape-examples-multiple/scrape.mk
|
||||
|
||||
all: scrape
|
|
@ -0,0 +1,6 @@
|
|||
fn main() {}
|
||||
|
||||
#[test]
|
||||
fn a_test() {
|
||||
foobar::ok();
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' ''
|
||||
|
||||
pub fn ok() {}
|
10
src/test/ui/check-cfg/empty-names.rs
Normal file
10
src/test/ui/check-cfg/empty-names.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Check warning for unexpected cfg
|
||||
//
|
||||
// check-pass
|
||||
// compile-flags: --check-cfg=names() -Z unstable-options
|
||||
|
||||
#[cfg(unknown_key = "value")]
|
||||
//~^ WARNING unexpected `cfg` condition name
|
||||
pub fn f() {}
|
||||
|
||||
fn main() {}
|
10
src/test/ui/check-cfg/empty-names.stderr
Normal file
10
src/test/ui/check-cfg/empty-names.stderr
Normal file
|
@ -0,0 +1,10 @@
|
|||
warning: unexpected `cfg` condition name
|
||||
--> $DIR/empty-names.rs:6:7
|
||||
|
|
||||
LL | #[cfg(unknown_key = "value")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
6
src/test/ui/check-cfg/empty-values.rs
Normal file
6
src/test/ui/check-cfg/empty-values.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Check that a an empty values() is rejected
|
||||
//
|
||||
// check-fail
|
||||
// compile-flags: --check-cfg=values() -Z unstable-options
|
||||
|
||||
fn main() {}
|
2
src/test/ui/check-cfg/empty-values.stderr
Normal file
2
src/test/ui/check-cfg/empty-values.stderr
Normal file
|
@ -0,0 +1,2 @@
|
|||
error: invalid `--check-cfg` argument: `values()` (expected `names(name1, name2, ... nameN)` or `values(name, "value1", "value2", ... "valueN")`)
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
error: invalid `--check-cfg` argument: `anything_else(...)` (expected `names(name1, name2, ... nameN)` or `values(name, "value1", "value2", ... "valueN")`)
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
error: invalid `--check-cfg` argument: `names("NOT_IDENT")` (`names()` arguments must be simple identifers)
|
||||
|
10
src/test/ui/check-cfg/invalid-arguments.rs
Normal file
10
src/test/ui/check-cfg/invalid-arguments.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Check that invalid --check-cfg are rejected
|
||||
//
|
||||
// check-fail
|
||||
// revisions: anything_else names_simple_ident values_simple_ident values_string_literals
|
||||
// [anything_else]compile-flags: -Z unstable-options --check-cfg=anything_else(...)
|
||||
// [names_simple_ident]compile-flags: -Z unstable-options --check-cfg=names("NOT_IDENT")
|
||||
// [values_simple_ident]compile-flags: -Z unstable-options --check-cfg=values("NOT_IDENT")
|
||||
// [values_string_literals]compile-flags: -Z unstable-options --check-cfg=values(test,12)
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,2 @@
|
|||
error: invalid `--check-cfg` argument: `values("NOT_IDENT")` (`values()` first argument must be a simple identifer)
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
error: invalid `--check-cfg` argument: `values(test,12)` (`values()` arguments must be string literals)
|
||||
|
14
src/test/ui/check-cfg/invalid-cfg-name.rs
Normal file
14
src/test/ui/check-cfg/invalid-cfg-name.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Check warning for invalid configuration name
|
||||
//
|
||||
// edition:2018
|
||||
// check-pass
|
||||
// compile-flags: --check-cfg=names() -Z unstable-options
|
||||
|
||||
#[cfg(widnows)]
|
||||
//~^ WARNING unexpected `cfg` condition name
|
||||
pub fn f() {}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn g() {}
|
||||
|
||||
pub fn main() {}
|
10
src/test/ui/check-cfg/invalid-cfg-name.stderr
Normal file
10
src/test/ui/check-cfg/invalid-cfg-name.stderr
Normal file
|
@ -0,0 +1,10 @@
|
|||
warning: unexpected `cfg` condition name
|
||||
--> $DIR/invalid-cfg-name.rs:7:7
|
||||
|
|
||||
LL | #[cfg(widnows)]
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
17
src/test/ui/check-cfg/invalid-cfg-value.rs
Normal file
17
src/test/ui/check-cfg/invalid-cfg-value.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Check warning for invalid configuration value
|
||||
//
|
||||
// edition:2018
|
||||
// check-pass
|
||||
// compile-flags: --check-cfg=values(feature,"serde","full") --cfg=feature="rand" -Z unstable-options
|
||||
|
||||
#[cfg(feature = "sedre")]
|
||||
//~^ WARNING unexpected `cfg` condition value
|
||||
pub fn f() {}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub fn g() {}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn h() {}
|
||||
|
||||
pub fn main() {}
|
10
src/test/ui/check-cfg/invalid-cfg-value.stderr
Normal file
10
src/test/ui/check-cfg/invalid-cfg-value.stderr
Normal file
|
@ -0,0 +1,10 @@
|
|||
warning: unexpected `cfg` condition value
|
||||
--> $DIR/invalid-cfg-value.rs:7:7
|
||||
|
|
||||
LL | #[cfg(feature = "sedre")]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
|
@ -57,20 +57,20 @@ fn _rpit_dyn() -> Box<dyn Tr1<As1: Copy>> { Box::new(S1) }
|
|||
|
||||
const _cdef: impl Tr1<As1: Copy> = S1;
|
||||
//~^ ERROR associated type bounds are unstable
|
||||
//~| ERROR `impl Trait` not allowed outside of function and method return types [E0562]
|
||||
//~| ERROR `impl Trait` only allowed in function and inherent method return types
|
||||
// FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
|
||||
// const _cdef_dyn: &dyn Tr1<As1: Copy> = &S1;
|
||||
|
||||
static _sdef: impl Tr1<As1: Copy> = S1;
|
||||
//~^ ERROR associated type bounds are unstable
|
||||
//~| ERROR `impl Trait` not allowed outside of function and method return types [E0562]
|
||||
//~| ERROR `impl Trait` only allowed in function and inherent method return types
|
||||
// FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
|
||||
// static _sdef_dyn: &dyn Tr1<As1: Copy> = &S1;
|
||||
|
||||
fn main() {
|
||||
let _: impl Tr1<As1: Copy> = S1;
|
||||
//~^ ERROR associated type bounds are unstable
|
||||
//~| ERROR `impl Trait` not allowed outside of function and method return types [E0562]
|
||||
//~| ERROR `impl Trait` only allowed in function and inherent method return types
|
||||
// FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
|
||||
// let _: &dyn Tr1<As1: Copy> = &S1;
|
||||
}
|
||||
|
|
|
@ -115,19 +115,19 @@ LL | let _: impl Tr1<As1: Copy> = S1;
|
|||
= note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information
|
||||
= help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
|
||||
|
||||
error[E0562]: `impl Trait` not allowed outside of function and method return types
|
||||
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
|
||||
--> $DIR/feature-gate-associated_type_bounds.rs:58:14
|
||||
|
|
||||
LL | const _cdef: impl Tr1<As1: Copy> = S1;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0562]: `impl Trait` not allowed outside of function and method return types
|
||||
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
|
||||
--> $DIR/feature-gate-associated_type_bounds.rs:64:15
|
||||
|
|
||||
LL | static _sdef: impl Tr1<As1: Copy> = S1;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0562]: `impl Trait` not allowed outside of function and method return types
|
||||
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
|
||||
--> $DIR/feature-gate-associated_type_bounds.rs:71:12
|
||||
|
|
||||
LL | let _: impl Tr1<As1: Copy> = S1;
|
||||
|
|
3
src/test/ui/feature-gates/feature-gate-check-cfg.rs
Normal file
3
src/test/ui/feature-gates/feature-gate-check-cfg.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
// compile-flags: --check-cfg "names()"
|
||||
|
||||
fn main() {}
|
2
src/test/ui/feature-gates/feature-gate-check-cfg.stderr
Normal file
2
src/test/ui/feature-gates/feature-gate-check-cfg.stderr
Normal file
|
@ -0,0 +1,2 @@
|
|||
error: the `-Z unstable-options` flag must also be passed to enable the flag `check-cfg`
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
// check-fail
|
||||
// known-bug
|
||||
|
||||
// This should pass, but it requires `Sized` to be coinductive.
|
||||
|
||||
|
@ -11,7 +12,6 @@ trait Allocator {
|
|||
enum LinkedList<A: Allocator> {
|
||||
Head,
|
||||
Next(A::Allocated<Self>)
|
||||
//~^ overflow
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0275]: overflow evaluating the requirement `LinkedList<A>: Sized`
|
||||
--> $DIR/issue-80626.rs:13:10
|
||||
--> $DIR/issue-80626.rs:14:10
|
||||
|
|
||||
LL | Next(A::Allocated<Self>)
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// check-fail
|
||||
// known-bug
|
||||
|
||||
// This should pass, but seems to run into a TAIT issue.
|
||||
|
||||
|
@ -20,7 +21,6 @@ trait Yay<AdditionalValue> {
|
|||
|
||||
impl<'a> Yay<&'a ()> for () {
|
||||
type InnerStream<'s> = impl Stream<Item = i32> + 's;
|
||||
//~^ the type
|
||||
fn foo<'s>() -> Self::InnerStream<'s> { todo!() }
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
error[E0477]: the type `impl Stream<Item = i32>` does not fulfill the required lifetime
|
||||
--> $DIR/issue-86218.rs:22:28
|
||||
--> $DIR/issue-86218.rs:23:28
|
||||
|
|
||||
LL | type InnerStream<'s> = impl Stream<Item = i32> + 's;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: type must outlive the lifetime `'s` as defined here as required by this binding
|
||||
--> $DIR/issue-86218.rs:22:22
|
||||
--> $DIR/issue-86218.rs:23:22
|
||||
|
|
||||
LL | type InnerStream<'s> = impl Stream<Item = i32> + 's;
|
||||
| ^^
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// check-fail
|
||||
// known-bug
|
||||
|
||||
// This should pass, but we need an extension of implied bounds (probably).
|
||||
|
||||
|
@ -23,7 +24,7 @@ struct Foo<T>(T);
|
|||
#[derive(Debug)]
|
||||
struct FooRef<'a, U>(&'a [U]);
|
||||
|
||||
impl<'b, T, U> AsRef2 for Foo<T> //~ the type parameter
|
||||
impl<'b, T, U> AsRef2 for Foo<T>
|
||||
where
|
||||
// * `for<'b, 'c> T: AsRef2<Output<'b> = &'c [U]>>` does not work
|
||||
//
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
|
||||
--> $DIR/issue-87735.rs:26:13
|
||||
--> $DIR/issue-87735.rs:27:13
|
||||
|
|
||||
LL | impl<'b, T, U> AsRef2 for Foo<T>
|
||||
| ^ unconstrained type parameter
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// check-fail
|
||||
// known-bug
|
||||
|
||||
// This should pass, but unnormalized input args aren't treated as implied.
|
||||
|
||||
|
@ -14,7 +15,7 @@ struct Foo;
|
|||
impl MyTrait for Foo {
|
||||
type Assoc<'a, 'b> where 'b: 'a = u32;
|
||||
|
||||
fn do_sth(_: u32) {} //~ lifetime bound
|
||||
fn do_sth(_: u32) {}
|
||||
// fn do_sth(_: Self::Assoc<'static, 'static>) {}
|
||||
// fn do_sth(_: Self::Assoc<'_, '_>) {}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
error[E0478]: lifetime bound not satisfied
|
||||
--> $DIR/issue-87748.rs:17:5
|
||||
--> $DIR/issue-87748.rs:18:5
|
||||
|
|
||||
LL | fn do_sth(_: u32) {}
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: lifetime parameter instantiated with the anonymous lifetime #2 defined here
|
||||
--> $DIR/issue-87748.rs:17:5
|
||||
--> $DIR/issue-87748.rs:18:5
|
||||
|
|
||||
LL | fn do_sth(_: u32) {}
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
note: but lifetime parameter must outlive the anonymous lifetime #1 defined here
|
||||
--> $DIR/issue-87748.rs:17:5
|
||||
--> $DIR/issue-87748.rs:18:5
|
||||
|
|
||||
LL | fn do_sth(_: u32) {}
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// check-fail
|
||||
// known-bug
|
||||
|
||||
// This should pass.
|
||||
|
||||
|
@ -15,7 +16,6 @@ struct Bar;
|
|||
|
||||
impl Foo for Bar {
|
||||
type Ass = Bar;
|
||||
//~^ overflow
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0275]: overflow evaluating the requirement `<Bar as Foo>::Ass == _`
|
||||
--> $DIR/issue-87755.rs:17:16
|
||||
--> $DIR/issue-87755.rs:18:16
|
||||
|
|
||||
LL | type Ass = Bar;
|
||||
| ^^^
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// check-fail
|
||||
// known-bug
|
||||
|
||||
// This should pass, but using a type alias vs a reference directly
|
||||
// changes late-bound -> early-bound.
|
||||
|
@ -18,7 +19,7 @@ impl Scanner for IdScanner {
|
|||
type Input<'a> = &'a str;
|
||||
type Token<'a> = &'a str;
|
||||
|
||||
fn scan<'a>(&mut self, s : &'a str) -> &'a str { //~ lifetime parameters
|
||||
fn scan<'a>(&mut self, s : &'a str) -> &'a str {
|
||||
s
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0195]: lifetime parameters or bounds on method `scan` do not match the trait declaration
|
||||
--> $DIR/issue-87803.rs:21:12
|
||||
--> $DIR/issue-87803.rs:22:12
|
||||
|
|
||||
LL | fn scan<'a>(&mut self, i : Self::Input<'a>) -> Self::Token<'a>;
|
||||
| ---- lifetimes in impl do not match this method in trait
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// check-fail
|
||||
// known-bug
|
||||
|
||||
// This should pass, but has a missed normalization due to HRTB.
|
||||
|
||||
|
@ -25,7 +26,6 @@ fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>))
|
|||
fn main() {
|
||||
do_something(SomeImplementation(), |_| ());
|
||||
do_something(SomeImplementation(), test);
|
||||
//~^ type mismatch
|
||||
}
|
||||
|
||||
fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0631]: type mismatch in function arguments
|
||||
--> $DIR/issue-88382.rs:27:40
|
||||
--> $DIR/issue-88382.rs:28:40
|
||||
|
|
||||
LL | do_something(SomeImplementation(), test);
|
||||
| ------------ ^^^^ expected signature of `for<'a> fn(&mut <SomeImplementation as Iterable>::Iterator<'a>) -> _`
|
||||
|
@ -10,7 +10,7 @@ LL | fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {}
|
|||
| ------------------------------------------------- found signature of `for<'r> fn(&'r mut std::iter::Empty<usize>) -> _`
|
||||
|
|
||||
note: required by a bound in `do_something`
|
||||
--> $DIR/issue-88382.rs:21:56
|
||||
--> $DIR/issue-88382.rs:22:56
|
||||
|
|
||||
LL | fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `do_something`
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// check-fail
|
||||
// known-bug
|
||||
|
||||
// This should pass, but has a missed normalization due to HRTB.
|
||||
|
||||
|
@ -27,5 +28,4 @@ impl Trait for Foo {
|
|||
|
||||
fn main() {
|
||||
test(Foo);
|
||||
//~^ the trait bound
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
error[E0277]: the trait bound `for<'a> <_ as Trait>::Assoc<'a>: Marker` is not satisfied
|
||||
--> $DIR/issue-88460.rs:29:5
|
||||
--> $DIR/issue-88460.rs:30:5
|
||||
|
|
||||
LL | test(Foo);
|
||||
| ^^^^ the trait `for<'a> Marker` is not implemented for `<_ as Trait>::Assoc<'a>`
|
||||
|
|
||||
note: required by a bound in `test`
|
||||
--> $DIR/issue-88460.rs:16:27
|
||||
--> $DIR/issue-88460.rs:17:27
|
||||
|
|
||||
LL | fn test<T>(value: T)
|
||||
| ---- required by a bound in this
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// check-fail
|
||||
// known-bug
|
||||
|
||||
// This should pass, but requires more logic.
|
||||
|
||||
|
@ -23,7 +24,7 @@ struct TestB<Q, F>
|
|||
f: F,
|
||||
}
|
||||
|
||||
impl<'q, Q, I, F> A for TestB<Q, F> //~ the type parameter
|
||||
impl<'q, Q, I, F> A for TestB<Q, F>
|
||||
where
|
||||
Q: A<I<'q> = &'q I>,
|
||||
F: Fn(I),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0207]: the type parameter `I` is not constrained by the impl trait, self type, or predicates
|
||||
--> $DIR/issue-88526.rs:26:13
|
||||
--> $DIR/issue-88526.rs:27:13
|
||||
|
|
||||
LL | impl<'q, Q, I, F> A for TestB<Q, F>
|
||||
| ^ unconstrained type parameter
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// check-fail
|
||||
// edition:2021
|
||||
// known-bug
|
||||
|
||||
// This should pass, but seems to run into a TAIT bug.
|
||||
|
||||
|
@ -31,11 +32,11 @@ trait X {
|
|||
struct Y;
|
||||
|
||||
impl X for Y {
|
||||
type LineStream<'a, Repr> = impl Stream<Item = Repr>; //~ could not find
|
||||
type LineStream<'a, Repr> = impl Stream<Item = Repr>;
|
||||
|
||||
type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>> ;
|
||||
|
||||
fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> { //~ type mismatch
|
||||
fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {
|
||||
async {empty()}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == impl Stream<Item = Repr>`
|
||||
--> $DIR/issue-89008.rs:38:43
|
||||
--> $DIR/issue-89008.rs:39:43
|
||||
|
|
||||
LL | type LineStream<'a, Repr> = impl Stream<Item = Repr>;
|
||||
| ------------------------ the expected opaque type
|
||||
|
@ -11,7 +11,7 @@ LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {
|
|||
found struct `Empty<_>`
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/issue-89008.rs:34:33
|
||||
--> $DIR/issue-89008.rs:35:33
|
||||
|
|
||||
LL | type LineStream<'a, Repr> = impl Stream<Item = Repr>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -17,7 +17,6 @@ impl<T> UnsafeCopy for T {}
|
|||
fn main() {
|
||||
let b = Box::new(42usize);
|
||||
let copy = <()>::copy(&b);
|
||||
//~^ type annotations needed
|
||||
|
||||
let raw_b = Box::deref(&b) as *const _;
|
||||
let raw_copy = Box::deref(©) as *const _;
|
||||
|
|
|
@ -27,13 +27,6 @@ help: consider restricting type parameter `T`
|
|||
LL | type Copy<T: std::clone::Clone>: Copy = Box<T>;
|
||||
| +++++++++++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/issue-74824.rs:19:16
|
||||
|
|
||||
LL | let copy = <()>::copy(&b);
|
||||
| ^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `copy`
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0282.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
35
src/test/ui/generic-associated-types/issue-93874.rs
Normal file
35
src/test/ui/generic-associated-types/issue-93874.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
// check-pass
|
||||
|
||||
#![feature(generic_associated_types)]
|
||||
|
||||
pub trait Build {
|
||||
type Output<O>;
|
||||
fn build<O>(self, input: O) -> Self::Output<O>;
|
||||
}
|
||||
|
||||
pub struct IdentityBuild;
|
||||
impl Build for IdentityBuild {
|
||||
type Output<O> = O;
|
||||
fn build<O>(self, input: O) -> Self::Output<O> {
|
||||
input
|
||||
}
|
||||
}
|
||||
|
||||
fn a() {
|
||||
let _x: u8 = IdentityBuild.build(10);
|
||||
}
|
||||
|
||||
fn b() {
|
||||
let _x: Vec<u8> = IdentityBuild.build(Vec::new());
|
||||
}
|
||||
|
||||
fn c() {
|
||||
let mut f = IdentityBuild.build(|| ());
|
||||
(f)();
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
a();
|
||||
b();
|
||||
c();
|
||||
}
|
|
@ -2,6 +2,6 @@ use std::fmt::Debug;
|
|||
|
||||
fn main() {
|
||||
let x: Option<impl Debug> = Some(44_u32);
|
||||
//~^ `impl Trait` not allowed outside of function and method return types
|
||||
//~^ `impl Trait` only allowed in function and inherent method return types
|
||||
println!("{:?}", x);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error[E0562]: `impl Trait` not allowed outside of function and method return types
|
||||
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
|
||||
--> $DIR/issue-54600.rs:4:19
|
||||
|
|
||||
LL | let x: Option<impl Debug> = Some(44_u32);
|
||||
|
|
|
@ -3,5 +3,5 @@ use std::ops::Add;
|
|||
fn main() {
|
||||
let i: i32 = 0;
|
||||
let j: &impl Add = &i;
|
||||
//~^ `impl Trait` not allowed outside of function and method return types
|
||||
//~^ `impl Trait` only allowed in function and inherent method return types
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error[E0562]: `impl Trait` not allowed outside of function and method return types
|
||||
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
|
||||
--> $DIR/issue-54840.rs:5:13
|
||||
|
|
||||
LL | let j: &impl Add = &i;
|
||||
|
|
|
@ -8,5 +8,5 @@ fn mk_gen() -> impl Generator<Return=!, Yield=()> {
|
|||
|
||||
fn main() {
|
||||
let gens: [impl Generator<Return=!, Yield=()>;2] = [ mk_gen(), mk_gen() ];
|
||||
//~^ `impl Trait` not allowed outside of function and method return types
|
||||
//~^ `impl Trait` only allowed in function and inherent method return types
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error[E0562]: `impl Trait` not allowed outside of function and method return types
|
||||
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
|
||||
--> $DIR/issue-58504.rs:10:16
|
||||
|
|
||||
LL | let gens: [impl Generator<Return=!, Yield=()>;2] = [ mk_gen(), mk_gen() ];
|
||||
|
|
|
@ -5,9 +5,9 @@ impl Lam for B {}
|
|||
pub struct Wrap<T>(T);
|
||||
|
||||
const _A: impl Lam = {
|
||||
//~^ `impl Trait` not allowed outside of function and method return types
|
||||
//~^ `impl Trait` only allowed in function and inherent method return types
|
||||
let x: Wrap<impl Lam> = Wrap(B);
|
||||
//~^ `impl Trait` not allowed outside of function and method return types
|
||||
//~^ `impl Trait` only allowed in function and inherent method return types
|
||||
x.0
|
||||
};
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
error[E0562]: `impl Trait` not allowed outside of function and method return types
|
||||
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
|
||||
--> $DIR/issue-58956.rs:7:11
|
||||
|
|
||||
LL | const _A: impl Lam = {
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0562]: `impl Trait` not allowed outside of function and method return types
|
||||
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
|
||||
--> $DIR/issue-58956.rs:9:17
|
||||
|
|
||||
LL | let x: Wrap<impl Lam> = Wrap(B);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
fn main() {
|
||||
let x : (impl Copy,) = (true,);
|
||||
//~^ `impl Trait` not allowed outside of function and method return types
|
||||
//~^ `impl Trait` only allowed in function and inherent method return types
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error[E0562]: `impl Trait` not allowed outside of function and method return types
|
||||
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
|
||||
--> $DIR/issue-70971.rs:2:14
|
||||
|
|
||||
LL | let x : (impl Copy,) = (true,);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
struct Bug {
|
||||
V1: [(); {
|
||||
let f: impl core::future::Future<Output = u8> = async { 1 };
|
||||
//~^ `impl Trait` not allowed outside of function and method return types
|
||||
//~^ `impl Trait` only allowed in function and inherent method return types
|
||||
//~| expected identifier
|
||||
1
|
||||
}],
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue