Auto merge of #148931 - Zalathar:rollup-yfyhpcw, r=Zalathar
Rollup of 15 pull requests Successful merges: - rust-lang/rust#148543 (Correctly link to associated trait items in reexports) - rust-lang/rust#148808 (Some resolve cleanups) - rust-lang/rust#148812 (coverage: Associate hole spans with expansion tree nodes ) - rust-lang/rust#148826 (CStr docs: Fix CStr vs &CStr confusion) - rust-lang/rust#148850 (Implement `Read::read_array`) - rust-lang/rust#148867 (Refactor `Box::take`) - rust-lang/rust#148870 (Remove unused LLVMModuleRef argument) - rust-lang/rust#148878 (error when ABI does not support guaranteed tail calls) - rust-lang/rust#148901 (Disable rustdoc-test-builder test partially for SGX target.) - rust-lang/rust#148902 (add missing s390x target feature to std detect test) - rust-lang/rust#148904 (waffle: stop watching codegen ssa) - rust-lang/rust#148906 (Expose fmt::Arguments::from_str as unstable.) - rust-lang/rust#148907 (add assembly test for infinite recursion with `become`) - rust-lang/rust#148928 (Move & adjust some `!`-adjacent tests) - rust-lang/rust#148929 (ignore `build-rust-analyzer` even if it's a symlink) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
c880acdd31
38 changed files with 426 additions and 147 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -48,7 +48,7 @@ no_llvm_build
|
|||
/llvm/
|
||||
/mingw-build/
|
||||
/build
|
||||
/build-rust-analyzer/
|
||||
/build-rust-analyzer
|
||||
/dist/
|
||||
/unicode-downloads
|
||||
/target
|
||||
|
|
|
|||
|
|
@ -276,6 +276,51 @@ impl ExternAbi {
|
|||
_ => CVariadicStatus::NotSupported,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the ABI supports guaranteed tail calls.
|
||||
#[cfg(feature = "nightly")]
|
||||
pub fn supports_guaranteed_tail_call(self) -> bool {
|
||||
match self {
|
||||
Self::CmseNonSecureCall | Self::CmseNonSecureEntry => {
|
||||
// See https://godbolt.org/z/9jhdeqErv. The CMSE calling conventions clear registers
|
||||
// before returning, and hence cannot guarantee a tail call.
|
||||
false
|
||||
}
|
||||
Self::AvrInterrupt
|
||||
| Self::AvrNonBlockingInterrupt
|
||||
| Self::Msp430Interrupt
|
||||
| Self::RiscvInterruptM
|
||||
| Self::RiscvInterruptS
|
||||
| Self::X86Interrupt => {
|
||||
// See https://godbolt.org/z/Edfjnxxcq. Interrupts cannot be called directly.
|
||||
false
|
||||
}
|
||||
Self::GpuKernel | Self::PtxKernel => {
|
||||
// See https://godbolt.org/z/jq5TE5jK1.
|
||||
false
|
||||
}
|
||||
Self::Custom => {
|
||||
// This ABI does not support calls at all (except via assembly).
|
||||
false
|
||||
}
|
||||
Self::C { .. }
|
||||
| Self::System { .. }
|
||||
| Self::Rust
|
||||
| Self::RustCall
|
||||
| Self::RustCold
|
||||
| Self::RustInvalid
|
||||
| Self::Unadjusted
|
||||
| Self::EfiApi
|
||||
| Self::Aapcs { .. }
|
||||
| Self::Cdecl { .. }
|
||||
| Self::Stdcall { .. }
|
||||
| Self::Fastcall { .. }
|
||||
| Self::Thiscall { .. }
|
||||
| Self::Vectorcall { .. }
|
||||
| Self::SysV64 { .. }
|
||||
| Self::Win64 { .. } => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_names() -> Vec<&'static str> {
|
||||
|
|
|
|||
|
|
@ -683,7 +683,7 @@ pub(crate) unsafe fn llvm_optimize(
|
|||
// Here we map the old arguments to the new arguments, with an offset of 1 to make sure
|
||||
// that we don't use the newly added `%dyn_ptr`.
|
||||
unsafe {
|
||||
llvm::LLVMRustOffloadMapper(cx.llmod(), old_fn, new_fn);
|
||||
llvm::LLVMRustOffloadMapper(old_fn, new_fn);
|
||||
}
|
||||
|
||||
llvm::set_linkage(new_fn, llvm::get_linkage(old_fn));
|
||||
|
|
|
|||
|
|
@ -2025,7 +2025,7 @@ unsafe extern "C" {
|
|||
) -> &Attribute;
|
||||
|
||||
// Operations on functions
|
||||
pub(crate) fn LLVMRustOffloadMapper<'a>(M: &'a Module, Fn: &'a Value, Fn: &'a Value);
|
||||
pub(crate) fn LLVMRustOffloadMapper<'a>(Fn: &'a Value, Fn: &'a Value);
|
||||
pub(crate) fn LLVMRustGetOrInsertFunction<'a>(
|
||||
M: &'a Module,
|
||||
Name: *const c_char,
|
||||
|
|
|
|||
|
|
@ -1099,6 +1099,9 @@ pub struct Indeterminate;
|
|||
pub struct DeriveResolution {
|
||||
pub path: ast::Path,
|
||||
pub item: Annotatable,
|
||||
// FIXME: currently this field is only used in `is_none`/`is_some` conditions. However, the
|
||||
// `Arc<SyntaxExtension>` will be used if the FIXME in `MacroExpander::fully_expand_fragment`
|
||||
// is completed.
|
||||
pub exts: Option<Arc<SyntaxExtension>>,
|
||||
pub is_const: bool,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,9 +144,7 @@ extern "C" void LLVMRustPrintStatistics(RustStringRef OutBuf) {
|
|||
llvm::PrintStatistics(OS);
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustOffloadMapper(LLVMModuleRef M, LLVMValueRef OldFn,
|
||||
LLVMValueRef NewFn) {
|
||||
llvm::Module *module = llvm::unwrap(M);
|
||||
extern "C" void LLVMRustOffloadMapper(LLVMValueRef OldFn, LLVMValueRef NewFn) {
|
||||
llvm::Function *oldFn = llvm::unwrap<llvm::Function>(OldFn);
|
||||
llvm::Function *newFn = llvm::unwrap<llvm::Function>(NewFn);
|
||||
|
||||
|
|
|
|||
|
|
@ -135,6 +135,10 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
|
|||
self.report_abi_mismatch(expr.span, caller_sig.abi, callee_sig.abi);
|
||||
}
|
||||
|
||||
if !callee_sig.abi.supports_guaranteed_tail_call() {
|
||||
self.report_unsupported_abi(expr.span, callee_sig.abi);
|
||||
}
|
||||
|
||||
// FIXME(explicit_tail_calls): this currently fails for cases where opaques are used.
|
||||
// e.g.
|
||||
// ```
|
||||
|
|
@ -358,6 +362,16 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
|
|||
self.found_errors = Err(err);
|
||||
}
|
||||
|
||||
fn report_unsupported_abi(&mut self, sp: Span, callee_abi: ExternAbi) {
|
||||
let err = self
|
||||
.tcx
|
||||
.dcx()
|
||||
.struct_span_err(sp, "ABI does not support guaranteed tail calls")
|
||||
.with_note(format!("`become` is not supported for `extern {callee_abi}` functions"))
|
||||
.emit();
|
||||
self.found_errors = Err(err);
|
||||
}
|
||||
|
||||
fn report_signature_mismatch(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::coverage::BasicCoverageBlock;
|
||||
use rustc_span::{ExpnId, ExpnKind, Span};
|
||||
|
||||
use crate::coverage::from_mir;
|
||||
use crate::coverage::graph::CoverageGraph;
|
||||
use crate::coverage::hir_info::ExtractedHirInfo;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) struct SpanWithBcb {
|
||||
pub(crate) span: Span,
|
||||
|
|
@ -70,6 +75,10 @@ pub(crate) struct ExpnNode {
|
|||
pub(crate) spans: Vec<SpanWithBcb>,
|
||||
/// Expansions whose call-site is in this expansion.
|
||||
pub(crate) child_expn_ids: FxIndexSet<ExpnId>,
|
||||
|
||||
/// Hole spans belonging to this expansion, to be carved out from the
|
||||
/// code spans during span refinement.
|
||||
pub(crate) hole_spans: Vec<Span>,
|
||||
}
|
||||
|
||||
impl ExpnNode {
|
||||
|
|
@ -88,17 +97,27 @@ impl ExpnNode {
|
|||
|
||||
spans: vec![],
|
||||
child_expn_ids: FxIndexSet::default(),
|
||||
|
||||
hole_spans: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a collection of span/BCB pairs from potentially-different syntax contexts,
|
||||
/// Extracts raw span/BCB pairs from potentially-different syntax contexts, and
|
||||
/// arranges them into an "expansion tree" based on their expansion call-sites.
|
||||
pub(crate) fn build_expn_tree(spans: impl IntoIterator<Item = SpanWithBcb>) -> ExpnTree {
|
||||
pub(crate) fn build_expn_tree(
|
||||
mir_body: &mir::Body<'_>,
|
||||
hir_info: &ExtractedHirInfo,
|
||||
graph: &CoverageGraph,
|
||||
) -> ExpnTree {
|
||||
let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, graph);
|
||||
|
||||
let mut nodes = FxIndexMap::default();
|
||||
let new_node = |&expn_id: &ExpnId| ExpnNode::new(expn_id);
|
||||
|
||||
for span_with_bcb in spans {
|
||||
for from_mir::RawSpanFromMir { raw_span, bcb } in raw_spans {
|
||||
let span_with_bcb = SpanWithBcb { span: raw_span, bcb };
|
||||
|
||||
// Create a node for this span's enclosing expansion, and add the span to it.
|
||||
let expn_id = span_with_bcb.span.ctxt().outer_expn();
|
||||
let node = nodes.entry(expn_id).or_insert_with_key(new_node);
|
||||
|
|
@ -123,5 +142,13 @@ pub(crate) fn build_expn_tree(spans: impl IntoIterator<Item = SpanWithBcb>) -> E
|
|||
}
|
||||
}
|
||||
|
||||
// Associate each hole span (extracted from HIR) with its corresponding
|
||||
// expansion tree node.
|
||||
for &hole_span in &hir_info.hole_spans {
|
||||
let expn_id = hole_span.ctxt().outer_expn();
|
||||
let Some(node) = nodes.get_mut(&expn_id) else { continue };
|
||||
node.hole_spans.push(hole_span);
|
||||
}
|
||||
|
||||
ExpnTree { nodes }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,19 +142,3 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
|
|||
| TerminatorKind::InlineAsm { .. } => Some(terminator.source_info.span),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Hole {
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
impl Hole {
|
||||
pub(crate) fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool {
|
||||
if !self.span.overlaps_or_adjacent(other.span) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.span = self.span.to(other.span);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ use rustc_middle::mir::coverage::{
|
|||
use rustc_middle::mir::{self, BasicBlock, StatementKind};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
use crate::coverage::expansion;
|
||||
use crate::coverage::graph::CoverageGraph;
|
||||
use crate::coverage::hir_info::ExtractedHirInfo;
|
||||
use crate::coverage::spans::extract_refined_covspans;
|
||||
|
|
@ -23,10 +24,12 @@ pub(crate) fn extract_mappings_from_mir<'tcx>(
|
|||
hir_info: &ExtractedHirInfo,
|
||||
graph: &CoverageGraph,
|
||||
) -> ExtractedMappings {
|
||||
let expn_tree = expansion::build_expn_tree(mir_body, hir_info, graph);
|
||||
|
||||
let mut mappings = vec![];
|
||||
|
||||
// Extract ordinary code mappings from MIR statement/terminator spans.
|
||||
extract_refined_covspans(tcx, mir_body, hir_info, graph, &mut mappings);
|
||||
extract_refined_covspans(tcx, hir_info, graph, &expn_tree, &mut mappings);
|
||||
|
||||
extract_branch_mappings(mir_body, hir_info, graph, &mut mappings);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use crate::coverage::mappings::ExtractedMappings;
|
|||
|
||||
mod counters;
|
||||
mod expansion;
|
||||
mod from_mir;
|
||||
mod graph;
|
||||
mod hir_info;
|
||||
mod mappings;
|
||||
|
|
|
|||
|
|
@ -1,22 +1,18 @@
|
|||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::coverage::{Mapping, MappingKind, START_BCB};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{BytePos, DesugaringKind, ExpnId, ExpnKind, MacroKind, Span};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::coverage::expansion::{self, ExpnTree, SpanWithBcb};
|
||||
use crate::coverage::expansion::{ExpnTree, SpanWithBcb};
|
||||
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
|
||||
use crate::coverage::hir_info::ExtractedHirInfo;
|
||||
use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir};
|
||||
|
||||
mod from_mir;
|
||||
|
||||
pub(super) fn extract_refined_covspans<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mir_body: &mir::Body<'tcx>,
|
||||
hir_info: &ExtractedHirInfo,
|
||||
graph: &CoverageGraph,
|
||||
expn_tree: &ExpnTree,
|
||||
mappings: &mut Vec<Mapping>,
|
||||
) {
|
||||
if hir_info.is_async_fn {
|
||||
|
|
@ -32,22 +28,32 @@ pub(super) fn extract_refined_covspans<'tcx>(
|
|||
|
||||
let &ExtractedHirInfo { body_span, .. } = hir_info;
|
||||
|
||||
let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, graph);
|
||||
// Use the raw spans to build a tree of expansions for this function.
|
||||
let expn_tree = expansion::build_expn_tree(
|
||||
raw_spans
|
||||
.into_iter()
|
||||
.map(|RawSpanFromMir { raw_span, bcb }| SpanWithBcb { span: raw_span, bcb }),
|
||||
);
|
||||
// If there somehow isn't an expansion tree node corresponding to the
|
||||
// body span, return now and don't create any mappings.
|
||||
let Some(node) = expn_tree.get(body_span.ctxt().outer_expn()) else { return };
|
||||
|
||||
let mut covspans = vec![];
|
||||
let mut push_covspan = |covspan: Covspan| {
|
||||
|
||||
for &SpanWithBcb { span, bcb } in &node.spans {
|
||||
covspans.push(Covspan { span, bcb });
|
||||
}
|
||||
|
||||
// For each expansion with its call-site in the body span, try to
|
||||
// distill a corresponding covspan.
|
||||
for &child_expn_id in &node.child_expn_ids {
|
||||
if let Some(covspan) = single_covspan_for_child_expn(tcx, graph, &expn_tree, child_expn_id)
|
||||
{
|
||||
covspans.push(covspan);
|
||||
}
|
||||
}
|
||||
|
||||
covspans.retain(|covspan: &Covspan| {
|
||||
let covspan_span = covspan.span;
|
||||
// Discard any spans not contained within the function body span.
|
||||
// Also discard any spans that fill the entire body, because they tend
|
||||
// to represent compiler-inserted code, e.g. implicitly returning `()`.
|
||||
if !body_span.contains(covspan_span) || body_span.source_equal(covspan_span) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Each pushed covspan should have the same context as the body span.
|
||||
|
|
@ -57,27 +63,11 @@ pub(super) fn extract_refined_covspans<'tcx>(
|
|||
false,
|
||||
"span context mismatch: body_span={body_span:?}, covspan.span={covspan_span:?}"
|
||||
);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
covspans.push(covspan);
|
||||
};
|
||||
|
||||
if let Some(node) = expn_tree.get(body_span.ctxt().outer_expn()) {
|
||||
for &SpanWithBcb { span, bcb } in &node.spans {
|
||||
push_covspan(Covspan { span, bcb });
|
||||
}
|
||||
|
||||
// For each expansion with its call-site in the body span, try to
|
||||
// distill a corresponding covspan.
|
||||
for &child_expn_id in &node.child_expn_ids {
|
||||
if let Some(covspan) =
|
||||
single_covspan_for_child_expn(tcx, graph, &expn_tree, child_expn_id)
|
||||
{
|
||||
push_covspan(covspan);
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
// Only proceed if we found at least one usable span.
|
||||
if covspans.is_empty() {
|
||||
|
|
@ -107,14 +97,8 @@ pub(super) fn extract_refined_covspans<'tcx>(
|
|||
covspans.dedup_by(|b, a| a.span.source_equal(b.span));
|
||||
|
||||
// Sort the holes, and merge overlapping/adjacent holes.
|
||||
let mut holes = hir_info
|
||||
.hole_spans
|
||||
.iter()
|
||||
.copied()
|
||||
// Discard any holes that aren't directly visible within the body span.
|
||||
.filter(|&hole_span| body_span.contains(hole_span) && body_span.eq_ctxt(hole_span))
|
||||
.map(|span| Hole { span })
|
||||
.collect::<Vec<_>>();
|
||||
let mut holes = node.hole_spans.iter().copied().map(|span| Hole { span }).collect::<Vec<_>>();
|
||||
|
||||
holes.sort_by(|a, b| compare_spans(a.span, b.span));
|
||||
holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b));
|
||||
|
||||
|
|
@ -295,3 +279,19 @@ fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> {
|
|||
})
|
||||
.ok()?
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Hole {
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl Hole {
|
||||
fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool {
|
||||
if !self.span.overlaps_or_adjacent(other.span) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.span = self.span.to(other.span);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -458,14 +458,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
let mut result = Err(Determinacy::Determined);
|
||||
for derive in parent_scope.derives {
|
||||
let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
|
||||
match this.reborrow().resolve_macro_path(
|
||||
match this.reborrow().resolve_derive_macro_path(
|
||||
derive,
|
||||
MacroKind::Derive,
|
||||
parent_scope,
|
||||
true,
|
||||
force,
|
||||
ignore_import,
|
||||
None,
|
||||
) {
|
||||
Ok((Some(ext), _)) => {
|
||||
if ext.helper_attrs.contains(&ident.name) {
|
||||
|
|
|
|||
|
|
@ -396,14 +396,11 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
|
|||
for (i, resolution) in entry.resolutions.iter_mut().enumerate() {
|
||||
if resolution.exts.is_none() {
|
||||
resolution.exts = Some(
|
||||
match self.cm().resolve_macro_path(
|
||||
match self.cm().resolve_derive_macro_path(
|
||||
&resolution.path,
|
||||
MacroKind::Derive,
|
||||
&parent_scope,
|
||||
true,
|
||||
force,
|
||||
None,
|
||||
None,
|
||||
) {
|
||||
Ok((Some(ext), _)) => {
|
||||
if !ext.helper_attrs.is_empty() {
|
||||
|
|
@ -571,7 +568,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
path,
|
||||
kind,
|
||||
parent_scope,
|
||||
true,
|
||||
force,
|
||||
deleg_impl,
|
||||
invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)),
|
||||
|
|
@ -713,26 +709,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
Ok((ext, res))
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_macro_path<'r>(
|
||||
pub(crate) fn resolve_derive_macro_path<'r>(
|
||||
self: CmResolver<'r, 'ra, 'tcx>,
|
||||
path: &ast::Path,
|
||||
kind: MacroKind,
|
||||
parent_scope: &ParentScope<'ra>,
|
||||
trace: bool,
|
||||
force: bool,
|
||||
ignore_import: Option<Import<'ra>>,
|
||||
suggestion_span: Option<Span>,
|
||||
) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> {
|
||||
self.resolve_macro_or_delegation_path(
|
||||
path,
|
||||
kind,
|
||||
MacroKind::Derive,
|
||||
parent_scope,
|
||||
trace,
|
||||
force,
|
||||
None,
|
||||
None,
|
||||
ignore_import,
|
||||
suggestion_span,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -741,7 +733,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
ast_path: &ast::Path,
|
||||
kind: MacroKind,
|
||||
parent_scope: &ParentScope<'ra>,
|
||||
trace: bool,
|
||||
force: bool,
|
||||
deleg_impl: Option<LocalDefId>,
|
||||
invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
|
||||
|
|
@ -780,16 +771,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
PathResult::Module(..) => unreachable!(),
|
||||
};
|
||||
|
||||
if trace {
|
||||
self.multi_segment_macro_resolutions.borrow_mut(&self).push((
|
||||
path,
|
||||
path_span,
|
||||
kind,
|
||||
*parent_scope,
|
||||
res.ok(),
|
||||
ns,
|
||||
));
|
||||
}
|
||||
self.multi_segment_macro_resolutions.borrow_mut(&self).push((
|
||||
path,
|
||||
path_span,
|
||||
kind,
|
||||
*parent_scope,
|
||||
res.ok(),
|
||||
ns,
|
||||
));
|
||||
|
||||
self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span);
|
||||
res
|
||||
|
|
@ -807,15 +796,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
return Err(Determinacy::Undetermined);
|
||||
}
|
||||
|
||||
if trace {
|
||||
self.single_segment_macro_resolutions.borrow_mut(&self).push((
|
||||
path[0].ident,
|
||||
kind,
|
||||
*parent_scope,
|
||||
binding.ok(),
|
||||
suggestion_span,
|
||||
));
|
||||
}
|
||||
self.single_segment_macro_resolutions.borrow_mut(&self).push((
|
||||
path[0].ident,
|
||||
kind,
|
||||
*parent_scope,
|
||||
binding.ok(),
|
||||
suggestion_span,
|
||||
));
|
||||
|
||||
let res = binding.map(|binding| binding.res());
|
||||
self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span);
|
||||
|
|
|
|||
|
|
@ -725,9 +725,9 @@ impl<T, A: Allocator> Box<T, A> {
|
|||
#[unstable(feature = "box_take", issue = "147212")]
|
||||
pub fn take(boxed: Self) -> (T, Box<mem::MaybeUninit<T>, A>) {
|
||||
unsafe {
|
||||
let (raw, alloc) = Box::into_raw_with_allocator(boxed);
|
||||
let (raw, alloc) = Box::into_non_null_with_allocator(boxed);
|
||||
let value = raw.read();
|
||||
let uninit = Box::from_raw_in(raw.cast::<mem::MaybeUninit<T>>(), alloc);
|
||||
let uninit = Box::from_non_null_in(raw.cast_uninit(), alloc);
|
||||
(value, uninit)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@
|
|||
#![feature(exact_size_is_empty)]
|
||||
#![feature(extend_one)]
|
||||
#![feature(extend_one_unchecked)]
|
||||
#![feature(fmt_arguments_from_str)]
|
||||
#![feature(fmt_internals)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(formatting_options)]
|
||||
|
|
|
|||
|
|
@ -15,18 +15,18 @@ use crate::{fmt, ops, slice, str};
|
|||
// actually reference libstd or liballoc in intra-doc links. so, the best we can do is remove the
|
||||
// links to `CString` and `String` for now until a solution is developed
|
||||
|
||||
/// Representation of a borrowed C string.
|
||||
/// A dynamically-sized view of a C string.
|
||||
///
|
||||
/// This type represents a borrowed reference to a nul-terminated
|
||||
/// The type `&CStr` represents a reference to a borrowed nul-terminated
|
||||
/// array of bytes. It can be constructed safely from a <code>&[[u8]]</code>
|
||||
/// slice, or unsafely from a raw `*const c_char`. It can be expressed as a
|
||||
/// literal in the form `c"Hello world"`.
|
||||
///
|
||||
/// The `CStr` can then be converted to a Rust <code>&[str]</code> by performing
|
||||
/// The `&CStr` can then be converted to a Rust <code>&[str]</code> by performing
|
||||
/// UTF-8 validation, or into an owned `CString`.
|
||||
///
|
||||
/// `&CStr` is to `CString` as <code>&[str]</code> is to `String`: the former
|
||||
/// in each pair are borrowed references; the latter are owned
|
||||
/// in each pair are borrowing references; the latter are owned
|
||||
/// strings.
|
||||
///
|
||||
/// Note that this structure does **not** have a guaranteed layout (the `repr(transparent)`
|
||||
|
|
|
|||
|
|
@ -734,7 +734,21 @@ impl<'a> Arguments<'a> {
|
|||
unsafe { Arguments { template: mem::transmute(template), args: mem::transmute(args) } }
|
||||
}
|
||||
|
||||
// Same as `from_str`, but not const.
|
||||
// Used by format_args!() expansion when arguments are inlined,
|
||||
// e.g. format_args!("{}", 123), which is not allowed in const.
|
||||
#[inline]
|
||||
pub fn from_str_nonconst(s: &'static str) -> Arguments<'a> {
|
||||
Arguments::from_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Arguments<'a> {
|
||||
/// Create a `fmt::Arguments` object for a single static string.
|
||||
///
|
||||
/// Formatting this `fmt::Arguments` will just produce the string as-is.
|
||||
#[inline]
|
||||
#[unstable(feature = "fmt_arguments_from_str", issue = "148905")]
|
||||
pub const fn from_str(s: &'static str) -> Arguments<'a> {
|
||||
// SAFETY: This is the "static str" representation of fmt::Arguments; see above.
|
||||
unsafe {
|
||||
|
|
@ -744,14 +758,6 @@ impl<'a> Arguments<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Same as `from_str`, but not const.
|
||||
// Used by format_args!() expansion when arguments are inlined,
|
||||
// e.g. format_args!("{}", 123), which is not allowed in const.
|
||||
#[inline]
|
||||
pub fn from_str_nonconst(s: &'static str) -> Arguments<'a> {
|
||||
Arguments::from_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
|
|
|||
|
|
@ -991,7 +991,7 @@ pub(crate) mod builtin {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_diagnostic_item = "format_args_macro"]
|
||||
#[allow_internal_unsafe]
|
||||
#[allow_internal_unstable(fmt_internals)]
|
||||
#[allow_internal_unstable(fmt_internals, fmt_arguments_from_str)]
|
||||
#[rustc_builtin_macro]
|
||||
#[macro_export]
|
||||
macro_rules! format_args {
|
||||
|
|
@ -1005,7 +1005,7 @@ pub(crate) mod builtin {
|
|||
///
|
||||
/// This macro will be removed once `format_args` is allowed in const contexts.
|
||||
#[unstable(feature = "const_format_args", issue = "none")]
|
||||
#[allow_internal_unstable(fmt_internals, const_fmt_arguments_new)]
|
||||
#[allow_internal_unstable(fmt_internals, fmt_arguments_from_str)]
|
||||
#[rustc_builtin_macro]
|
||||
#[macro_export]
|
||||
macro_rules! const_format_args {
|
||||
|
|
@ -1020,7 +1020,7 @@ pub(crate) mod builtin {
|
|||
reason = "`format_args_nl` is only for internal \
|
||||
language use and is subject to change"
|
||||
)]
|
||||
#[allow_internal_unstable(fmt_internals)]
|
||||
#[allow_internal_unstable(fmt_internals, fmt_arguments_from_str)]
|
||||
#[rustc_builtin_macro]
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ pub use self::{
|
|||
stdio::{Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout},
|
||||
util::{Empty, Repeat, Sink, empty, repeat, sink},
|
||||
};
|
||||
use crate::mem::take;
|
||||
use crate::mem::{MaybeUninit, take};
|
||||
use crate::ops::{Deref, DerefMut};
|
||||
use crate::{cmp, fmt, slice, str, sys};
|
||||
|
||||
|
|
@ -1242,6 +1242,46 @@ pub trait Read {
|
|||
{
|
||||
Take { inner: self, len: limit, limit }
|
||||
}
|
||||
|
||||
/// Read and return a fixed array of bytes from this source.
|
||||
///
|
||||
/// This function uses an array sized based on a const generic size known at compile time. You
|
||||
/// can specify the size with turbofish (`reader.read_array::<8>()`), or let type inference
|
||||
/// determine the number of bytes needed based on how the return value gets used. For instance,
|
||||
/// this function works well with functions like [`u64::from_le_bytes`] to turn an array of
|
||||
/// bytes into an integer of the same size.
|
||||
///
|
||||
/// Like `read_exact`, if this function encounters an "end of file" before reading the desired
|
||||
/// number of bytes, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(read_array)]
|
||||
/// use std::io::Cursor;
|
||||
/// use std::io::prelude::*;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let mut buf = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2]);
|
||||
/// let x = u64::from_le_bytes(buf.read_array()?);
|
||||
/// let y = u32::from_be_bytes(buf.read_array()?);
|
||||
/// let z = u16::from_be_bytes(buf.read_array()?);
|
||||
/// assert_eq!(x, 0x807060504030201);
|
||||
/// assert_eq!(y, 0x9080706);
|
||||
/// assert_eq!(z, 0x504);
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "read_array", issue = "148848")]
|
||||
fn read_array<const N: usize>(&mut self) -> Result<[u8; N]>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut buf = [MaybeUninit::uninit(); N];
|
||||
let mut borrowed_buf = BorrowedBuf::from(buf.as_mut_slice());
|
||||
self.read_buf_exact(borrowed_buf.unfilled())?;
|
||||
// Guard against incorrect `read_buf_exact` implementations.
|
||||
assert_eq!(borrowed_buf.len(), N);
|
||||
Ok(unsafe { MaybeUninit::array_assume_init(buf) })
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads all bytes from a [reader][Read] into a new [`String`].
|
||||
|
|
|
|||
|
|
@ -348,6 +348,7 @@
|
|||
#![feature(int_from_ascii)]
|
||||
#![feature(ip)]
|
||||
#![feature(lazy_get)]
|
||||
#![feature(maybe_uninit_array_assume_init)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(maybe_uninit_write_slice)]
|
||||
#![feature(panic_can_unwind)]
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
all(target_arch = "powerpc64", target_os = "linux"),
|
||||
feature(stdarch_powerpc_feature_detection)
|
||||
)]
|
||||
#![cfg_attr(all(target_arch = "s390x", target_os = "linux"), feature(s390x_target_feature))]
|
||||
|
||||
#[test]
|
||||
#[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))]
|
||||
|
|
|
|||
|
|
@ -838,9 +838,23 @@ fn print_higher_ranked_params_with_space(
|
|||
pub(crate) fn print_anchor(did: DefId, text: Symbol, cx: &Context<'_>) -> impl Display {
|
||||
fmt::from_fn(move |f| {
|
||||
if let Ok(HrefInfo { url, kind, rust_path }) = href(did, cx) {
|
||||
let tcx = cx.tcx();
|
||||
let def_kind = tcx.def_kind(did);
|
||||
let anchor = if matches!(
|
||||
def_kind,
|
||||
DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst | DefKind::Variant
|
||||
) {
|
||||
let parent_def_id = tcx.parent(did);
|
||||
let item_type =
|
||||
ItemType::from_def_kind(def_kind, Some(tcx.def_kind(parent_def_id)));
|
||||
format!("#{}.{}", item_type.as_str(), tcx.item_name(did))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
write!(
|
||||
f,
|
||||
r#"<a class="{kind}" href="{url}" title="{kind} {path}">{text}</a>"#,
|
||||
r#"<a class="{kind}" href="{url}{anchor}" title="{kind} {path}">{text}</a>"#,
|
||||
path = join_path_syms(rust_path),
|
||||
text = EscapeBodyText(text.as_str()),
|
||||
)
|
||||
|
|
|
|||
21
tests/assembly-llvm/tail-call-infinite-recursion.rs
Normal file
21
tests/assembly-llvm/tail-call-infinite-recursion.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
//@ add-minicore
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target x86_64-unknown-linux-gnu -Copt-level=0 -Cllvm-args=-x86-asm-syntax=intel
|
||||
//@ needs-llvm-components: x86
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(no_core, explicit_tail_calls)]
|
||||
#![crate_type = "lib"]
|
||||
#![no_core]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// Test that an infinite loop via guaranteed tail calls does not blow the stack.
|
||||
|
||||
// CHECK-LABEL: inf
|
||||
// CHECK: mov rax, qword ptr [rip + inf@GOTPCREL]
|
||||
// CHECK: jmp rax
|
||||
#[unsafe(no_mangle)]
|
||||
fn inf() -> ! {
|
||||
become inf()
|
||||
}
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
// skip-filecheck
|
||||
//
|
||||
// check that we mark blocks with `!` locals as unreachable.
|
||||
// (and currently don't do the same for other uninhabited types)
|
||||
#![feature(never_type)]
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// skip-filecheck
|
||||
|
||||
//@ edition: 2021
|
||||
// In ed 2021 and below, we don't fallback `!` to `()`.
|
||||
// In ed 2021 and below, we fallback `!` to `()`.
|
||||
// This would introduce a `! -> ()` coercion which would
|
||||
// be UB if we didn't disallow this explicitly.
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,10 @@ fn main() {
|
|||
|
||||
// Some targets (for example wasm) cannot execute doctests directly even with a runner,
|
||||
// so only exercise the success path when the target can run on the host.
|
||||
if target().contains("wasm") || std::env::var_os("REMOTE_TEST_CLIENT").is_some() {
|
||||
if target().contains("wasm")
|
||||
|| target().contains("sgx")
|
||||
|| std::env::var_os("REMOTE_TEST_CLIENT").is_some()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
19
tests/rustdoc/import_trait_associated_functions.rs
Normal file
19
tests/rustdoc/import_trait_associated_functions.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// This test ensures that reexports of associated items links to the associated items.
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/148008>.
|
||||
|
||||
#![feature(import_trait_associated_functions)]
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
//@ has 'foo/index.html'
|
||||
|
||||
pub trait Test {
|
||||
fn method();
|
||||
const CONST: u8;
|
||||
type Type;
|
||||
}
|
||||
|
||||
//@ has - '//*[@id="reexport.method"]//a[@href="trait.Test.html#tymethod.method"]' 'method'
|
||||
//@ has - '//*[@id="reexport.CONST"]//a[@href="trait.Test.html#associatedconstant.CONST"]' 'CONST'
|
||||
//@ has - '//*[@id="reexport.Type"]//a[@href="trait.Test.html#associatedtype.Type"]' 'Type'
|
||||
pub use self::Test::{method, CONST, Type};
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
// Regression test for #122561
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/122561>.
|
||||
//
|
||||
// Tests suggestions for type mismatch of loop expressions.
|
||||
|
||||
fn for_infinite() -> bool {
|
||||
for i in 0.. {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
warning: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/coerce-loop-issue-122561.rs:47:5
|
||||
--> $DIR/coerce-loop-issue-122561.rs:49:5
|
||||
|
|
||||
LL | while true {
|
||||
| ^^^^^^^^^^ help: use `loop`
|
||||
|
|
@ -7,13 +7,13 @@ LL | while true {
|
|||
= note: `#[warn(while_true)]` on by default
|
||||
|
||||
warning: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/coerce-loop-issue-122561.rs:71:5
|
||||
--> $DIR/coerce-loop-issue-122561.rs:73:5
|
||||
|
|
||||
LL | while true {
|
||||
| ^^^^^^^^^^ help: use `loop`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:41:24
|
||||
--> $DIR/coerce-loop-issue-122561.rs:43:24
|
||||
|
|
||||
LL | fn for_in_arg(a: &[(); for x in 0..2 {}]) -> bool {
|
||||
| ^^^^^^^^^^^^^^^^ expected `usize`, found `()`
|
||||
|
|
@ -25,7 +25,7 @@ LL | fn for_in_arg(a: &[(); for x in 0..2 {} /* `usize` value */]) -> bool {
|
|||
| +++++++++++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:4:5
|
||||
--> $DIR/coerce-loop-issue-122561.rs:6:5
|
||||
|
|
||||
LL | fn for_infinite() -> bool {
|
||||
| ---- expected `bool` because of return type
|
||||
|
|
@ -43,7 +43,7 @@ LL + /* `bool` value */
|
|||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:11:5
|
||||
--> $DIR/coerce-loop-issue-122561.rs:13:5
|
||||
|
|
||||
LL | fn for_finite() -> String {
|
||||
| ------ expected `String` because of return type
|
||||
|
|
@ -61,7 +61,7 @@ LL + /* `String` value */
|
|||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:18:5
|
||||
--> $DIR/coerce-loop-issue-122561.rs:20:5
|
||||
|
|
||||
LL | fn for_zero_times() -> bool {
|
||||
| ---- expected `bool` because of return type
|
||||
|
|
@ -79,7 +79,7 @@ LL + /* `bool` value */
|
|||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:25:5
|
||||
--> $DIR/coerce-loop-issue-122561.rs:27:5
|
||||
|
|
||||
LL | fn for_never_type() -> ! {
|
||||
| - expected `!` because of return type
|
||||
|
|
@ -98,7 +98,7 @@ LL + /* `loop {}` or `panic!("...")` */
|
|||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:33:32
|
||||
--> $DIR/coerce-loop-issue-122561.rs:35:32
|
||||
|
|
||||
LL | fn for_single_line() -> bool { for i in 0.. { return false; } }
|
||||
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
||||
|
|
@ -112,7 +112,7 @@ LL | fn for_single_line() -> bool { for i in 0.. { return false; } /* `bool` val
|
|||
| ++++++++++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:47:5
|
||||
--> $DIR/coerce-loop-issue-122561.rs:49:5
|
||||
|
|
||||
LL | fn while_inifinite() -> bool {
|
||||
| ---- expected `bool` because of return type
|
||||
|
|
@ -131,7 +131,7 @@ LL + /* `bool` value */
|
|||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:56:5
|
||||
--> $DIR/coerce-loop-issue-122561.rs:58:5
|
||||
|
|
||||
LL | fn while_finite() -> bool {
|
||||
| ---- expected `bool` because of return type
|
||||
|
|
@ -151,7 +151,7 @@ LL + /* `bool` value */
|
|||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:64:5
|
||||
--> $DIR/coerce-loop-issue-122561.rs:66:5
|
||||
|
|
||||
LL | fn while_zero_times() -> bool {
|
||||
| ---- expected `bool` because of return type
|
||||
|
|
@ -169,7 +169,7 @@ LL + /* `bool` value */
|
|||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:71:5
|
||||
--> $DIR/coerce-loop-issue-122561.rs:73:5
|
||||
|
|
||||
LL | fn while_never_type() -> ! {
|
||||
| - expected `!` because of return type
|
||||
|
|
@ -188,7 +188,7 @@ LL + /* `loop {}` or `panic!("...")` */
|
|||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:85:5
|
||||
--> $DIR/coerce-loop-issue-122561.rs:87:5
|
||||
|
|
||||
LL | / for i in 0.. {
|
||||
LL | |
|
||||
|
|
@ -203,7 +203,7 @@ LL + /* `i32` value */
|
|||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:92:9
|
||||
--> $DIR/coerce-loop-issue-122561.rs:94:9
|
||||
|
|
||||
LL | / for i in 0..5 {
|
||||
LL | |
|
||||
|
|
@ -218,7 +218,7 @@ LL + /* `usize` value */
|
|||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:98:9
|
||||
--> $DIR/coerce-loop-issue-122561.rs:100:9
|
||||
|
|
||||
LL | / while false {
|
||||
LL | |
|
||||
|
|
@ -233,7 +233,7 @@ LL + /* `usize` value */
|
|||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:104:23
|
||||
--> $DIR/coerce-loop-issue-122561.rs:106:23
|
||||
|
|
||||
LL | let _ = |a: &[(); for x in 0..2 {}]| {};
|
||||
| ^^^^^^^^^^^^^^^^ expected `usize`, found `()`
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
|
|||
#[derive(Copy, Clone)]
|
||||
enum Never {}
|
||||
|
||||
// An enum with 3 variants of which some are uninhabited -- so the uninhabited variants *do*
|
||||
// An enum with 4 variants of which only some are uninhabited -- so the uninhabited variants *do*
|
||||
// have a discriminant.
|
||||
enum UninhDiscriminant {
|
||||
A,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,18 @@
|
|||
// Regression test for <https://github.com/rust-lang/rust/issues/120337>.
|
||||
//
|
||||
// This checks that const eval doesn't cause an ICE when reading an uninhabited
|
||||
// variant. (N.B. this is UB, but not currently detected by rustc)
|
||||
//
|
||||
//@ check-pass
|
||||
#![feature(never_type)]
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum E { A(!), }
|
||||
|
||||
pub union U { u: (), e: E, }
|
||||
|
||||
pub const C: () = {
|
||||
let E::A(ref a) = unsafe { &(&U { u: () }).e};
|
||||
let E::A(ref a) = unsafe { &(&U { u: () }).e };
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
//@ add-minicore
|
||||
//@ ignore-backends: gcc
|
||||
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
|
||||
//@ needs-llvm-components: arm
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(no_core, explicit_tail_calls, abi_cmse_nonsecure_call)]
|
||||
#![no_core]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
unsafe extern "C" {
|
||||
safe fn magic() -> extern "cmse-nonsecure-call" fn(u32, u32) -> u32;
|
||||
}
|
||||
|
||||
// The `cmse-nonsecure-call` ABI can only occur on function pointers:
|
||||
//
|
||||
// - a `cmse-nonsecure-call` definition throws an error
|
||||
// - a `cmse-nonsecure-call` become in a definition with any other ABI is an ABI mismatch
|
||||
#[no_mangle]
|
||||
extern "cmse-nonsecure-call" fn become_nonsecure_call_1(x: u32, y: u32) -> u32 {
|
||||
//~^ ERROR the `"cmse-nonsecure-call"` ABI is only allowed on function pointers
|
||||
unsafe {
|
||||
let f = magic();
|
||||
become f(1, 2)
|
||||
//~^ ERROR ABI does not support guaranteed tail calls
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn become_nonsecure_call_2(x: u32, y: u32) -> u32 {
|
||||
unsafe {
|
||||
let f = magic();
|
||||
become f(1, 2)
|
||||
//~^ ERROR mismatched function ABIs
|
||||
//~| ERROR ABI does not support guaranteed tail calls
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
error[E0781]: the `"cmse-nonsecure-call"` ABI is only allowed on function pointers
|
||||
--> $DIR/cmse-nonsecure-call.rs:21:1
|
||||
|
|
||||
LL | extern "cmse-nonsecure-call" fn become_nonsecure_call_1(x: u32, y: u32) -> u32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: ABI does not support guaranteed tail calls
|
||||
--> $DIR/cmse-nonsecure-call.rs:25:9
|
||||
|
|
||||
LL | become f(1, 2)
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `become` is not supported for `extern "cmse-nonsecure-call"` functions
|
||||
|
||||
error: mismatched function ABIs
|
||||
--> $DIR/cmse-nonsecure-call.rs:34:9
|
||||
|
|
||||
LL | become f(1, 2)
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `become` requires caller and callee to have the same ABI
|
||||
= note: caller ABI is `"C"`, while callee ABI is `"cmse-nonsecure-call"`
|
||||
|
||||
error: ABI does not support guaranteed tail calls
|
||||
--> $DIR/cmse-nonsecure-call.rs:34:9
|
||||
|
|
||||
LL | become f(1, 2)
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `become` is not supported for `extern "cmse-nonsecure-call"` functions
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0781`.
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
//@ add-minicore
|
||||
//@ ignore-backends: gcc
|
||||
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
|
||||
//@ needs-llvm-components: arm
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(no_core, explicit_tail_calls, cmse_nonsecure_entry)]
|
||||
#![no_core]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
#[inline(never)]
|
||||
extern "cmse-nonsecure-entry" fn entry(c: bool, x: u32, y: u32) -> u32 {
|
||||
if c { x } else { y }
|
||||
}
|
||||
|
||||
// A `cmse-nonsecure-entry` clears registers before returning, so a tail call cannot be guaranteed.
|
||||
#[unsafe(no_mangle)]
|
||||
extern "cmse-nonsecure-entry" fn become_nonsecure_entry(c: bool, x: u32, y: u32) -> u32 {
|
||||
become entry(c, x, y)
|
||||
//~^ ERROR ABI does not support guaranteed tail calls
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
error: ABI does not support guaranteed tail calls
|
||||
--> $DIR/cmse-nonsecure-entry.rs:20:5
|
||||
|
|
||||
LL | become entry(c, x, y)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `become` is not supported for `extern "cmse-nonsecure-entry"` functions
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -922,9 +922,6 @@ cc = ["@davidtwco", "@wesleywiser"]
|
|||
[mentions."compiler/rustc_codegen_cranelift"]
|
||||
cc = ["@bjorn3"]
|
||||
|
||||
[mentions."compiler/rustc_codegen_ssa"]
|
||||
cc = ["@WaffleLapkin"]
|
||||
|
||||
[mentions."compiler/rustc_codegen_gcc"]
|
||||
cc = ["@antoyo", "@GuillaumeGomez"]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue