Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2025-02-06 05:01:51 +00:00
commit 7afb84525a
277 changed files with 4863 additions and 2198 deletions

View file

@ -1098,9 +1098,9 @@ dependencies = [
[[package]]
name = "elsa"
version = "1.7.1"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "848fe615fbb0a74d9ae68dcaa510106d32e37d9416207bbea4bd008bd89c47ed"
checksum = "2343daaeabe09879d4ea058bb4f1e63da3fc07dadc6634e01bda1b3d6a9d9d2b"
dependencies = [
"stable_deref_trait",
]

View file

@ -3348,11 +3348,18 @@ pub struct Impl {
pub items: ThinVec<P<AssocItem>>,
}
#[derive(Clone, Encodable, Decodable, Debug, Default)]
pub struct FnContract {
pub requires: Option<P<Expr>>,
pub ensures: Option<P<Expr>>,
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct Fn {
pub defaultness: Defaultness,
pub generics: Generics,
pub sig: FnSig,
pub contract: Option<P<FnContract>>,
pub body: Option<P<Block>>,
}
@ -3650,7 +3657,7 @@ mod size_asserts {
static_assert_size!(Block, 32);
static_assert_size!(Expr, 72);
static_assert_size!(ExprKind, 40);
static_assert_size!(Fn, 160);
static_assert_size!(Fn, 168);
static_assert_size!(ForeignItem, 88);
static_assert_size!(ForeignItemKind, 16);
static_assert_size!(GenericArg, 24);

View file

@ -143,6 +143,10 @@ pub trait MutVisitor: Sized {
walk_flat_map_assoc_item(self, i, ctxt)
}
fn visit_contract(&mut self, c: &mut P<FnContract>) {
walk_contract(self, c);
}
fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
walk_fn_decl(self, d);
}
@ -958,13 +962,16 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
_ctxt,
_ident,
_vis,
Fn { defaultness, generics, body, sig: FnSig { header, decl, span } },
Fn { defaultness, generics, contract, body, sig: FnSig { header, decl, span } },
) => {
// Identifier and visibility are visited as a part of the item.
visit_defaultness(vis, defaultness);
vis.visit_fn_header(header);
vis.visit_generics(generics);
vis.visit_fn_decl(decl);
if let Some(contract) = contract {
vis.visit_contract(contract);
}
if let Some(body) = body {
vis.visit_block(body);
}
@ -979,6 +986,16 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
}
}
fn walk_contract<T: MutVisitor>(vis: &mut T, contract: &mut P<FnContract>) {
let FnContract { requires, ensures } = contract.deref_mut();
if let Some(pred) = requires {
vis.visit_expr(pred);
}
if let Some(pred) = ensures {
vis.visit_expr(pred);
}
}
fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut P<FnDecl>) {
let FnDecl { inputs, output } = decl.deref_mut();
inputs.flat_map_in_place(|param| vis.flat_map_param(param));

View file

@ -188,6 +188,9 @@ pub trait Visitor<'ast>: Sized {
fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) -> Self::Result {
walk_closure_binder(self, b)
}
fn visit_contract(&mut self, c: &'ast FnContract) -> Self::Result {
walk_contract(self, c)
}
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) -> Self::Result {
walk_where_predicate(self, p)
}
@ -800,6 +803,17 @@ pub fn walk_closure_binder<'a, V: Visitor<'a>>(
V::Result::output()
}
pub fn walk_contract<'a, V: Visitor<'a>>(visitor: &mut V, c: &'a FnContract) -> V::Result {
let FnContract { requires, ensures } = c;
if let Some(pred) = requires {
visitor.visit_expr(pred);
}
if let Some(pred) = ensures {
visitor.visit_expr(pred);
}
V::Result::output()
}
pub fn walk_where_predicate<'a, V: Visitor<'a>>(
visitor: &mut V,
predicate: &'a WherePredicate,
@ -862,12 +876,13 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
_ctxt,
_ident,
_vis,
Fn { defaultness: _, sig: FnSig { header, decl, span: _ }, generics, body },
Fn { defaultness: _, sig: FnSig { header, decl, span: _ }, generics, contract, body },
) => {
// Identifier and visibility are visited as a part of the item.
try_visit!(visitor.visit_fn_header(header));
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_fn_decl(decl));
visit_opt!(visitor, visit_contract, contract);
visit_opt!(visitor, visit_block, body);
}
FnKind::Closure(binder, coroutine_kind, decl, body) => {

View file

@ -311,8 +311,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ExprKind::Continue(self.lower_jump_destination(e.id, *opt_label))
}
ExprKind::Ret(e) => {
let e = e.as_ref().map(|x| self.lower_expr(x));
hir::ExprKind::Ret(e)
let expr = e.as_ref().map(|x| self.lower_expr(x));
self.checked_return(expr)
}
ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
ExprKind::Become(sub_expr) => {
@ -379,6 +379,32 @@ impl<'hir> LoweringContext<'_, 'hir> {
})
}
/// Create an `ExprKind::Ret` that is preceded by a call to check contract ensures clause.
fn checked_return(&mut self, opt_expr: Option<&'hir hir::Expr<'hir>>) -> hir::ExprKind<'hir> {
let checked_ret = if let Some(Some((span, fresh_ident))) =
self.contract.as_ref().map(|c| c.ensures.as_ref().map(|e| (e.expr.span, e.fresh_ident)))
{
let expr = opt_expr.unwrap_or_else(|| self.expr_unit(span));
Some(self.inject_ensures_check(expr, span, fresh_ident.0, fresh_ident.2))
} else {
opt_expr
};
hir::ExprKind::Ret(checked_ret)
}
/// Wraps an expression with a call to the ensures check before it gets returned.
pub(crate) fn inject_ensures_check(
&mut self,
expr: &'hir hir::Expr<'hir>,
span: Span,
check_ident: Ident,
check_hir_id: HirId,
) -> &'hir hir::Expr<'hir> {
let checker_fn = self.expr_ident(span, check_ident, check_hir_id);
let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None);
self.expr_call(span, checker_fn, std::slice::from_ref(expr))
}
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
self.with_new_scopes(c.value.span, |this| {
let def_id = this.local_def_id(c.id);
@ -1991,7 +2017,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
),
))
} else {
self.arena.alloc(self.expr(try_span, hir::ExprKind::Ret(Some(from_residual_expr))))
let ret_expr = self.checked_return(Some(from_residual_expr));
self.arena.alloc(self.expr(try_span, ret_expr))
};
self.lower_attrs(ret_expr.hir_id, &attrs);
@ -2040,7 +2067,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let target_id = Ok(catch_id);
hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr))
} else {
hir::ExprKind::Ret(Some(from_yeet_expr))
self.checked_return(Some(from_yeet_expr))
}
}

View file

@ -207,9 +207,40 @@ impl<'hir> LoweringContext<'_, 'hir> {
sig: FnSig { decl, header, span: fn_sig_span },
generics,
body,
contract,
..
}) => {
self.with_new_scopes(*fn_sig_span, |this| {
assert!(this.contract.is_none());
if let Some(contract) = contract {
let requires = contract.requires.clone();
let ensures = contract.ensures.clone();
let ensures = ensures.map(|ens| {
// FIXME: this needs to be a fresh (or illegal) identifier to prevent
// accidental capture of a parameter or global variable.
let checker_ident: Ident =
Ident::from_str_and_span("__ensures_checker", ens.span);
let (checker_pat, checker_hir_id) = this.pat_ident_binding_mode_mut(
ens.span,
checker_ident,
hir::BindingMode::NONE,
);
crate::FnContractLoweringEnsures {
expr: ens,
fresh_ident: (checker_ident, checker_pat, checker_hir_id),
}
});
// Note: `with_new_scopes` will reinstall the outer
// item's contract (if any) after its callback finishes.
this.contract.replace(crate::FnContractLoweringInfo {
span,
requires,
ensures,
});
}
// Note: we don't need to change the return type from `T` to
// `impl Future<Output = T>` here because lower_body
// only cares about the input argument patterns in the function
@ -1054,10 +1085,64 @@ impl<'hir> LoweringContext<'_, 'hir> {
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::BodyId {
self.lower_body(|this| {
(
this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x))),
body(this),
)
let params =
this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x)));
let result = body(this);
let opt_contract = this.contract.take();
// { body }
// ==>
// { contract_requires(PRECOND); { body } }
let Some(contract) = opt_contract else { return (params, result) };
let result_ref = this.arena.alloc(result);
let lit_unit = |this: &mut LoweringContext<'_, 'hir>| {
this.expr(contract.span, hir::ExprKind::Tup(&[]))
};
let precond: hir::Stmt<'hir> = if let Some(req) = contract.requires {
let lowered_req = this.lower_expr_mut(&req);
let precond = this.expr_call_lang_item_fn_mut(
req.span,
hir::LangItem::ContractCheckRequires,
&*arena_vec![this; lowered_req],
);
this.stmt_expr(req.span, precond)
} else {
let u = lit_unit(this);
this.stmt_expr(contract.span, u)
};
let (postcond_checker, result) = if let Some(ens) = contract.ensures {
let crate::FnContractLoweringEnsures { expr: ens, fresh_ident } = ens;
let lowered_ens: hir::Expr<'hir> = this.lower_expr_mut(&ens);
let postcond_checker = this.expr_call_lang_item_fn(
ens.span,
hir::LangItem::ContractBuildCheckEnsures,
&*arena_vec![this; lowered_ens],
);
let checker_binding_pat = fresh_ident.1;
(
this.stmt_let_pat(
None,
ens.span,
Some(postcond_checker),
this.arena.alloc(checker_binding_pat),
hir::LocalSource::Contract,
),
this.inject_ensures_check(result_ref, ens.span, fresh_ident.0, fresh_ident.2),
)
} else {
let u = lit_unit(this);
(this.stmt_expr(contract.span, u), &*result_ref)
};
let block = this.block_all(
contract.span,
arena_vec![this; precond, postcond_checker],
Some(result),
);
(params, this.expr_block(block))
})
}

View file

@ -86,6 +86,19 @@ mod path;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
#[derive(Debug, Clone)]
struct FnContractLoweringInfo<'hir> {
pub span: Span,
pub requires: Option<ast::ptr::P<ast::Expr>>,
pub ensures: Option<FnContractLoweringEnsures<'hir>>,
}
#[derive(Debug, Clone)]
struct FnContractLoweringEnsures<'hir> {
expr: ast::ptr::P<ast::Expr>,
fresh_ident: (Ident, hir::Pat<'hir>, HirId),
}
struct LoweringContext<'a, 'hir> {
tcx: TyCtxt<'hir>,
resolver: &'a mut ResolverAstLowering,
@ -100,6 +113,8 @@ struct LoweringContext<'a, 'hir> {
/// Collect items that were created by lowering the current owner.
children: Vec<(LocalDefId, hir::MaybeOwner<'hir>)>,
contract: Option<FnContractLoweringInfo<'hir>>,
coroutine_kind: Option<hir::CoroutineKind>,
/// When inside an `async` context, this is the `HirId` of the
@ -148,6 +163,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
bodies: Vec::new(),
attrs: SortedMap::default(),
children: Vec::default(),
contract: None,
current_hir_id_owner: hir::CRATE_OWNER_ID,
item_local_id_counter: hir::ItemLocalId::ZERO,
ident_and_label_to_local_id: Default::default(),
@ -834,12 +850,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let was_in_loop_condition = self.is_in_loop_condition;
self.is_in_loop_condition = false;
let old_contract = self.contract.take();
let catch_scope = self.catch_scope.take();
let loop_scope = self.loop_scope.take();
let ret = f(self);
self.catch_scope = catch_scope;
self.loop_scope = loop_scope;
self.contract = old_contract;
self.is_in_loop_condition = was_in_loop_condition;
self.current_item = current_item;

View file

@ -917,7 +917,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
walk_list!(self, visit_attribute, &item.attrs);
return; // Avoid visiting again.
}
ItemKind::Fn(func @ box Fn { defaultness, generics: _, sig, body }) => {
ItemKind::Fn(func @ box Fn { defaultness, generics: _, sig, contract: _, body }) => {
self.check_defaultness(item.span, *defaultness);
let is_intrinsic =

View file

@ -548,6 +548,8 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
gate_all!(unsafe_fields, "`unsafe` fields are experimental");
gate_all!(unsafe_binders, "unsafe binder types are experimental");
gate_all!(contracts, "contracts are incomplete");
gate_all!(contracts_internals, "contract internal machinery is for internal use only");
if !visitor.features.never_patterns() {
if let Some(spans) = spans.get(&sym::never_patterns) {

View file

@ -650,13 +650,17 @@ impl<'a> State<'a> {
attrs: &[ast::Attribute],
func: &ast::Fn,
) {
let ast::Fn { defaultness, generics, sig, body } = func;
let ast::Fn { defaultness, generics, sig, contract, body } = func;
if body.is_some() {
self.head("");
}
self.print_visibility(vis);
self.print_defaultness(*defaultness);
self.print_fn(&sig.decl, sig.header, Some(name), generics);
if let Some(contract) = &contract {
self.nbsp();
self.print_contract(contract);
}
if let Some(body) = body {
self.nbsp();
self.print_block_with_attrs(body, attrs);
@ -665,6 +669,21 @@ impl<'a> State<'a> {
}
}
fn print_contract(&mut self, contract: &ast::FnContract) {
if let Some(pred) = &contract.requires {
self.word("rustc_requires");
self.popen();
self.print_expr(pred, FixupContext::default());
self.pclose();
}
if let Some(pred) = &contract.ensures {
self.word("rustc_ensures");
self.popen();
self.print_expr(pred, FixupContext::default());
self.pclose();
}
}
pub(crate) fn print_fn(
&mut self,
decl: &ast::FnDecl,

View file

@ -1653,6 +1653,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::SizedBound,
);
}
&Rvalue::NullaryOp(NullOp::ContractChecks, _) => {}
&Rvalue::NullaryOp(NullOp::UbChecks, _) => {}
Rvalue::ShallowInitBox(operand, ty) => {

View file

@ -85,6 +85,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
defaultness: ast::Defaultness::Final,
sig,
generics: Generics::default(),
contract: None,
body,
}));

View file

@ -0,0 +1,176 @@
#![allow(unused_imports, unused_variables)]
use rustc_ast::token;
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_errors::ErrorGuaranteed;
use rustc_expand::base::{AttrProcMacro, ExtCtxt};
use rustc_span::Span;
use rustc_span::symbol::{Ident, Symbol, kw, sym};
pub(crate) struct ExpandRequires;
pub(crate) struct ExpandEnsures;
impl AttrProcMacro for ExpandRequires {
fn expand<'cx>(
&self,
ecx: &'cx mut ExtCtxt<'_>,
span: Span,
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
expand_requires_tts(ecx, span, annotation, annotated)
}
}
impl AttrProcMacro for ExpandEnsures {
fn expand<'cx>(
&self,
ecx: &'cx mut ExtCtxt<'_>,
span: Span,
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
expand_ensures_tts(ecx, span, annotation, annotated)
}
}
/// Expand the function signature to include the contract clause.
///
/// The contracts clause will be injected before the function body and the optional where clause.
/// For that, we search for the body / where token, and invoke the `inject` callback to generate the
/// contract clause in the right place.
///
// FIXME: this kind of manual token tree munging does not have significant precedent among
// rustc builtin macros, probably because most builtin macros use direct AST manipulation to
// accomplish similar goals. But since our attributes need to take arbitrary expressions, and
// our attribute infrastructure does not yet support mixing a token-tree annotation with an AST
// annotated, we end up doing token tree manipulation.
fn expand_contract_clause(
ecx: &mut ExtCtxt<'_>,
attr_span: Span,
annotated: TokenStream,
inject: impl FnOnce(&mut TokenStream) -> Result<(), ErrorGuaranteed>,
) -> Result<TokenStream, ErrorGuaranteed> {
let mut new_tts = TokenStream::default();
let mut cursor = annotated.iter();
let is_kw = |tt: &TokenTree, sym: Symbol| {
if let TokenTree::Token(token, _) = tt { token.is_ident_named(sym) } else { false }
};
// Find the `fn` keyword to check if this is a function.
if cursor
.find(|tt| {
new_tts.push_tree((*tt).clone());
is_kw(tt, kw::Fn)
})
.is_none()
{
return Err(ecx
.sess
.dcx()
.span_err(attr_span, "contract annotations can only be used on functions"));
}
// Found the `fn` keyword, now find either the `where` token or the function body.
let next_tt = loop {
let Some(tt) = cursor.next() else {
return Err(ecx.sess.dcx().span_err(
attr_span,
"contract annotations is only supported in functions with bodies",
));
};
// If `tt` is the last element. Check if it is the function body.
if cursor.peek().is_none() {
if let TokenTree::Delimited(_, _, token::Delimiter::Brace, _) = tt {
break tt;
} else {
return Err(ecx.sess.dcx().span_err(
attr_span,
"contract annotations is only supported in functions with bodies",
));
}
}
if is_kw(tt, kw::Where) {
break tt;
}
new_tts.push_tree(tt.clone());
};
// At this point, we've transcribed everything from the `fn` through the formal parameter list
// and return type declaration, (if any), but `tt` itself has *not* been transcribed.
//
// Now inject the AST contract form.
//
inject(&mut new_tts)?;
// Above we injected the internal AST requires/ensures construct. Now copy over all the other
// token trees.
new_tts.push_tree(next_tt.clone());
while let Some(tt) = cursor.next() {
new_tts.push_tree(tt.clone());
if cursor.peek().is_none()
&& !matches!(tt, TokenTree::Delimited(_, _, token::Delimiter::Brace, _))
{
return Err(ecx.sess.dcx().span_err(
attr_span,
"contract annotations is only supported in functions with bodies",
));
}
}
// Record the span as a contract attribute expansion.
// This is used later to stop users from using the extended syntax directly
// which is gated via `contracts_internals`.
ecx.psess().contract_attribute_spans.push(attr_span);
Ok(new_tts)
}
fn expand_requires_tts(
_ecx: &mut ExtCtxt<'_>,
attr_span: Span,
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
expand_contract_clause(_ecx, attr_span, annotated, |new_tts| {
new_tts.push_tree(TokenTree::Token(
token::Token::from_ast_ident(Ident::new(kw::ContractRequires, attr_span)),
Spacing::Joint,
));
new_tts.push_tree(TokenTree::Token(
token::Token::new(token::TokenKind::OrOr, attr_span),
Spacing::Alone,
));
new_tts.push_tree(TokenTree::Delimited(
DelimSpan::from_single(attr_span),
DelimSpacing::new(Spacing::JointHidden, Spacing::JointHidden),
token::Delimiter::Parenthesis,
annotation,
));
Ok(())
})
}
fn expand_ensures_tts(
_ecx: &mut ExtCtxt<'_>,
attr_span: Span,
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
expand_contract_clause(_ecx, attr_span, annotated, |new_tts| {
new_tts.push_tree(TokenTree::Token(
token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, attr_span)),
Spacing::Joint,
));
new_tts.push_tree(TokenTree::Delimited(
DelimSpan::from_single(attr_span),
DelimSpacing::new(Spacing::JointHidden, Spacing::JointHidden),
token::Delimiter::Parenthesis,
annotation,
));
Ok(())
})
}

View file

@ -1034,6 +1034,7 @@ impl<'a> MethodDef<'a> {
defaultness,
sig,
generics: fn_generics,
contract: None,
body: Some(body_block),
})),
tokens: None,

View file

@ -81,6 +81,7 @@ impl AllocFnFactory<'_, '_> {
defaultness: ast::Defaultness::Final,
sig,
generics: Generics::default(),
contract: None,
body,
}));
let item = self.cx.item(

View file

@ -55,6 +55,7 @@ mod trace_macros;
pub mod asm;
pub mod cmdline_attrs;
pub mod contracts;
pub mod proc_macro_harness;
pub mod standard_library_imports;
pub mod test_harness;
@ -137,4 +138,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })));
let requires = SyntaxExtensionKind::Attr(Box::new(contracts::ExpandRequires));
register(sym::contracts_requires, requires);
let ensures = SyntaxExtensionKind::Attr(Box::new(contracts::ExpandEnsures));
register(sym::contracts_ensures, ensures);
}

View file

@ -344,6 +344,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
defaultness,
sig,
generics: ast::Generics::default(),
contract: None,
body: Some(main_body),
}));

View file

@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644
[dependencies]
core = { path = "../core" }
-compiler_builtins = { version = "=0.1.143", features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "=0.1.143", features = ['rustc-dep-of-std', 'no-f16-f128'] }
-compiler_builtins = { version = "=0.1.145", features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "=0.1.145", features = ['rustc-dep-of-std', 'no-f16-f128'] }
[dev-dependencies]
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }

View file

@ -868,7 +868,16 @@ fn codegen_stmt<'tcx>(
NullOp::UbChecks => {
let val = fx.tcx.sess.ub_checks();
let val = CValue::by_val(
fx.bcx.ins().iconst(types::I8, i64::try_from(val).unwrap()),
fx.bcx.ins().iconst(types::I8, i64::from(val)),
fx.layout_of(fx.tcx.types.bool),
);
lval.write_cvalue(fx, val);
return;
}
NullOp::ContractChecks => {
let val = fx.tcx.sess.contract_checks();
let val = CValue::by_val(
fx.bcx.ins().iconst(types::I8, i64::from(val)),
fx.layout_of(fx.tcx.types.bool),
);
lval.write_cvalue(fx, val);

View file

@ -8,7 +8,7 @@ use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::LayoutOf;
#[cfg(feature = "master")]
use rustc_session::config;
use rustc_target::abi::call::{ArgAttributes, CastTarget, FnAbi, PassMode, Reg, RegKind};
use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode, Reg, RegKind};
use crate::builder::Builder;
use crate::context::CodegenCx;
@ -132,10 +132,10 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
if cx.sess().opts.optimize == config::OptLevel::No {
return ty;
}
if attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NoAlias) {
if attrs.regular.contains(rustc_target::callconv::ArgAttribute::NoAlias) {
ty = ty.make_restrict()
}
if attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NonNull) {
if attrs.regular.contains(rustc_target::callconv::ArgAttribute::NonNull) {
non_null_args.push(arg_index as i32 + 1);
}
ty

View file

@ -29,7 +29,7 @@ use rustc_middle::ty::layout::{
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use rustc_target::abi::call::FnAbi;
use rustc_target::callconv::FnAbi;
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, WasmCAbi, X86Abi};
use crate::common::{SignType, TypeReflection, type_is_pointer};

View file

@ -1,6 +1,7 @@
#[cfg(feature = "master")]
use gccjit::{FnAttribute, VarAttribute, Visibility};
use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue, Type};
use rustc_abi::{self as abi, Align, HasDataLayout, Primitive, Size, WrappingRange};
use rustc_codegen_ssa::traits::{
BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
};
@ -14,7 +15,6 @@ use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Instance};
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId;
use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange};
use crate::base;
use crate::context::CodegenCx;

View file

@ -3,6 +3,7 @@ use std::cell::{Cell, RefCell};
use gccjit::{
Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type,
};
use rustc_abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
use rustc_codegen_ssa::base::wants_msvc_seh;
use rustc_codegen_ssa::errors as ssa_errors;
use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, MiscCodegenMethods};
@ -18,7 +19,6 @@ use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt};
use rustc_session::Session;
use rustc_span::source_map::respan;
use rustc_span::{DUMMY_SP, Span};
use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
use rustc_target::spec::{
HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi,
};

View file

@ -1,6 +1,7 @@
use std::ops::Range;
use gccjit::{Location, RValue};
use rustc_abi::Size;
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoCodegenMethods};
use rustc_data_structures::sync::Lrc;
@ -10,8 +11,7 @@ use rustc_middle::mir::{self, Body, SourceScope};
use rustc_middle::ty::{ExistentialTraitRef, Instance, Ty};
use rustc_session::config::DebugInfo;
use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol};
use rustc_target::abi::Size;
use rustc_target::abi::call::FnAbi;
use rustc_target::callconv::FnAbi;
use crate::builder::Builder;
use crate::context::CodegenCx;

View file

@ -4,7 +4,7 @@ use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type};
use rustc_codegen_ssa::traits::BaseTypeCodegenMethods;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::abi::call::FnAbi;
use rustc_target::callconv::FnAbi;
use crate::abi::{FnAbiGcc, FnAbiGccExt};
use crate::context::CodegenCx;

View file

@ -3,12 +3,11 @@
//! 128-bit integers on 32-bit platforms and thus require to be handled manually.
use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp};
use rustc_abi::{Endian, ExternAbi};
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, BuilderMethods, OverflowOp};
use rustc_middle::ty::{self, Ty};
use rustc_target::abi::Endian;
use rustc_target::abi::call::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode};
use rustc_target::spec;
use rustc_target::callconv::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode};
use crate::builder::{Builder, ToGccComp};
use crate::common::{SignType, TypeReflection};
@ -401,7 +400,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
conv: Conv::C,
can_unwind: false,
};
fn_abi.adjust_for_foreign_abi(self.cx, spec::abi::Abi::C { unwind: false }).unwrap();
fn_abi.adjust_for_foreign_abi(self.cx, ExternAbi::C { unwind: false }).unwrap();
let ret_indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });

View file

@ -7,6 +7,9 @@ use std::iter;
#[cfg(feature = "master")]
use gccjit::FunctionType;
use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp};
#[cfg(feature = "master")]
use rustc_abi::ExternAbi;
use rustc_abi::HasDataLayout;
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::base::wants_msvc_seh;
use rustc_codegen_ssa::common::IntPredicate;
@ -25,11 +28,8 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
use rustc_middle::ty::{self, Instance, Ty};
use rustc_span::{Span, Symbol, sym};
use rustc_target::abi::HasDataLayout;
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
use rustc_target::spec::PanicStrategy;
#[cfg(feature = "master")]
use rustc_target::spec::abi::Abi;
#[cfg(feature = "master")]
use crate::abi::FnAbiGccExt;
@ -1238,7 +1238,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(
tcx.types.unit,
false,
rustc_hir::Safety::Unsafe,
Abi::Rust,
ExternAbi::Rust,
)),
);
// `unsafe fn(*mut i8, *mut i8) -> ()`
@ -1249,7 +1249,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(
tcx.types.unit,
false,
rustc_hir::Safety::Unsafe,
Abi::Rust,
ExternAbi::Rust,
)),
);
// `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32`
@ -1258,7 +1258,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(
tcx.types.i32,
false,
rustc_hir::Safety::Unsafe,
Abi::Rust,
ExternAbi::Rust,
));
let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen);
cx.rust_try_fn.set(Some(rust_try));

View file

@ -3,6 +3,7 @@ use std::iter::FromIterator;
use gccjit::{BinaryOp, RValue, ToRValue, Type};
#[cfg(feature = "master")]
use gccjit::{ComparisonOp, UnaryOp};
use rustc_abi::{Align, Size};
use rustc_codegen_ssa::base::compare_simd_types;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
#[cfg(feature = "master")]
@ -17,7 +18,6 @@ use rustc_middle::mir::BinOp;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::{self, Ty};
use rustc_span::{Span, Symbol, sym};
use rustc_target::abi::{Align, Size};
use crate::builder::Builder;
#[cfg(not(feature = "master"))]

View file

@ -4,13 +4,13 @@ use std::convert::TryInto;
#[cfg(feature = "master")]
use gccjit::CType;
use gccjit::{RValue, Struct, Type};
use rustc_abi::{AddressSpace, Align, Integer, Size};
use rustc_codegen_ssa::common::TypeKind;
use rustc_codegen_ssa::traits::{
BaseTypeCodegenMethods, DerivedTypeCodegenMethods, TypeMembershipCodegenMethods,
};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, ty};
use rustc_target::abi::{AddressSpace, Align, Integer, Size};
use crate::common::TypeReflection;
use crate::context::CodegenCx;

View file

@ -3,7 +3,9 @@ use std::fmt::Write;
use gccjit::{Struct, Type};
use rustc_abi as abi;
use rustc_abi::Primitive::*;
use rustc_abi::{BackendRepr, FieldsShape, Integer, PointeeInfo, Size, Variants};
use rustc_abi::{
BackendRepr, FieldsShape, Integer, PointeeInfo, Reg, Size, TyAbiInterface, Variants,
};
use rustc_codegen_ssa::traits::{
BaseTypeCodegenMethods, DerivedTypeCodegenMethods, LayoutTypeCodegenMethods,
};
@ -11,8 +13,7 @@ use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt};
use rustc_target::abi::TyAbiInterface;
use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
use rustc_target::callconv::{CastTarget, FnAbi};
use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType};
use crate::context::CodegenCx;

View file

@ -127,7 +127,7 @@ fn make_mir_scope<'ll, 'tcx>(
})
}
None => unsafe {
llvm::LLVMRustDIBuilderCreateLexicalBlock(
llvm::LLVMDIBuilderCreateLexicalBlock(
DIB(cx),
parent_scope.dbg_scope,
file_metadata,

View file

@ -931,7 +931,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
unsafe {
let compile_unit_file = llvm::LLVMRustDIBuilderCreateFile(
debug_context.builder,
debug_context.builder.as_ref(),
name_in_debuginfo.as_c_char_ptr(),
name_in_debuginfo.len(),
work_dir.as_c_char_ptr(),
@ -944,7 +944,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
);
let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
debug_context.builder,
debug_context.builder.as_ref(),
dwarf_const::DW_LANG_Rust,
compile_unit_file,
producer.as_c_char_ptr(),
@ -1641,7 +1641,14 @@ pub(crate) fn extend_scope_to_file<'ll>(
file: &SourceFile,
) -> &'ll DILexicalBlock {
let file_metadata = file_metadata(cx, file);
unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlockFile(DIB(cx), scope_metadata, file_metadata) }
unsafe {
llvm::LLVMDIBuilderCreateLexicalBlockFile(
DIB(cx),
scope_metadata,
file_metadata,
/* Discriminator (default) */ 0u32,
)
}
}
fn tuple_field_name(field_index: usize) -> Cow<'static, str> {

View file

@ -34,7 +34,7 @@ use crate::builder::Builder;
use crate::common::{AsCCharPtr, CodegenCx};
use crate::llvm;
use crate::llvm::debuginfo::{
DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType,
DIArray, DIBuilderBox, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType,
DIVariable,
};
use crate::value::Value;
@ -61,7 +61,7 @@ const DW_TAG_arg_variable: c_uint = 0x101;
/// A context object for maintaining all state needed by the debuginfo module.
pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
llmod: &'ll llvm::Module,
builder: &'ll mut DIBuilder<'ll>,
builder: DIBuilderBox<'ll>,
created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>,
type_map: metadata::TypeMap<'ll, 'tcx>,
@ -69,18 +69,10 @@ pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
recursion_marker_type: OnceCell<&'ll DIType>,
}
impl Drop for CodegenUnitDebugContext<'_, '_> {
fn drop(&mut self) {
unsafe {
llvm::LLVMRustDIBuilderDispose(&mut *(self.builder as *mut _));
}
}
}
impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
pub(crate) fn new(llmod: &'ll llvm::Module) -> Self {
debug!("CodegenUnitDebugContext::new");
let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) };
let builder = DIBuilderBox::new(llmod);
// DIBuilder inherits context from the module, so we'd better use the same one
CodegenUnitDebugContext {
llmod,
@ -93,7 +85,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
}
pub(crate) fn finalize(&self, sess: &Session) {
unsafe { llvm::LLVMRustDIBuilderFinalize(self.builder) };
unsafe { llvm::LLVMDIBuilderFinalize(self.builder.as_ref()) };
match sess.target.debuginfo_kind {
DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym => {
@ -105,7 +97,11 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
// Android has the same issue (#22398)
llvm::add_module_flag_u32(
self.llmod,
llvm::ModuleFlagMergeBehavior::Warning,
// In the case where multiple CGUs with different dwarf version
// values are being merged together, such as with cross-crate
// LTO, then we want to use the highest version of dwarf
// we can. This matches Clang's behavior as well.
llvm::ModuleFlagMergeBehavior::Max,
"Dwarf Version",
sess.dwarf_version(),
);
@ -582,7 +578,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
(line, col)
};
unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation(line, col, scope, inlined_at) }
unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
}
fn create_vtable_debuginfo(

View file

@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, Instance};
use super::utils::{DIB, debug_context};
use crate::common::{AsCCharPtr, CodegenCx};
use crate::common::CodegenCx;
use crate::llvm;
use crate::llvm::debuginfo::DIScope;
@ -33,12 +33,12 @@ pub(crate) fn item_namespace<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'l
};
let scope = unsafe {
llvm::LLVMRustDIBuilderCreateNameSpace(
llvm::LLVMDIBuilderCreateNameSpace(
DIB(cx),
parent_scope,
namespace_name_string.as_c_char_ptr(),
namespace_name_string.as_ptr(),
namespace_name_string.len(),
false, // ExportSymbols (only relevant for C++ anonymous namespaces)
llvm::False, // ExportSymbols (only relevant for C++ anonymous namespaces)
)
};

View file

@ -41,7 +41,7 @@ pub(crate) fn debug_context<'a, 'll, 'tcx>(
#[inline]
#[allow(non_snake_case)]
pub(crate) fn DIB<'a, 'll>(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> {
cx.dbg_cx.as_ref().unwrap().builder
cx.dbg_cx.as_ref().unwrap().builder.as_ref()
}
pub(crate) fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {

View file

@ -1,3 +1,15 @@
//! Bindings to the LLVM-C API (`LLVM*`), and to our own `extern "C"` wrapper
//! functions around the unstable LLVM C++ API (`LLVMRust*`).
//!
//! ## Passing pointer/length strings as `*const c_uchar`
//!
//! Normally it's a good idea for Rust-side bindings to match the corresponding
//! C-side function declarations as closely as possible. But when passing `&str`
//! or `&[u8]` data as a pointer/length pair, it's more convenient to declare
//! the Rust-side pointer as `*const c_uchar` instead of `*const c_char`.
//! Both pointer types have the same ABI, and using `*const c_uchar` avoids
//! the need for an extra cast from `*const u8` on the Rust side.
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
@ -5,17 +17,18 @@ use std::fmt::Debug;
use std::marker::PhantomData;
use std::ptr;
use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
use bitflags::bitflags;
use libc::{c_char, c_int, c_uchar, c_uint, c_ulonglong, c_void, size_t};
use rustc_macros::TryFromU32;
use rustc_target::spec::SymbolVisibility;
use super::RustString;
use super::debuginfo::{
DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator,
DIFile, DIFlags, DIGlobalVariableExpression, DILexicalBlock, DILocation, DINameSpace,
DISPFlags, DIScope, DISubprogram, DISubrange, DITemplateTypeParameter, DIType, DIVariable,
DebugEmissionKind, DebugNameTableKind,
DIFile, DIFlags, DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram,
DISubrange, DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind,
};
use crate::llvm;
/// In the LLVM-C API, boolean values are passed as `typedef int LLVMBool`,
/// which has a different ABI from Rust or C++ `bool`.
@ -789,12 +802,50 @@ pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void
pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
pub mod debuginfo {
use std::ptr;
use bitflags::bitflags;
use super::{InvariantOpaque, Metadata};
use crate::llvm::{self, Module};
/// Opaque target type for references to an LLVM debuginfo builder.
///
/// `&'_ DIBuilder<'ll>` corresponds to `LLVMDIBuilderRef`, which is the
/// LLVM-C wrapper for `DIBuilder *`.
///
/// Debuginfo builders are created and destroyed during codegen, so the
/// builder reference typically has a shorter lifetime than the LLVM
/// session (`'ll`) that it participates in.
#[repr(C)]
pub struct DIBuilder<'a>(InvariantOpaque<'a>);
pub struct DIBuilder<'ll>(InvariantOpaque<'ll>);
/// Owning pointer to a `DIBuilder<'ll>` that will dispose of the builder
/// when dropped. Use `.as_ref()` to get the underlying `&DIBuilder`
/// needed for debuginfo FFI calls.
pub(crate) struct DIBuilderBox<'ll> {
raw: ptr::NonNull<DIBuilder<'ll>>,
}
impl<'ll> DIBuilderBox<'ll> {
pub(crate) fn new(llmod: &'ll Module) -> Self {
let raw = unsafe { llvm::LLVMCreateDIBuilder(llmod) };
let raw = ptr::NonNull::new(raw).unwrap();
Self { raw }
}
pub(crate) fn as_ref(&self) -> &DIBuilder<'ll> {
// SAFETY: This is an owning pointer, so `&DIBuilder` is valid
// for as long as `&self` is.
unsafe { self.raw.as_ref() }
}
}
impl<'ll> Drop for DIBuilderBox<'ll> {
fn drop(&mut self) {
unsafe { llvm::LLVMDisposeDIBuilder(self.raw) };
}
}
pub type DIDescriptor = Metadata;
pub type DILocation = Metadata;
@ -914,7 +965,6 @@ pub mod debuginfo {
}
}
use bitflags::bitflags;
// These values **must** match with LLVMRustAllocKindFlags
bitflags! {
#[repr(transparent)]
@ -1675,6 +1725,50 @@ unsafe extern "C" {
) -> &'a Value;
}
// FFI bindings for `DIBuilder` functions in the LLVM-C API.
// Try to keep these in the same order as in `llvm/include/llvm-c/DebugInfo.h`.
//
// FIXME(#134001): Audit all `Option` parameters, especially in lists, to check
// that they really are nullable on the C/C++ side. LLVM doesn't appear to
// actually document which ones are nullable.
unsafe extern "C" {
pub(crate) fn LLVMCreateDIBuilder<'ll>(M: &'ll Module) -> *mut DIBuilder<'ll>;
pub(crate) fn LLVMDisposeDIBuilder<'ll>(Builder: ptr::NonNull<DIBuilder<'ll>>);
pub(crate) fn LLVMDIBuilderFinalize<'ll>(Builder: &DIBuilder<'ll>);
pub(crate) fn LLVMDIBuilderCreateNameSpace<'ll>(
Builder: &DIBuilder<'ll>,
ParentScope: Option<&'ll Metadata>,
Name: *const c_uchar,
NameLen: size_t,
ExportSymbols: llvm::Bool,
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreateLexicalBlock<'ll>(
Builder: &DIBuilder<'ll>,
Scope: &'ll Metadata,
File: &'ll Metadata,
Line: c_uint,
Column: c_uint,
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreateLexicalBlockFile<'ll>(
Builder: &DIBuilder<'ll>,
Scope: &'ll Metadata,
File: &'ll Metadata,
Discriminator: c_uint, // (optional "DWARF path discriminator"; default is 0)
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreateDebugLocation<'ll>(
Ctx: &'ll Context,
Line: c_uint,
Column: c_uint,
Scope: &'ll Metadata,
InlinedAt: Option<&'ll Metadata>,
) -> &'ll Metadata;
}
#[link(name = "llvm-wrapper", kind = "static")]
unsafe extern "C" {
pub fn LLVMRustInstallErrorHandlers();
@ -1942,12 +2036,6 @@ unsafe extern "C" {
ValueLen: size_t,
);
pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>;
pub fn LLVMRustDIBuilderDispose<'a>(Builder: &'a mut DIBuilder<'a>);
pub fn LLVMRustDIBuilderFinalize(Builder: &DIBuilder<'_>);
pub fn LLVMRustDIBuilderCreateCompileUnit<'a>(
Builder: &DIBuilder<'a>,
Lang: c_uint,
@ -2110,20 +2198,6 @@ unsafe extern "C" {
Type: &'a DIType,
) -> &'a DIDerivedType;
pub fn LLVMRustDIBuilderCreateLexicalBlock<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIScope,
File: &'a DIFile,
Line: c_uint,
Col: c_uint,
) -> &'a DILexicalBlock;
pub fn LLVMRustDIBuilderCreateLexicalBlockFile<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIScope,
File: &'a DIFile,
) -> &'a DILexicalBlock;
pub fn LLVMRustDIBuilderCreateStaticVariable<'a>(
Builder: &DIBuilder<'a>,
Context: Option<&'a DIScope>,
@ -2248,14 +2322,6 @@ unsafe extern "C" {
Ty: &'a DIType,
) -> &'a DITemplateTypeParameter;
pub fn LLVMRustDIBuilderCreateNameSpace<'a>(
Builder: &DIBuilder<'a>,
Scope: Option<&'a DIScope>,
Name: *const c_char,
NameLen: size_t,
ExportSymbols: bool,
) -> &'a DINameSpace;
pub fn LLVMRustDICompositeTypeReplaceArrays<'a>(
Builder: &DIBuilder<'a>,
CompositeType: &'a DIType,
@ -2263,12 +2329,6 @@ unsafe extern "C" {
Params: Option<&'a DIArray>,
);
pub fn LLVMRustDIBuilderCreateDebugLocation<'a>(
Line: c_uint,
Column: c_uint,
Scope: &'a DIScope,
InlinedAt: Option<&'a DILocation>,
) -> &'a DILocation;
pub fn LLVMRustDILocationCloneWithBaseDiscriminator<'a>(
Location: &'a DILocation,
BD: c_uint,

View file

@ -741,6 +741,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let val = bx.tcx().sess.ub_checks();
bx.cx().const_bool(val)
}
mir::NullOp::ContractChecks => {
let val = bx.tcx().sess.contract_checks();
bx.cx().const_bool(val)
}
};
let tcx = self.cx.tcx();
OperandRef {

View file

@ -675,7 +675,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
Rvalue::Cast(_, _, _) => {}
Rvalue::NullaryOp(
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks,
NullOp::SizeOf
| NullOp::AlignOf
| NullOp::OffsetOf(_)
| NullOp::UbChecks
| NullOp::ContractChecks,
_,
) => {}
Rvalue::ShallowInitBox(_, _) => {}

View file

@ -293,6 +293,9 @@ pub trait Machine<'tcx>: Sized {
/// Determines the result of a `NullaryOp::UbChecks` invocation.
fn ub_checks(_ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool>;
/// Determines the result of a `NullaryOp::ContractChecks` invocation.
fn contract_checks(_ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool>;
/// Called when the interpreter encounters a `StatementKind::ConstEvalCounter` instruction.
/// You can use this to detect long or endlessly running programs.
#[inline]
@ -679,6 +682,13 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
interp_ok(true)
}
#[inline(always)]
fn contract_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> {
// We can't look at `tcx.sess` here as that can differ across crates, which can lead to
// unsound differences in evaluating the same constant at different instantiation sites.
interp_ok(true)
}
#[inline(always)]
fn adjust_global_allocation<'b>(
_ecx: &InterpCx<$tcx, Self>,

View file

@ -537,6 +537,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
ImmTy::from_uint(val, usize_layout())
}
UbChecks => ImmTy::from_bool(M::ub_checks(self)?, *self.tcx),
ContractChecks => ImmTy::from_bool(M::contract_checks(self)?, *self.tcx),
})
}
}

View file

@ -8,7 +8,7 @@ edition = "2021"
arrayvec = { version = "0.7", default-features = false }
bitflags = "2.4.1"
either = "1.0"
elsa = "=1.7.1"
elsa = "1.11.0"
ena = "0.14.3"
indexmap = "2.4.0"
jobserver_crate = { version = "0.1.28", package = "jobserver" }

View file

@ -19,6 +19,7 @@ const GATED_CFGS: &[GatedCfg] = &[
// (name in cfg, feature, function to check if the feature is enabled)
(sym::overflow_checks, sym::cfg_overflow_checks, Features::cfg_overflow_checks),
(sym::ub_checks, sym::cfg_ub_checks, Features::cfg_ub_checks),
(sym::contract_checks, sym::cfg_contract_checks, Features::cfg_contract_checks),
(sym::target_thread_local, sym::cfg_target_thread_local, Features::cfg_target_thread_local),
(
sym::target_has_atomic_equal_alignment,

View file

@ -403,6 +403,8 @@ declare_features! (
(unstable, c_variadic, "1.34.0", Some(44930)),
/// Allows the use of `#[cfg(<true/false>)]`.
(unstable, cfg_boolean_literals, "1.83.0", Some(131204)),
/// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled.
(unstable, cfg_contract_checks, "CURRENT_RUSTC_VERSION", Some(128044)),
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
(unstable, cfg_overflow_checks, "1.71.0", Some(111466)),
/// Provides the relocation model information as cfg entry
@ -445,6 +447,10 @@ declare_features! (
(unstable, const_trait_impl, "1.42.0", Some(67792)),
/// Allows the `?` operator in const contexts.
(unstable, const_try, "1.56.0", Some(74935)),
/// Allows use of contracts attributes.
(incomplete, contracts, "CURRENT_RUSTC_VERSION", Some(128044)),
/// Allows access to internal machinery used to implement contracts.
(internal, contracts_internals, "CURRENT_RUSTC_VERSION", Some(128044)),
/// Allows coroutines to be cloned.
(unstable, coroutine_clone, "1.65.0", Some(95360)),
/// Allows defining coroutines.

View file

@ -2654,6 +2654,8 @@ pub enum LocalSource {
/// A desugared `expr = expr`, where the LHS is a tuple, struct, array or underscore expression.
/// The span is that of the `=` sign.
AssignDesugar(Span),
/// A contract `#[ensures(..)]` attribute injects a let binding for the check that runs at point of return.
Contract,
}
/// Hints at the original code for a `match _ { .. }`.

View file

@ -423,6 +423,10 @@ language_item_table! {
String, sym::String, string, Target::Struct, GenericRequirement::None;
CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None;
// Experimental lang items for implementing contract pre- and post-condition checking.
ContractBuildCheckEnsures, sym::contract_build_check_ensures, contract_build_check_ensures_fn, Target::Fn, GenericRequirement::None;
ContractCheckRequires, sym::contract_check_requires, contract_check_requires_fn, Target::Fn, GenericRequirement::None;
}
pub enum GenericRequirement {

View file

@ -132,6 +132,9 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
| sym::aggregate_raw_ptr
| sym::ptr_metadata
| sym::ub_checks
| sym::contract_checks
| sym::contract_check_requires
| sym::contract_check_ensures
| sym::fadd_algebraic
| sym::fsub_algebraic
| sym::fmul_algebraic
@ -219,6 +222,16 @@ pub fn check_intrinsic_type(
}
};
(n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
} else if intrinsic_name == sym::contract_check_ensures {
// contract_check_ensures::<'a, Ret, C>(&'a Ret, C)
// where C: impl Fn(&'a Ret) -> bool,
//
// so: two type params, one lifetime param, 0 const params, two inputs, no return
let p = generics.param_at(0, tcx);
let r = ty::Region::new_early_param(tcx, p.to_early_bound_region_data());
let ref_ret = Ty::new_imm_ref(tcx, r, param(1));
(2, 1, 0, vec![ref_ret, param(2)], tcx.types.unit, hir::Safety::Safe)
} else {
let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
let (n_tps, n_cts, inputs, output) = match intrinsic_name {
@ -610,6 +623,11 @@ pub fn check_intrinsic_type(
sym::box_new => (1, 0, vec![param(0)], Ty::new_box(tcx, param(0))),
// contract_checks() -> bool
sym::contract_checks => (0, 0, Vec::new(), tcx.types.bool),
// contract_check_requires::<C>(C) -> bool, where C: impl Fn() -> bool
sym::contract_check_requires => (1, 0, vec![param(0)], tcx.types.unit),
sym::simd_eq
| sym::simd_ne
| sym::simd_lt

View file

@ -831,7 +831,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
// prim -> prim
(Int(CEnum), Int(_)) => {
self.cenum_impl_drop_lint(fcx);
self.err_if_cenum_impl_drop(fcx);
Ok(CastKind::EnumCast)
}
(Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
@ -1091,19 +1091,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
}
}
fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
fn err_if_cenum_impl_drop(&self, fcx: &FnCtxt<'a, 'tcx>) {
if let ty::Adt(d, _) = self.expr_ty.kind()
&& d.has_dtor(fcx.tcx)
{
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
fcx.tcx.emit_node_span_lint(
lint::builtin::CENUM_IMPL_DROP_CAST,
self.expr.hir_id,
self.span,
errors::CastEnumDrop { expr_ty, cast_ty },
);
fcx.dcx().emit_err(errors::CastEnumDrop { span: self.span, expr_ty, cast_ty });
}
}

View file

@ -677,9 +677,11 @@ pub(crate) struct CannotCastToBool<'tcx> {
pub help: CannotCastToBoolHelp,
}
#[derive(LintDiagnostic)]
#[derive(Diagnostic)]
#[diag(hir_typeck_cast_enum_drop)]
pub(crate) struct CastEnumDrop<'tcx> {
#[primary_span]
pub span: Span,
pub expr_ty: Ty<'tcx>,
pub cast_ty: Ty<'tcx>,
}

View file

@ -269,6 +269,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// diverging expression (e.g. it arose from desugaring of `try { return }`),
// we skip issuing a warning because it is autogenerated code.
ExprKind::Call(..) if expr.span.is_desugaring(DesugaringKind::TryBlock) => {}
// Likewise, do not lint unreachable code injected via contracts desugaring.
ExprKind::Call(..) if expr.span.is_desugaring(DesugaringKind::Contract) => {}
ExprKind::Call(callee, _) => self.warn_if_unreachable(expr.hir_id, callee.span, "call"),
ExprKind::MethodCall(segment, ..) => {
self.warn_if_unreachable(expr.hir_id, segment.ident.span, "call")

View file

@ -570,8 +570,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
let ty = match &lt.kind {
rustc_hir::PatExprKind::Lit { lit, .. } => {
self.check_expr_lit(lit, Expectation::NoExpectation)
rustc_hir::PatExprKind::Lit { lit, negated } => {
let ty = self.check_expr_lit(lit, Expectation::NoExpectation);
if *negated {
self.register_bound(
ty,
self.tcx.require_lang_item(LangItem::Neg, Some(lt.span)),
ObligationCause::dummy_with_span(lt.span),
);
}
ty
}
rustc_hir::PatExprKind::ConstBlock(c) => {
self.check_expr_const_block(c, Expectation::NoExpectation)

View file

@ -595,6 +595,11 @@ fn register_builtins(store: &mut LintStore) {
<https://github.com/rust-lang/rust/pull/125380> for more information",
);
store.register_removed("unsupported_calling_conventions", "converted into hard error");
store.register_removed(
"cenum_impl_drop_cast",
"converted into hard error, \
see <https://github.com/rust-lang/rust/issues/73333> for more information",
);
}
fn register_internals(store: &mut LintStore) {

View file

@ -27,7 +27,6 @@ declare_lint_pass! {
BARE_TRAIT_OBJECTS,
BINDINGS_WITH_VARIANT_NAME,
BREAK_WITH_LABEL_AND_LOOP,
CENUM_IMPL_DROP_CAST,
COHERENCE_LEAK_CHECK,
CONFLICTING_REPR_HINTS,
CONST_EVALUATABLE_UNCHECKED,
@ -2612,58 +2611,6 @@ declare_lint! {
@edition Edition2024 => Warn;
}
declare_lint! {
/// The `cenum_impl_drop_cast` lint detects an `as` cast of a field-less
/// `enum` that implements [`Drop`].
///
/// [`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html
///
/// ### Example
///
/// ```rust,compile_fail
/// # #![allow(unused)]
/// enum E {
/// A,
/// }
///
/// impl Drop for E {
/// fn drop(&mut self) {
/// println!("Drop");
/// }
/// }
///
/// fn main() {
/// let e = E::A;
/// let i = e as u32;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Casting a field-less `enum` that does not implement [`Copy`] to an
/// integer moves the value without calling `drop`. This can result in
/// surprising behavior if it was expected that `drop` should be called.
/// Calling `drop` automatically would be inconsistent with other move
/// operations. Since neither behavior is clear or consistent, it was
/// decided that a cast of this nature will no longer be allowed.
///
/// This is a [future-incompatible] lint to transition this to a hard error
/// in the future. See [issue #73333] for more details.
///
/// [future-incompatible]: ../index.md#future-incompatible-lints
/// [issue #73333]: https://github.com/rust-lang/rust/issues/73333
/// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
pub CENUM_IMPL_DROP_CAST,
Deny,
"a C-like enum implementing Drop is cast",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
reference: "issue #73333 <https://github.com/rust-lang/rust/issues/73333>",
};
}
declare_lint! {
/// The `fuzzy_provenance_casts` lint detects an `as` cast between an integer
/// and a pointer.

View file

@ -1003,10 +1003,6 @@ extern "C" void LLVMRustDIBuilderDispose(LLVMDIBuilderRef Builder) {
delete unwrap(Builder);
}
extern "C" void LLVMRustDIBuilderFinalize(LLVMDIBuilderRef Builder) {
unwrap(Builder)->finalize();
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit(
LLVMDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef,
const char *Producer, size_t ProducerLen, bool isOptimized,
@ -1183,20 +1179,6 @@ LLVMRustDIBuilderCreateQualifiedType(LLVMDIBuilderRef Builder, unsigned Tag,
unwrap(Builder)->createQualifiedType(Tag, unwrapDI<DIType>(Type)));
}
extern "C" LLVMMetadataRef
LLVMRustDIBuilderCreateLexicalBlock(LLVMDIBuilderRef Builder,
LLVMMetadataRef Scope, LLVMMetadataRef File,
unsigned Line, unsigned Col) {
return wrap(unwrap(Builder)->createLexicalBlock(
unwrapDI<DIDescriptor>(Scope), unwrapDI<DIFile>(File), Line, Col));
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlockFile(
LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File) {
return wrap(unwrap(Builder)->createLexicalBlockFile(
unwrapDI<DIDescriptor>(Scope), unwrapDI<DIFile>(File)));
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable(
LLVMDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name,
size_t NameLen, const char *LinkageName, size_t LinkageNameLen,
@ -1325,14 +1307,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
unwrapDI<DIType>(Ty), IsDefault));
}
extern "C" LLVMMetadataRef
LLVMRustDIBuilderCreateNameSpace(LLVMDIBuilderRef Builder,
LLVMMetadataRef Scope, const char *Name,
size_t NameLen, bool ExportSymbols) {
return wrap(unwrap(Builder)->createNameSpace(
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ExportSymbols));
}
extern "C" void LLVMRustDICompositeTypeReplaceArrays(
LLVMDIBuilderRef Builder, LLVMMetadataRef CompositeTy,
LLVMMetadataRef Elements, LLVMMetadataRef Params) {
@ -1341,16 +1315,6 @@ extern "C" void LLVMRustDICompositeTypeReplaceArrays(
DINodeArray(unwrap<MDTuple>(Params)));
}
extern "C" LLVMMetadataRef
LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
LLVMMetadataRef ScopeRef,
LLVMMetadataRef InlinedAt) {
MDNode *Scope = unwrapDIPtr<MDNode>(ScopeRef);
DILocation *Loc = DILocation::get(Scope->getContext(), Line, Column, Scope,
unwrapDIPtr<MDNode>(InlinedAt));
return wrap(Loc);
}
extern "C" LLVMMetadataRef
LLVMRustDILocationCloneWithBaseDiscriminator(LLVMMetadataRef Location,
unsigned BD) {

View file

@ -1104,6 +1104,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
NullOp::AlignOf => write!(fmt, "AlignOf({t})"),
NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"),
NullOp::UbChecks => write!(fmt, "UbChecks()"),
NullOp::ContractChecks => write!(fmt, "ContractChecks()"),
}
}
ThreadLocalRef(did) => ty::tls::with(|tcx| {

View file

@ -1591,6 +1591,9 @@ pub enum NullOp<'tcx> {
/// Returns whether we should perform some UB-checking at runtime.
/// See the `ub_checks` intrinsic docs for details.
UbChecks,
/// Returns whether we should perform contract-checking at runtime.
/// See the `contract_checks` intrinsic docs for details.
ContractChecks,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]

View file

@ -230,7 +230,8 @@ impl<'tcx> Rvalue<'tcx> {
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
tcx.types.usize
}
Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool,
Rvalue::NullaryOp(NullOp::ContractChecks, _)
| Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool,
Rvalue::Aggregate(ref ak, ref ops) => match **ak {
AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64),
AggregateKind::Tuple => {

View file

@ -105,13 +105,12 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>
return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar));
}
let trunc = |n| {
let width = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) {
Ok(layout) => layout.size,
Err(_) => {
tcx.dcx().bug(format!("couldn't compute width of literal: {:?}", lit_input.lit))
}
};
let trunc = |n, width: ty::UintTy| {
let width = width
.normalize(tcx.data_layout.pointer_size.bits().try_into().unwrap())
.bit_width()
.unwrap();
let width = Size::from_bits(width);
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
let result = width.truncate(n);
trace!("trunc result: {}", result);
@ -145,9 +144,11 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
}
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() })
}
(ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => trunc(n.get(), *ui),
(ast::LitKind::Int(n, _), ty::Int(i)) => trunc(
if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() },
i.to_unsigned(),
),
(ast::LitKind::Float(n, _), ty::Float(fty)) => {
parse_float_into_constval(*n, *fty, neg).unwrap()
}

View file

@ -1,4 +1,5 @@
use rustc_ast as ast;
use rustc_abi::Size;
use rustc_ast::{self as ast};
use rustc_hir::LangItem;
use rustc_middle::bug;
use rustc_middle::mir::interpret::LitToConstInput;
@ -17,13 +18,12 @@ pub(crate) fn lit_to_const<'tcx>(
return ty::Const::new_error(tcx, guar);
}
let trunc = |n| {
let width = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) {
Ok(layout) => layout.size,
Err(_) => {
tcx.dcx().bug(format!("couldn't compute width of literal: {:?}", lit_input.lit))
}
};
let trunc = |n, width: ty::UintTy| {
let width = width
.normalize(tcx.data_layout.pointer_size.bits().try_into().unwrap())
.bit_width()
.unwrap();
let width = Size::from_bits(width);
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
let result = width.truncate(n);
trace!("trunc result: {}", result);
@ -55,9 +55,15 @@ pub(crate) fn lit_to_const<'tcx>(
let bytes = data as &[u8];
ty::ValTree::from_raw_bytes(tcx, bytes)
}
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
let scalar_int =
trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() });
(ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => {
let scalar_int = trunc(n.get(), *ui);
ty::ValTree::from_scalar_int(scalar_int)
}
(ast::LitKind::Int(n, _), ty::Int(i)) => {
let scalar_int = trunc(
if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() },
i.to_unsigned(),
);
ty::ValTree::from_scalar_int(scalar_int)
}
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),

View file

@ -417,7 +417,11 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
| Rvalue::Discriminant(..)
| Rvalue::Len(..)
| Rvalue::NullaryOp(
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbChecks,
NullOp::SizeOf
| NullOp::AlignOf
| NullOp::OffsetOf(..)
| NullOp::UbChecks
| NullOp::ContractChecks,
_,
) => {}
}

View file

@ -545,6 +545,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
.offset_of_subfield(self.typing_env(), layout, fields.iter())
.bytes(),
NullOp::UbChecks => return None,
NullOp::ContractChecks => return None,
};
let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
let imm = ImmTy::from_uint(val, usize_layout);

View file

@ -629,6 +629,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
.offset_of_subfield(self.typing_env, op_layout, fields.iter())
.bytes(),
NullOp::UbChecks => return None,
NullOp::ContractChecks => return None,
};
ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into()
}

View file

@ -34,6 +34,17 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
});
terminator.kind = TerminatorKind::Goto { target };
}
sym::contract_checks => {
let target = target.unwrap();
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
*destination,
Rvalue::NullaryOp(NullOp::ContractChecks, tcx.types.bool),
))),
});
terminator.kind = TerminatorKind::Goto { target };
}
sym::forget => {
let target = target.unwrap();
block.statements.push(Statement {

View file

@ -457,6 +457,7 @@ impl<'tcx> Validator<'_, 'tcx> {
NullOp::AlignOf => {}
NullOp::OffsetOf(_) => {}
NullOp::UbChecks => {}
NullOp::ContractChecks => {}
},
Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),

View file

@ -1379,7 +1379,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
Rvalue::Repeat(_, _)
| Rvalue::ThreadLocalRef(_)
| Rvalue::RawPtr(_, _)
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _)
| Rvalue::NullaryOp(
NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks | NullOp::ContractChecks,
_,
)
| Rvalue::Discriminant(_) => {}
Rvalue::WrapUnsafeBinder(op, ty) => {

View file

@ -4,7 +4,7 @@ use rustc_ast::{
WhereClause, token,
};
use rustc_errors::{Applicability, PResult};
use rustc_span::{Ident, Span, kw};
use rustc_span::{Ident, Span, kw, sym};
use thin_vec::ThinVec;
use super::{ForceCollect, Parser, Trailing, UsePreAttrPos};
@ -297,6 +297,42 @@ impl<'a> Parser<'a> {
})
}
/// Parses an experimental fn contract
/// (`contract_requires(WWW) contract_ensures(ZZZ)`)
pub(super) fn parse_contract(
&mut self,
) -> PResult<'a, Option<rustc_ast::ptr::P<ast::FnContract>>> {
let gate = |span| {
if self.psess.contract_attribute_spans.contains(span) {
// span was generated via a builtin contracts attribute, so gate as end-user visible
self.psess.gated_spans.gate(sym::contracts, span);
} else {
// span was not generated via a builtin contracts attribute, so gate as internal machinery
self.psess.gated_spans.gate(sym::contracts_internals, span);
}
};
let requires = if self.eat_keyword_noexpect(exp!(ContractRequires).kw) {
let precond = self.parse_expr()?;
gate(precond.span);
Some(precond)
} else {
None
};
let ensures = if self.eat_keyword_noexpect(exp!(ContractEnsures).kw) {
let postcond = self.parse_expr()?;
gate(postcond.span);
Some(postcond)
} else {
None
};
if requires.is_none() && ensures.is_none() {
Ok(None)
} else {
Ok(Some(rustc_ast::ptr::P(ast::FnContract { requires, ensures })))
}
}
/// Parses an optional where-clause.
///
/// ```ignore (only-for-syntax-highlight)

View file

@ -213,9 +213,12 @@ impl<'a> Parser<'a> {
self.parse_use_item()?
} else if self.check_fn_front_matter(check_pub, case) {
// FUNCTION ITEM
let (ident, sig, generics, body) =
let (ident, sig, generics, contract, body) =
self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?;
(ident, ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, body })))
(
ident,
ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, contract, body })),
)
} else if self.eat_keyword(exp!(Extern)) {
if self.eat_keyword(exp!(Crate)) {
// EXTERN CRATE
@ -2372,7 +2375,7 @@ impl<'a> Parser<'a> {
sig_lo: Span,
vis: &Visibility,
case: Case,
) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
) -> PResult<'a, (Ident, FnSig, Generics, Option<P<FnContract>>, Option<P<Block>>)> {
let fn_span = self.token.span;
let header = self.parse_fn_front_matter(vis, case)?; // `const ... fn`
let ident = self.parse_ident()?; // `foo`
@ -2398,6 +2401,8 @@ impl<'a> Parser<'a> {
// inside `parse_fn_body()`.
let fn_params_end = self.prev_token.span.shrink_to_hi();
let contract = self.parse_contract()?;
generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
// `fn_params_end` is needed only when it's followed by a where clause.
@ -2409,7 +2414,7 @@ impl<'a> Parser<'a> {
let body =
self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body, fn_params_end)?;
let fn_sig_span = sig_lo.to(sig_hi);
Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body))
Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, contract, body))
}
/// Provide diagnostics when function body is not found

View file

@ -83,6 +83,8 @@ pub enum TokenType {
KwCatch,
KwConst,
KwContinue,
KwContractEnsures,
KwContractRequires,
KwCrate,
KwDefault,
KwDyn,
@ -217,6 +219,8 @@ impl TokenType {
KwCatch,
KwConst,
KwContinue,
KwContractEnsures,
KwContractRequires,
KwCrate,
KwDefault,
KwDyn,
@ -289,6 +293,8 @@ impl TokenType {
TokenType::KwCatch => Some(kw::Catch),
TokenType::KwConst => Some(kw::Const),
TokenType::KwContinue => Some(kw::Continue),
TokenType::KwContractEnsures => Some(kw::ContractEnsures),
TokenType::KwContractRequires => Some(kw::ContractRequires),
TokenType::KwCrate => Some(kw::Crate),
TokenType::KwDefault => Some(kw::Default),
TokenType::KwDyn => Some(kw::Dyn),
@ -519,6 +525,8 @@ macro_rules! exp {
(Catch) => { exp!(@kw, Catch, KwCatch) };
(Const) => { exp!(@kw, Const, KwConst) };
(Continue) => { exp!(@kw, Continue, KwContinue) };
(ContractEnsures) => { exp!(@kw, ContractEnsures, KwContractEnsures) };
(ContractRequires) => { exp!(@kw, ContractRequires, KwContractRequires) };
(Crate) => { exp!(@kw, Crate, KwCrate) };
(Default) => { exp!(@kw, Default, KwDefault) };
(Dyn) => { exp!(@kw, Dyn, KwDyn) };

View file

@ -174,10 +174,13 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
_ctxt,
_ident,
_vis,
Fn { sig: FnSig { header, decl, span: _ }, generics, body, .. },
Fn { sig: FnSig { header, decl, span: _ }, generics, contract, body, .. },
) if let Some(coroutine_kind) = header.coroutine_kind => {
self.visit_fn_header(header);
self.visit_generics(generics);
if let Some(contract) = contract {
self.visit_contract(contract);
}
// For async functions, we need to create their inner defs inside of a
// closure to match their desugared representation. Besides that,

View file

@ -1019,7 +1019,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
// Create a label rib for the function.
this.with_label_rib(RibKind::FnOrCoroutine, |this| {
match fn_kind {
FnKind::Fn(_, _, _, Fn { sig, generics, body, .. }) => {
FnKind::Fn(_, _, _, Fn { sig, generics, contract, body, .. }) => {
this.visit_generics(generics);
let declaration = &sig.decl;
@ -1046,6 +1046,10 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
},
);
if let Some(contract) = contract {
this.visit_contract(contract);
}
if let Some(body) = body {
// Ignore errors in function bodies if this is rustdoc
// Be sure not to set this until the function signature has been resolved.

View file

@ -119,6 +119,7 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) {
(sym::overflow_checks, None) => disallow(cfg, "-C overflow-checks"),
(sym::debug_assertions, None) => disallow(cfg, "-C debug-assertions"),
(sym::ub_checks, None) => disallow(cfg, "-Z ub-checks"),
(sym::contract_checks, None) => disallow(cfg, "-Z contract-checks"),
(sym::sanitize, None | Some(_)) => disallow(cfg, "-Z sanitizer"),
(
sym::sanitizer_cfi_generalize_pointers | sym::sanitizer_cfi_normalize_integers,
@ -300,6 +301,11 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg {
if sess.is_nightly_build() && sess.opts.unstable_opts.emscripten_wasm_eh {
ins_none!(sym::emscripten_wasm_eh);
}
if sess.contract_checks() {
ins_none!(sym::contract_checks);
}
ret
}
@ -464,6 +470,7 @@ impl CheckCfg {
ins!(sym::target_thread_local, no_values);
ins!(sym::ub_checks, no_values);
ins!(sym::contract_checks, no_values);
ins!(sym::unix, no_values);
ins!(sym::windows, no_values);

View file

@ -2114,6 +2114,8 @@ options! {
"the backend to use"),
combine_cgu: bool = (false, parse_bool, [TRACKED],
"combine CGUs into a single one"),
contract_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
"emit runtime checks for contract pre- and post-conditions (default: no)"),
coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED],
"control details of coverage instrumentation"),
crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],

View file

@ -207,6 +207,10 @@ pub struct ParseSess {
pub config: Cfg,
pub check_config: CheckCfg,
pub edition: Edition,
/// Places where contract attributes were expanded into unstable AST forms.
/// This is used to allowlist those spans (so that we only check them against the feature
/// gate for the externally visible interface, and not internal implmentation machinery).
pub contract_attribute_spans: AppendOnlyVec<Span>,
/// Places where raw identifiers were used. This is used to avoid complaining about idents
/// clashing with keywords in new editions.
pub raw_identifier_spans: AppendOnlyVec<Span>,
@ -255,6 +259,7 @@ impl ParseSess {
config: Cfg::default(),
check_config: CheckCfg::default(),
edition: ExpnId::root().expn_data().edition,
contract_attribute_spans: Default::default(),
raw_identifier_spans: Default::default(),
bad_unicode_identifiers: Lock::new(Default::default()),
source_map,

View file

@ -709,6 +709,10 @@ impl Session {
self.opts.unstable_opts.ub_checks.unwrap_or(self.opts.debug_assertions)
}
pub fn contract_checks(&self) -> bool {
self.opts.unstable_opts.contract_checks.unwrap_or(false)
}
pub fn relocation_model(&self) -> RelocModel {
self.opts.cg.relocation_model.unwrap_or(self.target.relocation_model)
}

View file

@ -291,6 +291,7 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
indices.iter().map(|idx| idx.stable(tables)).collect(),
),
UbChecks => stable_mir::mir::NullOp::UbChecks,
ContractChecks => stable_mir::mir::NullOp::ContractChecks,
}
}
}

View file

@ -1163,6 +1163,8 @@ pub enum DesugaringKind {
WhileLoop,
/// `async Fn()` bound modifier
BoundModifier,
/// Calls to contract checks (`#[requires]` to precond, `#[ensures]` to postcond)
Contract,
}
impl DesugaringKind {
@ -1179,6 +1181,7 @@ impl DesugaringKind {
DesugaringKind::ForLoop => "`for` loop",
DesugaringKind::WhileLoop => "`while` loop",
DesugaringKind::BoundModifier => "trait bound modifier",
DesugaringKind::Contract => "contract check",
}
}
}

View file

@ -118,6 +118,8 @@ symbols! {
MacroRules: "macro_rules",
Raw: "raw",
Reuse: "reuse",
ContractEnsures: "contract_ensures",
ContractRequires: "contract_requires",
Safe: "safe",
Union: "union",
Yeet: "yeet",
@ -569,6 +571,7 @@ symbols! {
cfg_attr,
cfg_attr_multi,
cfg_boolean_literals,
cfg_contract_checks,
cfg_doctest,
cfg_emscripten_wasm_eh,
cfg_eval,
@ -678,6 +681,14 @@ symbols! {
const_ty_placeholder: "<const_ty>",
constant,
constructor,
contract_build_check_ensures,
contract_check_ensures,
contract_check_requires,
contract_checks,
contracts,
contracts_ensures,
contracts_internals,
contracts_requires,
convert_identity,
copy,
copy_closures,

View file

@ -18,6 +18,11 @@ pub(crate) fn target() -> Target {
pointer_width: 32,
data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
arch: "powerpc".into(),
options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
options: TargetOptions {
endian: Endian::Big,
features: "+secure-plt".into(),
mcount: "_mcount".into(),
..base
},
}
}

View file

@ -21,6 +21,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
abi: "spe".into(),
endian: Endian::Big,
features: "+secure-plt".into(),
mcount: "_mcount".into(),
..base
},

View file

@ -608,7 +608,8 @@ impl Rvalue {
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
Ok(Ty::usize_ty())
}
Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
Rvalue::NullaryOp(NullOp::ContractChecks, _)
| Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
Rvalue::Aggregate(ak, ops) => match *ak {
AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
AggregateKind::Tuple => Ok(Ty::new_tuple(
@ -1007,6 +1008,8 @@ pub enum NullOp {
OffsetOf(Vec<(VariantIdx, FieldIdx)>),
/// cfg!(ub_checks), but at codegen time
UbChecks,
/// cfg!(contract_checks), but at codegen time
ContractChecks,
}
impl Operand {

View file

@ -61,9 +61,9 @@ dependencies = [
[[package]]
name = "compiler_builtins"
version = "0.1.143"
version = "0.1.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85ba2077e3eab3dd81be4ece6b7fb2ad0887c1fb813e9a45400baf75c6c7c29"
checksum = "da0705f5abaaab7168ccc14f8f340ded61be2bd3ebea86b9834b6acbc8495de8"
dependencies = [
"cc",
"rustc-std-workspace-core",

View file

@ -10,7 +10,7 @@ edition = "2021"
[dependencies]
core = { path = "../core" }
compiler_builtins = { version = "=0.1.143", features = ['rustc-dep-of-std'] }
compiler_builtins = { version = "=0.1.145", features = ['rustc-dep-of-std'] }
[dev-dependencies]
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }

View file

@ -0,0 +1,21 @@
//! Unstable module containing the unstable contracts lang items and attribute macros.
#![cfg(not(bootstrap))]
pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires};
/// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }`
/// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }`
/// (including the implicit return of the tail expression, if any).
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
#[lang = "contract_build_check_ensures"]
#[track_caller]
pub fn build_check_ensures<Ret, C>(cond: C) -> impl (Fn(Ret) -> Ret) + Copy
where
C: for<'a> Fn(&'a Ret) -> bool + Copy + 'static,
{
#[track_caller]
move |ret| {
crate::intrinsics::contract_check_ensures(&ret, cond);
ret
}
}

View file

@ -1228,6 +1228,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
/// assert_eq!(format!("{:?}", wrapped), "'a'");
/// ```
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
#[must_use = "returns a type implementing Debug and Display, which do not have any effects unless they are used"]
pub fn from_fn<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result>(f: F) -> FromFn<F> {
FromFn(f)
}

View file

@ -4064,6 +4064,52 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize)
// Runtime NOP
}
/// Returns whether we should perform contract-checking at runtime.
///
/// This is meant to be similar to the ub_checks intrinsic, in terms
/// of not prematurely commiting at compile-time to whether contract
/// checking is turned on, so that we can specify contracts in libstd
/// and let an end user opt into turning them on.
#[cfg(not(bootstrap))]
#[rustc_const_unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
#[inline(always)]
#[rustc_intrinsic]
pub const fn contract_checks() -> bool {
// FIXME: should this be `false` or `cfg!(contract_checks)`?
// cfg!(contract_checks)
false
}
/// Check if the pre-condition `cond` has been met.
///
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
/// returns false.
#[cfg(not(bootstrap))]
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
#[lang = "contract_check_requires"]
#[rustc_intrinsic]
pub fn contract_check_requires<C: Fn() -> bool>(cond: C) {
if contract_checks() && !cond() {
// Emit no unwind panic in case this was a safety requirement.
crate::panicking::panic_nounwind("failed requires check");
}
}
/// Check if the post-condition `cond` has been met.
///
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
/// returns false.
#[cfg(not(bootstrap))]
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
#[rustc_intrinsic]
pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) {
if contract_checks() && !cond(ret) {
crate::panicking::panic_nounwind("failed ensures check");
}
}
/// The intrinsic will return the size stored in that vtable.
///
/// # Safety

View file

@ -113,6 +113,7 @@
#![feature(bigint_helper_methods)]
#![feature(bstr)]
#![feature(bstr_internals)]
#![feature(closure_track_caller)]
#![feature(const_carrying_mul_add)]
#![feature(const_eval_select)]
#![feature(core_intrinsics)]
@ -247,6 +248,10 @@ pub mod autodiff {
pub use crate::macros::builtin::autodiff;
}
#[cfg(not(bootstrap))]
#[unstable(feature = "contracts", issue = "128044")]
pub mod contracts;
#[unstable(feature = "cfg_match", issue = "115585")]
pub use crate::macros::cfg_match;

View file

@ -1777,6 +1777,32 @@ pub(crate) mod builtin {
/* compiler built-in */
}
/// Attribute macro applied to a function to give it a post-condition.
///
/// The attribute carries an argument token-tree which is
/// eventually parsed as a unary closure expression that is
/// invoked on a reference to the return value.
#[cfg(not(bootstrap))]
#[unstable(feature = "contracts", issue = "128044")]
#[allow_internal_unstable(contracts_internals)]
#[rustc_builtin_macro]
pub macro contracts_ensures($item:item) {
/* compiler built-in */
}
/// Attribute macro applied to a function to give it a precondition.
///
/// The attribute carries an argument token-tree which is
/// eventually parsed as an boolean expression with access to the
/// function's formal parameters
#[cfg(not(bootstrap))]
#[unstable(feature = "contracts", issue = "128044")]
#[allow_internal_unstable(contracts_internals)]
#[rustc_builtin_macro]
pub macro contracts_requires($item:item) {
/* compiler built-in */
}
/// Attribute macro applied to a function to register it as a handler for allocation failure.
///
/// See also [`std::alloc::handle_alloc_error`](../../../std/alloc/fn.handle_alloc_error.html).

View file

@ -182,10 +182,10 @@ pub use self::function::{Fn, FnMut, FnOnce};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::index::{Index, IndexMut};
pub(crate) use self::index_range::IndexRange;
#[unstable(feature = "one_sided_range", issue = "69780")]
pub use self::range::OneSidedRange;
#[stable(feature = "inclusive_range", since = "1.26.0")]
pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
#[unstable(feature = "one_sided_range", issue = "69780")]
pub use self::range::{OneSidedRange, OneSidedRangeBound};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]

View file

@ -979,6 +979,19 @@ impl<T> RangeBounds<T> for RangeToInclusive<&T> {
}
}
/// An internal helper for `split_off` functions indicating
/// which end a `OneSidedRange` is bounded on.
#[unstable(feature = "one_sided_range", issue = "69780")]
#[allow(missing_debug_implementations)]
pub enum OneSidedRangeBound {
/// The range is bounded inclusively from below and is unbounded above.
StartInclusive,
/// The range is bounded exclusively from above and is unbounded below.
End,
/// The range is bounded inclusively from above and is unbounded below.
EndInclusive,
}
/// `OneSidedRange` is implemented for built-in range types that are unbounded
/// on one side. For example, `a..`, `..b` and `..=c` implement `OneSidedRange`,
/// but `..`, `d..e`, and `f..=g` do not.
@ -986,13 +999,38 @@ impl<T> RangeBounds<T> for RangeToInclusive<&T> {
/// Types that implement `OneSidedRange<T>` must return `Bound::Unbounded`
/// from one of `RangeBounds::start_bound` or `RangeBounds::end_bound`.
#[unstable(feature = "one_sided_range", issue = "69780")]
pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> {}
pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> {
/// An internal-only helper function for `split_off` and
/// `split_off_mut` that returns the bound of the one-sided range.
fn bound(self) -> (OneSidedRangeBound, T);
}
#[unstable(feature = "one_sided_range", issue = "69780")]
impl<T> OneSidedRange<T> for RangeTo<T> where Self: RangeBounds<T> {}
impl<T> OneSidedRange<T> for RangeTo<T>
where
Self: RangeBounds<T>,
{
fn bound(self) -> (OneSidedRangeBound, T) {
(OneSidedRangeBound::End, self.end)
}
}
#[unstable(feature = "one_sided_range", issue = "69780")]
impl<T> OneSidedRange<T> for RangeFrom<T> where Self: RangeBounds<T> {}
impl<T> OneSidedRange<T> for RangeFrom<T>
where
Self: RangeBounds<T>,
{
fn bound(self) -> (OneSidedRangeBound, T) {
(OneSidedRangeBound::StartInclusive, self.start)
}
}
#[unstable(feature = "one_sided_range", issue = "69780")]
impl<T> OneSidedRange<T> for RangeToInclusive<T> where Self: RangeBounds<T> {}
impl<T> OneSidedRange<T> for RangeToInclusive<T>
where
Self: RangeBounds<T>,
{
fn bound(self) -> (OneSidedRangeBound, T) {
(OneSidedRangeBound::EndInclusive, self.end)
}
}

View file

@ -10,7 +10,7 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less};
use crate::intrinsics::{exact_div, unchecked_sub};
use crate::mem::{self, SizedTypeProperties};
use crate::num::NonZero;
use crate::ops::{Bound, OneSidedRange, Range, RangeBounds, RangeInclusive};
use crate::ops::{OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeInclusive};
use crate::panic::const_panic;
use crate::simd::{self, Simd};
use crate::ub_checks::assert_unsafe_precondition;
@ -83,14 +83,12 @@ pub use raw::{from_raw_parts, from_raw_parts_mut};
/// which to split. Returns `None` if the split index would overflow.
#[inline]
fn split_point_of(range: impl OneSidedRange<usize>) -> Option<(Direction, usize)> {
use Bound::*;
use OneSidedRangeBound::{End, EndInclusive, StartInclusive};
Some(match (range.start_bound(), range.end_bound()) {
(Unbounded, Excluded(i)) => (Direction::Front, *i),
(Unbounded, Included(i)) => (Direction::Front, i.checked_add(1)?),
(Excluded(i), Unbounded) => (Direction::Back, i.checked_add(1)?),
(Included(i), Unbounded) => (Direction::Back, *i),
_ => unreachable!(),
Some(match range.bound() {
(StartInclusive, i) => (Direction::Back, i),
(End, i) => (Direction::Front, i),
(EndInclusive, i) => (Direction::Front, i.checked_add(1)?),
})
}
@ -4294,25 +4292,25 @@ impl<T> [T] {
///
/// # Examples
///
/// Taking the first three elements of a slice:
/// Splitting off the first three elements of a slice:
///
/// ```
/// #![feature(slice_take)]
///
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
/// let mut first_three = slice.take(..3).unwrap();
/// let mut first_three = slice.split_off(..3).unwrap();
///
/// assert_eq!(slice, &['d']);
/// assert_eq!(first_three, &['a', 'b', 'c']);
/// ```
///
/// Taking the last two elements of a slice:
/// Splitting off the last two elements of a slice:
///
/// ```
/// #![feature(slice_take)]
///
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
/// let mut tail = slice.take(2..).unwrap();
/// let mut tail = slice.split_off(2..).unwrap();
///
/// assert_eq!(slice, &['a', 'b']);
/// assert_eq!(tail, &['c', 'd']);
@ -4325,16 +4323,19 @@ impl<T> [T] {
///
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
///
/// assert_eq!(None, slice.take(5..));
/// assert_eq!(None, slice.take(..5));
/// assert_eq!(None, slice.take(..=4));
/// assert_eq!(None, slice.split_off(5..));
/// assert_eq!(None, slice.split_off(..5));
/// assert_eq!(None, slice.split_off(..=4));
/// let expected: &[char] = &['a', 'b', 'c', 'd'];
/// assert_eq!(Some(expected), slice.take(..4));
/// assert_eq!(Some(expected), slice.split_off(..4));
/// ```
#[inline]
#[must_use = "method does not modify the slice if the range is out of bounds"]
#[unstable(feature = "slice_take", issue = "62280")]
pub fn take<'a, R: OneSidedRange<usize>>(self: &mut &'a Self, range: R) -> Option<&'a Self> {
pub fn split_off<'a, R: OneSidedRange<usize>>(
self: &mut &'a Self,
range: R,
) -> Option<&'a Self> {
let (direction, split_index) = split_point_of(range)?;
if split_index > self.len() {
return None;
@ -4363,13 +4364,13 @@ impl<T> [T] {
///
/// # Examples
///
/// Taking the first three elements of a slice:
/// Splitting off the first three elements of a slice:
///
/// ```
/// #![feature(slice_take)]
///
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
/// let mut first_three = slice.take_mut(..3).unwrap();
/// let mut first_three = slice.split_off_mut(..3).unwrap();
///
/// assert_eq!(slice, &mut ['d']);
/// assert_eq!(first_three, &mut ['a', 'b', 'c']);
@ -4381,7 +4382,7 @@ impl<T> [T] {
/// #![feature(slice_take)]
///
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
/// let mut tail = slice.take_mut(2..).unwrap();
/// let mut tail = slice.split_off_mut(2..).unwrap();
///
/// assert_eq!(slice, &mut ['a', 'b']);
/// assert_eq!(tail, &mut ['c', 'd']);
@ -4394,16 +4395,16 @@ impl<T> [T] {
///
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
///
/// assert_eq!(None, slice.take_mut(5..));
/// assert_eq!(None, slice.take_mut(..5));
/// assert_eq!(None, slice.take_mut(..=4));
/// assert_eq!(None, slice.split_off_mut(5..));
/// assert_eq!(None, slice.split_off_mut(..5));
/// assert_eq!(None, slice.split_off_mut(..=4));
/// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd'];
/// assert_eq!(Some(expected), slice.take_mut(..4));
/// assert_eq!(Some(expected), slice.split_off_mut(..4));
/// ```
#[inline]
#[must_use = "method does not modify the slice if the range is out of bounds"]
#[unstable(feature = "slice_take", issue = "62280")]
pub fn take_mut<'a, R: OneSidedRange<usize>>(
pub fn split_off_mut<'a, R: OneSidedRange<usize>>(
self: &mut &'a mut Self,
range: R,
) -> Option<&'a mut Self> {
@ -4435,14 +4436,14 @@ impl<T> [T] {
/// #![feature(slice_take)]
///
/// let mut slice: &[_] = &['a', 'b', 'c'];
/// let first = slice.take_first().unwrap();
/// let first = slice.split_off_first().unwrap();
///
/// assert_eq!(slice, &['b', 'c']);
/// assert_eq!(first, &'a');
/// ```
#[inline]
#[unstable(feature = "slice_take", issue = "62280")]
pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> {
pub fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> {
let (first, rem) = self.split_first()?;
*self = rem;
Some(first)
@ -4459,7 +4460,7 @@ impl<T> [T] {
/// #![feature(slice_take)]
///
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
/// let first = slice.take_first_mut().unwrap();
/// let first = slice.split_off_first_mut().unwrap();
/// *first = 'd';
///
/// assert_eq!(slice, &['b', 'c']);
@ -4467,7 +4468,7 @@ impl<T> [T] {
/// ```
#[inline]
#[unstable(feature = "slice_take", issue = "62280")]
pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
pub fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
let (first, rem) = mem::take(self).split_first_mut()?;
*self = rem;
Some(first)
@ -4484,14 +4485,14 @@ impl<T> [T] {
/// #![feature(slice_take)]
///
/// let mut slice: &[_] = &['a', 'b', 'c'];
/// let last = slice.take_last().unwrap();
/// let last = slice.split_off_last().unwrap();
///
/// assert_eq!(slice, &['a', 'b']);
/// assert_eq!(last, &'c');
/// ```
#[inline]
#[unstable(feature = "slice_take", issue = "62280")]
pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> {
pub fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> {
let (last, rem) = self.split_last()?;
*self = rem;
Some(last)
@ -4508,7 +4509,7 @@ impl<T> [T] {
/// #![feature(slice_take)]
///
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
/// let last = slice.take_last_mut().unwrap();
/// let last = slice.split_off_last_mut().unwrap();
/// *last = 'd';
///
/// assert_eq!(slice, &['a', 'b']);
@ -4516,7 +4517,7 @@ impl<T> [T] {
/// ```
#[inline]
#[unstable(feature = "slice_take", issue = "62280")]
pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
pub fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
let (last, rem) = mem::take(self).split_last_mut()?;
*self = rem;
Some(last)

View file

@ -160,6 +160,182 @@ impl str {
self.len() == 0
}
/// Converts a slice of bytes to a string slice.
///
/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice
/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between
/// the two. Not all byte slices are valid string slices, however: [`&str`] requires
/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid
/// UTF-8, and then does the conversion.
///
/// [`&str`]: str
/// [byteslice]: prim@slice
///
/// If you are sure that the byte slice is valid UTF-8, and you don't want to
/// incur the overhead of the validity check, there is an unsafe version of
/// this function, [`from_utf8_unchecked`], which has the same
/// behavior but skips the check.
///
/// If you need a `String` instead of a `&str`, consider
/// [`String::from_utf8`][string].
///
/// [string]: ../std/string/struct.String.html#method.from_utf8
///
/// Because you can stack-allocate a `[u8; N]`, and you can take a
/// [`&[u8]`][byteslice] of it, this function is one way to have a
/// stack-allocated string. There is an example of this in the
/// examples section below.
///
/// [byteslice]: slice
///
/// # Errors
///
/// Returns `Err` if the slice is not UTF-8 with a description as to why the
/// provided slice is not UTF-8.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use std::str;
///
/// // some bytes, in a vector
/// let sparkle_heart = vec![240, 159, 146, 150];
///
/// // We can use the ? (try) operator to check if the bytes are valid
/// let sparkle_heart = str::from_utf8(&sparkle_heart)?;
///
/// assert_eq!("💖", sparkle_heart);
/// # Ok::<_, str::Utf8Error>(())
/// ```
///
/// Incorrect bytes:
///
/// ```
/// use std::str;
///
/// // some invalid bytes, in a vector
/// let sparkle_heart = vec![0, 159, 146, 150];
///
/// assert!(str::from_utf8(&sparkle_heart).is_err());
/// ```
///
/// See the docs for [`Utf8Error`] for more details on the kinds of
/// errors that can be returned.
///
/// A "stack allocated string":
///
/// ```
/// use std::str;
///
/// // some bytes, in a stack-allocated array
/// let sparkle_heart = [240, 159, 146, 150];
///
/// // We know these bytes are valid, so just use `unwrap()`.
/// let sparkle_heart: &str = str::from_utf8(&sparkle_heart).unwrap();
///
/// assert_eq!("💖", sparkle_heart);
/// ```
#[unstable(feature = "inherent_str_constructors", issue = "131114")]
pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
converts::from_utf8(v)
}
/// Converts a mutable slice of bytes to a mutable string slice.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use std::str;
///
/// // "Hello, Rust!" as a mutable vector
/// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33];
///
/// // As we know these bytes are valid, we can use `unwrap()`
/// let outstr = str::from_utf8_mut(&mut hellorust).unwrap();
///
/// assert_eq!("Hello, Rust!", outstr);
/// ```
///
/// Incorrect bytes:
///
/// ```
/// use std::str;
///
/// // Some invalid bytes in a mutable vector
/// let mut invalid = vec![128, 223];
///
/// assert!(str::from_utf8_mut(&mut invalid).is_err());
/// ```
/// See the docs for [`Utf8Error`] for more details on the kinds of
/// errors that can be returned.
#[unstable(feature = "inherent_str_constructors", issue = "131114")]
#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")]
pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
converts::from_utf8_mut(v)
}
/// Converts a slice of bytes to a string slice without checking
/// that the string contains valid UTF-8.
///
/// See the safe version, [`from_utf8`], for more information.
///
/// # Safety
///
/// The bytes passed in must be valid UTF-8.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use std::str;
///
/// // some bytes, in a vector
/// let sparkle_heart = vec![240, 159, 146, 150];
///
/// let sparkle_heart = unsafe {
/// str::from_utf8_unchecked(&sparkle_heart)
/// };
///
/// assert_eq!("💖", sparkle_heart);
/// ```
#[inline]
#[must_use]
#[unstable(feature = "inherent_str_constructors", issue = "131114")]
pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
// SAFETY: converts::from_utf8_unchecked has the same safety requirements as this function.
unsafe { converts::from_utf8_unchecked(v) }
}
/// Converts a slice of bytes to a string slice without checking
/// that the string contains valid UTF-8; mutable version.
///
/// See the immutable version, [`from_utf8_unchecked()`] for more information.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use std::str;
///
/// let mut heart = vec![240, 159, 146, 150];
/// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) };
///
/// assert_eq!("💖", heart);
/// ```
#[inline]
#[must_use]
#[unstable(feature = "inherent_str_constructors", issue = "131114")]
pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
// SAFETY: converts::from_utf8_unchecked_mut has the same safety requirements as this function.
unsafe { converts::from_utf8_unchecked_mut(v) }
}
/// Checks that `index`-th byte is the first byte in a UTF-8 code point
/// sequence or the end of the string.
///

View file

@ -2399,18 +2399,18 @@ fn slice_rsplit_once() {
assert_eq!(v.rsplit_once(|&x| x == 0), None);
}
macro_rules! take_tests {
macro_rules! split_off_tests {
(slice: &[], $($tts:tt)*) => {
take_tests!(ty: &[()], slice: &[], $($tts)*);
split_off_tests!(ty: &[()], slice: &[], $($tts)*);
};
(slice: &mut [], $($tts:tt)*) => {
take_tests!(ty: &mut [()], slice: &mut [], $($tts)*);
split_off_tests!(ty: &mut [()], slice: &mut [], $($tts)*);
};
(slice: &$slice:expr, $($tts:tt)*) => {
take_tests!(ty: &[_], slice: &$slice, $($tts)*);
split_off_tests!(ty: &[_], slice: &$slice, $($tts)*);
};
(slice: &mut $slice:expr, $($tts:tt)*) => {
take_tests!(ty: &mut [_], slice: &mut $slice, $($tts)*);
split_off_tests!(ty: &mut [_], slice: &mut $slice, $($tts)*);
};
(ty: $ty:ty, slice: $slice:expr, method: $method:ident, $(($test_name:ident, ($($args:expr),*), $output:expr, $remaining:expr),)*) => {
$(
@ -2425,64 +2425,64 @@ macro_rules! take_tests {
};
}
take_tests! {
slice: &[0, 1, 2, 3], method: take,
(take_in_bounds_range_to, (..1), Some(&[0] as _), &[1, 2, 3]),
(take_in_bounds_range_to_inclusive, (..=0), Some(&[0] as _), &[1, 2, 3]),
(take_in_bounds_range_from, (2..), Some(&[2, 3] as _), &[0, 1]),
(take_oob_range_to, (..5), None, &[0, 1, 2, 3]),
(take_oob_range_to_inclusive, (..=4), None, &[0, 1, 2, 3]),
(take_oob_range_from, (5..), None, &[0, 1, 2, 3]),
split_off_tests! {
slice: &[0, 1, 2, 3], method: split_off,
(split_off_in_bounds_range_to, (..1), Some(&[0] as _), &[1, 2, 3]),
(split_off_in_bounds_range_to_inclusive, (..=0), Some(&[0] as _), &[1, 2, 3]),
(split_off_in_bounds_range_from, (2..), Some(&[2, 3] as _), &[0, 1]),
(split_off_oob_range_to, (..5), None, &[0, 1, 2, 3]),
(split_off_oob_range_to_inclusive, (..=4), None, &[0, 1, 2, 3]),
(split_off_oob_range_from, (5..), None, &[0, 1, 2, 3]),
}
take_tests! {
slice: &mut [0, 1, 2, 3], method: take_mut,
(take_mut_in_bounds_range_to, (..1), Some(&mut [0] as _), &mut [1, 2, 3]),
(take_mut_in_bounds_range_to_inclusive, (..=0), Some(&mut [0] as _), &mut [1, 2, 3]),
(take_mut_in_bounds_range_from, (2..), Some(&mut [2, 3] as _), &mut [0, 1]),
(take_mut_oob_range_to, (..5), None, &mut [0, 1, 2, 3]),
(take_mut_oob_range_to_inclusive, (..=4), None, &mut [0, 1, 2, 3]),
(take_mut_oob_range_from, (5..), None, &mut [0, 1, 2, 3]),
split_off_tests! {
slice: &mut [0, 1, 2, 3], method: split_off_mut,
(split_off_mut_in_bounds_range_to, (..1), Some(&mut [0] as _), &mut [1, 2, 3]),
(split_off_mut_in_bounds_range_to_inclusive, (..=0), Some(&mut [0] as _), &mut [1, 2, 3]),
(split_off_mut_in_bounds_range_from, (2..), Some(&mut [2, 3] as _), &mut [0, 1]),
(split_off_mut_oob_range_to, (..5), None, &mut [0, 1, 2, 3]),
(split_off_mut_oob_range_to_inclusive, (..=4), None, &mut [0, 1, 2, 3]),
(split_off_mut_oob_range_from, (5..), None, &mut [0, 1, 2, 3]),
}
take_tests! {
slice: &[1, 2], method: take_first,
(take_first_nonempty, (), Some(&1), &[2]),
split_off_tests! {
slice: &[1, 2], method: split_off_first,
(split_off_first_nonempty, (), Some(&1), &[2]),
}
take_tests! {
slice: &mut [1, 2], method: take_first_mut,
(take_first_mut_nonempty, (), Some(&mut 1), &mut [2]),
split_off_tests! {
slice: &mut [1, 2], method: split_off_first_mut,
(split_off_first_mut_nonempty, (), Some(&mut 1), &mut [2]),
}
take_tests! {
slice: &[1, 2], method: take_last,
(take_last_nonempty, (), Some(&2), &[1]),
split_off_tests! {
slice: &[1, 2], method: split_off_last,
(split_off_last_nonempty, (), Some(&2), &[1]),
}
take_tests! {
slice: &mut [1, 2], method: take_last_mut,
(take_last_mut_nonempty, (), Some(&mut 2), &mut [1]),
split_off_tests! {
slice: &mut [1, 2], method: split_off_last_mut,
(split_off_last_mut_nonempty, (), Some(&mut 2), &mut [1]),
}
take_tests! {
slice: &[], method: take_first,
(take_first_empty, (), None, &[]),
split_off_tests! {
slice: &[], method: split_off_first,
(split_off_first_empty, (), None, &[]),
}
take_tests! {
slice: &mut [], method: take_first_mut,
(take_first_mut_empty, (), None, &mut []),
split_off_tests! {
slice: &mut [], method: split_off_first_mut,
(split_off_first_mut_empty, (), None, &mut []),
}
take_tests! {
slice: &[], method: take_last,
(take_last_empty, (), None, &[]),
split_off_tests! {
slice: &[], method: split_off_last,
(split_off_last_empty, (), None, &[]),
}
take_tests! {
slice: &mut [], method: take_last_mut,
(take_last_mut_empty, (), None, &mut []),
split_off_tests! {
slice: &mut [], method: split_off_last_mut,
(split_off_last_mut_empty, (), None, &mut []),
}
#[cfg(not(miri))] // unused in Miri
@ -2497,19 +2497,19 @@ macro_rules! empty_max_mut {
}
#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations)
take_tests! {
slice: &[(); usize::MAX], method: take,
(take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]),
(take_oob_max_range_to_inclusive, (..=usize::MAX), None, EMPTY_MAX),
(take_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX),
split_off_tests! {
slice: &[(); usize::MAX], method: split_off,
(split_off_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]),
(split_off_oob_max_range_to_inclusive, (..=usize::MAX), None, EMPTY_MAX),
(split_off_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX),
}
#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations)
take_tests! {
slice: &mut [(); usize::MAX], method: take_mut,
(take_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]),
(take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
(take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
split_off_tests! {
slice: &mut [(); usize::MAX], method: split_off_mut,
(split_off_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]),
(split_off_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
(split_off_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
}
#[test]

View file

@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core", public = true }
compiler_builtins = { version = "=0.1.143" }
compiler_builtins = { version = "=0.1.145" }
unwind = { path = "../unwind" }
hashbrown = { version = "0.15", default-features = false, features = [
'rustc-dep-of-std',

View file

@ -6,8 +6,7 @@ mod tests;
pub use core::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use crate::sys::net::netc as c;
use crate::sys_common::net::LookupHost;
use crate::sys::net::{LookupHost, netc as c};
use crate::sys_common::{FromInner, IntoInner};
use crate::{io, iter, mem, option, slice, vec};

View file

@ -15,7 +15,8 @@ use crate::io::prelude::*;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::iter::FusedIterator;
use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
use crate::sys_common::{AsInner, FromInner, IntoInner, net as net_imp};
use crate::sys::net as net_imp;
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
/// A TCP stream between a local and a remote socket.

View file

@ -12,7 +12,8 @@ mod tests;
use crate::fmt;
use crate::io::{self, ErrorKind};
use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
use crate::sys_common::{AsInner, FromInner, IntoInner, net as net_imp};
use crate::sys::net as net_imp;
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
/// A UDP socket.

View file

@ -1,6 +1,6 @@
use crate::os::fd::owned::OwnedFd;
use crate::os::fd::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::{net, sys};
macro_rules! impl_as_raw_fd {
@ -24,7 +24,7 @@ macro_rules! impl_from_raw_fd {
unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
unsafe {
let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)));
net::$t::from_inner(sys_common::net::$t::from_inner(socket))
net::$t::from_inner(sys::net::$t::from_inner(socket))
}
}
}

View file

@ -23,7 +23,7 @@ macro_rules! impl_from_raw_fd {
unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
unsafe {
let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)));
net::$t::from_inner(sys_common::net::$t::from_inner(socket))
net::$t::from_inner(sys::net::$t::from_inner(socket))
}
}
}

View file

@ -48,7 +48,7 @@
use crate::marker::PhantomData;
use crate::mem::ManuallyDrop;
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::{fmt, net, sys};
/// Raw file descriptors.
@ -387,7 +387,7 @@ macro_rules! impl_from_raw_fd {
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
let socket = unsafe { sys::net::Socket::from_raw_fd(fd) };
net::$t::from_inner(sys_common::net::$t::from_inner(socket))
net::$t::from_inner(sys::net::$t::from_inner(socket))
}
}
)*};

View file

@ -6,7 +6,7 @@
use crate::os::windows::io::{AsHandle, AsSocket};
use crate::os::windows::io::{OwnedHandle, OwnedSocket};
use crate::os::windows::raw;
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::{fs, io, net, ptr, sys};
/// Raw HANDLEs.
@ -262,7 +262,7 @@ impl FromRawSocket for net::TcpStream {
unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
unsafe {
let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock))
net::TcpStream::from_inner(sys::net::TcpStream::from_inner(sock))
}
}
}
@ -272,7 +272,7 @@ impl FromRawSocket for net::TcpListener {
unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
unsafe {
let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock))
net::TcpListener::from_inner(sys::net::TcpListener::from_inner(sock))
}
}
}
@ -282,7 +282,7 @@ impl FromRawSocket for net::UdpSocket {
unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
unsafe {
let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock));
net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock))
net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(sock))
}
}
}

View file

@ -12,6 +12,7 @@ pub mod anonymous_pipe;
pub mod backtrace;
pub mod cmath;
pub mod exit_guard;
pub mod net;
pub mod os_str;
pub mod path;
pub mod random;

Some files were not shown because too many files have changed in this diff Show more