Auto merge of #137446 - matthiaskrgr:rollup-16moy6v, r=matthiaskrgr

Rollup of 6 pull requests

Successful merges:

 - #135501 (Inject `compiler_builtins` during postprocessing and ensure it is made private)
 - #137121 (stabilize `(const_)ptr_sub_ptr`)
 - #137180 (Give `global_asm` a fake body to store typeck results, represent `sym fn` as a hir expr to fix `sym fn` operands with lifetimes)
 - #137256 (compiler: untangle SIMD alignment assumptions)
 - #137383 (stabilize `unsigned_is_multiple_of`)
 - #137415 (Remove invalid suggestion of into_iter for extern macro)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-02-23 02:05:13 +00:00
commit bca5f37cbd
94 changed files with 704 additions and 539 deletions

View file

@ -57,7 +57,7 @@ impl Reg {
128 => dl.f128_align.abi,
_ => panic!("unsupported float: {self:?}"),
},
RegKind::Vector => dl.vector_align(self.size).abi,
RegKind::Vector => dl.llvmlike_vector_align(self.size).abi,
}
}
}

View file

@ -310,10 +310,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align };
let mut max_repr_align = repr.align;
// If all the non-ZST fields have the same ABI and union ABI optimizations aren't
// disabled, we can use that common ABI for the union as a whole.
// If all the non-ZST fields have the same repr and union repr optimizations aren't
// disabled, we can use that common repr for the union as a whole.
struct AbiMismatch;
let mut common_non_zst_abi_and_align = if repr.inhibits_union_abi_opt() {
let mut common_non_zst_repr_and_align = if repr.inhibits_union_abi_opt() {
// Can't optimize
Err(AbiMismatch)
} else {
@ -337,14 +337,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
continue;
}
if let Ok(common) = common_non_zst_abi_and_align {
if let Ok(common) = common_non_zst_repr_and_align {
// Discard valid range information and allow undef
let field_abi = field.backend_repr.to_union();
if let Some((common_abi, common_align)) = common {
if common_abi != field_abi {
// Different fields have different ABI: disable opt
common_non_zst_abi_and_align = Err(AbiMismatch);
common_non_zst_repr_and_align = Err(AbiMismatch);
} else {
// Fields with the same non-Aggregate ABI should also
// have the same alignment
@ -357,7 +357,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
}
} else {
// First non-ZST field: record its ABI and alignment
common_non_zst_abi_and_align = Ok(Some((field_abi, field.align.abi)));
common_non_zst_repr_and_align = Ok(Some((field_abi, field.align.abi)));
}
}
}
@ -376,16 +376,25 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
// If all non-ZST fields have the same ABI, we may forward that ABI
// for the union as a whole, unless otherwise inhibited.
let abi = match common_non_zst_abi_and_align {
let backend_repr = match common_non_zst_repr_and_align {
Err(AbiMismatch) | Ok(None) => BackendRepr::Memory { sized: true },
Ok(Some((abi, _))) => {
if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) {
// Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
Ok(Some((repr, _))) => match repr {
// Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
BackendRepr::Scalar(_) | BackendRepr::ScalarPair(_, _)
if repr.scalar_align(dl).unwrap() != align.abi =>
{
BackendRepr::Memory { sized: true }
} else {
abi
}
}
// Vectors require at least element alignment, else disable the opt
BackendRepr::Vector { element, count: _ } if element.align(dl).abi > align.abi => {
BackendRepr::Memory { sized: true }
}
// the alignment tests passed and we can use this
BackendRepr::Scalar(..)
| BackendRepr::ScalarPair(..)
| BackendRepr::Vector { .. }
| BackendRepr::Memory { .. } => repr,
},
};
let Some(union_field_count) = NonZeroUsize::new(only_variant.len()) else {
@ -400,7 +409,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
Ok(LayoutData {
variants: Variants::Single { index: only_variant_idx },
fields: FieldsShape::Union(union_field_count),
backend_repr: abi,
backend_repr,
largest_niche: None,
uninhabited: false,
align,

View file

@ -408,16 +408,21 @@ impl TargetDataLayout {
}
}
/// psABI-mandated alignment for a vector type, if any
#[inline]
pub fn vector_align(&self, vec_size: Size) -> AbiAndPrefAlign {
for &(size, align) in &self.vector_align {
if size == vec_size {
return align;
}
}
// Default to natural alignment, which is what LLVM does.
// That is, use the size, rounded up to a power of 2.
AbiAndPrefAlign::new(Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap())
fn cabi_vector_align(&self, vec_size: Size) -> Option<AbiAndPrefAlign> {
self.vector_align
.iter()
.find(|(size, _align)| *size == vec_size)
.map(|(_size, align)| *align)
}
/// an alignment resembling the one LLVM would pick for a vector
#[inline]
pub fn llvmlike_vector_align(&self, vec_size: Size) -> AbiAndPrefAlign {
self.cabi_vector_align(vec_size).unwrap_or(AbiAndPrefAlign::new(
Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap(),
))
}
}
@ -810,20 +815,19 @@ impl Align {
self.bits().try_into().unwrap()
}
/// Computes the best alignment possible for the given offset
/// (the largest power of two that the offset is a multiple of).
/// Obtain the greatest factor of `size` that is an alignment
/// (the largest power of two the Size is a multiple of).
///
/// N.B., for an offset of `0`, this happens to return `2^64`.
/// Note that all numbers are factors of 0
#[inline]
pub fn max_for_offset(offset: Size) -> Align {
Align { pow2: offset.bytes().trailing_zeros() as u8 }
pub fn max_aligned_factor(size: Size) -> Align {
Align { pow2: size.bytes().trailing_zeros() as u8 }
}
/// Lower the alignment, if necessary, such that the given offset
/// is aligned to it (the offset is a multiple of the alignment).
/// Reduces Align to an aligned factor of `size`.
#[inline]
pub fn restrict_for_offset(self, offset: Size) -> Align {
self.min(Align::max_for_offset(offset))
pub fn restrict_for_offset(self, size: Size) -> Align {
self.min(Align::max_aligned_factor(size))
}
}
@ -1455,37 +1459,38 @@ impl BackendRepr {
matches!(*self, BackendRepr::Scalar(s) if s.is_bool())
}
/// Returns the fixed alignment of this ABI, if any is mandated.
pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> {
Some(match *self {
BackendRepr::Scalar(s) => s.align(cx),
BackendRepr::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)),
BackendRepr::Vector { element, count } => {
cx.data_layout().vector_align(element.size(cx) * count)
}
BackendRepr::Memory { .. } => return None,
})
/// The psABI alignment for a `Scalar` or `ScalarPair`
///
/// `None` for other variants.
pub fn scalar_align<C: HasDataLayout>(&self, cx: &C) -> Option<Align> {
match *self {
BackendRepr::Scalar(s) => Some(s.align(cx).abi),
BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.align(cx)).abi),
// The align of a Vector can vary in surprising ways
BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => None,
}
}
/// Returns the fixed size of this ABI, if any is mandated.
pub fn inherent_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
Some(match *self {
BackendRepr::Scalar(s) => {
// No padding in scalars.
s.size(cx)
}
/// The psABI size for a `Scalar` or `ScalarPair`
///
/// `None` for other variants
pub fn scalar_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
match *self {
// No padding in scalars.
BackendRepr::Scalar(s) => Some(s.size(cx)),
// May have some padding between the pair.
BackendRepr::ScalarPair(s1, s2) => {
// May have some padding between the pair.
let field2_offset = s1.size(cx).align_to(s2.align(cx).abi);
(field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi)
let size = (field2_offset + s2.size(cx)).align_to(
self.scalar_align(cx)
// We absolutely must have an answer here or everything is FUBAR.
.unwrap(),
);
Some(size)
}
BackendRepr::Vector { element, count } => {
// No padding in vectors, except possibly for trailing padding
// to make the size a multiple of align (e.g. for vectors of size 3).
(element.size(cx) * count).align_to(self.inherent_align(cx)?.abi)
}
BackendRepr::Memory { .. } => return None,
})
// The size of a Vector can vary in surprising ways
BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => None,
}
}
/// Discard validity range information and allow undef.

View file

@ -1,13 +1,12 @@
use std::collections::hash_map::Entry;
use std::fmt::Write;
use rustc_ast::ptr::P;
use rustc_ast::*;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_session::parse::feature_err;
use rustc_span::{Span, kw, sym};
use rustc_span::{Span, sym};
use rustc_target::asm;
use super::LoweringContext;
@ -230,20 +229,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
tokens: None,
};
// Wrap the expression in an AnonConst.
let parent_def_id = self.current_hir_id_owner.def_id;
let node_id = self.next_node_id();
self.create_def(
parent_def_id,
node_id,
kw::Empty,
DefKind::AnonConst,
*op_sp,
);
let anon_const = AnonConst { id: node_id, value: P(expr) };
hir::InlineAsmOperand::SymFn {
anon_const: self.lower_anon_const_to_anon_const(&anon_const),
}
hir::InlineAsmOperand::SymFn { expr: self.lower_expr(&expr) }
}
}
InlineAsmOperand::Label { block } => {

View file

@ -251,7 +251,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
.arena
.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
},
ItemKind::GlobalAsm(asm) => hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm)),
ItemKind::GlobalAsm(asm) => {
let asm = self.lower_inline_asm(span, asm);
let fake_body =
self.lower_body(|this| (&[], this.expr(span, hir::ExprKind::InlineAsm(asm))));
hir::ItemKind::GlobalAsm { asm, fake_body }
}
ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
// We lower
//

View file

@ -126,6 +126,11 @@ pub(crate) enum DefiningTy<'tcx> {
/// The MIR represents an inline const. The signature has no inputs and a
/// single return value found via `InlineConstArgs::ty`.
InlineConst(DefId, GenericArgsRef<'tcx>),
// Fake body for a global asm. Not particularly useful or interesting,
// but we need it so we can properly store the typeck results of the asm
// operands, which aren't associated with a body otherwise.
GlobalAsm(DefId),
}
impl<'tcx> DefiningTy<'tcx> {
@ -138,9 +143,10 @@ impl<'tcx> DefiningTy<'tcx> {
DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(),
DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().upvar_tys(),
DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(),
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
ty::List::empty()
}
DefiningTy::FnDef(..)
| DefiningTy::Const(..)
| DefiningTy::InlineConst(..)
| DefiningTy::GlobalAsm(_) => ty::List::empty(),
}
}
@ -152,7 +158,10 @@ impl<'tcx> DefiningTy<'tcx> {
DefiningTy::Closure(..)
| DefiningTy::CoroutineClosure(..)
| DefiningTy::Coroutine(..) => 1,
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
DefiningTy::FnDef(..)
| DefiningTy::Const(..)
| DefiningTy::InlineConst(..)
| DefiningTy::GlobalAsm(_) => 0,
}
}
@ -171,7 +180,8 @@ impl<'tcx> DefiningTy<'tcx> {
| DefiningTy::Coroutine(def_id, ..)
| DefiningTy::FnDef(def_id, ..)
| DefiningTy::Const(def_id, ..)
| DefiningTy::InlineConst(def_id, ..) => def_id,
| DefiningTy::InlineConst(def_id, ..)
| DefiningTy::GlobalAsm(def_id) => def_id,
}
}
}
@ -411,6 +421,7 @@ impl<'tcx> UniversalRegions<'tcx> {
tcx.def_path_str_with_args(def_id, args),
));
}
DefiningTy::GlobalAsm(_) => unreachable!(),
}
}
@ -633,6 +644,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
DefiningTy::InlineConst(self.mir_def.to_def_id(), args)
}
}
BodyOwnerKind::GlobalAsm => DefiningTy::GlobalAsm(self.mir_def.to_def_id()),
}
}
@ -666,6 +679,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
}
DefiningTy::FnDef(_, args) | DefiningTy::Const(_, args) => args,
DefiningTy::GlobalAsm(_) => ty::List::empty(),
};
let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));
@ -802,6 +817,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let ty = args.as_inline_const().ty();
ty::Binder::dummy(tcx.mk_type_list(&[ty]))
}
DefiningTy::GlobalAsm(def_id) => {
ty::Binder::dummy(tcx.mk_type_list(&[tcx.type_of(def_id).instantiate_identity()]))
}
};
// FIXME(#129952): We probably want a more principled approach here.

View file

@ -19,16 +19,12 @@ pub fn inject(
let edition = sess.psess.edition;
// the first name in this list is the crate name of the crate with the prelude
let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) {
let name: Symbol = if attr::contains_name(pre_configured_attrs, sym::no_core) {
return 0;
} else if attr::contains_name(pre_configured_attrs, sym::no_std) {
if attr::contains_name(pre_configured_attrs, sym::compiler_builtins) {
&[sym::core]
} else {
&[sym::core, sym::compiler_builtins]
}
sym::core
} else {
&[sym::std]
sym::std
};
let expn_id = resolver.expansion_for_ast_pass(
@ -43,36 +39,16 @@ pub fn inject(
let ecfg = ExpansionConfig::default("std_lib_injection".to_string(), features);
let cx = ExtCtxt::new(sess, ecfg, resolver, None);
// .rev() to preserve ordering above in combination with insert(0, ...)
for &name in names.iter().rev() {
let ident_span = if edition >= Edition2018 { span } else { call_site };
let item = if name == sym::compiler_builtins {
// compiler_builtins is a private implementation detail. We only
// need to insert it into the crate graph for linking and should not
// expose any of its public API.
//
// FIXME(#113634) We should inject this during post-processing like
// we do for the panic runtime, profiler runtime, etc.
cx.item(
span,
Ident::new(kw::Underscore, ident_span),
thin_vec![],
ast::ItemKind::ExternCrate(Some(name)),
)
} else {
cx.item(
span,
Ident::new(name, ident_span),
thin_vec![cx.attr_word(sym::macro_use, span)],
ast::ItemKind::ExternCrate(None),
)
};
krate.items.insert(0, item);
}
let ident_span = if edition >= Edition2018 { span } else { call_site };
// The crates have been injected, the assumption is that the first one is
// the one with the prelude.
let name = names[0];
let item = cx.item(
span,
Ident::new(name, ident_span),
thin_vec![cx.attr_word(sym::macro_use, span)],
ast::ItemKind::ExternCrate(None),
);
krate.items.insert(0, item);
let root = (edition == Edition2015).then_some(kw::PathRoot);
@ -88,6 +64,7 @@ pub fn inject(
.map(|&symbol| Ident::new(symbol, span))
.collect();
// Inject the relevant crate's prelude.
let use_item = cx.item(
span,
Ident::empty(),

View file

@ -15,7 +15,7 @@ index 7165c3e48af..968552ad435 100644
edition = "2021"
[dependencies]
core = { path = "../core" }
core = { path = "../core", public = true }
-compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std', 'no-f16-f128'] }

View file

@ -16,7 +16,7 @@ use crate::prelude::*;
pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
let item = tcx.hir_item(item_id);
if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind {
if let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind {
let is_x86 =
matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64);
@ -55,7 +55,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
}
}
}
InlineAsmOperand::SymFn { anon_const } => {
InlineAsmOperand::SymFn { expr } => {
if cfg!(not(feature = "inline_asm_sym")) {
tcx.dcx().span_err(
item.span,
@ -63,7 +63,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
);
}
let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
let ty = tcx.typeck(item_id.owner_id).expr_ty(expr);
let instance = match ty.kind() {
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
_ => span_bug!(op_sp, "asm sym is not a function"),

View file

@ -36,7 +36,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
}
MonoItem::GlobalAsm(item_id) => {
let item = cx.tcx().hir_item(item_id);
if let hir::ItemKind::GlobalAsm(asm) = item.kind {
if let hir::ItemKind::GlobalAsm { asm, .. } = item.kind {
let operands: Vec<_> = asm
.operands
.iter()
@ -71,11 +71,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
}
}
}
hir::InlineAsmOperand::SymFn { ref anon_const } => {
let ty = cx
.tcx()
.typeck_body(anon_const.body)
.node_type(anon_const.hir_id);
hir::InlineAsmOperand::SymFn { expr } => {
let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr);
let instance = match ty.kind() {
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
_ => span_bug!(*op_sp, "asm sym is not a function"),

View file

@ -1913,13 +1913,18 @@ pub enum BodyOwnerKind {
/// Initializer of a `static` item.
Static(Mutability),
/// Fake body for a global asm to store its const-like value types.
GlobalAsm,
}
impl BodyOwnerKind {
pub fn is_fn_or_closure(self) -> bool {
match self {
BodyOwnerKind::Fn | BodyOwnerKind::Closure => true,
BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) => false,
BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) | BodyOwnerKind::GlobalAsm => {
false
}
}
}
}
@ -3420,7 +3425,7 @@ pub enum InlineAsmOperand<'hir> {
anon_const: &'hir AnonConst,
},
SymFn {
anon_const: &'hir AnonConst,
expr: &'hir Expr<'hir>,
},
SymStatic {
path: QPath<'hir>,
@ -3848,7 +3853,7 @@ impl<'hir> Item<'hir> {
expect_foreign_mod, (ExternAbi, &'hir [ForeignItemRef]),
ItemKind::ForeignMod { abi, items }, (*abi, items);
expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm(asm), asm;
expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm { asm, .. }, asm;
expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>),
ItemKind::TyAlias(ty, generics), (ty, generics);
@ -4015,7 +4020,15 @@ pub enum ItemKind<'hir> {
/// An external module, e.g. `extern { .. }`.
ForeignMod { abi: ExternAbi, items: &'hir [ForeignItemRef] },
/// Module-level inline assembly (from `global_asm!`).
GlobalAsm(&'hir InlineAsm<'hir>),
GlobalAsm {
asm: &'hir InlineAsm<'hir>,
/// A fake body which stores typeck results for the global asm's sym_fn
/// operands, which are represented as path expressions. This body contains
/// a single [`ExprKind::InlineAsm`] which points to the asm in the field
/// above, and which is typechecked like a inline asm expr just for the
/// typeck results.
fake_body: BodyId,
},
/// A type alias, e.g., `type Foo = Bar<u8>`.
TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
/// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`.
@ -4081,7 +4094,7 @@ impl ItemKind<'_> {
ItemKind::Macro(..) => "macro",
ItemKind::Mod(..) => "module",
ItemKind::ForeignMod { .. } => "extern block",
ItemKind::GlobalAsm(..) => "global asm item",
ItemKind::GlobalAsm { .. } => "global asm item",
ItemKind::TyAlias(..) => "type alias",
ItemKind::Enum(..) => "enum",
ItemKind::Struct(..) => "struct",
@ -4540,6 +4553,10 @@ impl<'hir> Node<'hir> {
..
}) => Some((owner_id.def_id, *body)),
Node::Item(Item {
owner_id, kind: ItemKind::GlobalAsm { asm: _, fake_body }, ..
}) => Some((owner_id.def_id, *fake_body)),
Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => {
Some((*def_id, *body))
}

View file

@ -573,9 +573,13 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
try_visit!(visitor.visit_id(item.hir_id()));
walk_list!(visitor, visit_foreign_item_ref, items);
}
ItemKind::GlobalAsm(asm) => {
ItemKind::GlobalAsm { asm: _, fake_body } => {
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(visitor.visit_inline_asm(asm, item.hir_id()));
// Visit the fake body, which contains the asm statement.
// Therefore we should not visit the asm statement again
// outside of the body, or some visitors won't have their
// typeck results set correctly.
try_visit!(visitor.visit_nested_body(fake_body));
}
ItemKind::TyAlias(ref ty, ref generics) => {
try_visit!(visitor.visit_id(item.hir_id()));
@ -1442,10 +1446,12 @@ pub fn walk_inline_asm<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_expr(in_expr));
visit_opt!(visitor, visit_expr, out_expr);
}
InlineAsmOperand::Const { anon_const, .. }
| InlineAsmOperand::SymFn { anon_const, .. } => {
InlineAsmOperand::Const { anon_const, .. } => {
try_visit!(visitor.visit_anon_const(anon_const));
}
InlineAsmOperand::SymFn { expr, .. } => {
try_visit!(visitor.visit_expr(expr));
}
InlineAsmOperand::SymStatic { path, .. } => {
try_visit!(visitor.visit_qpath(path, id, *op_sp));
}

View file

@ -110,7 +110,7 @@ impl Target {
ItemKind::Macro(..) => Target::MacroDef,
ItemKind::Mod(..) => Target::Mod,
ItemKind::ForeignMod { .. } => Target::ForeignMod,
ItemKind::GlobalAsm(..) => Target::GlobalAsm,
ItemKind::GlobalAsm { .. } => Target::GlobalAsm,
ItemKind::TyAlias(..) => Target::TyAlias,
ItemKind::Enum(..) => Target::Enum,
ItemKind::Struct(..) => Target::Struct,

View file

@ -15,7 +15,6 @@ use rustc_lint_defs::builtin::{
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::span_bug;
use rustc_middle::ty::error::TypeErrorToStringExt;
use rustc_middle::ty::fold::{BottomUpFolder, fold_regions};
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
@ -35,7 +34,6 @@ use {rustc_attr_parsing as attr, rustc_hir as hir};
use super::compare_impl_item::check_type_bounds;
use super::*;
use crate::check::intrinsicck::InlineAsmCtxt;
pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: ExternAbi) {
if !tcx.sess.target.is_abi_supported(abi) {
@ -895,13 +893,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
}
}
}
DefKind::GlobalAsm => {
let it = tcx.hir().expect_item(def_id);
let hir::ItemKind::GlobalAsm(asm) = it.kind else {
span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it)
};
InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, def_id);
}
_ => {}
}
}

View file

@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, LangItem};
use rustc_middle::bug;
use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::{Symbol, sym};
@ -16,10 +16,11 @@ use rustc_target::asm::{
use crate::errors::RegisterTypeUnstable;
pub struct InlineAsmCtxt<'a, 'tcx> {
pub struct InlineAsmCtxt<'a, 'tcx: 'a> {
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
get_operand_ty: Box<dyn Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
target_features: &'tcx FxIndexSet<Symbol>,
expr_ty: Box<dyn Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
}
enum NonAsmTypeReason<'tcx> {
@ -29,25 +30,24 @@ enum NonAsmTypeReason<'tcx> {
}
impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self {
pub fn new(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
get_operand_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
) -> Self {
InlineAsmCtxt {
tcx,
typing_env: ty::TypingEnv {
typing_mode: ty::TypingMode::non_body_analysis(),
param_env: ty::ParamEnv::empty(),
},
get_operand_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")),
target_features: tcx.asm_target_features(def_id),
expr_ty: Box::new(get_operand_ty),
}
}
// FIXME(#132279): This likely causes us to incorrectly handle opaque types in their
// defining scope.
pub fn new_in_fn(
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
get_operand_ty: impl Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
) -> Self {
InlineAsmCtxt { tcx, typing_env, get_operand_ty: Box::new(get_operand_ty) }
fn expr_ty(&self, expr: &hir::Expr<'tcx>) -> Ty<'tcx> {
(self.expr_ty)(expr)
}
// FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
@ -139,9 +139,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
template: &[InlineAsmTemplatePiece],
is_input: bool,
tied_input: Option<(&'tcx hir::Expr<'tcx>, Option<InlineAsmType>)>,
target_features: &FxIndexSet<Symbol>,
) -> Option<InlineAsmType> {
let ty = (self.get_operand_ty)(expr);
let ty = self.expr_ty(expr);
if ty.has_non_region_infer() {
bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty);
}
@ -229,7 +228,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
if let Some((in_expr, Some(in_asm_ty))) = tied_input {
if in_asm_ty != asm_ty {
let msg = "incompatible types for asm inout argument";
let in_expr_ty = (self.get_operand_ty)(in_expr);
let in_expr_ty = self.expr_ty(in_expr);
self.tcx
.dcx()
.struct_span_err(vec![in_expr.span, expr.span], msg)
@ -291,7 +290,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
// (!). In that case we still need the earlier check to verify that the
// register class is usable at all.
if let Some(feature) = feature {
if !target_features.contains(feature) {
if !self.target_features.contains(feature) {
let msg = format!("`{feature}` target feature is not enabled");
self.tcx
.dcx()
@ -351,14 +350,13 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
Some(asm_ty)
}
pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: LocalDefId) {
let target_features = self.tcx.asm_target_features(enclosing_id.to_def_id());
pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
let Some(asm_arch) = self.tcx.sess.asm_arch else {
self.tcx.dcx().delayed_bug("target architecture does not support asm");
return;
};
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
for (idx, &(op, op_sp)) in asm.operands.iter().enumerate() {
// Validate register classes against currently enabled target
// features. We check that at least one type is available for
// the enabled features.
@ -381,12 +379,12 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
if let Err(msg) = reg.validate(
asm_arch,
self.tcx.sess.relocation_model(),
target_features,
self.target_features,
&self.tcx.sess.target,
op.is_clobber(),
) {
let msg = format!("cannot use register `{}`: {}", reg.name(), msg);
self.tcx.dcx().span_err(*op_sp, msg);
self.tcx.dcx().span_err(op_sp, msg);
continue;
}
}
@ -401,7 +399,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
{
match feature {
Some(feature) => {
if target_features.contains(&feature) {
if self.target_features.contains(&feature) {
missing_required_features.clear();
break;
} else {
@ -426,7 +424,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
reg_class.name(),
feature
);
self.tcx.dcx().span_err(*op_sp, msg);
self.tcx.dcx().span_err(op_sp, msg);
// register isn't enabled, don't do more checks
continue;
}
@ -440,7 +438,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
.intersperse(", ")
.collect::<String>(),
);
self.tcx.dcx().span_err(*op_sp, msg);
self.tcx.dcx().span_err(op_sp, msg);
// register isn't enabled, don't do more checks
continue;
}
@ -448,52 +446,21 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
}
}
match *op {
match op {
hir::InlineAsmOperand::In { reg, expr } => {
self.check_asm_operand_type(
idx,
reg,
expr,
asm.template,
true,
None,
target_features,
);
self.check_asm_operand_type(idx, reg, expr, asm.template, true, None);
}
hir::InlineAsmOperand::Out { reg, late: _, expr } => {
if let Some(expr) = expr {
self.check_asm_operand_type(
idx,
reg,
expr,
asm.template,
false,
None,
target_features,
);
self.check_asm_operand_type(idx, reg, expr, asm.template, false, None);
}
}
hir::InlineAsmOperand::InOut { reg, late: _, expr } => {
self.check_asm_operand_type(
idx,
reg,
expr,
asm.template,
false,
None,
target_features,
);
self.check_asm_operand_type(idx, reg, expr, asm.template, false, None);
}
hir::InlineAsmOperand::SplitInOut { reg, late: _, in_expr, out_expr } => {
let in_ty = self.check_asm_operand_type(
idx,
reg,
in_expr,
asm.template,
true,
None,
target_features,
);
let in_ty =
self.check_asm_operand_type(idx, reg, in_expr, asm.template, true, None);
if let Some(out_expr) = out_expr {
self.check_asm_operand_type(
idx,
@ -502,7 +469,6 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
asm.template,
false,
Some((in_expr, in_ty)),
target_features,
);
}
}
@ -514,11 +480,25 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
);
}
// Typeck has checked that SymFn refers to a function.
hir::InlineAsmOperand::SymFn { anon_const } => {
debug_assert_matches!(
self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
ty::Error(_) | ty::FnDef(..)
);
hir::InlineAsmOperand::SymFn { expr } => {
let ty = self.expr_ty(expr);
match ty.kind() {
ty::FnDef(..) => {}
ty::Error(_) => {}
_ => {
self.tcx
.dcx()
.struct_span_err(op_sp, "invalid `sym` operand")
.with_span_label(
expr.span,
format!("is {} `{}`", ty.kind().article(), ty),
)
.with_help(
"`sym` operands must refer to either a function or a static",
)
.emit();
}
}
}
// AST lowering guarantees that SymStatic points to a static.
hir::InlineAsmOperand::SymStatic { .. } => {}

View file

@ -680,7 +680,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
| hir::ItemKind::Use(..)
| hir::ItemKind::Macro(..)
| hir::ItemKind::Mod(_)
| hir::ItemKind::GlobalAsm(_) => {}
| hir::ItemKind::GlobalAsm { .. } => {}
hir::ItemKind::ForeignMod { items, .. } => {
for item in *items {
let item = tcx.hir_foreign_item(item.id);

View file

@ -189,8 +189,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// Exclude `GlobalAsm` here which cannot have generics.
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
if asm.operands.iter().any(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const }
| hir::InlineAsmOperand::SymFn { anon_const } => {
hir::InlineAsmOperand::Const { anon_const } => {
anon_const.hir_id == hir_id
}
_ => false,

View file

@ -623,7 +623,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
| hir::ItemKind::Mod(..)
| hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::Static(..)
| hir::ItemKind::GlobalAsm(..) => {
| hir::ItemKind::GlobalAsm { .. } => {
// These sorts of items have no lifetime parameters at all.
intravisit::walk_item(self, item);
}

View file

@ -35,13 +35,6 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx
let parent_node_id = tcx.parent_hir_id(hir_id);
let parent_node = tcx.hir_node(parent_node_id);
let find_sym_fn = |&(op, op_sp)| match op {
hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == hir_id => {
Some((anon_const, op_sp))
}
_ => None,
};
let find_const = |&(op, op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => {
Some((anon_const, op_sp))
@ -59,31 +52,7 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx
// Anon consts outside the type system.
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_sym_fn) =>
{
let ty = tcx.typeck(def_id).node_type(hir_id);
match ty.kind() {
ty::Error(_) => ty,
ty::FnDef(..) => ty,
_ => {
let guar = tcx
.dcx()
.struct_span_err(op_sp, "invalid `sym` operand")
.with_span_label(
tcx.def_span(anon_const.def_id),
format!("is {} `{}`", ty.kind().article(), ty),
)
.with_help("`sym` operands must refer to either a function or a static")
.emit();
Ty::new_error(tcx, guar)
}
}
}
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
| Node::Item(&Item { kind: ItemKind::GlobalAsm { asm, .. }, .. })
if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_const) =>
{
let ty = tcx.typeck(def_id).node_type(hir_id);
@ -313,12 +282,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_adt(tcx, def, args)
}
ItemKind::GlobalAsm { .. } => tcx.typeck(def_id).node_type(hir_id),
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
| ItemKind::Macro(..)
| ItemKind::Mod(..)
| ItemKind::ForeignMod { .. }
| ItemKind::GlobalAsm(..)
| ItemKind::ExternCrate(..)
| ItemKind::Use(..) => {
span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind);

View file

@ -692,7 +692,7 @@ impl<'a> State<'a> {
}
self.bclose(item.span);
}
hir::ItemKind::GlobalAsm(asm) => {
hir::ItemKind::GlobalAsm { asm, .. } => {
self.head("global_asm!");
self.print_inline_asm(asm);
self.end()
@ -1431,10 +1431,10 @@ impl<'a> State<'a> {
s.space();
s.print_anon_const(anon_const);
}
hir::InlineAsmOperand::SymFn { ref anon_const } => {
hir::InlineAsmOperand::SymFn { ref expr } => {
s.word("sym_fn");
s.space();
s.print_anon_const(anon_const);
s.print_expr(expr);
}
hir::InlineAsmOperand::SymStatic { ref path, def_id: _ } => {
s.word("sym_static");

View file

@ -3763,7 +3763,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut diverge = asm.asm_macro.diverges(asm.options);
for (op, _op_sp) in asm.operands {
match op {
match *op {
hir::InlineAsmOperand::In { expr, .. } => {
self.check_expr_asm_operand(expr, true);
}
@ -3778,10 +3778,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_expr_asm_operand(out_expr, false);
}
}
hir::InlineAsmOperand::SymFn { expr } => {
self.check_expr(expr);
}
// `AnonConst`s have their own body and is type-checked separately.
// As they don't flow into the type system we don't need them to
// be well-formed.
hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } => {}
hir::InlineAsmOperand::Const { .. } => {}
hir::InlineAsmOperand::SymStatic { .. } => {}
hir::InlineAsmOperand::Label { block } => {
let previous_diverges = self.diverges.get();

View file

@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len());
for (asm, hir_id) in deferred_asm_checks.drain(..) {
let enclosing_id = self.tcx.hir_enclosing_body_owner(hir_id);
let get_operand_ty = |expr| {
let expr_ty = |expr: &hir::Expr<'tcx>| {
let ty = self.typeck_results.borrow().expr_ty_adjusted(expr);
let ty = self.resolve_vars_if_possible(ty);
if ty.has_non_region_infer() {
@ -110,12 +110,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.erase_regions(ty)
}
};
InlineAsmCtxt::new_in_fn(
self.tcx,
self.infcx.typing_env(self.param_env),
get_operand_ty,
)
.check_asm(asm, enclosing_id);
InlineAsmCtxt::new(self.tcx, enclosing_id, expr_ty).check_asm(asm);
}
}

View file

@ -133,7 +133,12 @@ fn typeck_with_inspect<'tcx>(
}
let mut fcx = FnCtxt::new(&root_ctxt, param_env, def_id);
if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() {
if let hir::Node::Item(hir::Item { kind: hir::ItemKind::GlobalAsm { .. }, .. }) = node {
// Check the fake body of a global ASM. There's not much to do here except
// for visit the asm expr of the body.
let ty = fcx.check_expr(body.value);
fcx.write_ty(id, ty);
} else if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() {
let fn_sig = if decl.output.is_suggestable_infer_ty().is_some() {
// In the case that we're recovering `fn() -> W<_>` or some other return
// type that has an infer in it, lower the type directly so that it'll
@ -277,12 +282,9 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
Some(fcx.next_ty_var(span))
}
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), span, .. })
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), span, .. }) => {
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm { asm, .. }, span, .. }) => {
asm.operands.iter().find_map(|(op, _op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const }
| hir::InlineAsmOperand::SymFn { anon_const }
if anon_const.hir_id == id =>
{
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => {
Some(fcx.next_ty_var(span))
}
_ => None,

View file

@ -905,11 +905,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if self.impl_into_iterator_should_be_iterator(rcvr_ty, span, unsatisfied_predicates)
{
err.span_label(span, format!("`{rcvr_ty}` is not an iterator"));
err.multipart_suggestion_verbose(
"call `.into_iter()` first",
vec![(span.shrink_to_lo(), format!("into_iter()."))],
Applicability::MaybeIncorrect,
);
if !span.in_external_macro(self.tcx.sess.source_map()) {
err.multipart_suggestion_verbose(
"call `.into_iter()` first",
vec![(span.shrink_to_lo(), format!("into_iter()."))],
Applicability::MaybeIncorrect,
);
}
return err.emit();
} else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) {
// We special case the situation where we are looking for `_` in

View file

@ -48,13 +48,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for param in body.params {
wbcx.visit_node_id(param.pat.span, param.hir_id);
}
// Type only exists for constants and statics, not functions.
match self.tcx.hir_body_owner_kind(item_def_id) {
hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => {
// Visit the type of a const or static, which is used during THIR building.
hir::BodyOwnerKind::Const { .. }
| hir::BodyOwnerKind::Static(_)
| hir::BodyOwnerKind::GlobalAsm => {
let item_hir_id = self.tcx.local_def_id_to_hir_id(item_def_id);
wbcx.visit_node_id(body.value.span, item_hir_id);
}
hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (),
// For closures and consts, we already plan to visit liberated signatures.
hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {}
}
wbcx.visit_body(body);
wbcx.visit_min_capture_map();

View file

@ -261,7 +261,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
HirItem::ForeignMod { .. } => ("ItemForeignMod", LABELS_HIR_ONLY),
// Module-level inline assembly (from global_asm!)
HirItem::GlobalAsm(..) => ("ItemGlobalAsm", LABELS_HIR_ONLY),
HirItem::GlobalAsm { .. } => ("ItemGlobalAsm", LABELS_HIR_ONLY),
// A type alias, e.g., `type Foo = Bar<u8>`
HirItem::TyAlias(..) => ("ItemTy", LABELS_HIR_ONLY),

View file

@ -2907,7 +2907,13 @@ enum AsmLabelKind {
impl<'tcx> LateLintPass<'tcx> for AsmLabels {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
if let hir::Expr {
kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, options, .. }),
kind:
hir::ExprKind::InlineAsm(hir::InlineAsm {
asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm,
template_strs,
options,
..
}),
..
} = expr
{

View file

@ -1740,7 +1740,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
hir::ItemKind::Impl(..)
| hir::ItemKind::TraitAlias(..)
| hir::ItemKind::Trait(..)
| hir::ItemKind::GlobalAsm(..)
| hir::ItemKind::GlobalAsm { .. }
| hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::Mod(..)
| hir::ItemKind::Macro(..)

View file

@ -47,6 +47,9 @@ metadata_crate_dep_rustc_driver =
metadata_crate_location_unknown_type =
extern location for {$crate_name} is of an unknown type: {$path}
metadata_crate_not_compiler_builtins =
the crate `{$crate_name}` resolved as `compiler_builtins` but is not `#![compiler_builtins]`
metadata_crate_not_panic_runtime =
the crate `{$crate_name}` is not a panic runtime

View file

@ -32,7 +32,7 @@ use rustc_session::lint::{self, BuiltinLintDiag};
use rustc_session::output::validate_crate_name;
use rustc_session::search_paths::PathKind;
use rustc_span::edition::Edition;
use rustc_span::{DUMMY_SP, Ident, STDLIB_STABLE_CRATES, Span, Symbol, sym};
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
use rustc_target::spec::{PanicStrategy, Target, TargetTuple};
use tracing::{debug, info, trace};
@ -147,6 +147,7 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
writeln!(fmt, " cnum: {cnum}")?;
writeln!(fmt, " hash: {}", data.hash())?;
writeln!(fmt, " reqd: {:?}", data.dep_kind())?;
writeln!(fmt, " priv: {:?}", data.is_private_dep())?;
let CrateSource { dylib, rlib, rmeta } = data.source();
if let Some(dylib) = dylib {
writeln!(fmt, " dylib: {}", dylib.0.display())?;
@ -162,6 +163,53 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
}
}
/// Reason that a crate is being sourced as a dependency.
#[derive(Clone, Copy)]
enum CrateOrigin<'a> {
/// This crate was a dependency of another crate.
IndirectDependency {
/// Where this dependency was included from.
dep_root: &'a CratePaths,
/// True if the parent is private, meaning the dependent should also be private.
parent_private: bool,
/// Dependency info about this crate.
dep: &'a CrateDep,
},
/// Injected by `rustc`.
Injected,
/// Provided by `extern crate foo` or as part of the extern prelude.
Extern,
}
impl<'a> CrateOrigin<'a> {
/// Return the dependency root, if any.
fn dep_root(&self) -> Option<&'a CratePaths> {
match self {
CrateOrigin::IndirectDependency { dep_root, .. } => Some(dep_root),
_ => None,
}
}
/// Return dependency information, if any.
fn dep(&self) -> Option<&'a CrateDep> {
match self {
CrateOrigin::IndirectDependency { dep, .. } => Some(dep),
_ => None,
}
}
/// `Some(true)` if the dependency is private or its parent is private, `Some(false)` if the
/// dependency is not private, `None` if it could not be determined.
fn private_dep(&self) -> Option<bool> {
match self {
CrateOrigin::IndirectDependency { parent_private, dep, .. } => {
Some(dep.is_private || *parent_private)
}
_ => None,
}
}
}
impl CStore {
pub fn from_tcx(tcx: TyCtxt<'_>) -> FreezeReadGuard<'_, CStore> {
FreezeReadGuard::map(tcx.untracked().cstore.read(), |cstore| {
@ -497,25 +545,13 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
&self,
name: Symbol,
private_dep: Option<bool>,
dep_root: Option<&CratePaths>,
origin: CrateOrigin<'_>,
) -> bool {
// Standard library crates are never private.
if STDLIB_STABLE_CRATES.contains(&name) {
tracing::info!("returning false for {name} is private");
return false;
}
let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep);
// Any descendants of `std` should be private. These crates are usually not marked
// private in metadata, so we ignore that field.
if extern_private.is_none()
&& let Some(dep) = dep_root
&& STDLIB_STABLE_CRATES.contains(&dep.name)
{
if matches!(origin, CrateOrigin::Injected) {
return true;
}
let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep);
match (extern_private, private_dep) {
// Explicit non-private via `--extern`, explicit non-private from metadata, or
// unspecified with default to public.
@ -528,7 +564,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
fn register_crate(
&mut self,
host_lib: Option<Library>,
dep_root: Option<&CratePaths>,
origin: CrateOrigin<'_>,
lib: Library,
dep_kind: CrateDepKind,
name: Symbol,
@ -540,7 +576,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
let Library { source, metadata } = lib;
let crate_root = metadata.get_root();
let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
let private_dep = self.is_private_dep(name, private_dep, dep_root);
let private_dep = self.is_private_dep(name, private_dep, origin);
// Claim this crate number and cache it
let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?;
@ -556,14 +592,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
// Maintain a reference to the top most crate.
// Stash paths for top-most crate locally if necessary.
let crate_paths;
let dep_root = if let Some(dep_root) = dep_root {
let dep_root = if let Some(dep_root) = origin.dep_root() {
dep_root
} else {
crate_paths = CratePaths::new(crate_root.name(), source.clone());
&crate_paths
};
let cnum_map = self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind)?;
let cnum_map =
self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind, private_dep)?;
let raw_proc_macros = if crate_root.is_proc_macro_crate() {
let temp_root;
@ -664,17 +701,19 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
name: Symbol,
span: Span,
dep_kind: CrateDepKind,
origin: CrateOrigin<'_>,
) -> Option<CrateNum> {
self.used_extern_options.insert(name);
match self.maybe_resolve_crate(name, dep_kind, None) {
match self.maybe_resolve_crate(name, dep_kind, origin) {
Ok(cnum) => {
self.cstore.set_used_recursively(cnum);
Some(cnum)
}
Err(err) => {
debug!("failed to resolve crate {} {:?}", name, dep_kind);
let missing_core =
self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
let missing_core = self
.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, CrateOrigin::Extern)
.is_err();
err.report(self.sess, span, missing_core);
None
}
@ -685,20 +724,20 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
&'b mut self,
name: Symbol,
mut dep_kind: CrateDepKind,
dep_of: Option<(&'b CratePaths, &'b CrateDep)>,
origin: CrateOrigin<'b>,
) -> Result<CrateNum, CrateError> {
info!("resolving crate `{}`", name);
if !name.as_str().is_ascii() {
return Err(CrateError::NonAsciiName(name));
}
let dep_root = dep_of.map(|d| d.0);
let dep = dep_of.map(|d| d.1);
let dep_root = origin.dep_root();
let dep = origin.dep();
let hash = dep.map(|d| d.hash);
let host_hash = dep.map(|d| d.host_hash).flatten();
let extra_filename = dep.map(|d| &d.extra_filename[..]);
let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate };
let private_dep = dep.map(|d| d.is_private);
let private_dep = origin.private_dep();
let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
(LoadResult::Previous(cnum), None)
@ -731,12 +770,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
match result {
(LoadResult::Previous(cnum), None) => {
info!("library for `{}` was loaded previously", name);
info!("library for `{}` was loaded previously, cnum {cnum}", name);
// When `private_dep` is none, it indicates the directly dependent crate. If it is
// not specified by `--extern` on command line parameters, it may be
// `private-dependency` when `register_crate` is called for the first time. Then it must be updated to
// `public-dependency` here.
let private_dep = self.is_private_dep(name, private_dep, dep_root);
let private_dep = self.is_private_dep(name, private_dep, origin);
let data = self.cstore.get_crate_data_mut(cnum);
if data.is_proc_macro_crate() {
dep_kind = CrateDepKind::MacrosOnly;
@ -747,7 +786,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
(LoadResult::Loaded(library), host_library) => {
info!("register newly loaded library for `{}`", name);
self.register_crate(host_library, dep_root, library, dep_kind, name, private_dep)
self.register_crate(host_library, origin, library, dep_kind, name, private_dep)
}
_ => panic!(),
}
@ -783,6 +822,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
metadata: &MetadataBlob,
krate: CrateNum,
dep_kind: CrateDepKind,
parent_is_private: bool,
) -> Result<CrateNumMap, CrateError> {
debug!(
"resolving deps of external crate `{}` with dep root `{}`",
@ -801,17 +841,26 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
crate_num_map.push(krate);
for dep in deps {
info!(
"resolving dep `{}`->`{}` hash: `{}` extra filename: `{}`",
"resolving dep `{}`->`{}` hash: `{}` extra filename: `{}` private {}",
crate_root.name(),
dep.name,
dep.hash,
dep.extra_filename
dep.extra_filename,
dep.is_private,
);
let dep_kind = match dep_kind {
CrateDepKind::MacrosOnly => CrateDepKind::MacrosOnly,
_ => dep.kind,
};
let cnum = self.maybe_resolve_crate(dep.name, dep_kind, Some((dep_root, &dep)))?;
let cnum = self.maybe_resolve_crate(
dep.name,
dep_kind,
CrateOrigin::IndirectDependency {
dep_root,
parent_private: parent_is_private,
dep: &dep,
},
)?;
crate_num_map.push(cnum);
}
@ -905,7 +954,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
};
info!("panic runtime not found -- loading {}", name);
let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else {
let Some(cnum) =
self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
else {
return;
};
let data = self.cstore.get_crate_data(cnum);
@ -934,7 +985,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
info!("loading profiler");
let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else {
let Some(cnum) =
self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
else {
return;
};
let data = self.cstore.get_crate_data(cnum);
@ -1047,12 +1100,54 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
if entry.force {
let name_interned = Symbol::intern(name);
if !self.used_extern_options.contains(&name_interned) {
self.resolve_crate(name_interned, DUMMY_SP, CrateDepKind::Explicit);
self.resolve_crate(
name_interned,
DUMMY_SP,
CrateDepKind::Explicit,
CrateOrigin::Extern,
);
}
}
}
}
/// Inject the `compiler_builtins` crate if it is not already in the graph.
fn inject_compiler_builtins(&mut self, krate: &ast::Crate) {
// `compiler_builtins` does not get extern builtins, nor do `#![no_core]` crates
if attr::contains_name(&krate.attrs, sym::compiler_builtins)
|| attr::contains_name(&krate.attrs, sym::no_core)
{
info!("`compiler_builtins` unneeded");
return;
}
// If a `#![compiler_builtins]` crate already exists, avoid injecting it twice. This is
// the common case since usually it appears as a dependency of `std` or `alloc`.
for (cnum, cmeta) in self.cstore.iter_crate_data() {
if cmeta.is_compiler_builtins() {
info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection");
return;
}
}
// `compiler_builtins` is not yet in the graph; inject it. Error on resolution failure.
let Some(cnum) = self.resolve_crate(
sym::compiler_builtins,
krate.spans.inner_span.shrink_to_lo(),
CrateDepKind::Explicit,
CrateOrigin::Injected,
) else {
info!("`compiler_builtins` not resolved");
return;
};
// Sanity check that the loaded crate is `#![compiler_builtins]`
let cmeta = self.cstore.get_crate_data(cnum);
if !cmeta.is_compiler_builtins() {
self.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() });
}
}
fn inject_dependency_if(
&mut self,
krate: CrateNum,
@ -1162,6 +1257,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
pub fn postprocess(&mut self, krate: &ast::Crate) {
self.inject_compiler_builtins(krate);
self.inject_forced_externs();
self.inject_profiler_runtime();
self.inject_allocator_crate(krate);
@ -1173,6 +1269,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
info!("{:?}", CrateDump(self.cstore));
}
/// Process an `extern crate foo` AST node.
pub fn process_extern_crate(
&mut self,
item: &ast::Item,
@ -1198,7 +1295,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
CrateDepKind::Explicit
};
let cnum = self.resolve_crate(name, item.span, dep_kind)?;
let cnum = self.resolve_crate(name, item.span, dep_kind, CrateOrigin::Extern)?;
let path_len = definitions.def_path(def_id).data.len();
self.cstore.update_extern_crate(
@ -1217,7 +1314,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit)?;
let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?;
self.cstore.update_extern_crate(
cnum,
@ -1234,7 +1331,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok()
self.maybe_resolve_crate(name, CrateDepKind::Explicit, CrateOrigin::Extern).ok()
}
}

View file

@ -332,6 +332,12 @@ pub struct CrateNotPanicRuntime {
pub crate_name: Symbol,
}
#[derive(Diagnostic)]
#[diag(metadata_crate_not_compiler_builtins)]
pub struct CrateNotCompilerBuiltins {
pub crate_name: Symbol,
}
#[derive(Diagnostic)]
#[diag(metadata_no_panic_strategy)]
pub struct NoPanicStrategy {

View file

@ -260,7 +260,7 @@ pub(crate) struct CrateLocator<'a> {
crate_rejections: CrateRejections,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub(crate) struct CratePaths {
pub(crate) name: Symbol,
source: CrateSource,
@ -272,7 +272,7 @@ impl CratePaths {
}
}
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub(crate) enum CrateFlavor {
Rlib,
Rmeta,
@ -893,13 +893,13 @@ fn get_flavor_from_path(path: &Path) -> CrateFlavor {
// ------------------------------------------ Error reporting -------------------------------------
#[derive(Clone)]
#[derive(Clone, Debug)]
struct CrateMismatch {
path: PathBuf,
got: String,
}
#[derive(Clone, Default)]
#[derive(Clone, Debug, Default)]
struct CrateRejections {
via_hash: Vec<CrateMismatch>,
via_triple: Vec<CrateMismatch>,
@ -912,6 +912,7 @@ struct CrateRejections {
/// Candidate rejection reasons collected during crate search.
/// If no candidate is accepted, then these reasons are presented to the user,
/// otherwise they are ignored.
#[derive(Debug)]
pub(crate) struct CombinedLocatorError {
crate_name: Symbol,
dep_root: Option<CratePaths>,
@ -921,6 +922,7 @@ pub(crate) struct CombinedLocatorError {
crate_rejections: CrateRejections,
}
#[derive(Debug)]
pub(crate) enum CrateError {
NonAsciiName(Symbol),
ExternLocationNotExist(Symbol, PathBuf),

View file

@ -1936,6 +1936,10 @@ impl CrateMetadata {
self.root.needs_panic_runtime
}
pub(crate) fn is_private_dep(&self) -> bool {
self.private_dep
}
pub(crate) fn is_panic_runtime(&self) -> bool {
self.root.panic_runtime
}
@ -1944,6 +1948,10 @@ impl CrateMetadata {
self.root.profiler_runtime
}
pub(crate) fn is_compiler_builtins(&self) -> bool {
self.root.compiler_builtins
}
pub(crate) fn needs_allocator(&self) -> bool {
self.root.needs_allocator
}

View file

@ -305,6 +305,7 @@ impl<'tcx> TyCtxt<'tcx> {
DefKind::Static { safety: _, mutability, nested: false } => {
BodyOwnerKind::Static(mutability)
}
DefKind::GlobalAsm => BodyOwnerKind::GlobalAsm,
dk => bug!("{:?} is not a body node: {:?}", def_id, dk),
}
}
@ -327,7 +328,7 @@ impl<'tcx> TyCtxt<'tcx> {
ConstContext::ConstFn
}
BodyOwnerKind::Fn if self.is_const_default_method(def_id) => ConstContext::ConstFn,
BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None,
BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None,
};
Some(ccx)
@ -1166,7 +1167,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
ItemKind::Macro(..) => "macro",
ItemKind::Mod(..) => "mod",
ItemKind::ForeignMod { .. } => "foreign mod",
ItemKind::GlobalAsm(..) => "global asm",
ItemKind::GlobalAsm { .. } => "global asm",
ItemKind::TyAlias(..) => "ty",
ItemKind::Enum(..) => "enum",
ItemKind::Struct(..) => "struct",

View file

@ -94,6 +94,7 @@ thir_with_elements! {
pub enum BodyTy<'tcx> {
Const(Ty<'tcx>),
Fn(FnSig<'tcx>),
GlobalAsm(Ty<'tcx>),
}
/// Description of a type-checked function parameter.
@ -605,8 +606,7 @@ pub enum InlineAsmOperand<'tcx> {
span: Span,
},
SymFn {
value: mir::Const<'tcx>,
span: Span,
value: ExprId,
},
SymStatic {
def_id: DefId,

View file

@ -172,7 +172,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
}
Out { expr: None, reg: _, late: _ }
| Const { value: _, span: _ }
| SymFn { value: _, span: _ }
| SymFn { value: _ }
| SymStatic { def_id: _ } => {}
Label { block } => visitor.visit_block(&visitor.thir()[*block]),
}

View file

@ -1472,7 +1472,11 @@ impl<'tcx> TyCtxt<'tcx> {
self.codegen_fn_attrs(def_id)
} else if matches!(
def_kind,
DefKind::AnonConst | DefKind::AssocConst | DefKind::Const | DefKind::InlineConst
DefKind::AnonConst
| DefKind::AssocConst
| DefKind::Const
| DefKind::InlineConst
| DefKind::GlobalAsm
) {
CodegenFnAttrs::EMPTY
} else {

View file

@ -482,15 +482,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}),
}
}
thir::InlineAsmOperand::SymFn { value, span } => {
mir::InlineAsmOperand::SymFn {
value: Box::new(ConstOperand {
span,
user_ty: None,
const_: value,
}),
}
}
thir::InlineAsmOperand::SymFn { value } => mir::InlineAsmOperand::SymFn {
value: Box::new(this.as_constant(&this.thir[value])),
},
thir::InlineAsmOperand::SymStatic { def_id } => {
mir::InlineAsmOperand::SymStatic { def_id }
}
@ -518,10 +512,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
let asm_macro = match asm_macro {
AsmMacro::Asm => InlineAsmMacro::Asm,
AsmMacro::GlobalAsm => {
span_bug!(expr_span, "unexpected global_asm! in inline asm")
}
AsmMacro::Asm | AsmMacro::GlobalAsm => InlineAsmMacro::Asm,
AsmMacro::NakedAsm => InlineAsmMacro::NakedAsm,
};

View file

@ -61,7 +61,9 @@ pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
Ok((thir, expr)) => {
let build_mir = |thir: &Thir<'tcx>| match thir.body_type {
thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, thir, expr, fn_sig),
thir::BodyTy::Const(ty) => construct_const(tcx, def, thir, expr, ty),
thir::BodyTy::Const(ty) | thir::BodyTy::GlobalAsm(ty) => {
construct_const(tcx, def, thir, expr, ty)
}
};
// this must run before MIR dump, because
@ -576,6 +578,7 @@ fn construct_const<'a, 'tcx>(
let span = tcx.def_span(def);
(span, span)
}
Node::Item(hir::Item { kind: hir::ItemKind::GlobalAsm { .. }, span, .. }) => (*span, *span),
_ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def),
};

View file

@ -2,6 +2,7 @@ use std::borrow::Cow;
use std::mem;
use std::ops::Bound;
use rustc_ast::AsmMacro;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::DiagArgValue;
use rustc_hir::def::DefKind;
@ -559,7 +560,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
}
}
ExprKind::InlineAsm(box InlineAsmExpr {
asm_macro: _,
asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm,
ref operands,
template: _,
options: _,
@ -583,7 +584,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
}
Out { expr: None, reg: _, late: _ }
| Const { value: _, span: _ }
| SymFn { value: _, span: _ }
| SymFn { value: _ }
| SymStatic { def_id: _ } => {}
Label { block } => {
// Label blocks are safe context.

View file

@ -737,13 +737,8 @@ impl<'tcx> ThirBuildCx<'tcx> {
InlineAsmOperand::Const { value, span }
}
hir::InlineAsmOperand::SymFn { ref anon_const } => {
let value =
mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id())
.instantiate_identity();
let span = tcx.def_span(anon_const.def_id);
InlineAsmOperand::SymFn { value, span }
hir::InlineAsmOperand::SymFn { expr } => {
InlineAsmOperand::SymFn { value: self.mirror_expr(expr) }
}
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
InlineAsmOperand::SymStatic { def_id }

View file

@ -76,23 +76,29 @@ impl<'tcx> ThirBuildCx<'tcx> {
let hir = tcx.hir();
let hir_id = tcx.local_def_id_to_hir_id(def);
let body_type = if tcx.hir_body_owner_kind(def).is_fn_or_closure() {
// fetch the fully liberated fn signature (that is, all bound
// types/lifetimes replaced)
BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id])
} else {
// Get the revealed type of this const. This is *not* the adjusted
// type of its body, which may be a subtype of this type. For
// example:
//
// fn foo(_: &()) {}
// static X: fn(&'static ()) = foo;
//
// The adjusted type of the body of X is `for<'a> fn(&'a ())` which
// is not the same as the type of X. We need the type of the return
// place to be the type of the constant because NLL typeck will
// equate them.
BodyTy::Const(typeck_results.node_type(hir_id))
let body_type = match tcx.hir_body_owner_kind(def) {
rustc_hir::BodyOwnerKind::Fn | rustc_hir::BodyOwnerKind::Closure => {
// fetch the fully liberated fn signature (that is, all bound
// types/lifetimes replaced)
BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id])
}
rustc_hir::BodyOwnerKind::Const { .. } | rustc_hir::BodyOwnerKind::Static(_) => {
// Get the revealed type of this const. This is *not* the adjusted
// type of its body, which may be a subtype of this type. For
// example:
//
// fn foo(_: &()) {}
// static X: fn(&'static ()) = foo;
//
// The adjusted type of the body of X is `for<'a> fn(&'a ())` which
// is not the same as the type of X. We need the type of the return
// place to be the type of the constant because NLL typeck will
// equate them.
BodyTy::Const(typeck_results.node_type(hir_id))
}
rustc_hir::BodyOwnerKind::GlobalAsm => {
BodyTy::GlobalAsm(typeck_results.node_type(hir_id))
}
};
Self {

View file

@ -921,10 +921,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
print_indented!(self, "}", depth_lvl + 1);
}
InlineAsmOperand::SymFn { value, span } => {
InlineAsmOperand::SymFn { value } => {
print_indented!(self, "InlineAsmOperand::SymFn {", depth_lvl);
print_indented!(self, format!("value: {:?}", *value), depth_lvl + 1);
print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
print_indented!(self, "value: ", depth_lvl + 1);
self.print_expr(*value, depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1);
}
InlineAsmOperand::SymStatic { def_id } => {

View file

@ -479,24 +479,23 @@ fn collect_items_rec<'tcx>(
recursion_depth_reset = None;
let item = tcx.hir_item(item_id);
if let hir::ItemKind::GlobalAsm(asm) = item.kind {
if let hir::ItemKind::GlobalAsm { asm, .. } = item.kind {
for (op, op_sp) in asm.operands {
match op {
match *op {
hir::InlineAsmOperand::Const { .. } => {
// Only constants which resolve to a plain integer
// are supported. Therefore the value should not
// depend on any other items.
}
hir::InlineAsmOperand::SymFn { anon_const } => {
let fn_ty =
tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
hir::InlineAsmOperand::SymFn { expr } => {
let fn_ty = tcx.typeck(item_id.owner_id).expr_ty(expr);
visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items);
}
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
let instance = Instance::mono(tcx, *def_id);
let instance = Instance::mono(tcx, def_id);
if tcx.should_codegen_locally(instance) {
trace!("collecting static {:?}", def_id);
used_items.push(dummy_spanned(MonoItem::Static(*def_id)));
used_items.push(dummy_spanned(MonoItem::Static(def_id)));
}
}
hir::InlineAsmOperand::In { .. }

View file

@ -246,7 +246,7 @@ impl<'tcx> ReachableContext<'tcx> {
| hir::ItemKind::Struct(..)
| hir::ItemKind::Enum(..)
| hir::ItemKind::Union(..)
| hir::ItemKind::GlobalAsm(..) => {}
| hir::ItemKind::GlobalAsm { .. } => {}
}
}
Node::TraitItem(trait_method) => {

View file

@ -645,7 +645,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
// The interface is empty, and no nested items.
hir::ItemKind::Use(..)
| hir::ItemKind::ExternCrate(..)
| hir::ItemKind::GlobalAsm(..) => {}
| hir::ItemKind::GlobalAsm { .. } => {}
// The interface is empty, and all nested items are processed by `visit_item`.
hir::ItemKind::Mod(..) => {}
hir::ItemKind::Macro(macro_def, _) => {

View file

@ -13,7 +13,6 @@
#![feature(core_intrinsics)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(ptr_sub_ptr)]
#![feature(rustdoc_internals)]
#![warn(unreachable_pub)]
// tidy-alphabetical-end

View file

@ -547,12 +547,15 @@ fn layout_of_uncached<'tcx>(
(
BackendRepr::Memory { sized: true },
AbiAndPrefAlign {
abi: Align::max_for_offset(size),
pref: dl.vector_align(size).pref,
abi: Align::max_aligned_factor(size),
pref: dl.llvmlike_vector_align(size).pref,
},
)
} else {
(BackendRepr::Vector { element: e_abi, count: e_len }, dl.vector_align(size))
(
BackendRepr::Vector { element: e_abi, count: e_len },
dl.llvmlike_vector_align(size),
)
};
let size = size.align_to(align.abi);

View file

@ -69,31 +69,30 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
}
fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) {
// Verify the ABI mandated alignment and size.
let align = layout.backend_repr.inherent_align(cx).map(|align| align.abi);
let size = layout.backend_repr.inherent_size(cx);
let Some((align, size)) = align.zip(size) else {
assert_matches!(
layout.layout.backend_repr(),
BackendRepr::Memory { .. },
"ABI unexpectedly missing alignment and/or size in {layout:#?}"
// Verify the ABI-mandated alignment and size for scalars.
let align = layout.backend_repr.scalar_align(cx);
let size = layout.backend_repr.scalar_size(cx);
if let Some(align) = align {
assert_eq!(
layout.layout.align().abi,
align,
"alignment mismatch between ABI and layout in {layout:#?}"
);
return;
};
assert_eq!(
layout.layout.align().abi,
align,
"alignment mismatch between ABI and layout in {layout:#?}"
);
assert_eq!(
layout.layout.size(),
size,
"size mismatch between ABI and layout in {layout:#?}"
);
}
if let Some(size) = size {
assert_eq!(
layout.layout.size(),
size,
"size mismatch between ABI and layout in {layout:#?}"
);
}
// Verify per-ABI invariants
match layout.layout.backend_repr() {
BackendRepr::Scalar(_) => {
// These must always be present for `Scalar` types.
let align = align.unwrap();
let size = size.unwrap();
// Check that this matches the underlying field.
let inner = skip_newtypes(cx, layout);
assert!(
@ -235,9 +234,15 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
"`ScalarPair` second field with bad ABI in {inner:#?}",
);
}
BackendRepr::Vector { element, .. } => {
assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`.
// FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair.
BackendRepr::Vector { element, count } => {
let align = layout.align.abi;
let size = layout.size;
let element_align = element.align(cx).abi;
let element_size = element.size(cx);
// Currently, vectors must always be aligned to at least their elements:
assert!(align >= element_align);
// And the size has to be element * count plus alignment padding, of course
assert!(size == (element_size * count).align_to(align));
}
BackendRepr::Memory { .. } => {} // Nothing to check.
}

View file

@ -1,3 +1,5 @@
cargo-features = ["public-dependency"]
[package]
name = "alloc"
version = "0.0.0"
@ -9,7 +11,7 @@ autobenches = false
edition = "2021"
[dependencies]
core = { path = "../core" }
core = { path = "../core", public = true }
compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std'] }
[dev-dependencies]

View file

@ -137,7 +137,6 @@
#![feature(pointer_like_trait)]
#![feature(ptr_internals)]
#![feature(ptr_metadata)]
#![feature(ptr_sub_ptr)]
#![feature(set_ptr_value)]
#![feature(sized_type_properties)]
#![feature(slice_from_ptr_range)]

View file

@ -3675,6 +3675,7 @@ pub const unsafe fn ptr_offset_from<T>(_ptr: *const T, _base: *const T) -> isize
#[rustc_nounwind]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
#[rustc_intrinsic_const_stable_indirect]
pub const unsafe fn ptr_offset_from_unsigned<T>(_ptr: *const T, _base: *const T) -> usize {
unimplemented!()
}

View file

@ -3320,14 +3320,14 @@ macro_rules! uint_impl {
/// Basic usage:
///
/// ```
/// #![feature(unsigned_is_multiple_of)]
#[doc = concat!("assert!(6_", stringify!($SelfT), ".is_multiple_of(2));")]
#[doc = concat!("assert!(!5_", stringify!($SelfT), ".is_multiple_of(2));")]
///
#[doc = concat!("assert!(0_", stringify!($SelfT), ".is_multiple_of(0));")]
#[doc = concat!("assert!(!6_", stringify!($SelfT), ".is_multiple_of(0));")]
/// ```
#[unstable(feature = "unsigned_is_multiple_of", issue = "128101")]
#[stable(feature = "unsigned_is_multiple_of", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "unsigned_is_multiple_of", since = "CURRENT_RUSTC_VERSION")]
#[must_use]
#[inline]
#[rustc_inherit_overflow_checks]

View file

@ -723,7 +723,6 @@ impl<T: ?Sized> *const T {
/// to [`sub`](#method.sub)). The following are all equivalent, assuming
/// that their safety preconditions are met:
/// ```rust
/// # #![feature(ptr_sub_ptr)]
/// # unsafe fn blah(ptr: *const i32, origin: *const i32, count: usize) -> bool { unsafe {
/// ptr.sub_ptr(origin) == count
/// # &&
@ -752,8 +751,6 @@ impl<T: ?Sized> *const T {
/// # Examples
///
/// ```
/// #![feature(ptr_sub_ptr)]
///
/// let a = [0; 5];
/// let ptr1: *const i32 = &a[1];
/// let ptr2: *const i32 = &a[3];
@ -767,8 +764,8 @@ impl<T: ?Sized> *const T {
/// // This would be incorrect, as the pointers are not correctly ordered:
/// // ptr1.sub_ptr(ptr2)
/// ```
#[unstable(feature = "ptr_sub_ptr", issue = "95892")]
#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
#[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn sub_ptr(self, origin: *const T) -> usize
@ -812,8 +809,8 @@ impl<T: ?Sized> *const T {
///
/// For non-`Sized` pointees this operation considers only the data pointers,
/// ignoring the metadata.
#[unstable(feature = "ptr_sub_ptr", issue = "95892")]
#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
#[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn byte_sub_ptr<U: ?Sized>(self, origin: *const U) -> usize {

View file

@ -895,7 +895,6 @@ impl<T: ?Sized> *mut T {
/// to [`sub`](#method.sub)). The following are all equivalent, assuming
/// that their safety preconditions are met:
/// ```rust
/// # #![feature(ptr_sub_ptr)]
/// # unsafe fn blah(ptr: *mut i32, origin: *mut i32, count: usize) -> bool { unsafe {
/// ptr.sub_ptr(origin) == count
/// # &&
@ -924,8 +923,6 @@ impl<T: ?Sized> *mut T {
/// # Examples
///
/// ```
/// #![feature(ptr_sub_ptr)]
///
/// let mut a = [0; 5];
/// let p: *mut i32 = a.as_mut_ptr();
/// unsafe {
@ -940,8 +937,8 @@ impl<T: ?Sized> *mut T {
///
/// // This would be incorrect, as the pointers are not correctly ordered:
/// // ptr1.offset_from(ptr2)
#[unstable(feature = "ptr_sub_ptr", issue = "95892")]
#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
#[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn sub_ptr(self, origin: *const T) -> usize
@ -962,8 +959,8 @@ impl<T: ?Sized> *mut T {
///
/// For non-`Sized` pointees this operation considers only the data pointers,
/// ignoring the metadata.
#[unstable(feature = "ptr_sub_ptr", issue = "95892")]
#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
#[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn byte_sub_ptr<U: ?Sized>(self, origin: *mut U) -> usize {

View file

@ -856,7 +856,6 @@ impl<T: ?Sized> NonNull<T> {
/// to [`sub`](#method.sub)). The following are all equivalent, assuming
/// that their safety preconditions are met:
/// ```rust
/// # #![feature(ptr_sub_ptr)]
/// # unsafe fn blah(ptr: std::ptr::NonNull<u32>, origin: std::ptr::NonNull<u32>, count: usize) -> bool { unsafe {
/// ptr.sub_ptr(origin) == count
/// # &&
@ -885,7 +884,6 @@ impl<T: ?Sized> NonNull<T> {
/// # Examples
///
/// ```
/// #![feature(ptr_sub_ptr)]
/// use std::ptr::NonNull;
///
/// let a = [0; 5];
@ -903,8 +901,8 @@ impl<T: ?Sized> NonNull<T> {
/// ```
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[unstable(feature = "ptr_sub_ptr", issue = "95892")]
#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
#[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")]
pub const unsafe fn sub_ptr(self, subtracted: NonNull<T>) -> usize
where
T: Sized,
@ -925,8 +923,8 @@ impl<T: ?Sized> NonNull<T> {
/// ignoring the metadata.
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[unstable(feature = "ptr_sub_ptr", issue = "95892")]
#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
#[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")]
pub const unsafe fn byte_sub_ptr<U: ?Sized>(self, origin: NonNull<U>) -> usize {
// SAFETY: the caller must uphold the safety contract for `byte_sub_ptr`.
unsafe { self.as_ptr().byte_sub_ptr(origin.as_ptr()) }

View file

@ -87,7 +87,6 @@
#![feature(try_blocks)]
#![feature(try_find)]
#![feature(try_trait_v2)]
#![feature(unsigned_is_multiple_of)]
#![feature(unsize)]
#![feature(unsized_tuple_coercion)]
#![feature(unwrap_infallible)]

View file

@ -388,7 +388,7 @@ mod uefi_command_internal {
}
}
pub fn start_image(&mut self) -> io::Result<r_efi::efi::Status> {
pub(crate) fn start_image(&mut self) -> io::Result<r_efi::efi::Status> {
self.update_st_crc32()?;
// Use our system table instead of the default one

View file

@ -84,7 +84,7 @@ pub(crate) mod system_time_internal {
// This algorithm is based on the one described in the post
// https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
pub const fn uefi_time_to_duration(t: r_efi::system::Time) -> Duration {
pub(crate) const fn uefi_time_to_duration(t: r_efi::system::Time) -> Duration {
assert!(t.month <= 12);
assert!(t.month != 0);

View file

@ -1,3 +1,5 @@
cargo-features = ["public-dependency"]
[package]
name = "sysroot"
version = "0.0.0"
@ -5,10 +7,10 @@ edition = "2021"
# this is a dummy crate to ensure that all required crates appear in the sysroot
[dependencies]
proc_macro = { path = "../proc_macro" }
proc_macro = { path = "../proc_macro", public = true }
profiler_builtins = { path = "../profiler_builtins", optional = true }
std = { path = "../std" }
test = { path = "../test" }
std = { path = "../std", public = true }
test = { path = "../test", public = true }
# Forward features to the `std` crate as necessary
[features]

View file

@ -1,3 +1,5 @@
cargo-features = ["public-dependency"]
[package]
name = "test"
version = "0.0.0"
@ -5,8 +7,8 @@ edition = "2021"
[dependencies]
getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] }
std = { path = "../std" }
core = { path = "../core" }
std = { path = "../std", public = true }
core = { path = "../core", public = true }
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
libc = { version = "0.2.150", default-features = false }

View file

@ -288,7 +288,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
| ItemKind::Use(_, _)
| ItemKind::ExternCrate(_)
| ItemKind::ForeignMod { .. }
| ItemKind::GlobalAsm(_)
| ItemKind::GlobalAsm { .. }
// We already have "visit_mod" above so no need to check it here.
| ItemKind::Mod(_) => {}
}

View file

@ -439,7 +439,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
}
// If we're inlining, skip private items.
_ if self.inlining && !is_pub => {}
hir::ItemKind::GlobalAsm(..) => {}
hir::ItemKind::GlobalAsm { .. } => {}
hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
hir::ItemKind::Use(path, kind) => {
for &res in &path.res {

View file

@ -362,7 +362,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
}
} else if let ItemKind::ForeignMod { .. } = item.kind {
continue;
} else if let ItemKind::GlobalAsm(_) = item.kind {
} else if let ItemKind::GlobalAsm { .. } = item.kind {
continue;
} else if let ItemKind::Use(path, use_kind) = item.kind {
if path.segments.is_empty() {
@ -467,7 +467,7 @@ fn convert_module_item_kind(value: &ItemKind<'_>) -> SourceItemOrderingModuleIte
ItemKind::Macro(..) => Macro,
ItemKind::Mod(..) => Mod,
ItemKind::ForeignMod { .. } => ForeignMod,
ItemKind::GlobalAsm(..) => GlobalAsm,
ItemKind::GlobalAsm { .. } => GlobalAsm,
ItemKind::TyAlias(..) => TyAlias,
ItemKind::Enum(..) => Enum,
ItemKind::Struct(..) => Struct,

View file

@ -217,7 +217,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
| hir::ItemKind::Union(..) => {},
hir::ItemKind::ExternCrate(..)
| hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::GlobalAsm(..)
| hir::ItemKind::GlobalAsm { .. }
| hir::ItemKind::Impl { .. }
| hir::ItemKind::Use(..) => note_prev_span_then_ret!(self.prev_span, it.span),
}

View file

@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
| hir::ItemKind::Static(..)
| hir::ItemKind::Struct(..)
| hir::ItemKind::TraitAlias(..)
| hir::ItemKind::GlobalAsm(..)
| hir::ItemKind::GlobalAsm { .. }
| hir::ItemKind::TyAlias(..)
| hir::ItemKind::Union(..)
| hir::ItemKind::ExternCrate(..)

View file

@ -82,7 +82,7 @@ impl Context {
}
self.const_span = Some(body_span);
},
hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => (),
hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::GlobalAsm => (),
}
}

View file

@ -968,7 +968,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.hash_expr(out_expr);
}
},
InlineAsmOperand::Const { anon_const } | InlineAsmOperand::SymFn { anon_const } => {
InlineAsmOperand::SymFn { expr } => {
self.hash_expr(expr);
}
InlineAsmOperand::Const { anon_const } => {
self.hash_body(anon_const.body);
},
InlineAsmOperand::SymStatic { path, def_id: _ } => self.hash_qpath(path),

View file

@ -16,7 +16,6 @@
#![feature(unqualified_local_imports)]
#![feature(derive_coerce_pointee)]
#![feature(arbitrary_self_types)]
#![feature(unsigned_is_multiple_of)]
#![feature(extract_if)]
// Configure clippy and other lints
#![allow(

View file

@ -1,6 +1,4 @@
//@normalize-stderr-test: "\d+ < \d+" -> "$$ADDR < $$ADDR"
#![feature(ptr_sub_ptr)]
fn main() {
let arr = [0u8; 8];
let ptr1 = arr.as_ptr();

View file

@ -1,5 +1,4 @@
//@compile-flags: -Zmiri-permissive-provenance
#![feature(ptr_sub_ptr)]
use std::{mem, ptr};
fn main() {

View file

@ -179,7 +179,7 @@ fn layout_of_simd_ty(
.size
.checked_mul(e_len, dl)
.ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?;
let align = dl.vector_align(size);
let align = dl.llvmlike_vector_align(size);
let size = size.align_to(align.abi);
// Compute the placement of the vector fields:

View file

@ -1,15 +0,0 @@
//@ known-bug: #111709
//@ edition: 2021
use core::arch::asm;
extern "C" fn test<T>() {}
fn uwu() {
unsafe {
asm!(
"/* {0} */",
sym test::<&mut ()>
);
}
}

View file

@ -1,25 +0,0 @@
//@ known-bug: #111709
//@ edition:2021
use core::arch::asm;
struct TrapFrame;
unsafe extern "C" fn _rust_abi_shim1<A, R>(arg: A, f: fn(A) -> R) -> R {
f(arg)
}
unsafe extern "C" fn _start_trap() {
extern "Rust" {
fn interrupt(tf: &mut TrapFrame);
}
asm!(
"
la a1, {irq}
call {shim}
",
shim = sym crate::_rust_abi_shim1::<&mut TrapFrame, ()>,
irq = sym interrupt,
options(noreturn)
)
}

View file

@ -1,6 +0,0 @@
//@ known-bug: #96304
#![feature(asm_sym)]
core::arch::global_asm!("/* {} */", sym<&'static ()>::clone);
pub fn main() {}

View file

@ -0,0 +1,11 @@
//@ build-pass
//@ needs-asm-support
fn foo<const N: usize>() {}
core::arch::global_asm!("/* {} */", sym foo::<{
|| {};
0
}>);
fn main() {}

View file

@ -0,0 +1,8 @@
//@ build-pass
//@ needs-asm-support
fn foo<T>() {}
core::arch::global_asm!("/* {} */", sym foo::<&'static ()>);
fn main() {}

View file

@ -0,0 +1,17 @@
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/inline-asm-with-lifetimes.rs:17:26
|
LL | fn test<'a: 'a, T>() {
| -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
LL | unsafe {
LL | asm!("/* {} */", sym dep::<'a, T> );
| ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | fn test<'a: 'a, T: 'a>() {
| ++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0309`.

View file

@ -0,0 +1,22 @@
//@ revisions: good bad
//@[good] build-pass
//@ needs-asm-support
use std::arch::asm;
// lifetime requirement, we should check it!!
#[cfg(bad)]
fn dep<'a, T: 'a>() {}
// no lifetime requirement
#[cfg(good)]
fn dep<'a: 'a, T>() {}
fn test<'a: 'a, T>() {
unsafe {
asm!("/* {} */", sym dep::<'a, T> );
//[bad]~^ ERROR the parameter type `T` may not live long enough
}
}
fn main() {}

View file

@ -1,8 +1,5 @@
//@ run-pass
#![feature(const_ptr_sub_ptr)]
#![feature(ptr_sub_ptr)]
struct Struct {
field: (),
}

View file

@ -1,5 +1,4 @@
//@ normalize-stderr: "\d+ bytes" -> "$$BYTES bytes"
#![feature(const_ptr_sub_ptr)]
#![feature(core_intrinsics)]
use std::intrinsics::{ptr_offset_from, ptr_offset_from_unsigned};

View file

@ -1,5 +1,5 @@
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:19:27
--> $DIR/offset_from_ub.rs:18:27
|
LL | let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
@ -12,67 +12,67 @@ error[E0080]: evaluation of constant value failed
note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `NOT_PTR`
--> $DIR/offset_from_ub.rs:25:14
--> $DIR/offset_from_ub.rs:24:14
|
LL | unsafe { (42 as *const u8).offset_from(&5u8) as usize }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:32:14
--> $DIR/offset_from_ub.rs:31:14
|
LL | unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 1_isize cannot be divided by 2_isize without remainder
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:39:14
--> $DIR/offset_from_ub.rs:38:14
|
LL | unsafe { ptr_offset_from(ptr2, ptr1) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:48:14
--> $DIR/offset_from_ub.rs:47:14
|
LL | unsafe { ptr_offset_from(end_ptr, start_ptr) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:57:14
--> $DIR/offset_from_ub.rs:56:14
|
LL | unsafe { ptr_offset_from(start_ptr, end_ptr) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:66:14
--> $DIR/offset_from_ub.rs:65:14
|
LL | unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:73:14
--> $DIR/offset_from_ub.rs:72:14
|
LL | unsafe { ptr_offset_from(ptr2, ptr1) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far ahead of second
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:79:14
--> $DIR/offset_from_ub.rs:78:14
|
LL | unsafe { ptr_offset_from(ptr1, ptr2) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:87:14
--> $DIR/offset_from_ub.rs:86:14
|
LL | unsafe { ptr_offset_from(ptr1, ptr2) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:94:14
--> $DIR/offset_from_ub.rs:93:14
|
LL | unsafe { ptr_offset_from_unsigned(p, p.add(2) ) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:101:14
--> $DIR/offset_from_ub.rs:100:14
|
LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second
@ -85,7 +85,7 @@ error[E0080]: evaluation of constant value failed
note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `OFFSET_VERY_FAR1`
--> $DIR/offset_from_ub.rs:110:14
--> $DIR/offset_from_ub.rs:109:14
|
LL | unsafe { ptr2.offset_from(ptr1) }
| ^^^^^^^^^^^^^^^^^^^^^^
@ -98,7 +98,7 @@ error[E0080]: evaluation of constant value failed
note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `OFFSET_VERY_FAR2`
--> $DIR/offset_from_ub.rs:116:14
--> $DIR/offset_from_ub.rs:115:14
|
LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -7,11 +7,5 @@ error: unwinding panics are not supported without std
= help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding
= note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem
error: requires `sized` lang_item
--> $DIR/empty-extern-arg.rs:6:11
|
LL | fn main() {}
| ^^
error: aborting due to 4 previous errors
error: aborting due to 3 previous errors

View file

@ -1,6 +1,5 @@
//@ aux-crate:priv:reexport=reexport.rs
//@ compile-flags: -Zunstable-options
//@ check-pass
// Checks the behavior of a reexported item from a private dependency.
@ -9,7 +8,7 @@
extern crate reexport;
// FIXME: This should trigger.
pub fn leaks_priv() -> reexport::Shared {
//~^ ERROR type `Shared` from private dependency 'shared' in public interface
reexport::Shared
}

View file

@ -0,0 +1,14 @@
error: type `Shared` from private dependency 'shared' in public interface
--> $DIR/reexport_from_priv.rs:11:1
|
LL | pub fn leaks_priv() -> reexport::Shared {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/reexport_from_priv.rs:7:9
|
LL | #![deny(exported_private_dependencies)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -1,7 +1,6 @@
//@ aux-crate:priv:shared=shared.rs
//@ aux-crate:priv:indirect1=indirect1.rs
//@ compile-flags: -Zunstable-options
//@ check-pass
// A shared dependency, where it is only indirectly public.
//
@ -23,7 +22,7 @@
extern crate shared;
extern crate indirect1;
// FIXME: This should trigger.
pub fn leaks_priv() -> shared::Shared {
//~^ ERROR type `Shared` from private dependency 'shared' in public interface
shared::Shared
}

View file

@ -0,0 +1,14 @@
error: type `Shared` from private dependency 'shared' in public interface
--> $DIR/shared_indirect.rs:25:1
|
LL | pub fn leaks_priv() -> shared::Shared {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/shared_indirect.rs:20:9
|
LL | #![deny(exported_private_dependencies)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -0,0 +1,19 @@
extern crate proc_macro;
use proc_macro::TokenStream;
fn items() -> impl IntoIterator<Item = i32> {
vec![1, 2, 3]
}
#[macro_export]
macro_rules! quote {
// Rule for any other number of tokens.
($($tt:tt)*) => {{
fn items() -> impl IntoIterator<Item = i32> {
vec![1, 2, 3]
}
let _s = TokenStream::new();
let other_items = items().map(|i| i + 1);
_s
}};
}

View file

@ -3,7 +3,8 @@
//@ edition:2018
//@ proc-macro: issue-59191.rs
//@ error-pattern: requires `sized` lang_item
//@ needs-unwind (affects error output)
//@ error-pattern: error: `#[panic_handler]` function required
#![feature(custom_inner_attributes)]
#![issue_59191::no_main]

View file

@ -1,10 +1,9 @@
error: requires `sized` lang_item
--> $DIR/issue-59191-replace-root-with-fn.rs:9:1
|
LL | #![issue_59191::no_main]
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the attribute macro `issue_59191::no_main` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `#[panic_handler]` function required, but not found
error: aborting due to 1 previous error
error: unwinding panics are not supported without std
|
= help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding
= note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem
error: aborting due to 2 previous errors

View file

@ -20,7 +20,6 @@ Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro
use core /* 0#1 */::prelude /* 0#1 */::rust_2018 /* 0#1 */::*;
#[macro_use /* 0#1 */]
extern crate core /* 0#1 */;
extern crate compiler_builtins /* NNN */ as _ /* 0#1 */;
// Don't load unnecessary hygiene information from std
extern crate std /* 0#0 */;

View file

@ -39,7 +39,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
use ::core /* 0#1 */::prelude /* 0#1 */::rust_2015 /* 0#1 */::*;
#[macro_use /* 0#1 */]
extern crate core /* 0#2 */;
extern crate compiler_builtins /* NNN */ as _ /* 0#2 */;
// Don't load unnecessary hygiene information from std
extern crate std /* 0#0 */;

View file

@ -0,0 +1,17 @@
//@ aux-crate: quote=quote-issue-137345.rs
extern crate proc_macro;
extern crate quote;
use proc_macro::TokenStream;
pub fn default_args_fn(_: TokenStream) -> TokenStream {
let decl_macro = TokenStream::new();
quote::quote! {
#(#decl_macro)*
}
.into() //~^^^ ERROR no method named `map` found for opaque type
}
fn main() {}

View file

@ -0,0 +1,13 @@
error[E0599]: no method named `map` found for opaque type `impl IntoIterator<Item = i32>` in the current scope
--> $DIR/valid-sugg-issue-137345.rs:11:5
|
LL | / quote::quote! {
LL | | #(#decl_macro)*
LL | | }
| |_____^ `impl IntoIterator<Item = i32>` is not an iterator
|
= note: this error originates in the macro `quote::quote` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0599`.