Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3680,6 +3680,9 @@ pub struct TraitImplHeader {

#[derive(Clone, Encodable, Decodable, Debug, Default, Walkable)]
pub struct FnContract {
/// Declarations of variables accessible both in the `requires` and
/// `ensures` clauses.
pub declarations: ThinVec<Stmt>,
pub requires: Option<Box<Expr>>,
pub ensures: Option<Box<Expr>>,
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break }
}

fn lower_stmts(
pub(super) fn lower_stmts(
&mut self,
mut ast_stmts: &[Stmt],
) -> (&'hir [hir::Stmt<'hir>], Option<&'hir hir::Expr<'hir>>) {
Expand Down
30 changes: 23 additions & 7 deletions compiler/rustc_ast_lowering/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
body: impl FnOnce(&mut Self) -> rustc_hir::Expr<'hir>,
contract: &rustc_ast::FnContract,
) -> rustc_hir::Expr<'hir> {
// The order in which things are lowered is important! I.e to
// refer to variables in contract_decls from postcond/precond,
// we must lower it first!
let contract_decls = self.lower_stmts(&contract.declarations).0;

match (&contract.requires, &contract.ensures) {
(Some(req), Some(ens)) => {
// Lower the fn contract, which turns:
Expand All @@ -27,6 +32,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// into:
//
// let __postcond = if contract_checks {
// CONTRACT_DECLARATIONS;
// contract_check_requires(PRECOND);
// Some(|ret_val| POSTCOND)
// } else {
Expand All @@ -45,8 +51,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let precond = self.lower_precond(req);
let postcond_checker = self.lower_postcond_checker(ens);

let contract_check =
self.lower_contract_check_with_postcond(Some(precond), postcond_checker);
let contract_check = self.lower_contract_check_with_postcond(
contract_decls,
Some(precond),
postcond_checker,
);

let wrapped_body =
self.wrap_body_with_contract_check(body, contract_check, postcond_checker.span);
Expand All @@ -68,15 +77,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// let ret = { body };
//
// if contract_checks {
// CONTRACT_DECLARATIONS;
// contract_check_ensures(__postcond, ret)
// } else {
// ret
// }
// }

let postcond_checker = self.lower_postcond_checker(ens);
let contract_check =
self.lower_contract_check_with_postcond(None, postcond_checker);
self.lower_contract_check_with_postcond(contract_decls, None, postcond_checker);

let wrapped_body =
self.wrap_body_with_contract_check(body, contract_check, postcond_checker.span);
Expand All @@ -91,12 +100,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
//
// {
// if contracts_checks {
// CONTRACT_DECLARATIONS;
// contract_requires(PRECOND);
// }
// body
// }
let precond = self.lower_precond(req);
let precond_check = self.lower_contract_check_just_precond(precond);
let precond_check = self.lower_contract_check_just_precond(contract_decls, precond);

let body = self.arena.alloc(body(self));

Expand Down Expand Up @@ -145,9 +155,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {

fn lower_contract_check_just_precond(
&mut self,
contract_decls: &'hir [rustc_hir::Stmt<'hir>],
precond: rustc_hir::Stmt<'hir>,
) -> rustc_hir::Stmt<'hir> {
let stmts = self.arena.alloc_from_iter([precond].into_iter());
let stmts = self
.arena
.alloc_from_iter(contract_decls.into_iter().map(|d| *d).chain([precond].into_iter()));

let then_block_stmts = self.block_all(precond.span, stmts, None);
let then_block = self.arena.alloc(self.expr_block(&then_block_stmts));
Expand All @@ -164,10 +177,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {

fn lower_contract_check_with_postcond(
&mut self,
contract_decls: &'hir [rustc_hir::Stmt<'hir>],
precond: Option<rustc_hir::Stmt<'hir>>,
postcond_checker: &'hir rustc_hir::Expr<'hir>,
) -> &'hir rustc_hir::Expr<'hir> {
let stmts = self.arena.alloc_from_iter(precond.into_iter());
let stmts = self
.arena
.alloc_from_iter(contract_decls.into_iter().map(|d| *d).chain(precond.into_iter()));
let span = match precond {
Some(precond) => precond.span,
None => postcond_checker.span,
Expand Down
35 changes: 5 additions & 30 deletions compiler/rustc_builtin_macros/src/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl AttrProcMacro for ExpandRequires {
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
expand_requires_tts(ecx, span, annotation, annotated)
expand_contract_clause_tts(ecx, span, annotation, annotated, kw::ContractRequires)
}
}

Expand All @@ -29,7 +29,7 @@ impl AttrProcMacro for ExpandEnsures {
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
expand_ensures_tts(ecx, span, annotation, annotated)
expand_contract_clause_tts(ecx, span, annotation, annotated, kw::ContractEnsures)
}
}

Expand Down Expand Up @@ -130,42 +130,17 @@ fn expand_contract_clause(
Ok(new_tts)
}

fn expand_requires_tts(
fn expand_contract_clause_tts(
ecx: &mut ExtCtxt<'_>,
attr_span: Span,
annotation: TokenStream,
annotated: TokenStream,
clause_keyword: rustc_span::Symbol,
) -> Result<TokenStream, ErrorGuaranteed> {
let feature_span = ecx.with_def_site_ctxt(attr_span);
expand_contract_clause(ecx, attr_span, annotated, |new_tts| {
new_tts.push_tree(TokenTree::Token(
token::Token::from_ast_ident(Ident::new(kw::ContractRequires, feature_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::Brace,
annotation,
));
Ok(())
})
}

fn expand_ensures_tts(
ecx: &mut ExtCtxt<'_>,
attr_span: Span,
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorGuaranteed> {
let feature_span = ecx.with_def_site_ctxt(attr_span);
expand_contract_clause(ecx, attr_span, annotated, |new_tts| {
new_tts.push_tree(TokenTree::Token(
token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, feature_span)),
token::Token::from_ast_ident(Ident::new(clause_keyword, feature_span)),
Spacing::Joint,
));
new_tts.push_tree(TokenTree::Delimited(
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_feature/src/removed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ declare_features! (
/// Allows deriving traits as per `SmartPointer` specification
(removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284),
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
(removed, doc_auto_cfg, "CURRENT_RUSTC_VERSION", Some(43781), Some("merged into `doc_cfg`"), 138907),
(removed, doc_auto_cfg, "1.92.0", Some(43781), Some("merged into `doc_cfg`"), 138907),
/// Allows `#[doc(cfg_hide(...))]`.
(removed, doc_cfg_hide, "CURRENT_RUSTC_VERSION", Some(43781), Some("merged into `doc_cfg`"), 138907),
(removed, doc_cfg_hide, "1.92.0", Some(43781), Some("merged into `doc_cfg`"), 138907),
/// Allows using `#[doc(keyword = "...")]`.
(removed, doc_keyword, "1.58.0", Some(51315),
Some("merged into `#![feature(rustdoc_internals)]`"), 90420),
Expand Down
52 changes: 13 additions & 39 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3046,46 +3046,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

foreign_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string());
let foreign_def_ids = foreign_preds
.iter()
.filter_map(|pred| match pred.self_ty().kind() {
ty::Adt(def, _) => Some(def.did()),
_ => None,
})
.collect::<FxIndexSet<_>>();
let mut foreign_spans: MultiSpan = foreign_def_ids
.iter()
.filter_map(|def_id| {
let span = self.tcx.def_span(*def_id);
if span.is_dummy() { None } else { Some(span) }
})
.collect::<Vec<_>>()
.into();
for pred in &foreign_preds {
if let ty::Adt(def, _) = pred.self_ty().kind() {
foreign_spans.push_span_label(
self.tcx.def_span(def.did()),
format!("not implement `{}`", pred.trait_ref.print_trait_sugared()),
);

for pred in foreign_preds {
let ty = pred.self_ty();
let ty::Adt(def, _) = ty.kind() else { continue };
let span = self.tcx.def_span(def.did());
if span.is_dummy() {
continue;
}
}
if foreign_spans.primary_span().is_some() {
let msg = if let [foreign_pred] = foreign_preds.as_slice() {
format!(
"the foreign item type `{}` doesn't implement `{}`",
foreign_pred.self_ty(),
foreign_pred.trait_ref.print_trait_sugared()
)
} else {
format!(
"the foreign item type{} {} implement required trait{} for this \
operation to be valid",
pluralize!(foreign_def_ids.len()),
if foreign_def_ids.len() > 1 { "don't" } else { "doesn't" },
pluralize!(foreign_preds.len()),
)
};
err.span_note(foreign_spans, msg);
let mut mspan: MultiSpan = span.into();
mspan.push_span_label(span, format!("`{ty}` is defined in another crate"));
err.span_note(
mspan,
format!("`{ty}` does not implement `{}`", pred.trait_ref.print_trait_sugared()),
);
}

let preds: Vec<_> = errors
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_index/src/idx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeInclusive<I> {
}
}

#[cfg(all(feature = "nightly", not(bootstrap)))]
#[cfg(feature = "nightly")]
impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeToInclusive<I> {
type Output = core::range::RangeToInclusive<usize>;
#[inline]
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_index/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// tidy-alphabetical-start
#![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))]
#![cfg_attr(bootstrap, feature(new_zeroed_alloc))]
#![cfg_attr(feature = "nightly", allow(internal_features))]
#![cfg_attr(feature = "nightly", feature(extend_one, step_trait, test))]
#![cfg_attr(feature = "nightly", feature(new_range_api))]
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_mir_transform/src/deduce_param_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ pub(super) fn deduced_param_attrs<'tcx>(

// Grab the optimized MIR. Analyze it to determine which arguments have been mutated.
let body: &Body<'tcx> = tcx.optimized_mir(def_id);
// Arguments spread at ABI level are currently unsupported.
if body.spread_arg.is_some() {
return &[];
}

let mut deduce = DeduceParamAttrs::new(body);
deduce.visit_body(body);
tracing::trace!(?deduce.usage);
Expand Down
24 changes: 24 additions & 0 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4036,6 +4036,30 @@ impl<'a> Parser<'a> {
self.mk_expr(span, ExprKind::Err(guar))
}

pub(crate) fn mk_unit_expr(&self, span: Span) -> Box<Expr> {
self.mk_expr(span, ExprKind::Tup(Default::default()))
}

pub(crate) fn mk_closure_expr(&self, span: Span, body: Box<Expr>) -> Box<Expr> {
self.mk_expr(
span,
ast::ExprKind::Closure(Box::new(ast::Closure {
binder: rustc_ast::ClosureBinder::NotPresent,
constness: rustc_ast::Const::No,
movability: rustc_ast::Movability::Movable,
capture_clause: rustc_ast::CaptureBy::Ref,
coroutine_kind: None,
fn_decl: Box::new(rustc_ast::FnDecl {
inputs: Default::default(),
output: rustc_ast::FnRetTy::Default(span),
}),
fn_arg_span: span,
fn_decl_span: span,
body,
})),
)
}

/// Create expression span ensuring the span of the parent node
/// is larger than the span of lhs and rhs, including the attributes.
fn mk_expr_sp(&self, lhs: &Box<Expr>, lhs_span: Span, op_span: Span, rhs_span: Span) -> Span {
Expand Down
47 changes: 35 additions & 12 deletions compiler/rustc_parse/src/parser/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,25 +312,48 @@ 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<Box<ast::FnContract>>> {
let requires = if self.eat_keyword_noexpect(exp!(ContractRequires).kw) {
let (declarations, requires) = self.parse_contract_requires()?;
let ensures = self.parse_contract_ensures()?;

if requires.is_none() && ensures.is_none() {
Ok(None)
} else {
Ok(Some(Box::new(ast::FnContract { declarations, requires, ensures })))
}
}

fn parse_contract_requires(
&mut self,
) -> PResult<'a, (ThinVec<rustc_ast::Stmt>, Option<Box<rustc_ast::Expr>>)> {
Ok(if self.eat_keyword_noexpect(exp!(ContractRequires).kw) {
self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span);
let precond = self.parse_expr()?;
Some(precond)
let mut decls_and_precond = self.parse_block()?;

let precond = match decls_and_precond.stmts.pop() {
Some(precond) => match precond.kind {
rustc_ast::StmtKind::Expr(expr) => expr,
// Insert dummy node that will be rejected by typechecker to
// avoid reinventing an error
_ => self.mk_unit_expr(decls_and_precond.span),
},
None => self.mk_unit_expr(decls_and_precond.span),
};
let precond = self.mk_closure_expr(precond.span, precond);
let decls = decls_and_precond.stmts;
(decls, Some(precond))
} else {
None
};
let ensures = if self.eat_keyword_noexpect(exp!(ContractEnsures).kw) {
(Default::default(), None)
})
}

fn parse_contract_ensures(&mut self) -> PResult<'a, Option<Box<rustc_ast::Expr>>> {
Ok(if self.eat_keyword_noexpect(exp!(ContractEnsures).kw) {
self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span);
let postcond = self.parse_expr()?;
Some(postcond)
} else {
None
};
if requires.is_none() && ensures.is_none() {
Ok(None)
} else {
Ok(Some(Box::new(ast::FnContract { requires, ensures })))
}
})
}

/// Parses an optional where-clause.
Expand Down
4 changes: 2 additions & 2 deletions library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ impl<T> Box<T> {
/// [zeroed]: mem::MaybeUninit::zeroed
#[cfg(not(no_global_oom_handling))]
#[inline]
#[stable(feature = "new_zeroed_alloc", since = "CURRENT_RUSTC_VERSION")]
#[stable(feature = "new_zeroed_alloc", since = "1.92.0")]
#[must_use]
pub fn new_zeroed() -> Box<mem::MaybeUninit<T>> {
Self::new_zeroed_in(Global)
Expand Down Expand Up @@ -692,7 +692,7 @@ impl<T> Box<[T]> {
///
/// [zeroed]: mem::MaybeUninit::zeroed
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "new_zeroed_alloc", since = "CURRENT_RUSTC_VERSION")]
#[stable(feature = "new_zeroed_alloc", since = "1.92.0")]
#[must_use]
pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
unsafe { RawVec::with_capacity_zeroed(len).into_box(len) }
Expand Down
Loading
Loading