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:
bors 2022-02-19 02:07:43 +00:00
commit 1882597991
127 changed files with 1593 additions and 577 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -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(&param.ty, ImplTraitContext::disallowed())
this.lower_ty_direct(
&param.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));
(

View file

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

View file

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

View file

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

View file

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

View file

@ -190,6 +190,7 @@ pub enum Attribute {
StackProtectStrong = 31,
StackProtect = 32,
NoUndef = 33,
SanitizeMemTag = 34,
}
/// LLVMIntPredicate

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -83,6 +83,7 @@ enum LLVMRustAttribute {
StackProtectStrong = 31,
StackProtect = 32,
NoUndef = 33,
SanitizeMemTag = 34,
};
typedef struct OpaqueRustString *RustStringRef;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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

View file

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

View file

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

View file

@ -0,0 +1,6 @@
extra_flags := --scrape-tests
deps := ex
-include ../rustdoc-scrape-examples-multiple/scrape.mk
all: scrape

View file

@ -0,0 +1,6 @@
fn main() {}
#[test]
fn a_test() {
foobar::ok();
}

View file

@ -0,0 +1,3 @@
// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' ''
pub fn ok() {}

View 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() {}

View 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

View 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() {}

View file

@ -0,0 +1,2 @@
error: invalid `--check-cfg` argument: `values()` (expected `names(name1, name2, ... nameN)` or `values(name, "value1", "value2", ... "valueN")`)

View file

@ -0,0 +1,2 @@
error: invalid `--check-cfg` argument: `anything_else(...)` (expected `names(name1, name2, ... nameN)` or `values(name, "value1", "value2", ... "valueN")`)

View file

@ -0,0 +1,2 @@
error: invalid `--check-cfg` argument: `names("NOT_IDENT")` (`names()` arguments must be simple identifers)

View 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() {}

View file

@ -0,0 +1,2 @@
error: invalid `--check-cfg` argument: `values("NOT_IDENT")` (`values()` first argument must be a simple identifer)

View file

@ -0,0 +1,2 @@
error: invalid `--check-cfg` argument: `values(test,12)` (`values()` arguments must be string literals)

View 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() {}

View 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

View 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() {}

View 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

View file

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

View file

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

View file

@ -0,0 +1,3 @@
// compile-flags: --check-cfg "names()"
fn main() {}

View file

@ -0,0 +1,2 @@
error: the `-Z unstable-options` flag must also be passed to enable the flag `check-cfg`

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(&copy) as *const _;

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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