rustc_intrinsic: support functions without body; they are implicitly marked as must-be-overridden
This commit is contained in:
parent
be65012aa3
commit
3cd3649c6c
19 changed files with 118 additions and 68 deletions
|
@ -222,6 +222,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
decl,
|
decl,
|
||||||
coroutine_kind,
|
coroutine_kind,
|
||||||
body.as_deref(),
|
body.as_deref(),
|
||||||
|
attrs,
|
||||||
);
|
);
|
||||||
|
|
||||||
let itctx = ImplTraitContext::Universal;
|
let itctx = ImplTraitContext::Universal;
|
||||||
|
@ -233,7 +234,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
header: this.lower_fn_header(*header, hir::Safety::Safe),
|
header: this.lower_fn_header(*header, hir::Safety::Safe),
|
||||||
span: this.lower_span(*fn_sig_span),
|
span: this.lower_span(*fn_sig_span),
|
||||||
};
|
};
|
||||||
hir::ItemKind::Fn { sig, generics, body: body_id }
|
hir::ItemKind::Fn { sig, generics, body: body_id, has_body: body.is_some() }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ItemKind::Mod(_, mod_kind) => match mod_kind {
|
ItemKind::Mod(_, mod_kind) => match mod_kind {
|
||||||
|
@ -439,6 +440,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
sig: delegation_results.sig,
|
sig: delegation_results.sig,
|
||||||
generics: delegation_results.generics,
|
generics: delegation_results.generics,
|
||||||
body: delegation_results.body_id,
|
body: delegation_results.body_id,
|
||||||
|
has_body: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
|
ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
|
||||||
|
@ -747,7 +749,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
|
|
||||||
fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
|
fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
|
||||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||||
self.lower_attrs(hir_id, &i.attrs);
|
let attrs = self.lower_attrs(hir_id, &i.attrs);
|
||||||
let trait_item_def_id = hir_id.expect_owner();
|
let trait_item_def_id = hir_id.expect_owner();
|
||||||
|
|
||||||
let (generics, kind, has_default) = match &i.kind {
|
let (generics, kind, has_default) = match &i.kind {
|
||||||
|
@ -785,6 +787,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&sig.decl,
|
&sig.decl,
|
||||||
sig.header.coroutine_kind,
|
sig.header.coroutine_kind,
|
||||||
Some(body),
|
Some(body),
|
||||||
|
attrs,
|
||||||
);
|
);
|
||||||
let (generics, sig) = self.lower_method_sig(
|
let (generics, sig) = self.lower_method_sig(
|
||||||
generics,
|
generics,
|
||||||
|
@ -877,7 +880,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let has_value = true;
|
let has_value = true;
|
||||||
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
|
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
|
||||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||||
self.lower_attrs(hir_id, &i.attrs);
|
let attrs = self.lower_attrs(hir_id, &i.attrs);
|
||||||
|
|
||||||
let (generics, kind) = match &i.kind {
|
let (generics, kind) = match &i.kind {
|
||||||
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
|
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
|
||||||
|
@ -900,6 +903,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&sig.decl,
|
&sig.decl,
|
||||||
sig.header.coroutine_kind,
|
sig.header.coroutine_kind,
|
||||||
body.as_deref(),
|
body.as_deref(),
|
||||||
|
attrs,
|
||||||
);
|
);
|
||||||
let (generics, sig) = self.lower_method_sig(
|
let (generics, sig) = self.lower_method_sig(
|
||||||
generics,
|
generics,
|
||||||
|
@ -1054,20 +1058,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_fn_body_block(
|
fn lower_fn_body_block(&mut self, decl: &FnDecl, body: &Block) -> hir::BodyId {
|
||||||
&mut self,
|
self.lower_fn_body(decl, |this| this.lower_block_expr(body))
|
||||||
span: Span,
|
|
||||||
decl: &FnDecl,
|
|
||||||
body: Option<&Block>,
|
|
||||||
) -> hir::BodyId {
|
|
||||||
self.lower_fn_body(decl, |this| this.lower_block_expr_opt(span, body))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> {
|
|
||||||
match block {
|
|
||||||
Some(block) => self.lower_block_expr(block),
|
|
||||||
None => self.expr_err(span, self.dcx().has_errors().unwrap()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId {
|
pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId {
|
||||||
|
@ -1089,9 +1081,37 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
decl: &FnDecl,
|
decl: &FnDecl,
|
||||||
coroutine_kind: Option<CoroutineKind>,
|
coroutine_kind: Option<CoroutineKind>,
|
||||||
body: Option<&Block>,
|
body: Option<&Block>,
|
||||||
|
attrs: &'hir [hir::Attribute],
|
||||||
) -> hir::BodyId {
|
) -> hir::BodyId {
|
||||||
let (Some(coroutine_kind), Some(body)) = (coroutine_kind, body) else {
|
let Some(body) = body else {
|
||||||
return self.lower_fn_body_block(span, decl, body);
|
// Functions without a body are an error, except if this is an intrinsic. For those we
|
||||||
|
// create a fake body so that the entire rest of the compiler doesn't have to deal with
|
||||||
|
// this as a special case.
|
||||||
|
return self.lower_fn_body(decl, |this| {
|
||||||
|
if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) {
|
||||||
|
let empty_block = hir::Block {
|
||||||
|
hir_id: this.next_id(),
|
||||||
|
stmts: &[],
|
||||||
|
expr: None,
|
||||||
|
rules: hir::BlockCheckMode::DefaultBlock,
|
||||||
|
span,
|
||||||
|
targeted_by_break: false,
|
||||||
|
};
|
||||||
|
let loop_ = hir::ExprKind::Loop(
|
||||||
|
this.arena.alloc(empty_block),
|
||||||
|
None,
|
||||||
|
hir::LoopSource::Loop,
|
||||||
|
span,
|
||||||
|
);
|
||||||
|
hir::Expr { hir_id: this.next_id(), kind: loop_, span }
|
||||||
|
} else {
|
||||||
|
this.expr_err(span, this.dcx().has_errors().unwrap())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
let Some(coroutine_kind) = coroutine_kind else {
|
||||||
|
// Typical case: not a coroutine.
|
||||||
|
return self.lower_fn_body_block(decl, body);
|
||||||
};
|
};
|
||||||
self.lower_body(|this| {
|
self.lower_body(|this| {
|
||||||
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
||||||
|
|
|
@ -920,7 +920,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => {
|
ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => {
|
||||||
self.check_defaultness(item.span, *defaultness);
|
self.check_defaultness(item.span, *defaultness);
|
||||||
|
|
||||||
if body.is_none() {
|
let is_intrinsic =
|
||||||
|
item.attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic);
|
||||||
|
if body.is_none() && !is_intrinsic {
|
||||||
self.dcx().emit_err(errors::FnWithoutBody {
|
self.dcx().emit_err(errors::FnWithoutBody {
|
||||||
span: item.span,
|
span: item.span,
|
||||||
replace_span: self.ending_semi_or_hi(item.span),
|
replace_span: self.ending_semi_or_hi(item.span),
|
||||||
|
|
|
@ -566,7 +566,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
| ty::InstanceKind::ThreadLocalShim(..)
|
| ty::InstanceKind::ThreadLocalShim(..)
|
||||||
| ty::InstanceKind::AsyncDropGlueCtorShim(..)
|
| ty::InstanceKind::AsyncDropGlueCtorShim(..)
|
||||||
| ty::InstanceKind::Item(_) => {
|
| ty::InstanceKind::Item(_) => {
|
||||||
// We need MIR for this fn
|
// We need MIR for this fn.
|
||||||
|
// Note that this can be an intrinsic, if we are executing its fallback body.
|
||||||
let Some((body, instance)) = M::find_mir_or_eval_fn(
|
let Some((body, instance)) = M::find_mir_or_eval_fn(
|
||||||
self,
|
self,
|
||||||
instance,
|
instance,
|
||||||
|
|
|
@ -1013,7 +1013,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
),
|
),
|
||||||
gated!(
|
gated!(
|
||||||
rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
|
rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
|
||||||
"the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies",
|
"the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items",
|
||||||
),
|
),
|
||||||
gated!(
|
gated!(
|
||||||
rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
|
rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
|
||||||
|
|
|
@ -3640,7 +3640,7 @@ impl<'hir> Item<'hir> {
|
||||||
ItemKind::Const(ty, generics, body), (ty, generics, *body);
|
ItemKind::Const(ty, generics, body), (ty, generics, *body);
|
||||||
|
|
||||||
expect_fn, (&FnSig<'hir>, &'hir Generics<'hir>, BodyId),
|
expect_fn, (&FnSig<'hir>, &'hir Generics<'hir>, BodyId),
|
||||||
ItemKind::Fn { sig, generics, body }, (sig, generics, *body);
|
ItemKind::Fn { sig, generics, body, .. }, (sig, generics, *body);
|
||||||
|
|
||||||
expect_macro, (&ast::MacroDef, MacroKind), ItemKind::Macro(def, mk), (def, *mk);
|
expect_macro, (&ast::MacroDef, MacroKind), ItemKind::Macro(def, mk), (def, *mk);
|
||||||
|
|
||||||
|
@ -3768,7 +3768,15 @@ pub enum ItemKind<'hir> {
|
||||||
/// A `const` item.
|
/// A `const` item.
|
||||||
Const(&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
|
Const(&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
|
||||||
/// A function declaration.
|
/// A function declaration.
|
||||||
Fn { sig: FnSig<'hir>, generics: &'hir Generics<'hir>, body: BodyId },
|
Fn {
|
||||||
|
sig: FnSig<'hir>,
|
||||||
|
generics: &'hir Generics<'hir>,
|
||||||
|
body: BodyId,
|
||||||
|
/// Whether this function actually has a body.
|
||||||
|
/// For functions without a body, `body` is synthesized (to avoid ICEs all over the
|
||||||
|
/// compiler), but that code should never be translated.
|
||||||
|
has_body: bool,
|
||||||
|
},
|
||||||
/// A MBE macro definition (`macro_rules!` or `macro`).
|
/// A MBE macro definition (`macro_rules!` or `macro`).
|
||||||
Macro(&'hir ast::MacroDef, MacroKind),
|
Macro(&'hir ast::MacroDef, MacroKind),
|
||||||
/// A module.
|
/// A module.
|
||||||
|
|
|
@ -1778,9 +1778,16 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Intrinsi
|
||||||
&& (matches!(tcx.fn_sig(def_id).skip_binder().abi(), ExternAbi::RustIntrinsic)
|
&& (matches!(tcx.fn_sig(def_id).skip_binder().abi(), ExternAbi::RustIntrinsic)
|
||||||
|| tcx.has_attr(def_id, sym::rustc_intrinsic))
|
|| tcx.has_attr(def_id, sym::rustc_intrinsic))
|
||||||
{
|
{
|
||||||
|
let must_be_overridden = tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden)
|
||||||
|
|| match tcx.hir_node_by_def_id(def_id) {
|
||||||
|
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { has_body, .. }, .. }) => {
|
||||||
|
!has_body
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
Some(ty::IntrinsicDef {
|
Some(ty::IntrinsicDef {
|
||||||
name: tcx.item_name(def_id.into()),
|
name: tcx.item_name(def_id.into()),
|
||||||
must_be_overridden: tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden),
|
must_be_overridden,
|
||||||
const_stable: tcx.has_attr(def_id, sym::rustc_intrinsic_const_stable_indirect),
|
const_stable: tcx.has_attr(def_id, sym::rustc_intrinsic_const_stable_indirect),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1005,11 +1005,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
if let Some(source_scope) = scope {
|
if let Some(source_scope) = scope {
|
||||||
self.source_scope = source_scope;
|
self.source_scope = source_scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.tcx.intrinsic(self.def_id).is_some_and(|i| i.must_be_overridden) {
|
if self.tcx.intrinsic(self.def_id).is_some_and(|i| i.must_be_overridden) {
|
||||||
let source_info = self.source_info(rustc_span::DUMMY_SP);
|
let source_info = self.source_info(rustc_span::DUMMY_SP);
|
||||||
self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
|
self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
|
||||||
self.cfg.start_new_block().unit()
|
self.cfg.start_new_block().unit()
|
||||||
} else {
|
} else {
|
||||||
|
// Ensure we don't silently codegen functions with fake bodies.
|
||||||
|
match self.tcx.hir_node(self.hir_id) {
|
||||||
|
hir::Node::Item(hir::Item {
|
||||||
|
kind: hir::ItemKind::Fn { has_body: false, .. },
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
self.tcx.dcx().span_delayed_bug(
|
||||||
|
expr_span,
|
||||||
|
format!("fn item without body has reached MIR building: {:?}", self.def_id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
self.expr_into_dest(Place::return_place(), block, expr_id)
|
self.expr_into_dest(Place::return_place(), block, expr_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,7 +190,8 @@ impl<'tcx> Inliner<'tcx> {
|
||||||
|
|
||||||
// Intrinsic fallback bodies are automatically made cross-crate inlineable,
|
// Intrinsic fallback bodies are automatically made cross-crate inlineable,
|
||||||
// but at this stage we don't know whether codegen knows the intrinsic,
|
// but at this stage we don't know whether codegen knows the intrinsic,
|
||||||
// so just conservatively don't inline it.
|
// so just conservatively don't inline it. This also ensures that we do not
|
||||||
|
// accidentally inline the body of an intrinsic that *must* be overridden.
|
||||||
if self.tcx.has_attr(callsite.callee.def_id(), sym::rustc_intrinsic) {
|
if self.tcx.has_attr(callsite.callee.def_id(), sym::rustc_intrinsic) {
|
||||||
return Err("Callee is an intrinsic, do not inline fallback bodies");
|
return Err("Callee is an intrinsic, do not inline fallback bodies");
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,7 +232,7 @@ use rustc_middle::{bug, span_bug};
|
||||||
use rustc_session::Limit;
|
use rustc_session::Limit;
|
||||||
use rustc_session::config::EntryFnType;
|
use rustc_session::config::EntryFnType;
|
||||||
use rustc_span::source_map::{Spanned, dummy_spanned, respan};
|
use rustc_span::source_map::{Spanned, dummy_spanned, respan};
|
||||||
use rustc_span::{DUMMY_SP, Span, sym};
|
use rustc_span::{DUMMY_SP, Span};
|
||||||
use tracing::{debug, instrument, trace};
|
use tracing::{debug, instrument, trace};
|
||||||
|
|
||||||
use crate::errors::{self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit};
|
use crate::errors::{self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit};
|
||||||
|
@ -894,9 +894,8 @@ fn visit_instance_use<'tcx>(
|
||||||
if !tcx.should_codegen_locally(instance) {
|
if !tcx.should_codegen_locally(instance) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let ty::InstanceKind::Intrinsic(def_id) = instance.def {
|
if let Some(intrinsic) = tcx.intrinsic(instance.def_id()) {
|
||||||
let name = tcx.item_name(def_id);
|
if let Some(_requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) {
|
||||||
if let Some(_requirement) = ValidityRequirement::from_intrinsic(name) {
|
|
||||||
// The intrinsics assert_inhabited, assert_zero_valid, and assert_mem_uninitialized_valid will
|
// The intrinsics assert_inhabited, assert_zero_valid, and assert_mem_uninitialized_valid will
|
||||||
// be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any
|
// be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any
|
||||||
// of those intrinsics, we need to include a mono item for panic_nounwind, else we may try to
|
// of those intrinsics, we need to include a mono item for panic_nounwind, else we may try to
|
||||||
|
@ -906,11 +905,12 @@ fn visit_instance_use<'tcx>(
|
||||||
if tcx.should_codegen_locally(panic_instance) {
|
if tcx.should_codegen_locally(panic_instance) {
|
||||||
output.push(create_fn_mono_item(tcx, panic_instance, source));
|
output.push(create_fn_mono_item(tcx, panic_instance, source));
|
||||||
}
|
}
|
||||||
} else if tcx.has_attr(def_id, sym::rustc_intrinsic)
|
} else if !intrinsic.must_be_overridden {
|
||||||
&& !tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden)
|
// Codegen the fallback body of intrinsics with fallback bodies.
|
||||||
{
|
// We explicitly skip this otherwise to ensure we get a linker error
|
||||||
// Codegen the fallback body of intrinsics with fallback bodies
|
// if anyone tries to call this intrinsic and the codegen backend did not
|
||||||
let instance = ty::Instance::new(def_id, instance.args);
|
// override the implementation.
|
||||||
|
let instance = ty::Instance::new(instance.def_id(), instance.args);
|
||||||
if tcx.should_codegen_locally(instance) {
|
if tcx.should_codegen_locally(instance) {
|
||||||
output.push(create_fn_mono_item(tcx, instance, source));
|
output.push(create_fn_mono_item(tcx, instance, source));
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,7 +242,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
|
||||||
let is_reachable_non_generic = matches!(
|
let is_reachable_non_generic = matches!(
|
||||||
tcx.hir_node_by_def_id(local_def_id),
|
tcx.hir_node_by_def_id(local_def_id),
|
||||||
Node::Item(&hir::Item {
|
Node::Item(&hir::Item {
|
||||||
kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn { .. },
|
kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn{ .. },
|
||||||
..
|
..
|
||||||
}) | Node::ImplItem(&hir::ImplItem {
|
}) | Node::ImplItem(&hir::ImplItem {
|
||||||
kind: hir::ImplItemKind::Fn(..),
|
kind: hir::ImplItemKind::Fn(..),
|
||||||
|
|
|
@ -3,11 +3,9 @@
|
||||||
|
|
||||||
#[unstable(feature = "unstable", issue = "42")]
|
#[unstable(feature = "unstable", issue = "42")]
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
#[rustc_intrinsic_must_be_overridden]
|
pub const unsafe fn size_of_val<T>(x: *const T) -> usize;
|
||||||
pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
|
|
||||||
|
|
||||||
#[unstable(feature = "unstable", issue = "42")]
|
#[unstable(feature = "unstable", issue = "42")]
|
||||||
#[rustc_const_unstable(feature = "unstable", issue = "42")]
|
#[rustc_const_unstable(feature = "unstable", issue = "42")]
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
#[rustc_intrinsic_must_be_overridden]
|
pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize;
|
||||||
pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 }
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//! neither within a crate nor cross-crate.
|
//! neither within a crate nor cross-crate.
|
||||||
//@ aux-build:unstable_intrinsic.rs
|
//@ aux-build:unstable_intrinsic.rs
|
||||||
#![feature(staged_api, rustc_attrs, intrinsics)]
|
#![feature(staged_api, rustc_attrs, intrinsics)]
|
||||||
#![stable(since="1.0.0", feature = "stable")]
|
#![stable(since = "1.0.0", feature = "stable")]
|
||||||
#![feature(local)]
|
#![feature(local)]
|
||||||
|
|
||||||
extern crate unstable_intrinsic;
|
extern crate unstable_intrinsic;
|
||||||
|
@ -30,14 +30,12 @@ const fn const_main() {
|
||||||
|
|
||||||
#[unstable(feature = "local", issue = "42")]
|
#[unstable(feature = "local", issue = "42")]
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
#[rustc_intrinsic_must_be_overridden]
|
pub const unsafe fn size_of_val<T>(x: *const T) -> usize;
|
||||||
pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
|
|
||||||
|
|
||||||
#[unstable(feature = "local", issue = "42")]
|
#[unstable(feature = "local", issue = "42")]
|
||||||
#[rustc_const_unstable(feature = "local", issue = "42")]
|
#[rustc_const_unstable(feature = "local", issue = "42")]
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
#[rustc_intrinsic_must_be_overridden]
|
pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize;
|
||||||
pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 }
|
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
|
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
|
||||||
|
@ -45,10 +43,7 @@ pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 }
|
||||||
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
|
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
|
||||||
// Const stability attributes are not inherited from parent items.
|
// Const stability attributes are not inherited from parent items.
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
#[rustc_intrinsic_must_be_overridden]
|
const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
|
||||||
const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe { copy(src, dst, count) }
|
unsafe { copy(src, dst, count) }
|
||||||
//~^ ERROR cannot be (indirectly) exposed to stable
|
//~^ ERROR cannot be (indirectly) exposed to stable
|
||||||
|
|
|
@ -69,7 +69,7 @@ LL | const fn const_main() {
|
||||||
|
|
|
|
||||||
|
|
||||||
error: intrinsic `copy::copy` cannot be (indirectly) exposed to stable
|
error: intrinsic `copy::copy` cannot be (indirectly) exposed to stable
|
||||||
--> $DIR/const-unstable-intrinsic.rs:53:14
|
--> $DIR/const-unstable-intrinsic.rs:48:14
|
||||||
|
|
|
|
||||||
LL | unsafe { copy(src, dst, count) }
|
LL | unsafe { copy(src, dst, count) }
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -77,7 +77,7 @@ LL | unsafe { copy(src, dst, count) }
|
||||||
= help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval)
|
= help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_intrinsic_const_stable_indirect]` (but this requires team approval)
|
||||||
|
|
||||||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
|
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
|
||||||
--> $DIR/const-unstable-intrinsic.rs:61:9
|
--> $DIR/const-unstable-intrinsic.rs:56:9
|
||||||
|
|
|
|
||||||
LL | super::size_of_val(src);
|
LL | super::size_of_val(src);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -9,8 +9,7 @@
|
||||||
//@ rustc-env:RUST_BACKTRACE=0
|
//@ rustc-env:RUST_BACKTRACE=0
|
||||||
|
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
#[rustc_intrinsic_must_be_overridden]
|
pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize);
|
||||||
pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
unsafe { const_deallocate(std::ptr::null_mut(), 0, 0) }
|
unsafe { const_deallocate(std::ptr::null_mut(), 0, 0) }
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: must be overridden by codegen backend, but isn't
|
error: must be overridden by codegen backend, but isn't
|
||||||
--> $DIR/not-overridden.rs:16:14
|
--> $DIR/not-overridden.rs:15:14
|
||||||
|
|
|
|
||||||
LL | unsafe { const_deallocate(std::ptr::null_mut(), 0, 0) }
|
LL | unsafe { const_deallocate(std::ptr::null_mut(), 0, 0) }
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
// Tests the different rules for `fn` forms requiring the presence or lack of a body.
|
// Tests the different rules for `fn` forms requiring the presence or lack of a body.
|
||||||
|
// Also ensures that functions without a body don't show other odd errors.
|
||||||
|
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
fn f1(); //~ ERROR free function without a body
|
fn f1(); //~ ERROR free function without a body
|
||||||
|
fn f1_rpit() -> impl Trait; //~ ERROR free function without a body
|
||||||
fn f2() {} // OK.
|
fn f2() {} // OK.
|
||||||
|
|
||||||
trait X {
|
trait X {
|
||||||
|
|
|
@ -1,13 +1,21 @@
|
||||||
error: free function without a body
|
error: free function without a body
|
||||||
--> $DIR/fn-body-optional-semantic-fail.rs:4:5
|
--> $DIR/fn-body-optional-semantic-fail.rs:7:5
|
||||||
|
|
|
|
||||||
LL | fn f1();
|
LL | fn f1();
|
||||||
| ^^^^^^^-
|
| ^^^^^^^-
|
||||||
| |
|
| |
|
||||||
| help: provide a definition for the function: `{ <body> }`
|
| help: provide a definition for the function: `{ <body> }`
|
||||||
|
|
||||||
|
error: free function without a body
|
||||||
|
--> $DIR/fn-body-optional-semantic-fail.rs:8:5
|
||||||
|
|
|
||||||
|
LL | fn f1_rpit() -> impl Trait;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||||
|
| |
|
||||||
|
| help: provide a definition for the function: `{ <body> }`
|
||||||
|
|
||||||
error: associated function in `impl` without body
|
error: associated function in `impl` without body
|
||||||
--> $DIR/fn-body-optional-semantic-fail.rs:14:9
|
--> $DIR/fn-body-optional-semantic-fail.rs:18:9
|
||||||
|
|
|
|
||||||
LL | fn f1();
|
LL | fn f1();
|
||||||
| ^^^^^^^-
|
| ^^^^^^^-
|
||||||
|
@ -15,7 +23,7 @@ LL | fn f1();
|
||||||
| help: provide a definition for the function: `{ <body> }`
|
| help: provide a definition for the function: `{ <body> }`
|
||||||
|
|
||||||
error: associated function in `impl` without body
|
error: associated function in `impl` without body
|
||||||
--> $DIR/fn-body-optional-semantic-fail.rs:19:9
|
--> $DIR/fn-body-optional-semantic-fail.rs:23:9
|
||||||
|
|
|
|
||||||
LL | fn f3();
|
LL | fn f3();
|
||||||
| ^^^^^^^-
|
| ^^^^^^^-
|
||||||
|
@ -23,7 +31,7 @@ LL | fn f3();
|
||||||
| help: provide a definition for the function: `{ <body> }`
|
| help: provide a definition for the function: `{ <body> }`
|
||||||
|
|
||||||
error: incorrect function inside `extern` block
|
error: incorrect function inside `extern` block
|
||||||
--> $DIR/fn-body-optional-semantic-fail.rs:25:12
|
--> $DIR/fn-body-optional-semantic-fail.rs:29:12
|
||||||
|
|
|
|
||||||
LL | extern "C" {
|
LL | extern "C" {
|
||||||
| ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body
|
| ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body
|
||||||
|
@ -36,5 +44,5 @@ LL | fn f6() {}
|
||||||
= help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
|
= help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
|
||||||
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
|
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,7 @@ impl Copy for bool {}
|
||||||
#[stable(feature = "test", since = "1.0.0")]
|
#[stable(feature = "test", since = "1.0.0")]
|
||||||
#[rustc_const_stable(feature = "test", since = "1.0.0")]
|
#[rustc_const_stable(feature = "test", since = "1.0.0")]
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
#[rustc_intrinsic_must_be_overridden]
|
const unsafe fn unreachable() -> !;
|
||||||
const unsafe fn unreachable() -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
macro_rules! cfg {
|
macro_rules! cfg {
|
||||||
|
|
|
@ -471,7 +471,6 @@ pub trait StructuralPartialEq {}
|
||||||
|
|
||||||
pub const fn drop<T: ~const Destruct>(_: T) {}
|
pub const fn drop<T: ~const Destruct>(_: T) {}
|
||||||
|
|
||||||
#[rustc_intrinsic_must_be_overridden]
|
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
const fn const_eval_select<ARG: Tuple, F, G, RET>(
|
const fn const_eval_select<ARG: Tuple, F, G, RET>(
|
||||||
arg: ARG,
|
arg: ARG,
|
||||||
|
@ -480,7 +479,4 @@ const fn const_eval_select<ARG: Tuple, F, G, RET>(
|
||||||
) -> RET
|
) -> RET
|
||||||
where
|
where
|
||||||
F: const FnOnce<ARG, Output = RET>,
|
F: const FnOnce<ARG, Output = RET>,
|
||||||
G: FnOnce<ARG, Output = RET>,
|
G: FnOnce<ARG, Output = RET>;
|
||||||
{
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue