Merge from rustc
This commit is contained in:
commit
7d12e50f73
1778 changed files with 31621 additions and 19057 deletions
14
Cargo.lock
14
Cargo.lock
|
|
@ -3301,6 +3301,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"itertools",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_lexer",
|
||||
"rustc_span",
|
||||
"thin-vec",
|
||||
|
|
@ -3621,6 +3622,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"annotate-snippets 0.11.4",
|
||||
"derive_setters",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
|
|
@ -3718,6 +3720,7 @@ name = "rustc_hir_analysis"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"rustc_abi",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
|
|
@ -3906,6 +3909,7 @@ dependencies = [
|
|||
name = "rustc_lint"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr",
|
||||
|
|
@ -3980,6 +3984,7 @@ dependencies = [
|
|||
"bitflags 2.6.0",
|
||||
"libloading",
|
||||
"odht",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
"rustc_data_structures",
|
||||
|
|
@ -4029,6 +4034,7 @@ dependencies = [
|
|||
"rustc_hir",
|
||||
"rustc_hir_pretty",
|
||||
"rustc_index",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_query_system",
|
||||
"rustc_serialize",
|
||||
|
|
@ -4073,6 +4079,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"polonius-engine",
|
||||
"regex",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -4094,6 +4101,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"either",
|
||||
"itertools",
|
||||
"rustc_abi",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
|
|
@ -4186,6 +4194,7 @@ dependencies = [
|
|||
name = "rustc_passes"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr",
|
||||
|
|
@ -4212,6 +4221,7 @@ name = "rustc_pattern_analysis"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc-hash 2.0.0",
|
||||
"rustc_abi",
|
||||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
"rustc_data_structures",
|
||||
|
|
@ -4351,6 +4361,7 @@ dependencies = [
|
|||
"bitflags 2.6.0",
|
||||
"getopts",
|
||||
"libc",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -4414,6 +4425,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"punycode",
|
||||
"rustc-demangle",
|
||||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_hir",
|
||||
|
|
@ -4495,6 +4507,7 @@ name = "rustc_transmute"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"rustc_abi",
|
||||
"rustc_ast_ir",
|
||||
"rustc_data_structures",
|
||||
"rustc_hir",
|
||||
|
|
@ -4502,7 +4515,6 @@ dependencies = [
|
|||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -68,15 +68,15 @@ Stabilized APIs
|
|||
- [`impl Default for std::collections::vec_deque::Iter`](https://doc.rust-lang.org/nightly/std/collections/vec_deque/struct.Iter.html#impl-Default-for-Iter%3C'_,+T%3E)
|
||||
- [`impl Default for std::collections::vec_deque::IterMut`](https://doc.rust-lang.org/nightly/std/collections/vec_deque/struct.IterMut.html#impl-Default-for-IterMut%3C'_,+T%3E)
|
||||
- [`Rc<T>::new_uninit`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new_uninit)
|
||||
- [`Rc<T>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init)
|
||||
- [`Rc<MaybeUninit<T>>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init)
|
||||
- [`Rc<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new_uninit_slice)
|
||||
- [`Rc<[MaybeUninit<T>]>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init-1)
|
||||
- [`Arc<T>::new_uninit`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.new_uninit)
|
||||
- [`Arc<T>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init)
|
||||
- [`Arc<MaybeUninit<T>>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init)
|
||||
- [`Arc<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.new_uninit_slice)
|
||||
- [`Arc<[MaybeUninit<T>]>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init-1)
|
||||
- [`Box<T>::new_uninit`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.new_uninit)
|
||||
- [`Box<T>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init)
|
||||
- [`Box<MaybeUninit<T>>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init)
|
||||
- [`Box<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.new_uninit_slice)
|
||||
- [`Box<[MaybeUninit<T>]>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init-1)
|
||||
- [`core::arch::x86_64::_bextri_u64`](https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bextri_u64.html)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use tracing::debug;
|
|||
|
||||
use crate::{
|
||||
Abi, AbiAndPrefAlign, Align, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
|
||||
LayoutS, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding,
|
||||
LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding,
|
||||
Variants, WrappingRange,
|
||||
};
|
||||
|
||||
|
|
@ -26,9 +26,9 @@ fn absent<'a, FieldIdx, VariantIdx, F>(fields: &IndexSlice<FieldIdx, F>) -> bool
|
|||
where
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||
{
|
||||
let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited());
|
||||
let uninhabited = fields.iter().any(|f| f.is_uninhabited());
|
||||
// We cannot ignore alignment; that might lead us to entirely discard a variant and
|
||||
// produce an enum that is less aligned than it should be!
|
||||
let is_1zst = fields.iter().all(|f| f.is_1zst());
|
||||
|
|
@ -89,7 +89,7 @@ impl<F> LayoutCalculatorError<F> {
|
|||
}
|
||||
|
||||
type LayoutCalculatorResult<FieldIdx, VariantIdx, F> =
|
||||
Result<LayoutS<FieldIdx, VariantIdx>, LayoutCalculatorError<F>>;
|
||||
Result<LayoutData<FieldIdx, VariantIdx>, LayoutCalculatorError<F>>;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LayoutCalculator<Cx> {
|
||||
|
|
@ -105,7 +105,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
&self,
|
||||
a: Scalar,
|
||||
b: Scalar,
|
||||
) -> LayoutS<FieldIdx, VariantIdx> {
|
||||
) -> LayoutData<FieldIdx, VariantIdx> {
|
||||
let dl = self.cx.data_layout();
|
||||
let b_align = b.align(dl);
|
||||
let align = a.align(dl).max(b_align).max(dl.aggregate_align);
|
||||
|
|
@ -119,7 +119,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
.chain(Niche::from_scalar(dl, Size::ZERO, a))
|
||||
.max_by_key(|niche| niche.available(dl));
|
||||
|
||||
LayoutS {
|
||||
LayoutData {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Arbitrary {
|
||||
offsets: [Size::ZERO, b_offset].into(),
|
||||
|
|
@ -138,7 +138,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
'a,
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
|
||||
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
|
||||
>(
|
||||
&self,
|
||||
fields: &IndexSlice<FieldIdx, F>,
|
||||
|
|
@ -211,9 +211,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
|
||||
pub fn layout_of_never_type<FieldIdx: Idx, VariantIdx: Idx>(
|
||||
&self,
|
||||
) -> LayoutS<FieldIdx, VariantIdx> {
|
||||
) -> LayoutData<FieldIdx, VariantIdx> {
|
||||
let dl = self.cx.data_layout();
|
||||
LayoutS {
|
||||
LayoutData {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Primitive,
|
||||
abi: Abi::Uninhabited,
|
||||
|
|
@ -229,7 +229,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
'a,
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
|
||||
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
|
||||
>(
|
||||
&self,
|
||||
repr: &ReprOptions,
|
||||
|
|
@ -292,7 +292,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
'a,
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
|
||||
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
|
||||
>(
|
||||
&self,
|
||||
repr: &ReprOptions,
|
||||
|
|
@ -384,7 +384,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
return Err(LayoutCalculatorError::EmptyUnion);
|
||||
};
|
||||
|
||||
Ok(LayoutS {
|
||||
Ok(LayoutData {
|
||||
variants: Variants::Single { index: only_variant_idx },
|
||||
fields: FieldsShape::Union(union_field_count),
|
||||
abi,
|
||||
|
|
@ -401,7 +401,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
'a,
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
|
||||
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
|
||||
>(
|
||||
&self,
|
||||
repr: &ReprOptions,
|
||||
|
|
@ -501,7 +501,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
'a,
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
|
||||
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
|
||||
>(
|
||||
&self,
|
||||
repr: &ReprOptions,
|
||||
|
|
@ -516,8 +516,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
// overall LayoutS. Store the overall LayoutS
|
||||
// and the variant LayoutSs here until then.
|
||||
struct TmpLayout<FieldIdx: Idx, VariantIdx: Idx> {
|
||||
layout: LayoutS<FieldIdx, VariantIdx>,
|
||||
variants: IndexVec<VariantIdx, LayoutS<FieldIdx, VariantIdx>>,
|
||||
layout: LayoutData<FieldIdx, VariantIdx>,
|
||||
variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>,
|
||||
}
|
||||
|
||||
let dl = self.cx.data_layout();
|
||||
|
|
@ -649,7 +649,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
Abi::Aggregate { sized: true }
|
||||
};
|
||||
|
||||
let layout = LayoutS {
|
||||
let layout = LayoutData {
|
||||
variants: Variants::Multiple {
|
||||
tag: niche_scalar,
|
||||
tag_encoding: TagEncoding::Niche {
|
||||
|
|
@ -681,7 +681,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
let discr_type = repr.discr_type();
|
||||
let bits = Integer::from_attr(dl, discr_type).size().bits();
|
||||
for (i, mut val) in discriminants {
|
||||
if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) {
|
||||
if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) {
|
||||
continue;
|
||||
}
|
||||
if discr_type.is_signed() {
|
||||
|
|
@ -958,7 +958,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
|
||||
let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
|
||||
|
||||
let tagged_layout = LayoutS {
|
||||
let tagged_layout = LayoutData {
|
||||
variants: Variants::Multiple {
|
||||
tag,
|
||||
tag_encoding: TagEncoding::Direct,
|
||||
|
|
@ -1013,7 +1013,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
'a,
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
|
||||
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
|
||||
>(
|
||||
&self,
|
||||
fields: &IndexSlice<FieldIdx, F>,
|
||||
|
|
@ -1341,7 +1341,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
unadjusted_abi_align
|
||||
};
|
||||
|
||||
Ok(LayoutS {
|
||||
Ok(LayoutData {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Arbitrary { offsets, memory_index },
|
||||
abi,
|
||||
|
|
@ -1357,10 +1357,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
'a,
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||
>(
|
||||
&self,
|
||||
layout: &LayoutS<FieldIdx, VariantIdx>,
|
||||
layout: &LayoutData<FieldIdx, VariantIdx>,
|
||||
fields: &IndexSlice<FieldIdx, F>,
|
||||
) -> String {
|
||||
let dl = self.cx.data_layout();
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ rustc_index::newtype_index! {
|
|||
}
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
|
||||
#[rustc_pass_by_value]
|
||||
pub struct Layout<'a>(pub Interned<'a, LayoutS<FieldIdx, VariantIdx>>);
|
||||
pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);
|
||||
|
||||
impl<'a> fmt::Debug for Layout<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
|
@ -68,8 +68,8 @@ impl<'a> fmt::Debug for Layout<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Deref for Layout<'a> {
|
||||
type Target = &'a LayoutS<FieldIdx, VariantIdx>;
|
||||
fn deref(&self) -> &&'a LayoutS<FieldIdx, VariantIdx> {
|
||||
type Target = &'a LayoutData<FieldIdx, VariantIdx>;
|
||||
fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
|
||||
&self.0.0
|
||||
}
|
||||
}
|
||||
|
|
@ -142,8 +142,8 @@ impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> {
|
|||
}
|
||||
|
||||
impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
|
||||
type Target = &'a LayoutS<FieldIdx, VariantIdx>;
|
||||
fn deref(&self) -> &&'a LayoutS<FieldIdx, VariantIdx> {
|
||||
type Target = &'a LayoutData<FieldIdx, VariantIdx>;
|
||||
fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
|
||||
&self.layout.0.0
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1485,7 +1485,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
|
|||
tag: Scalar,
|
||||
tag_encoding: TagEncoding<VariantIdx>,
|
||||
tag_field: usize,
|
||||
variants: IndexVec<VariantIdx, LayoutS<FieldIdx, VariantIdx>>,
|
||||
variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -1603,7 +1603,7 @@ impl Niche {
|
|||
// NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage.
|
||||
#[derive(PartialEq, Eq, Hash, Clone)]
|
||||
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
||||
pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> {
|
||||
pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> {
|
||||
/// Says where the fields are located within the layout.
|
||||
pub fields: FieldsShape<FieldIdx>,
|
||||
|
||||
|
|
@ -1643,7 +1643,7 @@ pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> {
|
|||
pub unadjusted_abi_align: Align,
|
||||
}
|
||||
|
||||
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
|
||||
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
|
||||
pub fn is_aggregate(&self) -> bool {
|
||||
match self.abi {
|
||||
|
|
@ -1652,11 +1652,16 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this is an uninhabited type
|
||||
pub fn is_uninhabited(&self) -> bool {
|
||||
self.abi.is_uninhabited()
|
||||
}
|
||||
|
||||
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
|
||||
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
|
||||
let size = scalar.size(cx);
|
||||
let align = scalar.align(cx);
|
||||
LayoutS {
|
||||
LayoutData {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Primitive,
|
||||
abi: Abi::Scalar(scalar),
|
||||
|
|
@ -1669,7 +1674,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutS<FieldIdx, VariantIdx>
|
||||
impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx>
|
||||
where
|
||||
FieldsShape<FieldIdx>: fmt::Debug,
|
||||
Variants<FieldIdx, VariantIdx>: fmt::Debug,
|
||||
|
|
@ -1678,7 +1683,7 @@ where
|
|||
// This is how `Layout` used to print before it become
|
||||
// `Interned<LayoutS>`. We print it like this to avoid having to update
|
||||
// expected output in a lot of tests.
|
||||
let LayoutS {
|
||||
let LayoutData {
|
||||
size,
|
||||
align,
|
||||
abi,
|
||||
|
|
@ -1723,7 +1728,7 @@ pub struct PointeeInfo {
|
|||
pub safe: Option<PointerKind>,
|
||||
}
|
||||
|
||||
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
|
||||
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||
/// Returns `true` if the layout corresponds to an unsized type.
|
||||
#[inline]
|
||||
pub fn is_unsized(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -2697,7 +2697,7 @@ impl fmt::Debug for ImplPolarity {
|
|||
}
|
||||
|
||||
/// The polarity of a trait bound.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum BoundPolarity {
|
||||
/// `Type: Trait`
|
||||
|
|
@ -2719,7 +2719,7 @@ impl BoundPolarity {
|
|||
}
|
||||
|
||||
/// The constness of a trait bound.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum BoundConstness {
|
||||
/// `Type: Trait`
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ impl AttrItem {
|
|||
self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
|
||||
}
|
||||
|
||||
fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
||||
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
||||
match &self.args {
|
||||
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
||||
MetaItemKind::list_from_tokens(args.tokens.clone())
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ impl Clone for TokenKind {
|
|||
// a copy. This is faster than the `derive(Clone)` version which has a
|
||||
// separate path for every variant.
|
||||
match self {
|
||||
Interpolated(nt) => Interpolated(nt.clone()),
|
||||
Interpolated(nt) => Interpolated(Lrc::clone(nt)),
|
||||
_ => unsafe { std::ptr::read(self) },
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ pub trait Visitor<'ast>: Sized {
|
|||
/// or `ControlFlow<T>`.
|
||||
type Result: VisitorResult = ();
|
||||
|
||||
fn visit_ident(&mut self, _ident: Ident) -> Self::Result {
|
||||
fn visit_ident(&mut self, _ident: &'ast Ident) -> Self::Result {
|
||||
Self::Result::output()
|
||||
}
|
||||
fn visit_foreign_item(&mut self, i: &'ast ForeignItem) -> Self::Result {
|
||||
|
|
@ -173,9 +173,6 @@ pub trait Visitor<'ast>: Sized {
|
|||
fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) -> Self::Result {
|
||||
self.visit_expr(ex)
|
||||
}
|
||||
fn visit_expr_post(&mut self, _ex: &'ast Expr) -> Self::Result {
|
||||
Self::Result::output()
|
||||
}
|
||||
fn visit_ty(&mut self, t: &'ast Ty) -> Self::Result {
|
||||
walk_ty(self, t)
|
||||
}
|
||||
|
|
@ -317,12 +314,12 @@ pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::R
|
|||
}
|
||||
|
||||
pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, Label { ident }: &'a Label) -> V::Result {
|
||||
visitor.visit_ident(*ident)
|
||||
visitor.visit_ident(ident)
|
||||
}
|
||||
|
||||
pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) -> V::Result {
|
||||
let Lifetime { id: _, ident } = lifetime;
|
||||
visitor.visit_ident(*ident)
|
||||
visitor.visit_ident(ident)
|
||||
}
|
||||
|
||||
pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result
|
||||
|
|
@ -429,7 +426,7 @@ impl WalkItemKind for ItemKind {
|
|||
}) => {
|
||||
try_visit!(walk_qself(visitor, qself));
|
||||
try_visit!(visitor.visit_path(path, *id));
|
||||
visit_opt!(visitor, visit_ident, *rename);
|
||||
visit_opt!(visitor, visit_ident, rename);
|
||||
visit_opt!(visitor, visit_block, body);
|
||||
}
|
||||
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||
|
|
@ -437,9 +434,9 @@ impl WalkItemKind for ItemKind {
|
|||
try_visit!(visitor.visit_path(prefix, *id));
|
||||
if let Some(suffixes) = suffixes {
|
||||
for (ident, rename) in suffixes {
|
||||
visitor.visit_ident(*ident);
|
||||
visitor.visit_ident(ident);
|
||||
if let Some(rename) = rename {
|
||||
visitor.visit_ident(*rename);
|
||||
visitor.visit_ident(rename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -472,7 +469,7 @@ where
|
|||
let Variant { attrs, id: _, span: _, vis, ident, data, disr_expr, is_placeholder: _ } = variant;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_vis(vis));
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_variant_data(data));
|
||||
visit_opt!(visitor, visit_variant_discr, disr_expr);
|
||||
V::Result::output()
|
||||
|
|
@ -481,7 +478,7 @@ where
|
|||
pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> V::Result {
|
||||
let ExprField { attrs, id: _, span: _, ident, expr, is_shorthand: _, is_placeholder: _ } = f;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_expr(expr));
|
||||
V::Result::output()
|
||||
}
|
||||
|
|
@ -489,7 +486,7 @@ pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) ->
|
|||
pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) -> V::Result {
|
||||
let PatField { ident, pat, is_shorthand: _, attrs, id: _, span: _, is_placeholder: _ } = fp;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_pat(pat));
|
||||
V::Result::output()
|
||||
}
|
||||
|
|
@ -564,7 +561,7 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>(
|
|||
match kind {
|
||||
UseTreeKind::Simple(rename) => {
|
||||
// The extra IDs are handled during AST lowering.
|
||||
visit_opt!(visitor, visit_ident, *rename);
|
||||
visit_opt!(visitor, visit_ident, rename);
|
||||
}
|
||||
UseTreeKind::Glob => {}
|
||||
UseTreeKind::Nested { ref items, span: _ } => {
|
||||
|
|
@ -581,7 +578,7 @@ pub fn walk_path_segment<'a, V: Visitor<'a>>(
|
|||
segment: &'a PathSegment,
|
||||
) -> V::Result {
|
||||
let PathSegment { ident, id: _, args } = segment;
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
visit_opt!(visitor, visit_generic_args, args);
|
||||
V::Result::output()
|
||||
}
|
||||
|
|
@ -627,7 +624,7 @@ pub fn walk_assoc_item_constraint<'a, V: Visitor<'a>>(
|
|||
constraint: &'a AssocItemConstraint,
|
||||
) -> V::Result {
|
||||
let AssocItemConstraint { id: _, ident, gen_args, kind, span: _ } = constraint;
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
visit_opt!(visitor, visit_generic_args, gen_args);
|
||||
match kind {
|
||||
AssocItemConstraintKind::Equality { term } => match term {
|
||||
|
|
@ -665,7 +662,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
|||
try_visit!(visitor.visit_pat(subpattern));
|
||||
}
|
||||
PatKind::Ident(_bmode, ident, optional_subpattern) => {
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
visit_opt!(visitor, visit_pat, optional_subpattern);
|
||||
}
|
||||
PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)),
|
||||
|
|
@ -751,7 +748,7 @@ pub fn walk_generic_param<'a, V: Visitor<'a>>(
|
|||
let GenericParam { id: _, ident, attrs, bounds, is_placeholder: _, kind, colon_span: _ } =
|
||||
param;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
||||
match kind {
|
||||
GenericParamKind::Lifetime => (),
|
||||
|
|
@ -889,7 +886,7 @@ impl WalkItemKind for AssocItemKind {
|
|||
}) => {
|
||||
try_visit!(walk_qself(visitor, qself));
|
||||
try_visit!(visitor.visit_path(path, *id));
|
||||
visit_opt!(visitor, visit_ident, *rename);
|
||||
visit_opt!(visitor, visit_ident, rename);
|
||||
visit_opt!(visitor, visit_block, body);
|
||||
}
|
||||
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||
|
|
@ -897,9 +894,9 @@ impl WalkItemKind for AssocItemKind {
|
|||
try_visit!(visitor.visit_path(prefix, id));
|
||||
if let Some(suffixes) = suffixes {
|
||||
for (ident, rename) in suffixes {
|
||||
visitor.visit_ident(*ident);
|
||||
visitor.visit_ident(ident);
|
||||
if let Some(rename) = rename {
|
||||
visitor.visit_ident(*rename);
|
||||
visitor.visit_ident(rename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -915,7 +912,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(
|
|||
item: &'a Item<impl WalkItemKind>,
|
||||
ctxt: AssocCtxt,
|
||||
) -> V::Result {
|
||||
let &Item { id: _, span: _, ident, ref vis, ref attrs, ref kind, tokens: _ } = item;
|
||||
let Item { id: _, span: _, ident, vis, attrs, kind, tokens: _ } = item;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_vis(vis));
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
|
|
@ -935,7 +932,7 @@ pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef)
|
|||
let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _ } = field;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_vis(vis));
|
||||
visit_opt!(visitor, visit_ident, *ident);
|
||||
visit_opt!(visitor, visit_ident, ident);
|
||||
try_visit!(visitor.visit_ty(ty));
|
||||
V::Result::output()
|
||||
}
|
||||
|
|
@ -1017,7 +1014,7 @@ pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs
|
|||
for FormatArgument { kind, expr } in arguments.all_args() {
|
||||
match kind {
|
||||
FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => {
|
||||
try_visit!(visitor.visit_ident(*ident))
|
||||
try_visit!(visitor.visit_ident(ident))
|
||||
}
|
||||
FormatArgumentKind::Normal => {}
|
||||
}
|
||||
|
|
@ -1137,7 +1134,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
|||
}
|
||||
ExprKind::Field(subexpression, ident) => {
|
||||
try_visit!(visitor.visit_expr(subexpression));
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
}
|
||||
ExprKind::Index(main_expression, index_expression, _span) => {
|
||||
try_visit!(visitor.visit_expr(main_expression));
|
||||
|
|
@ -1172,7 +1169,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
|||
ExprKind::FormatArgs(f) => try_visit!(visitor.visit_format_args(f)),
|
||||
ExprKind::OffsetOf(container, fields) => {
|
||||
try_visit!(visitor.visit_ty(container));
|
||||
walk_list!(visitor, visit_ident, fields.iter().copied());
|
||||
walk_list!(visitor, visit_ident, fields.iter());
|
||||
}
|
||||
ExprKind::Yield(optional_expression) => {
|
||||
visit_opt!(visitor, visit_expr, optional_expression);
|
||||
|
|
@ -1185,7 +1182,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
|||
ExprKind::Dummy => {}
|
||||
}
|
||||
|
||||
visitor.visit_expr_post(expression)
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) -> V::Result {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
| asm::InlineAsmArch::RiscV64
|
||||
| asm::InlineAsmArch::LoongArch64
|
||||
);
|
||||
if !is_stable && !self.tcx.features().asm_experimental_arch {
|
||||
if !is_stable && !self.tcx.features().asm_experimental_arch() {
|
||||
feature_err(
|
||||
&self.tcx.sess,
|
||||
sym::asm_experimental_arch,
|
||||
|
|
@ -65,7 +65,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
{
|
||||
self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp });
|
||||
}
|
||||
if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind {
|
||||
if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind() {
|
||||
feature_err(
|
||||
&self.tcx.sess,
|
||||
sym::asm_unwind,
|
||||
|
|
@ -237,7 +237,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
InlineAsmOperand::Label { block } => {
|
||||
if !self.tcx.features().asm_goto {
|
||||
if !self.tcx.features().asm_goto() {
|
||||
feature_err(
|
||||
sess,
|
||||
sym::asm_goto,
|
||||
|
|
|
|||
|
|
@ -10,17 +10,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
b: &Block,
|
||||
targeted_by_break: bool,
|
||||
) -> &'hir hir::Block<'hir> {
|
||||
self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break))
|
||||
let hir_id = self.lower_node_id(b.id);
|
||||
self.arena.alloc(self.lower_block_noalloc(hir_id, b, targeted_by_break))
|
||||
}
|
||||
|
||||
pub(super) fn lower_block_noalloc(
|
||||
&mut self,
|
||||
hir_id: hir::HirId,
|
||||
b: &Block,
|
||||
targeted_by_break: bool,
|
||||
) -> hir::Block<'hir> {
|
||||
let (stmts, expr) = self.lower_stmts(&b.stmts);
|
||||
let rules = self.lower_block_check_mode(&b.rules);
|
||||
let hir_id = self.lower_node_id(b.id);
|
||||
hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -259,10 +259,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self_param_id: pat_node_id,
|
||||
};
|
||||
self_resolver.visit_block(block);
|
||||
// Target expr needs to lower `self` path.
|
||||
this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id);
|
||||
this.lower_target_expr(&block)
|
||||
} else {
|
||||
let pat_hir_id = this.lower_node_id(pat_node_id);
|
||||
this.generate_arg(pat_hir_id, span)
|
||||
this.generate_arg(param.pat.hir_id, span)
|
||||
};
|
||||
args.push(arg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::assert_matches::assert_matches;
|
|||
use rustc_ast::ptr::P as AstP;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
|
@ -70,8 +71,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
_ => (),
|
||||
}
|
||||
|
||||
let hir_id = self.lower_node_id(e.id);
|
||||
self.lower_attrs(hir_id, &e.attrs);
|
||||
let expr_hir_id = self.lower_node_id(e.id);
|
||||
self.lower_attrs(expr_hir_id, &e.attrs);
|
||||
|
||||
let kind = match &e.kind {
|
||||
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||
|
|
@ -143,7 +144,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ExprKind::IncludedBytes(bytes) => {
|
||||
let lit = self.arena.alloc(respan(
|
||||
self.lower_span(e.span),
|
||||
LitKind::ByteStr(bytes.clone(), StrStyle::Cooked),
|
||||
LitKind::ByteStr(Lrc::clone(bytes), StrStyle::Cooked),
|
||||
));
|
||||
hir::ExprKind::Lit(lit)
|
||||
}
|
||||
|
|
@ -175,18 +176,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ExprKind::If(cond, then, else_opt) => {
|
||||
self.lower_expr_if(cond, then, else_opt.as_deref())
|
||||
}
|
||||
ExprKind::While(cond, body, opt_label) => self.with_loop_scope(e.id, |this| {
|
||||
let span = this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None);
|
||||
this.lower_expr_while_in_loop_scope(span, cond, body, *opt_label)
|
||||
}),
|
||||
ExprKind::Loop(body, opt_label, span) => self.with_loop_scope(e.id, |this| {
|
||||
hir::ExprKind::Loop(
|
||||
this.lower_block(body, false),
|
||||
this.lower_label(*opt_label),
|
||||
hir::LoopSource::Loop,
|
||||
this.lower_span(*span),
|
||||
)
|
||||
}),
|
||||
ExprKind::While(cond, body, opt_label) => {
|
||||
self.with_loop_scope(expr_hir_id, |this| {
|
||||
let span =
|
||||
this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None);
|
||||
let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id);
|
||||
this.lower_expr_while_in_loop_scope(span, cond, body, opt_label)
|
||||
})
|
||||
}
|
||||
ExprKind::Loop(body, opt_label, span) => {
|
||||
self.with_loop_scope(expr_hir_id, |this| {
|
||||
let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id);
|
||||
hir::ExprKind::Loop(
|
||||
this.lower_block(body, false),
|
||||
opt_label,
|
||||
hir::LoopSource::Loop,
|
||||
this.lower_span(*span),
|
||||
)
|
||||
})
|
||||
}
|
||||
ExprKind::TryBlock(body) => self.lower_expr_try_block(body),
|
||||
ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match(
|
||||
self.lower_expr(expr),
|
||||
|
|
@ -212,7 +220,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
binder,
|
||||
*capture_clause,
|
||||
e.id,
|
||||
hir_id,
|
||||
expr_hir_id,
|
||||
*coroutine_kind,
|
||||
fn_decl,
|
||||
body,
|
||||
|
|
@ -223,7 +231,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
binder,
|
||||
*capture_clause,
|
||||
e.id,
|
||||
hir_id,
|
||||
expr_hir_id,
|
||||
*constness,
|
||||
*movability,
|
||||
fn_decl,
|
||||
|
|
@ -250,8 +258,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)
|
||||
}
|
||||
ExprKind::Block(blk, opt_label) => {
|
||||
let opt_label = self.lower_label(*opt_label);
|
||||
hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
|
||||
// Different from loops, label of block resolves to block id rather than
|
||||
// expr node id.
|
||||
let block_hir_id = self.lower_node_id(blk.id);
|
||||
let opt_label = self.lower_label(*opt_label, blk.id, block_hir_id);
|
||||
let hir_block = self.arena.alloc(self.lower_block_noalloc(
|
||||
block_hir_id,
|
||||
blk,
|
||||
opt_label.is_some(),
|
||||
));
|
||||
hir::ExprKind::Block(hir_block, opt_label)
|
||||
}
|
||||
ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span),
|
||||
ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp(
|
||||
|
|
@ -354,7 +370,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
|
||||
};
|
||||
|
||||
hir::Expr { hir_id, kind, span: self.lower_span(e.span) }
|
||||
hir::Expr { hir_id: expr_hir_id, kind, span: self.lower_span(e.span) }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -504,7 +520,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let if_expr = self.expr(span, if_kind);
|
||||
let block = self.block_expr(self.arena.alloc(if_expr));
|
||||
let span = self.lower_span(span.with_hi(cond.span.hi()));
|
||||
let opt_label = self.lower_label(opt_label);
|
||||
hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span)
|
||||
}
|
||||
|
||||
|
|
@ -512,8 +527,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
/// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }`
|
||||
/// and save the block id to use it as a break target for desugaring of the `?` operator.
|
||||
fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> {
|
||||
self.with_catch_scope(body.id, |this| {
|
||||
let mut block = this.lower_block_noalloc(body, true);
|
||||
let body_hir_id = self.lower_node_id(body.id);
|
||||
self.with_catch_scope(body_hir_id, |this| {
|
||||
let mut block = this.lower_block_noalloc(body_hir_id, body, true);
|
||||
|
||||
// Final expression of the block (if present) or `()` with span at the end of block
|
||||
let (try_span, tail_expr) = if let Some(expr) = block.expr.take() {
|
||||
|
|
@ -521,7 +537,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
this.mark_span_with_reason(
|
||||
DesugaringKind::TryBlock,
|
||||
expr.span,
|
||||
Some(this.allow_try_trait.clone()),
|
||||
Some(Lrc::clone(&this.allow_try_trait)),
|
||||
),
|
||||
expr,
|
||||
)
|
||||
|
|
@ -529,7 +545,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let try_span = this.mark_span_with_reason(
|
||||
DesugaringKind::TryBlock,
|
||||
this.tcx.sess.source_map().end_point(body.span),
|
||||
Some(this.allow_try_trait.clone()),
|
||||
Some(Lrc::clone(&this.allow_try_trait)),
|
||||
);
|
||||
|
||||
(try_span, this.expr_unit(try_span))
|
||||
|
|
@ -575,7 +591,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
} else {
|
||||
// Either `body.is_none()` or `is_never_pattern` here.
|
||||
if !is_never_pattern {
|
||||
if self.tcx.features().never_patterns {
|
||||
if self.tcx.features().never_patterns() {
|
||||
// If the feature is off we already emitted the error after parsing.
|
||||
let suggestion = span.shrink_to_hi();
|
||||
self.dcx().emit_err(MatchArmWithNoBody { span, suggestion });
|
||||
|
|
@ -638,7 +654,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Async,
|
||||
self.lower_span(span),
|
||||
Some(self.allow_gen_future.clone()),
|
||||
Some(Lrc::clone(&self.allow_gen_future)),
|
||||
);
|
||||
let resume_ty =
|
||||
self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None);
|
||||
|
|
@ -717,14 +733,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
outer_hir_id: HirId,
|
||||
inner_hir_id: HirId,
|
||||
) {
|
||||
if self.tcx.features().async_fn_track_caller
|
||||
if self.tcx.features().async_fn_track_caller()
|
||||
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
|
||||
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
|
||||
{
|
||||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Async,
|
||||
span,
|
||||
Some(self.allow_gen_future.clone()),
|
||||
Some(Lrc::clone(&self.allow_gen_future)),
|
||||
);
|
||||
self.lower_attrs(inner_hir_id, &[Attribute {
|
||||
kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(
|
||||
|
|
@ -800,13 +816,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let features = match await_kind {
|
||||
FutureKind::Future => None,
|
||||
FutureKind::AsyncIterator => Some(self.allow_for_await.clone()),
|
||||
FutureKind::AsyncIterator => Some(Lrc::clone(&self.allow_for_await)),
|
||||
};
|
||||
let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features);
|
||||
let gen_future_span = self.mark_span_with_reason(
|
||||
DesugaringKind::Await,
|
||||
full_span,
|
||||
Some(self.allow_gen_future.clone()),
|
||||
Some(Lrc::clone(&self.allow_gen_future)),
|
||||
);
|
||||
let expr_hir_id = expr.hir_id;
|
||||
|
||||
|
|
@ -869,7 +885,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);
|
||||
let ready_field = self.single_pat_field(gen_future_span, x_pat);
|
||||
let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);
|
||||
let break_x = self.with_loop_scope(loop_node_id, move |this| {
|
||||
let break_x = self.with_loop_scope(loop_hir_id, move |this| {
|
||||
let expr_break =
|
||||
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
|
||||
this.arena.alloc(this.expr(gen_future_span, expr_break))
|
||||
|
|
@ -1101,8 +1117,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::CoroutineSource::Closure,
|
||||
);
|
||||
|
||||
let hir_id = this.lower_node_id(coroutine_kind.closure_id());
|
||||
this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
|
||||
this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id);
|
||||
|
||||
(parameters, expr)
|
||||
});
|
||||
|
|
@ -1465,8 +1480,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)
|
||||
}
|
||||
|
||||
fn lower_label(&self, opt_label: Option<Label>) -> Option<Label> {
|
||||
// Record labelled expr's HirId so that we can retrieve it in `lower_jump_destination` without
|
||||
// lowering node id again.
|
||||
fn lower_label(
|
||||
&mut self,
|
||||
opt_label: Option<Label>,
|
||||
dest_id: NodeId,
|
||||
dest_hir_id: hir::HirId,
|
||||
) -> Option<Label> {
|
||||
let label = opt_label?;
|
||||
self.ident_and_label_to_local_id.insert(dest_id, dest_hir_id.local_id);
|
||||
Some(Label { ident: self.lower_ident(label.ident) })
|
||||
}
|
||||
|
||||
|
|
@ -1474,17 +1497,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let target_id = match destination {
|
||||
Some((id, _)) => {
|
||||
if let Some(loop_id) = self.resolver.get_label_res(id) {
|
||||
Ok(self.lower_node_id(loop_id))
|
||||
let local_id = self.ident_and_label_to_local_id[&loop_id];
|
||||
let loop_hir_id = HirId { owner: self.current_hir_id_owner, local_id };
|
||||
Ok(loop_hir_id)
|
||||
} else {
|
||||
Err(hir::LoopIdError::UnresolvedLabel)
|
||||
}
|
||||
}
|
||||
None => self
|
||||
.loop_scope
|
||||
.map(|id| Ok(self.lower_node_id(id)))
|
||||
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)),
|
||||
None => {
|
||||
self.loop_scope.map(|id| Ok(id)).unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
|
||||
}
|
||||
};
|
||||
let label = self.lower_label(destination.map(|(_, label)| label));
|
||||
let label = destination
|
||||
.map(|(_, label)| label)
|
||||
.map(|label| Label { ident: self.lower_ident(label.ident) });
|
||||
hir::Destination { label, target_id }
|
||||
}
|
||||
|
||||
|
|
@ -1499,14 +1525,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn with_catch_scope<T>(&mut self, catch_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
fn with_catch_scope<T>(&mut self, catch_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let old_scope = self.catch_scope.replace(catch_id);
|
||||
let result = f(self);
|
||||
self.catch_scope = old_scope;
|
||||
result
|
||||
}
|
||||
|
||||
fn with_loop_scope<T>(&mut self, loop_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
fn with_loop_scope<T>(&mut self, loop_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
// We're no longer in the base loop's condition; we're in another loop.
|
||||
let was_in_loop_condition = self.is_in_loop_condition;
|
||||
self.is_in_loop_condition = false;
|
||||
|
|
@ -1572,7 +1598,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
}
|
||||
Some(hir::CoroutineKind::Coroutine(_)) => {
|
||||
if !self.tcx.features().coroutines {
|
||||
if !self.tcx.features().coroutines() {
|
||||
rustc_session::parse::feature_err(
|
||||
&self.tcx.sess,
|
||||
sym::coroutines,
|
||||
|
|
@ -1584,7 +1610,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
false
|
||||
}
|
||||
None => {
|
||||
if !self.tcx.features().coroutines {
|
||||
if !self.tcx.features().coroutines() {
|
||||
rustc_session::parse::feature_err(
|
||||
&self.tcx.sess,
|
||||
sym::coroutines,
|
||||
|
|
@ -1658,9 +1684,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
|
||||
let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None);
|
||||
|
||||
let loop_hir_id = self.lower_node_id(e.id);
|
||||
let label = self.lower_label(opt_label, e.id, loop_hir_id);
|
||||
|
||||
// `None => break`
|
||||
let none_arm = {
|
||||
let break_expr = self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span));
|
||||
let break_expr =
|
||||
self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span));
|
||||
let pat = self.pat_none(for_span);
|
||||
self.arm(pat, break_expr)
|
||||
};
|
||||
|
|
@ -1668,7 +1698,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// Some(<pat>) => <body>,
|
||||
let some_arm = {
|
||||
let some_pat = self.pat_some(pat_span, pat);
|
||||
let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
|
||||
let body_block =
|
||||
self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false));
|
||||
let body_expr = self.arena.alloc(self.expr_block(body_block));
|
||||
self.arm(some_pat, body_expr)
|
||||
};
|
||||
|
|
@ -1722,12 +1753,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// `[opt_ident]: loop { ... }`
|
||||
let kind = hir::ExprKind::Loop(
|
||||
loop_block,
|
||||
self.lower_label(opt_label),
|
||||
label,
|
||||
hir::LoopSource::ForLoop,
|
||||
self.lower_span(for_span.with_hi(head.span.hi())),
|
||||
);
|
||||
let loop_expr =
|
||||
self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: for_span });
|
||||
let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span });
|
||||
|
||||
// `mut iter => { ... }`
|
||||
let iter_arm = self.arm(iter_pat, loop_expr);
|
||||
|
|
@ -1812,13 +1842,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::QuestionMark,
|
||||
span,
|
||||
Some(self.allow_try_trait.clone()),
|
||||
Some(Lrc::clone(&self.allow_try_trait)),
|
||||
);
|
||||
let try_span = self.tcx.sess.source_map().end_point(span);
|
||||
let try_span = self.mark_span_with_reason(
|
||||
DesugaringKind::QuestionMark,
|
||||
try_span,
|
||||
Some(self.allow_try_trait.clone()),
|
||||
Some(Lrc::clone(&self.allow_try_trait)),
|
||||
);
|
||||
|
||||
// `Try::branch(<expr>)`
|
||||
|
|
@ -1867,8 +1897,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.arena.alloc(residual_expr),
|
||||
unstable_span,
|
||||
);
|
||||
let ret_expr = if let Some(catch_node) = self.catch_scope {
|
||||
let target_id = Ok(self.lower_node_id(catch_node));
|
||||
let ret_expr = if let Some(catch_id) = self.catch_scope {
|
||||
let target_id = Ok(catch_id);
|
||||
self.arena.alloc(self.expr(
|
||||
try_span,
|
||||
hir::ExprKind::Break(
|
||||
|
|
@ -1912,7 +1942,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let unstable_span = self.mark_span_with_reason(
|
||||
DesugaringKind::YeetExpr,
|
||||
span,
|
||||
Some(self.allow_try_trait.clone()),
|
||||
Some(Lrc::clone(&self.allow_try_trait)),
|
||||
);
|
||||
|
||||
let from_yeet_expr = self.wrap_in_try_constructor(
|
||||
|
|
@ -1922,8 +1952,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
yeeted_span,
|
||||
);
|
||||
|
||||
if let Some(catch_node) = self.catch_scope {
|
||||
let target_id = Ok(self.lower_node_id(catch_node));
|
||||
if let Some(catch_id) = self.catch_scope {
|
||||
let target_id = Ok(catch_id);
|
||||
hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr))
|
||||
} else {
|
||||
hir::ExprKind::Ret(Some(from_yeet_expr))
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
|||
owner: NodeId,
|
||||
f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
|
||||
) {
|
||||
let mut lctx = LoweringContext::new(self.tcx, self.resolver, self.ast_index);
|
||||
let mut lctx = LoweringContext::new(self.tcx, self.resolver);
|
||||
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
|
||||
|
||||
for (def_id, info) in lctx.children {
|
||||
|
|
@ -154,7 +154,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
|
||||
let mut ident = i.ident;
|
||||
let vis_span = self.lower_span(i.vis.span);
|
||||
let hir_id = self.lower_node_id(i.id);
|
||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||
let attrs = self.lower_attrs(hir_id, &i.attrs);
|
||||
let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind);
|
||||
let item = hir::Item {
|
||||
|
|
@ -193,8 +193,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
|
||||
let (generics, (ty, body_id)) = self.lower_generics(
|
||||
generics,
|
||||
Const::No,
|
||||
false,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
|
|
@ -225,16 +223,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) =
|
||||
this.lower_generics(generics, header.constness, false, id, itctx, |this| {
|
||||
this.lower_fn_decl(
|
||||
decl,
|
||||
id,
|
||||
*fn_sig_span,
|
||||
FnDeclKind::Fn,
|
||||
coroutine_kind,
|
||||
)
|
||||
});
|
||||
let (generics, decl) = this.lower_generics(generics, id, itctx, |this| {
|
||||
this.lower_fn_decl(decl, id, *fn_sig_span, FnDeclKind::Fn, coroutine_kind)
|
||||
});
|
||||
let sig = hir::FnSig {
|
||||
decl,
|
||||
header: this.lower_fn_header(*header, hir::Safety::Safe),
|
||||
|
|
@ -269,8 +260,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
add_ty_alias_where_clause(&mut generics, *where_clauses, true);
|
||||
let (generics, ty) = self.lower_generics(
|
||||
&generics,
|
||||
Const::No,
|
||||
false,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| match ty {
|
||||
|
|
@ -294,8 +283,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ItemKind::Enum(enum_definition, generics) => {
|
||||
let (generics, variants) = self.lower_generics(
|
||||
generics,
|
||||
Const::No,
|
||||
false,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
|
|
@ -309,8 +296,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ItemKind::Struct(struct_def, generics) => {
|
||||
let (generics, struct_def) = self.lower_generics(
|
||||
generics,
|
||||
Const::No,
|
||||
false,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_variant_data(hir_id, struct_def),
|
||||
|
|
@ -320,8 +305,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ItemKind::Union(vdata, generics) => {
|
||||
let (generics, vdata) = self.lower_generics(
|
||||
generics,
|
||||
Const::No,
|
||||
false,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_variant_data(hir_id, vdata),
|
||||
|
|
@ -353,7 +336,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// parent lifetime.
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, (trait_ref, lowered_ty)) =
|
||||
self.lower_generics(ast_generics, Const::No, false, id, itctx, |this| {
|
||||
self.lower_generics(ast_generics, id, itctx, |this| {
|
||||
let modifiers = TraitBoundModifiers {
|
||||
constness: BoundConstness::Never,
|
||||
asyncness: BoundAsyncness::Normal,
|
||||
|
|
@ -405,8 +388,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => {
|
||||
let (generics, (safety, items, bounds)) = self.lower_generics(
|
||||
generics,
|
||||
Const::No,
|
||||
false,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
|
|
@ -426,8 +407,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ItemKind::TraitAlias(generics, bounds) => {
|
||||
let (generics, bounds) = self.lower_generics(
|
||||
generics,
|
||||
Const::No,
|
||||
false,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
|
|
@ -604,55 +583,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ctxt: AssocCtxt,
|
||||
parent_hir: &'hir hir::OwnerInfo<'hir>,
|
||||
) -> hir::OwnerNode<'hir> {
|
||||
// Evaluate with the lifetimes in `params` in-scope.
|
||||
// This is used to track which lifetimes have already been defined,
|
||||
// and which need to be replicated when lowering an async fn.
|
||||
|
||||
let parent_item = parent_hir.node().expect_item();
|
||||
let constness = match parent_item.kind {
|
||||
match parent_item.kind {
|
||||
hir::ItemKind::Impl(impl_) => {
|
||||
self.is_in_trait_impl = impl_.of_trait.is_some();
|
||||
// N.B. the impl should always lower to methods that have `const host: bool` params if the trait
|
||||
// is const. It doesn't matter whether the `impl` itself is const. Disallowing const fn from
|
||||
// calling non-const impls are done through associated types.
|
||||
if let Some(def_id) = impl_.of_trait.and_then(|tr| tr.trait_def_id()) {
|
||||
if let Some(local_def) = def_id.as_local() {
|
||||
match &self.ast_index[local_def] {
|
||||
AstOwner::Item(ast::Item { attrs, .. }) => attrs
|
||||
.iter()
|
||||
.find(|attr| attr.has_name(sym::const_trait))
|
||||
.map_or(Const::No, |attr| Const::Yes(attr.span)),
|
||||
_ => Const::No,
|
||||
}
|
||||
} else if self.tcx.is_const_trait(def_id) {
|
||||
// FIXME(effects) span
|
||||
Const::Yes(self.tcx.def_ident_span(def_id).unwrap())
|
||||
} else {
|
||||
Const::No
|
||||
}
|
||||
} else {
|
||||
Const::No
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Trait(_, _, _, _, _) => parent_hir
|
||||
.attrs
|
||||
.get(parent_item.hir_id().local_id)
|
||||
.iter()
|
||||
.find(|attr| attr.has_name(sym::const_trait))
|
||||
.map_or(Const::No, |attr| Const::Yes(attr.span)),
|
||||
hir::ItemKind::Trait(_, _, _, _, _) => {}
|
||||
kind => {
|
||||
span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Evaluate with the lifetimes in `params` in-scope.
|
||||
// This is used to track which lifetimes have already been defined,
|
||||
// and which need to be replicated when lowering an async fn.
|
||||
match ctxt {
|
||||
AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item, constness)),
|
||||
AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item, constness)),
|
||||
AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)),
|
||||
AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item)),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> {
|
||||
let hir_id = self.lower_node_id(i.id);
|
||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||
let owner_id = hir_id.expect_owner();
|
||||
self.lower_attrs(hir_id, &i.attrs);
|
||||
let item = hir::ForeignItem {
|
||||
|
|
@ -663,7 +615,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let fdec = &sig.decl;
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, (decl, fn_args)) =
|
||||
self.lower_generics(generics, Const::No, false, i.id, itctx, |this| {
|
||||
self.lower_generics(generics, i.id, itctx, |this| {
|
||||
(
|
||||
// Disallow `impl Trait` in foreign items.
|
||||
this.lower_fn_decl(
|
||||
|
|
@ -775,12 +727,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_trait_item(
|
||||
&mut self,
|
||||
i: &AssocItem,
|
||||
trait_constness: Const,
|
||||
) -> &'hir hir::TraitItem<'hir> {
|
||||
let hir_id = self.lower_node_id(i.id);
|
||||
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);
|
||||
self.lower_attrs(hir_id, &i.attrs);
|
||||
let trait_item_def_id = hir_id.expect_owner();
|
||||
|
||||
|
|
@ -788,8 +736,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => {
|
||||
let (generics, kind) = self.lower_generics(
|
||||
generics,
|
||||
Const::No,
|
||||
false,
|
||||
i.id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
|
|
@ -810,7 +756,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
i.id,
|
||||
FnDeclKind::Trait,
|
||||
sig.header.coroutine_kind,
|
||||
trait_constness,
|
||||
);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
|
||||
}
|
||||
|
|
@ -829,7 +774,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
i.id,
|
||||
FnDeclKind::Trait,
|
||||
sig.header.coroutine_kind,
|
||||
trait_constness,
|
||||
);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
|
||||
}
|
||||
|
|
@ -838,8 +782,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
|
||||
let (generics, kind) = self.lower_generics(
|
||||
&generics,
|
||||
Const::No,
|
||||
false,
|
||||
i.id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
|
|
@ -912,22 +854,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.expr(span, hir::ExprKind::Err(guar))
|
||||
}
|
||||
|
||||
fn lower_impl_item(
|
||||
&mut self,
|
||||
i: &AssocItem,
|
||||
constness_of_trait: Const,
|
||||
) -> &'hir hir::ImplItem<'hir> {
|
||||
fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
|
||||
// Since `default impl` is not yet implemented, this is always true in impls.
|
||||
let has_value = true;
|
||||
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
|
||||
let hir_id = self.lower_node_id(i.id);
|
||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||
self.lower_attrs(hir_id, &i.attrs);
|
||||
|
||||
let (generics, kind) = match &i.kind {
|
||||
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
|
||||
generics,
|
||||
Const::No,
|
||||
false,
|
||||
i.id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
|
|
@ -953,7 +889,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
i.id,
|
||||
if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
|
||||
sig.header.coroutine_kind,
|
||||
constness_of_trait,
|
||||
);
|
||||
|
||||
(generics, hir::ImplItemKind::Fn(sig, body_id))
|
||||
|
|
@ -963,8 +898,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
|
||||
self.lower_generics(
|
||||
&generics,
|
||||
Const::No,
|
||||
false,
|
||||
i.id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| match ty {
|
||||
|
|
@ -1153,7 +1086,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
|
||||
// FIXME(async_fn_track_caller): Can this be moved above?
|
||||
let hir_id = this.lower_node_id(coroutine_kind.closure_id());
|
||||
let hir_id = expr.hir_id;
|
||||
this.maybe_forward_track_caller(body.span, fn_id, hir_id);
|
||||
|
||||
(parameters, expr)
|
||||
|
|
@ -1370,18 +1303,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
id: NodeId,
|
||||
kind: FnDeclKind,
|
||||
coroutine_kind: Option<CoroutineKind>,
|
||||
parent_constness: Const,
|
||||
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
|
||||
let header = self.lower_fn_header(sig.header, hir::Safety::Safe);
|
||||
// Don't pass along the user-provided constness of trait associated functions; we don't want to
|
||||
// synthesize a host effect param for them. We reject `const` on them during AST validation.
|
||||
let constness =
|
||||
if kind == FnDeclKind::Inherent { sig.header.constness } else { parent_constness };
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) =
|
||||
self.lower_generics(generics, constness, kind == FnDeclKind::Impl, id, itctx, |this| {
|
||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
|
||||
});
|
||||
let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
|
||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
|
||||
});
|
||||
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
||||
}
|
||||
|
||||
|
|
@ -1460,8 +1387,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
fn lower_generics<T>(
|
||||
&mut self,
|
||||
generics: &Generics,
|
||||
constness: Const,
|
||||
force_append_constness: bool,
|
||||
parent_node_id: NodeId,
|
||||
itctx: ImplTraitContext,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
|
|
@ -1512,7 +1437,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
continue;
|
||||
}
|
||||
let is_param = *is_param.get_or_insert_with(compute_is_param);
|
||||
if !is_param && !self.tcx.features().more_maybe_bounds {
|
||||
if !is_param && !self.tcx.features().more_maybe_bounds() {
|
||||
self.tcx
|
||||
.sess
|
||||
.create_feature_err(
|
||||
|
|
@ -1524,30 +1449,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
// Desugar `~const` bound in generics into an additional `const host: bool` param
|
||||
// if the effects feature is enabled. This needs to be done before we lower where
|
||||
// clauses since where clauses need to bind to the DefId of the host param
|
||||
let host_param_parts = if let Const::Yes(span) = constness
|
||||
// if this comes from implementing a `const` trait, we must force constness to be appended
|
||||
// to the impl item, no matter whether effects is enabled.
|
||||
&& (self.tcx.features().effects || force_append_constness)
|
||||
{
|
||||
let span = self.lower_span(span);
|
||||
let param_node_id = self.next_node_id();
|
||||
let hir_id = self.next_id();
|
||||
let def_id = self.create_def(
|
||||
self.local_def_id(parent_node_id),
|
||||
param_node_id,
|
||||
sym::host,
|
||||
DefKind::ConstParam,
|
||||
span,
|
||||
);
|
||||
self.host_param_id = Some(def_id);
|
||||
Some((span, hir_id, def_id))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
|
||||
predicates.extend(generics.params.iter().filter_map(|param| {
|
||||
self.lower_generic_bound_predicate(
|
||||
|
|
@ -1595,74 +1496,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
|
||||
predicates.extend(impl_trait_bounds.into_iter());
|
||||
|
||||
if let Some((span, hir_id, def_id)) = host_param_parts {
|
||||
let const_node_id = self.next_node_id();
|
||||
let anon_const_did =
|
||||
self.create_def(def_id, const_node_id, kw::Empty, DefKind::AnonConst, span);
|
||||
|
||||
let const_id = self.next_id();
|
||||
let const_expr_id = self.next_id();
|
||||
let bool_id = self.next_id();
|
||||
|
||||
self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
|
||||
self.children.push((anon_const_did, hir::MaybeOwner::NonOwner(const_id)));
|
||||
|
||||
let const_body = self.lower_body(|this| {
|
||||
(&[], hir::Expr {
|
||||
hir_id: const_expr_id,
|
||||
kind: hir::ExprKind::Lit(
|
||||
this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }),
|
||||
),
|
||||
span,
|
||||
})
|
||||
});
|
||||
|
||||
let default_ac = self.arena.alloc(hir::AnonConst {
|
||||
def_id: anon_const_did,
|
||||
hir_id: const_id,
|
||||
body: const_body,
|
||||
span,
|
||||
});
|
||||
let default_ct = self.arena.alloc(hir::ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Anon(default_ac),
|
||||
is_desugared_from_effects: false,
|
||||
});
|
||||
let param = hir::GenericParam {
|
||||
def_id,
|
||||
hir_id,
|
||||
name: hir::ParamName::Plain(Ident { name: sym::host, span }),
|
||||
span,
|
||||
kind: hir::GenericParamKind::Const {
|
||||
ty: self.arena.alloc(self.ty(
|
||||
span,
|
||||
hir::TyKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
self.arena.alloc(hir::Path {
|
||||
res: Res::PrimTy(hir::PrimTy::Bool),
|
||||
span,
|
||||
segments: self.arena.alloc_from_iter([hir::PathSegment {
|
||||
ident: Ident { name: sym::bool, span },
|
||||
hir_id: bool_id,
|
||||
res: Res::PrimTy(hir::PrimTy::Bool),
|
||||
args: None,
|
||||
infer_args: false,
|
||||
}]),
|
||||
}),
|
||||
)),
|
||||
)),
|
||||
default: Some(default_ct),
|
||||
is_host_effect: true,
|
||||
synthetic: true,
|
||||
},
|
||||
colon_span: None,
|
||||
pure_wrt_drop: false,
|
||||
source: hir::GenericParamSource::Generics,
|
||||
};
|
||||
|
||||
params.push(param);
|
||||
}
|
||||
|
||||
let lowered_generics = self.arena.alloc(hir::Generics {
|
||||
params: self.arena.alloc_from_iter(params),
|
||||
predicates: self.arena.alloc_from_iter(predicates),
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@
|
|||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
use rustc_ast::node_id::NodeMap;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, *};
|
||||
|
|
@ -115,8 +113,8 @@ struct LoweringContext<'a, 'hir> {
|
|||
/// outside of an `async fn`.
|
||||
current_item: Option<Span>,
|
||||
|
||||
catch_scope: Option<NodeId>,
|
||||
loop_scope: Option<NodeId>,
|
||||
catch_scope: Option<HirId>,
|
||||
loop_scope: Option<HirId>,
|
||||
is_in_loop_condition: bool,
|
||||
is_in_trait_impl: bool,
|
||||
is_in_dyn_type: bool,
|
||||
|
|
@ -140,7 +138,10 @@ struct LoweringContext<'a, 'hir> {
|
|||
impl_trait_defs: Vec<hir::GenericParam<'hir>>,
|
||||
impl_trait_bounds: Vec<hir::WherePredicate<'hir>>,
|
||||
|
||||
/// NodeIds that are lowered inside the current HIR owner.
|
||||
/// NodeIds of pattern identifiers and labelled nodes that are lowered inside the current HIR owner.
|
||||
ident_and_label_to_local_id: NodeMap<hir::ItemLocalId>,
|
||||
/// NodeIds that are lowered inside the current HIR owner. Only used for duplicate lowering check.
|
||||
#[cfg(debug_assertions)]
|
||||
node_id_to_local_id: NodeMap<hir::ItemLocalId>,
|
||||
|
||||
allow_try_trait: Lrc<[Symbol]>,
|
||||
|
|
@ -154,17 +155,10 @@ struct LoweringContext<'a, 'hir> {
|
|||
/// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
|
||||
/// field from the original parameter 'a to the new parameter 'a1.
|
||||
generics_def_id_map: Vec<LocalDefIdMap<LocalDefId>>,
|
||||
|
||||
host_param_id: Option<LocalDefId>,
|
||||
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn new(
|
||||
tcx: TyCtxt<'hir>,
|
||||
resolver: &'a mut ResolverAstLowering,
|
||||
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
|
||||
) -> Self {
|
||||
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self {
|
||||
Self {
|
||||
// Pseudo-globals.
|
||||
tcx,
|
||||
|
|
@ -178,6 +172,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
current_hir_id_owner: hir::CRATE_OWNER_ID,
|
||||
current_def_id_parent: CRATE_DEF_ID,
|
||||
item_local_id_counter: hir::ItemLocalId::ZERO,
|
||||
ident_and_label_to_local_id: Default::default(),
|
||||
#[cfg(debug_assertions)]
|
||||
node_id_to_local_id: Default::default(),
|
||||
trait_map: Default::default(),
|
||||
|
||||
|
|
@ -193,7 +189,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
impl_trait_defs: Vec::new(),
|
||||
impl_trait_bounds: Vec::new(),
|
||||
allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(),
|
||||
allow_gen_future: if tcx.features().async_fn_track_caller {
|
||||
allow_gen_future: if tcx.features().async_fn_track_caller() {
|
||||
[sym::gen_future, sym::closure_track_caller].into()
|
||||
} else {
|
||||
[sym::gen_future].into()
|
||||
|
|
@ -204,8 +200,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// interact with `gen`/`async gen` blocks
|
||||
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
|
||||
generics_def_id_map: Default::default(),
|
||||
host_param_id: None,
|
||||
ast_index,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -597,7 +591,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
let current_attrs = std::mem::take(&mut self.attrs);
|
||||
let current_bodies = std::mem::take(&mut self.bodies);
|
||||
let current_node_ids = std::mem::take(&mut self.node_id_to_local_id);
|
||||
let current_ident_and_label_to_local_id =
|
||||
std::mem::take(&mut self.ident_and_label_to_local_id);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let current_node_id_to_local_id = std::mem::take(&mut self.node_id_to_local_id);
|
||||
let current_trait_map = std::mem::take(&mut self.trait_map);
|
||||
let current_owner =
|
||||
std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id });
|
||||
|
|
@ -611,8 +609,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// and the caller to refer to some of the subdefinitions' nodes' `LocalDefId`s.
|
||||
|
||||
// Always allocate the first `HirId` for the owner itself.
|
||||
let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO);
|
||||
debug_assert_eq!(_old, None);
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO);
|
||||
debug_assert_eq!(_old, None);
|
||||
}
|
||||
|
||||
let item = self.with_def_id_parent(def_id, f);
|
||||
debug_assert_eq!(def_id, item.def_id().def_id);
|
||||
|
|
@ -623,7 +624,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
self.attrs = current_attrs;
|
||||
self.bodies = current_bodies;
|
||||
self.node_id_to_local_id = current_node_ids;
|
||||
self.ident_and_label_to_local_id = current_ident_and_label_to_local_id;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
self.node_id_to_local_id = current_node_id_to_local_id;
|
||||
}
|
||||
self.trait_map = current_trait_map;
|
||||
self.current_hir_id_owner = current_owner;
|
||||
self.item_local_id_counter = current_local_counter;
|
||||
|
|
@ -689,39 +695,37 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
|
||||
}
|
||||
|
||||
/// This method allocates a new `HirId` for the given `NodeId` and stores it in
|
||||
/// the `LoweringContext`'s `NodeId => HirId` map.
|
||||
/// This method allocates a new `HirId` for the given `NodeId`.
|
||||
/// Take care not to call this method if the resulting `HirId` is then not
|
||||
/// actually used in the HIR, as that would trigger an assertion in the
|
||||
/// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped
|
||||
/// properly. Calling the method twice with the same `NodeId` is fine though.
|
||||
/// properly. Calling the method twice with the same `NodeId` is also forbidden.
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn lower_node_id(&mut self, ast_node_id: NodeId) -> HirId {
|
||||
assert_ne!(ast_node_id, DUMMY_NODE_ID);
|
||||
|
||||
match self.node_id_to_local_id.entry(ast_node_id) {
|
||||
Entry::Occupied(o) => HirId { owner: self.current_hir_id_owner, local_id: *o.get() },
|
||||
Entry::Vacant(v) => {
|
||||
// Generate a new `HirId`.
|
||||
let owner = self.current_hir_id_owner;
|
||||
let local_id = self.item_local_id_counter;
|
||||
let hir_id = HirId { owner, local_id };
|
||||
let owner = self.current_hir_id_owner;
|
||||
let local_id = self.item_local_id_counter;
|
||||
assert_ne!(local_id, hir::ItemLocalId::ZERO);
|
||||
self.item_local_id_counter.increment_by(1);
|
||||
let hir_id = HirId { owner, local_id };
|
||||
|
||||
v.insert(local_id);
|
||||
self.item_local_id_counter.increment_by(1);
|
||||
|
||||
assert_ne!(local_id, hir::ItemLocalId::ZERO);
|
||||
if let Some(def_id) = self.opt_local_def_id(ast_node_id) {
|
||||
self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
|
||||
}
|
||||
|
||||
if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) {
|
||||
self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice());
|
||||
}
|
||||
|
||||
hir_id
|
||||
}
|
||||
if let Some(def_id) = self.opt_local_def_id(ast_node_id) {
|
||||
self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
|
||||
}
|
||||
|
||||
if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) {
|
||||
self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice());
|
||||
}
|
||||
|
||||
// Check whether the same `NodeId` is lowered more than once.
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let old = self.node_id_to_local_id.insert(ast_node_id, local_id);
|
||||
assert_eq!(old, None);
|
||||
}
|
||||
|
||||
hir_id
|
||||
}
|
||||
|
||||
/// Generate a new `HirId` without a backing `NodeId`.
|
||||
|
|
@ -738,7 +742,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
fn lower_res(&mut self, res: Res<NodeId>) -> Res {
|
||||
let res: Result<Res, ()> = res.apply_id(|id| {
|
||||
let owner = self.current_hir_id_owner;
|
||||
let local_id = self.node_id_to_local_id.get(&id).copied().ok_or(())?;
|
||||
let local_id = self.ident_and_label_to_local_id.get(&id).copied().ok_or(())?;
|
||||
Ok(HirId { owner, local_id })
|
||||
});
|
||||
trace!(?res);
|
||||
|
|
@ -1035,7 +1039,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
span: data.inputs_span,
|
||||
})
|
||||
};
|
||||
if !self.tcx.features().return_type_notation
|
||||
if !self.tcx.features().return_type_notation()
|
||||
&& self.tcx.sess.is_nightly_build()
|
||||
{
|
||||
add_feature_diagnostics(
|
||||
|
|
@ -1160,7 +1164,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
|
||||
ast::GenericArg::Type(ty) => {
|
||||
match &ty.kind {
|
||||
TyKind::Infer if self.tcx.features().generic_arg_infer => {
|
||||
TyKind::Infer if self.tcx.features().generic_arg_infer() => {
|
||||
return GenericArg::Infer(hir::InferArg {
|
||||
hir_id: self.lower_node_id(ty.id),
|
||||
span: self.lower_span(ty.span),
|
||||
|
|
@ -1500,7 +1504,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// is enabled. We don't check the span of the edition, since this is done
|
||||
// on a per-opaque basis to account for nested opaques.
|
||||
let always_capture_in_scope = match origin {
|
||||
_ if self.tcx.features().lifetime_capture_rules_2024 => true,
|
||||
_ if self.tcx.features().lifetime_capture_rules_2024() => true,
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => true,
|
||||
hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(),
|
||||
hir::OpaqueTyOrigin::AsyncFn { .. } => {
|
||||
|
|
@ -1519,7 +1523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// Feature gate for RPITIT + use<..>
|
||||
match origin {
|
||||
rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => {
|
||||
if !self.tcx.features().precise_capturing_in_traits
|
||||
if !self.tcx.features().precise_capturing_in_traits()
|
||||
&& let Some(span) = bounds.iter().find_map(|bound| match *bound {
|
||||
ast::GenericBound::Use(_, span) => Some(span),
|
||||
_ => None,
|
||||
|
|
@ -1874,7 +1878,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None),
|
||||
CoroutineKind::Gen { return_impl_trait_id, .. } => (return_impl_trait_id, None),
|
||||
CoroutineKind::AsyncGen { return_impl_trait_id, .. } => {
|
||||
(return_impl_trait_id, Some(self.allow_async_iterator.clone()))
|
||||
(return_impl_trait_id, Some(Lrc::clone(&self.allow_async_iterator)))
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1956,7 +1960,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
hir::GenericBound::Trait(hir::PolyTraitRef {
|
||||
bound_generic_params: &[],
|
||||
modifiers: hir::TraitBoundModifier::None,
|
||||
modifiers: hir::TraitBoundModifiers::NONE,
|
||||
trait_ref: hir::TraitRef {
|
||||
path: self.make_lang_item_path(trait_lang_item, opaque_ty_span, Some(bound_args)),
|
||||
hir_ref_id: self.next_id(),
|
||||
|
|
@ -2054,11 +2058,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
param: &GenericParam,
|
||||
source: hir::GenericParamSource,
|
||||
) -> hir::GenericParam<'hir> {
|
||||
let (name, kind) = self.lower_generic_param_kind(
|
||||
param,
|
||||
source,
|
||||
attr::contains_name(¶m.attrs, sym::rustc_runtime),
|
||||
);
|
||||
let (name, kind) = self.lower_generic_param_kind(param, source);
|
||||
|
||||
let hir_id = self.lower_node_id(param.id);
|
||||
self.lower_attrs(hir_id, ¶m.attrs);
|
||||
|
|
@ -2078,7 +2078,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
param: &GenericParam,
|
||||
source: hir::GenericParamSource,
|
||||
is_host_effect: bool,
|
||||
) -> (hir::ParamName, hir::GenericParamKind<'hir>) {
|
||||
match ¶m.kind {
|
||||
GenericParamKind::Lifetime => {
|
||||
|
|
@ -2144,7 +2143,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
(
|
||||
hir::ParamName::Plain(self.lower_ident(param.ident)),
|
||||
hir::GenericParamKind::Const { ty, default, is_host_effect, synthetic: false },
|
||||
hir::GenericParamKind::Const { ty, default, synthetic: false },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -2270,7 +2269,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> {
|
||||
match c.value.kind {
|
||||
ExprKind::Underscore => {
|
||||
if self.tcx.features().generic_arg_infer {
|
||||
if self.tcx.features().generic_arg_infer() {
|
||||
hir::ArrayLen::Infer(hir::InferArg {
|
||||
hir_id: self.lower_node_id(c.id),
|
||||
span: self.lower_span(c.value.span),
|
||||
|
|
@ -2445,22 +2444,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
fn lower_trait_bound_modifiers(
|
||||
&mut self,
|
||||
modifiers: TraitBoundModifiers,
|
||||
) -> hir::TraitBoundModifier {
|
||||
// Invalid modifier combinations will cause an error during AST validation.
|
||||
// Arbitrarily pick a placeholder for them to make compilation proceed.
|
||||
match (modifiers.constness, modifiers.polarity) {
|
||||
(BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None,
|
||||
(_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
|
||||
(BoundConstness::Never, BoundPolarity::Negative(_)) => {
|
||||
if self.tcx.features().negative_bounds {
|
||||
hir::TraitBoundModifier::Negative
|
||||
} else {
|
||||
hir::TraitBoundModifier::None
|
||||
}
|
||||
}
|
||||
(BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const,
|
||||
(BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst,
|
||||
}
|
||||
) -> hir::TraitBoundModifiers {
|
||||
hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity }
|
||||
}
|
||||
|
||||
// Helper methods for building HIR.
|
||||
|
|
@ -2626,7 +2611,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => {
|
||||
let principal = hir::PolyTraitRef {
|
||||
bound_generic_params: &[],
|
||||
modifiers: hir::TraitBoundModifier::None,
|
||||
modifiers: hir::TraitBoundModifiers::NONE,
|
||||
trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
|
||||
span: self.lower_span(span),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,13 +21,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
|
||||
ensure_sufficient_stack(|| {
|
||||
// loop here to avoid recursion
|
||||
let pat_hir_id = self.lower_node_id(pattern.id);
|
||||
let node = loop {
|
||||
match &pattern.kind {
|
||||
PatKind::Wild => break hir::PatKind::Wild,
|
||||
PatKind::Never => break hir::PatKind::Never,
|
||||
PatKind::Ident(binding_mode, ident, sub) => {
|
||||
let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s));
|
||||
break self.lower_pat_ident(pattern, *binding_mode, *ident, lower_sub);
|
||||
break self.lower_pat_ident(
|
||||
pattern,
|
||||
*binding_mode,
|
||||
*ident,
|
||||
pat_hir_id,
|
||||
lower_sub,
|
||||
);
|
||||
}
|
||||
PatKind::Lit(e) => {
|
||||
break hir::PatKind::Lit(self.lower_expr_within_pat(e, false));
|
||||
|
|
@ -119,7 +126,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
};
|
||||
|
||||
self.pat_with_node_id_of(pattern, node)
|
||||
self.pat_with_node_id_of(pattern, node, pat_hir_id)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -187,10 +194,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let mut prev_rest_span = None;
|
||||
|
||||
// Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
|
||||
let lower_rest_sub = |this: &mut Self, pat, &ann, &ident, sub| {
|
||||
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
|
||||
let node = this.lower_pat_ident(pat, ann, ident, lower_sub);
|
||||
this.pat_with_node_id_of(pat, node)
|
||||
let lower_rest_sub = |this: &mut Self, pat: &Pat, &ann, &ident, sub: &Pat| {
|
||||
let sub_hir_id = this.lower_node_id(sub.id);
|
||||
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub, sub_hir_id));
|
||||
let pat_hir_id = this.lower_node_id(pat.id);
|
||||
let node = this.lower_pat_ident(pat, ann, ident, pat_hir_id, lower_sub);
|
||||
this.pat_with_node_id_of(pat, node, pat_hir_id)
|
||||
};
|
||||
|
||||
let mut iter = pats.iter();
|
||||
|
|
@ -200,7 +209,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
|
||||
PatKind::Rest => {
|
||||
prev_rest_span = Some(pat.span);
|
||||
slice = Some(self.pat_wild_with_node_id_of(pat));
|
||||
let hir_id = self.lower_node_id(pat.id);
|
||||
slice = Some(self.pat_wild_with_node_id_of(pat, hir_id));
|
||||
break;
|
||||
}
|
||||
// Found a sub-slice pattern `$binding_mode $ident @ ..`.
|
||||
|
|
@ -248,19 +258,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
p: &Pat,
|
||||
annotation: BindingMode,
|
||||
ident: Ident,
|
||||
hir_id: hir::HirId,
|
||||
lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
|
||||
) -> hir::PatKind<'hir> {
|
||||
match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) {
|
||||
// `None` can occur in body-less function signatures
|
||||
res @ (None | Some(Res::Local(_))) => {
|
||||
let canonical_id = match res {
|
||||
Some(Res::Local(id)) => id,
|
||||
_ => p.id,
|
||||
let binding_id = match res {
|
||||
Some(Res::Local(id)) => {
|
||||
// In `Or` patterns like `VariantA(s) | VariantB(s, _)`, multiple identifier patterns
|
||||
// will be resolved to the same `Res::Local`. Thus they just share a single
|
||||
// `HirId`.
|
||||
if id == p.id {
|
||||
self.ident_and_label_to_local_id.insert(id, hir_id.local_id);
|
||||
hir_id
|
||||
} else {
|
||||
hir::HirId {
|
||||
owner: self.current_hir_id_owner,
|
||||
local_id: self.ident_and_label_to_local_id[&id],
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.ident_and_label_to_local_id.insert(p.id, hir_id.local_id);
|
||||
hir_id
|
||||
}
|
||||
};
|
||||
|
||||
hir::PatKind::Binding(
|
||||
annotation,
|
||||
self.lower_node_id(canonical_id),
|
||||
binding_id,
|
||||
self.lower_ident(ident),
|
||||
lower_sub(self),
|
||||
)
|
||||
|
|
@ -280,18 +306,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
|
||||
self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild))
|
||||
fn pat_wild_with_node_id_of(&mut self, p: &Pat, hir_id: hir::HirId) -> &'hir hir::Pat<'hir> {
|
||||
self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild, hir_id))
|
||||
}
|
||||
|
||||
/// Construct a `Pat` with the `HirId` of `p.id` lowered.
|
||||
fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> {
|
||||
hir::Pat {
|
||||
hir_id: self.lower_node_id(p.id),
|
||||
kind,
|
||||
span: self.lower_span(p.span),
|
||||
default_binding_modes: true,
|
||||
}
|
||||
/// Construct a `Pat` with the `HirId` of `p.id` already lowered.
|
||||
fn pat_with_node_id_of(
|
||||
&mut self,
|
||||
p: &Pat,
|
||||
kind: hir::PatKind<'hir>,
|
||||
hir_id: hir::HirId,
|
||||
) -> hir::Pat<'hir> {
|
||||
hir::Pat { hir_id, kind, span: self.lower_span(p.span), default_binding_modes: true }
|
||||
}
|
||||
|
||||
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
|
||||
|
|
|
|||
|
|
@ -34,7 +34,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
modifiers: Option<ast::TraitBoundModifiers>,
|
||||
) -> hir::QPath<'hir> {
|
||||
let qself_position = qself.as_ref().map(|q| q.position);
|
||||
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
|
||||
let qself = qself
|
||||
.as_ref()
|
||||
// Reject cases like `<impl Trait>::Assoc` and `<impl Trait as Trait>::Assoc`.
|
||||
.map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)));
|
||||
|
||||
let partial_res =
|
||||
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
|
||||
|
|
@ -70,11 +73,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let bound_modifier_allowed_features = if let Res::Def(DefKind::Trait, async_def_id) = res
|
||||
&& self.tcx.async_fn_trait_kind_from_def_id(async_def_id).is_some()
|
||||
{
|
||||
Some(self.allow_async_fn_traits.clone())
|
||||
Some(Lrc::clone(&self.allow_async_fn_traits))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Only permit `impl Trait` in the final segment. E.g., we permit `Option<impl Trait>`,
|
||||
// `option::Option<T>::Xyz<impl Trait>` and reject `option::Option<impl Trait>::Xyz`.
|
||||
let itctx = |i| {
|
||||
if i + 1 == p.segments.len() {
|
||||
itctx
|
||||
} else {
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path)
|
||||
}
|
||||
};
|
||||
|
||||
let path_span_lo = p.span.shrink_to_lo();
|
||||
let proj_start = p.segments.len() - unresolved_segments;
|
||||
let path = self.arena.alloc(hir::Path {
|
||||
|
|
@ -121,7 +134,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
segment,
|
||||
param_mode,
|
||||
generic_args_mode,
|
||||
itctx,
|
||||
itctx(i),
|
||||
bound_modifier_allowed_features.clone(),
|
||||
)
|
||||
},
|
||||
|
|
@ -185,7 +198,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
segment,
|
||||
param_mode,
|
||||
generic_args_mode,
|
||||
itctx,
|
||||
itctx(i),
|
||||
None,
|
||||
));
|
||||
let qpath = hir::QPath::TypeRelative(ty, hir_segment);
|
||||
|
|
@ -268,7 +281,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
span: data.inputs_span,
|
||||
})
|
||||
};
|
||||
if !self.tcx.features().return_type_notation
|
||||
if !self.tcx.features().return_type_notation()
|
||||
&& self.tcx.sess.is_nightly_build()
|
||||
{
|
||||
add_feature_diagnostics(
|
||||
|
|
@ -496,7 +509,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^
|
||||
// ```
|
||||
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => {
|
||||
if self.tcx.features().impl_trait_in_fn_trait_return {
|
||||
if self.tcx.features().impl_trait_in_fn_trait_return() {
|
||||
self.lower_ty(ty, itctx)
|
||||
} else {
|
||||
self.lower_ty(
|
||||
|
|
|
|||
|
|
@ -146,8 +146,6 @@ ast_passes_generic_before_constraints = generic arguments must come before the f
|
|||
|
||||
ast_passes_generic_default_trailing = generic parameters with a default must be trailing
|
||||
|
||||
ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
|
||||
|
||||
ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
|
||||
.help = remove one of these features
|
||||
|
||||
|
|
|
|||
|
|
@ -80,10 +80,6 @@ struct AstValidator<'a> {
|
|||
|
||||
disallow_tilde_const: Option<TildeConstReason>,
|
||||
|
||||
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
|
||||
/// or `Foo::Bar<impl Trait>`
|
||||
is_impl_trait_banned: bool,
|
||||
|
||||
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
|
||||
extern_mod_safety: Option<Safety>,
|
||||
|
||||
|
|
@ -123,12 +119,6 @@ impl<'a> AstValidator<'a> {
|
|||
self.extern_mod_safety = old;
|
||||
}
|
||||
|
||||
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.is_impl_trait_banned, true);
|
||||
f(self);
|
||||
self.is_impl_trait_banned = old;
|
||||
}
|
||||
|
||||
fn with_tilde_const(
|
||||
&mut self,
|
||||
disallowed: Option<TildeConstReason>,
|
||||
|
|
@ -213,43 +203,12 @@ impl<'a> AstValidator<'a> {
|
|||
.with_tilde_const(Some(TildeConstReason::TraitObject), |this| {
|
||||
visit::walk_ty(this, t)
|
||||
}),
|
||||
TyKind::Path(qself, path) => {
|
||||
// We allow these:
|
||||
// - `Option<impl Trait>`
|
||||
// - `option::Option<impl Trait>`
|
||||
// - `option::Option<T>::Foo<impl Trait>`
|
||||
//
|
||||
// But not these:
|
||||
// - `<impl Trait>::Foo`
|
||||
// - `option::Option<impl Trait>::Foo`.
|
||||
//
|
||||
// To implement this, we disallow `impl Trait` from `qself`
|
||||
// (for cases like `<impl Trait>::Foo>`)
|
||||
// but we allow `impl Trait` in `GenericArgs`
|
||||
// iff there are no more PathSegments.
|
||||
if let Some(qself) = qself {
|
||||
// `impl Trait` in `qself` is always illegal
|
||||
self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
|
||||
}
|
||||
|
||||
// Note that there should be a call to visit_path here,
|
||||
// so if any logic is added to process `Path`s a call to it should be
|
||||
// added both in visit_path and here. This code mirrors visit::walk_path.
|
||||
for (i, segment) in path.segments.iter().enumerate() {
|
||||
// Allow `impl Trait` iff we're on the final path segment
|
||||
if i == path.segments.len() - 1 {
|
||||
self.visit_path_segment(segment);
|
||||
} else {
|
||||
self.with_banned_impl_trait(|this| this.visit_path_segment(segment));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => visit::walk_ty(self, t),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
|
||||
if let Some(ident) = field.ident
|
||||
if let Some(ref ident) = field.ident
|
||||
&& ident.name == kw::Underscore
|
||||
{
|
||||
self.visit_vis(&field.vis);
|
||||
|
|
@ -295,7 +254,8 @@ impl<'a> AstValidator<'a> {
|
|||
return;
|
||||
};
|
||||
|
||||
let make_impl_const_sugg = if self.features.const_trait_impl
|
||||
let const_trait_impl = self.features.const_trait_impl();
|
||||
let make_impl_const_sugg = if const_trait_impl
|
||||
&& let TraitOrTraitImpl::TraitImpl {
|
||||
constness: Const::No,
|
||||
polarity: ImplPolarity::Positive,
|
||||
|
|
@ -308,13 +268,12 @@ impl<'a> AstValidator<'a> {
|
|||
None
|
||||
};
|
||||
|
||||
let make_trait_const_sugg = if self.features.const_trait_impl
|
||||
&& let TraitOrTraitImpl::Trait { span, constness: None } = parent
|
||||
{
|
||||
Some(span.shrink_to_lo())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let make_trait_const_sugg =
|
||||
if const_trait_impl && let TraitOrTraitImpl::Trait { span, constness: None } = parent {
|
||||
Some(span.shrink_to_lo())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let parent_constness = parent.constness();
|
||||
self.dcx().emit_err(errors::TraitFnConst {
|
||||
|
|
@ -737,10 +696,6 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
TyKind::ImplTrait(_, bounds) => {
|
||||
if self.is_impl_trait_banned {
|
||||
self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
|
||||
}
|
||||
|
||||
if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
|
||||
self.dcx().emit_err(errors::NestedImplTrait {
|
||||
span: ty.span,
|
||||
|
|
@ -899,7 +854,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
|
||||
this.visit_vis(&item.vis);
|
||||
this.visit_ident(item.ident);
|
||||
this.visit_ident(&item.ident);
|
||||
let disallowed = matches!(constness, Const::No)
|
||||
.then(|| TildeConstReason::TraitImpl { span: item.span });
|
||||
this.with_tilde_const(disallowed, |this| this.visit_generics(generics));
|
||||
|
|
@ -953,7 +908,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
|
||||
this.visit_vis(&item.vis);
|
||||
this.visit_ident(item.ident);
|
||||
this.visit_ident(&item.ident);
|
||||
this.with_tilde_const(
|
||||
Some(TildeConstReason::Impl { span: item.span }),
|
||||
|this| this.visit_generics(generics),
|
||||
|
|
@ -991,7 +946,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(item.ident);
|
||||
self.visit_ident(&item.ident);
|
||||
let kind =
|
||||
FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
|
|
@ -1058,7 +1013,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
// Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
|
||||
// context for the supertraits.
|
||||
this.visit_vis(&item.vis);
|
||||
this.visit_ident(item.ident);
|
||||
this.visit_ident(&item.ident);
|
||||
let disallowed = is_const_trait
|
||||
.is_none()
|
||||
.then(|| TildeConstReason::Trait { span: item.span });
|
||||
|
|
@ -1085,7 +1040,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
ItemKind::Struct(vdata, generics) => match vdata {
|
||||
VariantData::Struct { fields, .. } => {
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(item.ident);
|
||||
self.visit_ident(&item.ident);
|
||||
self.visit_generics(generics);
|
||||
// Permit `Anon{Struct,Union}` as field type.
|
||||
walk_list!(self, visit_struct_field_def, fields);
|
||||
|
|
@ -1101,7 +1056,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
match vdata {
|
||||
VariantData::Struct { fields, .. } => {
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(item.ident);
|
||||
self.visit_ident(&item.ident);
|
||||
self.visit_generics(generics);
|
||||
// Permit `Anon{Struct,Union}` as field type.
|
||||
walk_list!(self, visit_struct_field_def, fields);
|
||||
|
|
@ -1145,7 +1100,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
self.check_type_no_bounds(bounds, "this context");
|
||||
|
||||
if self.features.lazy_type_alias {
|
||||
if self.features.lazy_type_alias() {
|
||||
if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
|
||||
self.dcx().emit_err(err);
|
||||
}
|
||||
|
|
@ -1286,7 +1241,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
GenericBound::Trait(trait_ref) => {
|
||||
match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) {
|
||||
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
|
||||
if !self.features.more_maybe_bounds =>
|
||||
if !self.features.more_maybe_bounds() =>
|
||||
{
|
||||
self.sess
|
||||
.create_feature_err(
|
||||
|
|
@ -1299,7 +1254,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
.emit();
|
||||
}
|
||||
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
|
||||
if !self.features.more_maybe_bounds =>
|
||||
if !self.features.more_maybe_bounds() =>
|
||||
{
|
||||
self.sess
|
||||
.create_feature_err(
|
||||
|
|
@ -1521,7 +1476,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
|| matches!(sig.header.constness, Const::Yes(_)) =>
|
||||
{
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(item.ident);
|
||||
self.visit_ident(&item.ident);
|
||||
let kind = FnKind::Fn(
|
||||
FnCtxt::Assoc(ctxt),
|
||||
item.ident,
|
||||
|
|
@ -1729,7 +1684,6 @@ pub fn check_crate(
|
|||
has_proc_macro_decls: false,
|
||||
outer_impl_trait: None,
|
||||
disallow_tilde_const: Some(TildeConstReason::Item),
|
||||
is_impl_trait_banned: false,
|
||||
extern_mod_safety: None,
|
||||
lint_buffer: lints,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -418,13 +418,6 @@ pub(crate) struct TraitObjectBound {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_impl_trait_path, code = E0667)]
|
||||
pub(crate) struct ImplTraitPath {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_nested_impl_trait, code = E0666)]
|
||||
pub(crate) struct NestedImplTrait {
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@ use crate::errors;
|
|||
/// The common case.
|
||||
macro_rules! gate {
|
||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
|
||||
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
|
||||
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
|
||||
}
|
||||
}};
|
||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
|
||||
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
|
||||
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
|
|
@ -43,7 +43,7 @@ macro_rules! gate_alt {
|
|||
/// The case involving a multispan.
|
||||
macro_rules! gate_multi {
|
||||
($visitor:expr, $feature:ident, $spans:expr, $explain:expr) => {{
|
||||
if !$visitor.features.$feature {
|
||||
if !$visitor.features.$feature() {
|
||||
let spans: Vec<_> =
|
||||
$spans.filter(|span| !span.allows_unstable(sym::$feature)).collect();
|
||||
if !spans.is_empty() {
|
||||
|
|
@ -56,7 +56,7 @@ macro_rules! gate_multi {
|
|||
/// The legacy case.
|
||||
macro_rules! gate_legacy {
|
||||
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
|
||||
if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) {
|
||||
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
|
||||
feature_warn(&$visitor.sess, sym::$feature, $span, $explain);
|
||||
}
|
||||
}};
|
||||
|
|
@ -150,7 +150,7 @@ impl<'a> PostExpansionVisitor<'a> {
|
|||
|
||||
// FIXME(non_lifetime_binders): Const bound params are pretty broken.
|
||||
// Let's keep users from using this feature accidentally.
|
||||
if self.features.non_lifetime_binders {
|
||||
if self.features.non_lifetime_binders() {
|
||||
let const_param_spans: Vec<_> = params
|
||||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
|
|
@ -210,7 +210,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
|
||||
// Emit errors for non-staged-api crates.
|
||||
if !self.features.staged_api {
|
||||
if !self.features.staged_api() {
|
||||
if attr.has_name(sym::unstable)
|
||||
|| attr.has_name(sym::stable)
|
||||
|| attr.has_name(sym::rustc_const_unstable)
|
||||
|
|
@ -470,7 +470,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
// Limit `min_specialization` to only specializing functions.
|
||||
gate_alt!(
|
||||
&self,
|
||||
self.features.specialization || (is_fn && self.features.min_specialization),
|
||||
self.features.specialization() || (is_fn && self.features.min_specialization()),
|
||||
sym::specialization,
|
||||
i.span,
|
||||
"specialization is unstable"
|
||||
|
|
@ -548,7 +548,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(return_type_notation, "return type notation is experimental");
|
||||
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
||||
|
||||
if !visitor.features.never_patterns {
|
||||
if !visitor.features.never_patterns() {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
for &span in spans {
|
||||
if span.allows_unstable(sym::never_patterns) {
|
||||
|
|
@ -572,7 +572,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
}
|
||||
}
|
||||
|
||||
if !visitor.features.negative_bounds {
|
||||
if !visitor.features.negative_bounds() {
|
||||
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
|
||||
sess.dcx().emit_err(errors::NegativeBoundUnsupported { span });
|
||||
}
|
||||
|
|
@ -600,59 +600,61 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
}
|
||||
|
||||
fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) {
|
||||
// checks if `#![feature]` has been used to enable any lang feature
|
||||
// does not check the same for lib features unless there's at least one
|
||||
// declared lang feature
|
||||
if !sess.opts.unstable_features.is_nightly_build() {
|
||||
if features.declared_features.is_empty() {
|
||||
return;
|
||||
}
|
||||
for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
|
||||
let mut err = errors::FeatureOnNonNightly {
|
||||
span: attr.span,
|
||||
channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
|
||||
stable_features: vec![],
|
||||
sugg: None,
|
||||
};
|
||||
|
||||
let mut all_stable = true;
|
||||
for ident in
|
||||
attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident())
|
||||
{
|
||||
let name = ident.name;
|
||||
let stable_since = features
|
||||
.declared_lang_features
|
||||
.iter()
|
||||
.flat_map(|&(feature, _, since)| if feature == name { since } else { None })
|
||||
.next();
|
||||
if let Some(since) = stable_since {
|
||||
err.stable_features.push(errors::StableFeature { name, since });
|
||||
} else {
|
||||
all_stable = false;
|
||||
}
|
||||
}
|
||||
if all_stable {
|
||||
err.sugg = Some(attr.span);
|
||||
}
|
||||
sess.dcx().emit_err(err);
|
||||
}
|
||||
// checks if `#![feature]` has been used to enable any feature.
|
||||
if sess.opts.unstable_features.is_nightly_build() {
|
||||
return;
|
||||
}
|
||||
if features.enabled_features().is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut errored = false;
|
||||
for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
|
||||
// `feature(...)` used on non-nightly. This is definitely an error.
|
||||
let mut err = errors::FeatureOnNonNightly {
|
||||
span: attr.span,
|
||||
channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"),
|
||||
stable_features: vec![],
|
||||
sugg: None,
|
||||
};
|
||||
|
||||
let mut all_stable = true;
|
||||
for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) {
|
||||
let name = ident.name;
|
||||
let stable_since = features
|
||||
.enabled_lang_features()
|
||||
.iter()
|
||||
.find(|feat| feat.gate_name == name)
|
||||
.map(|feat| feat.stable_since)
|
||||
.flatten();
|
||||
if let Some(since) = stable_since {
|
||||
err.stable_features.push(errors::StableFeature { name, since });
|
||||
} else {
|
||||
all_stable = false;
|
||||
}
|
||||
}
|
||||
if all_stable {
|
||||
err.sugg = Some(attr.span);
|
||||
}
|
||||
sess.dcx().emit_err(err);
|
||||
errored = true;
|
||||
}
|
||||
// Just make sure we actually error if anything is listed in `enabled_features`.
|
||||
assert!(errored);
|
||||
}
|
||||
|
||||
fn check_incompatible_features(sess: &Session, features: &Features) {
|
||||
let declared_features = features
|
||||
.declared_lang_features
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|(name, span, _)| (name, span))
|
||||
.chain(features.declared_lib_features.iter().copied());
|
||||
let enabled_lang_features =
|
||||
features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
|
||||
let enabled_lib_features =
|
||||
features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
|
||||
let enabled_features = enabled_lang_features.chain(enabled_lib_features);
|
||||
|
||||
for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES
|
||||
.iter()
|
||||
.filter(|&&(f1, f2)| features.active(f1) && features.active(f2))
|
||||
.filter(|(f1, f2)| features.enabled(*f1) && features.enabled(*f2))
|
||||
{
|
||||
if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) {
|
||||
if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2)
|
||||
if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1) {
|
||||
if let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2)
|
||||
{
|
||||
let spans = vec![f1_span, f2_span];
|
||||
sess.dcx().emit_err(errors::IncompatibleFeatures {
|
||||
|
|
@ -671,10 +673,11 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) {
|
|||
}
|
||||
|
||||
// Ban GCE with the new solver, because it does not implement GCE correctly.
|
||||
if let Some(&(_, gce_span, _)) = features
|
||||
.declared_lang_features
|
||||
if let Some(gce_span) = features
|
||||
.enabled_lang_features()
|
||||
.iter()
|
||||
.find(|&&(feat, _, _)| feat == sym::generic_const_exprs)
|
||||
.find(|feat| feat.gate_name == sym::generic_const_exprs)
|
||||
.map(|feat| feat.attr_sp)
|
||||
{
|
||||
sess.dcx().emit_err(errors::IncompatibleFeatures {
|
||||
spans: vec![gce_span],
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ impl NodeCounter {
|
|||
}
|
||||
|
||||
impl<'ast> Visitor<'ast> for NodeCounter {
|
||||
fn visit_ident(&mut self, _ident: Ident) {
|
||||
fn visit_ident(&mut self, _ident: &Ident) {
|
||||
self.count += 1;
|
||||
}
|
||||
fn visit_foreign_item(&mut self, i: &ForeignItem) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||
# tidy-alphabetical-start
|
||||
itertools = "0.12"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
thin-vec = "0.2.12"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use rustc_ast::{
|
|||
GenericBound, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass,
|
||||
InlineAsmTemplatePiece, PatKind, RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr,
|
||||
};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::symbol::{Ident, IdentPrinter, Symbol, kw, sym};
|
||||
|
|
@ -105,7 +106,7 @@ fn split_block_comment_into_lines(text: &str, col: CharPos) -> Vec<String> {
|
|||
fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comment> {
|
||||
let sm = SourceMap::new(sm.path_mapping().clone());
|
||||
let source_file = sm.new_source_file(path, src);
|
||||
let text = (*source_file.src.as_ref().unwrap()).clone();
|
||||
let text = Lrc::clone(&(*source_file.src.as_ref().unwrap()));
|
||||
|
||||
let text: &str = text.as_str();
|
||||
let start_bpos = source_file.start_pos;
|
||||
|
|
@ -627,6 +628,13 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
|
||||
fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
|
||||
self.ibox(0);
|
||||
match item.unsafety {
|
||||
ast::Safety::Unsafe(_) => {
|
||||
self.word("unsafe");
|
||||
self.popen();
|
||||
}
|
||||
ast::Safety::Default | ast::Safety::Safe(_) => {}
|
||||
}
|
||||
match &item.args {
|
||||
AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
|
||||
Some(MacHeader::Path(&item.path)),
|
||||
|
|
@ -655,6 +663,10 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
self.word(token_str);
|
||||
}
|
||||
}
|
||||
match item.unsafety {
|
||||
ast::Safety::Unsafe(_) => self.pclose(),
|
||||
ast::Safety::Default | ast::Safety::Safe(_) => {}
|
||||
}
|
||||
self.end();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ impl<'a> State<'a> {
|
|||
self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
|
||||
}
|
||||
ast::ForeignItemKind::Static(box ast::StaticItem { ty, mutability, expr, safety }) => {
|
||||
self.print_safety(*safety);
|
||||
self.print_item_const(
|
||||
ident,
|
||||
Some(*mutability),
|
||||
|
|
@ -46,6 +45,7 @@ impl<'a> State<'a> {
|
|||
ty,
|
||||
expr.as_deref(),
|
||||
vis,
|
||||
*safety,
|
||||
ast::Defaultness::Final,
|
||||
)
|
||||
}
|
||||
|
|
@ -84,10 +84,12 @@ impl<'a> State<'a> {
|
|||
ty: &ast::Ty,
|
||||
body: Option<&ast::Expr>,
|
||||
vis: &ast::Visibility,
|
||||
safety: ast::Safety,
|
||||
defaultness: ast::Defaultness,
|
||||
) {
|
||||
self.head("");
|
||||
self.print_visibility(vis);
|
||||
self.print_safety(safety);
|
||||
self.print_defaultness(defaultness);
|
||||
let leading = match mutbl {
|
||||
None => "const",
|
||||
|
|
@ -181,6 +183,7 @@ impl<'a> State<'a> {
|
|||
ty,
|
||||
body.as_deref(),
|
||||
&item.vis,
|
||||
ast::Safety::Default,
|
||||
ast::Defaultness::Final,
|
||||
);
|
||||
}
|
||||
|
|
@ -192,6 +195,7 @@ impl<'a> State<'a> {
|
|||
ty,
|
||||
expr.as_deref(),
|
||||
&item.vis,
|
||||
ast::Safety::Default,
|
||||
*defaultness,
|
||||
);
|
||||
}
|
||||
|
|
@ -549,6 +553,7 @@ impl<'a> State<'a> {
|
|||
ty,
|
||||
expr.as_deref(),
|
||||
vis,
|
||||
ast::Safety::Default,
|
||||
*defaultness,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ attr_non_ident_feature =
|
|||
attr_rustc_allowed_unstable_pairing =
|
||||
`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
|
||||
|
||||
attr_rustc_const_stable_indirect_pairing =
|
||||
`const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied
|
||||
|
||||
attr_rustc_promotable_pairing =
|
||||
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ use rustc_session::lint::BuiltinLintDiag;
|
|||
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::{RustcVersion, Session};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::symbol::{Symbol, kw, sym};
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
|
||||
use crate::fluent_generated;
|
||||
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
|
||||
|
|
@ -92,7 +92,11 @@ impl Stability {
|
|||
#[derive(HashStable_Generic)]
|
||||
pub struct ConstStability {
|
||||
pub level: StabilityLevel,
|
||||
pub feature: Symbol,
|
||||
/// This can be `None` for functions that do not have an explicit const feature.
|
||||
/// We still track them for recursive const stability checks.
|
||||
pub feature: Option<Symbol>,
|
||||
/// This is true iff the `const_stable_indirect` attribute is present.
|
||||
pub const_stable_indirect: bool,
|
||||
/// whether the function has a `#[rustc_promotable]` attribute
|
||||
pub promotable: bool,
|
||||
}
|
||||
|
|
@ -268,17 +272,23 @@ pub fn find_stability(
|
|||
|
||||
/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
|
||||
/// attributes in `attrs`. Returns `None` if no stability attributes are found.
|
||||
///
|
||||
/// `is_const_fn` indicates whether this is a function marked as `const`. It will always
|
||||
/// be false for intrinsics in an `extern` block!
|
||||
pub fn find_const_stability(
|
||||
sess: &Session,
|
||||
attrs: &[Attribute],
|
||||
item_sp: Span,
|
||||
is_const_fn: bool,
|
||||
) -> Option<(ConstStability, Span)> {
|
||||
let mut const_stab: Option<(ConstStability, Span)> = None;
|
||||
let mut promotable = false;
|
||||
let mut const_stable_indirect = None;
|
||||
|
||||
for attr in attrs {
|
||||
match attr.name_or_empty() {
|
||||
sym::rustc_promotable => promotable = true,
|
||||
sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span),
|
||||
sym::rustc_const_unstable => {
|
||||
if const_stab.is_some() {
|
||||
sess.dcx()
|
||||
|
|
@ -287,8 +297,15 @@ pub fn find_const_stability(
|
|||
}
|
||||
|
||||
if let Some((feature, level)) = parse_unstability(sess, attr) {
|
||||
const_stab =
|
||||
Some((ConstStability { level, feature, promotable: false }, attr.span));
|
||||
const_stab = Some((
|
||||
ConstStability {
|
||||
level,
|
||||
feature: Some(feature),
|
||||
const_stable_indirect: false,
|
||||
promotable: false,
|
||||
},
|
||||
attr.span,
|
||||
));
|
||||
}
|
||||
}
|
||||
sym::rustc_const_stable => {
|
||||
|
|
@ -298,15 +315,22 @@ pub fn find_const_stability(
|
|||
break;
|
||||
}
|
||||
if let Some((feature, level)) = parse_stability(sess, attr) {
|
||||
const_stab =
|
||||
Some((ConstStability { level, feature, promotable: false }, attr.span));
|
||||
const_stab = Some((
|
||||
ConstStability {
|
||||
level,
|
||||
feature: Some(feature),
|
||||
const_stable_indirect: false,
|
||||
promotable: false,
|
||||
},
|
||||
attr.span,
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge the const-unstable info into the stability info
|
||||
// Merge promotable and not_exposed_on_stable into stability info
|
||||
if promotable {
|
||||
match &mut const_stab {
|
||||
Some((stab, _)) => stab.promotable = promotable,
|
||||
|
|
@ -317,6 +341,46 @@ pub fn find_const_stability(
|
|||
}
|
||||
}
|
||||
}
|
||||
if const_stable_indirect.is_some() {
|
||||
match &mut const_stab {
|
||||
Some((stab, _)) => {
|
||||
if stab.is_const_unstable() {
|
||||
stab.const_stable_indirect = true;
|
||||
} else {
|
||||
_ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
|
||||
span: item_sp,
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by
|
||||
// the `default_const_unstable` logic.
|
||||
}
|
||||
}
|
||||
}
|
||||
// Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const
|
||||
// fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const
|
||||
// stability checks for them. We need to do this because the default for whether an unmarked
|
||||
// function enforces recursive stability differs between staged-api crates and force-unmarked
|
||||
// crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect`
|
||||
// enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to
|
||||
// assume the function does not have recursive stability. All functions that *do* have recursive
|
||||
// stability must explicitly record this, and so that's what we do for all `const fn` in a
|
||||
// staged_api crate.
|
||||
if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() {
|
||||
let c = ConstStability {
|
||||
feature: None,
|
||||
const_stable_indirect: const_stable_indirect.is_some(),
|
||||
promotable: false,
|
||||
level: StabilityLevel::Unstable {
|
||||
reason: UnstableReason::Default,
|
||||
issue: None,
|
||||
is_soft: false,
|
||||
implied_by: None,
|
||||
},
|
||||
};
|
||||
const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP)));
|
||||
}
|
||||
|
||||
const_stab
|
||||
}
|
||||
|
|
@ -619,11 +683,11 @@ pub fn eval_condition(
|
|||
// we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
|
||||
// and `true`, and we want to keep the former working without feature gate
|
||||
gate_cfg(
|
||||
&((
|
||||
&(
|
||||
if *b { kw::True } else { kw::False },
|
||||
sym::cfg_boolean_literals,
|
||||
|features: &Features| features.cfg_boolean_literals,
|
||||
)),
|
||||
|features: &Features| features.cfg_boolean_literals(),
|
||||
),
|
||||
cfg.span(),
|
||||
sess,
|
||||
features,
|
||||
|
|
@ -711,7 +775,7 @@ pub fn eval_condition(
|
|||
}
|
||||
sym::target => {
|
||||
if let Some(features) = features
|
||||
&& !features.cfg_target_compact
|
||||
&& !features.cfg_target_compact()
|
||||
{
|
||||
feature_err(
|
||||
sess,
|
||||
|
|
@ -831,7 +895,7 @@ pub fn find_deprecation(
|
|||
attrs: &[Attribute],
|
||||
) -> Option<(Deprecation, Span)> {
|
||||
let mut depr: Option<(Deprecation, Span)> = None;
|
||||
let is_rustc = features.staged_api;
|
||||
let is_rustc = features.staged_api();
|
||||
|
||||
'outer: for attr in attrs {
|
||||
if !attr.has_name(sym::deprecated) {
|
||||
|
|
@ -891,7 +955,7 @@ pub fn find_deprecation(
|
|||
}
|
||||
}
|
||||
sym::suggestion => {
|
||||
if !features.deprecated_suggestion {
|
||||
if !features.deprecated_suggestion() {
|
||||
sess.dcx().emit_err(
|
||||
session_diagnostics::DeprecatedItemSuggestion {
|
||||
span: mi.span,
|
||||
|
|
@ -909,7 +973,7 @@ pub fn find_deprecation(
|
|||
sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
|
||||
span: meta.span(),
|
||||
item: pprust::path_to_string(&mi.path),
|
||||
expected: if features.deprecated_suggestion {
|
||||
expected: if features.deprecated_suggestion() {
|
||||
&["since", "note", "suggestion"]
|
||||
} else {
|
||||
&["since", "note"]
|
||||
|
|
|
|||
|
|
@ -318,6 +318,13 @@ pub(crate) struct RustcPromotablePairing {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_rustc_const_stable_indirect_pairing)]
|
||||
pub(crate) struct RustcConstStableIndirectPairing {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_rustc_allowed_unstable_pairing, code = E0789)]
|
||||
pub(crate) struct RustcAllowedUnstablePairing {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ impl<'tcx> UniverseInfo<'tcx> {
|
|||
UniverseInfoInner::RelateTys { expected, found } => {
|
||||
let err = mbcx.infcx.err_ctxt().report_mismatched_types(
|
||||
&cause,
|
||||
mbcx.param_env,
|
||||
expected,
|
||||
found,
|
||||
TypeError::RegionsPlaceholderMismatch,
|
||||
|
|
@ -480,12 +481,11 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>(
|
|||
.try_report_from_nll()
|
||||
.or_else(|| {
|
||||
if let SubregionOrigin::Subtype(trace) = cause {
|
||||
Some(
|
||||
infcx.err_ctxt().report_and_explain_type_error(
|
||||
*trace,
|
||||
TypeError::RegionsPlaceholderMismatch,
|
||||
),
|
||||
)
|
||||
Some(infcx.err_ctxt().report_and_explain_type_error(
|
||||
*trace,
|
||||
infcx.tcx.param_env(generic_param_scope),
|
||||
TypeError::RegionsPlaceholderMismatch,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -959,13 +959,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
None
|
||||
}
|
||||
}
|
||||
hir::ExprKind::MethodCall(_, _, args, span) => {
|
||||
if let Some(def_id) = typeck_results.type_dependent_def_id(*hir_id) {
|
||||
Some((def_id, *span, *args))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
hir::ExprKind::MethodCall(_, _, args, span) => typeck_results
|
||||
.type_dependent_def_id(*hir_id)
|
||||
.map(|def_id| (def_id, *span, *args)),
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -107,13 +107,13 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
param_env,
|
||||
body,
|
||||
promoted,
|
||||
universal_regions.clone(),
|
||||
Rc::clone(&universal_regions),
|
||||
location_table,
|
||||
borrow_set,
|
||||
&mut all_facts,
|
||||
flow_inits,
|
||||
move_data,
|
||||
elements.clone(),
|
||||
Rc::clone(&elements),
|
||||
upvars,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -733,7 +733,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
|
||||
// Now take member constraints into account.
|
||||
let member_constraints = self.member_constraints.clone();
|
||||
let member_constraints = Rc::clone(&self.member_constraints);
|
||||
for m_c_i in member_constraints.indices(scc_a) {
|
||||
self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i));
|
||||
}
|
||||
|
|
@ -1679,7 +1679,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
infcx: &InferCtxt<'tcx>,
|
||||
errors_buffer: &mut RegionErrors<'tcx>,
|
||||
) {
|
||||
let member_constraints = self.member_constraints.clone();
|
||||
let member_constraints = Rc::clone(&self.member_constraints);
|
||||
for m_c_i in member_constraints.all_indices() {
|
||||
debug!(?m_c_i);
|
||||
let m_c = &member_constraints[m_c_i];
|
||||
|
|
|
|||
|
|
@ -360,6 +360,7 @@ fn check_opaque_type_well_formed<'tcx>(
|
|||
.err_ctxt()
|
||||
.report_mismatched_types(
|
||||
&ObligationCause::misc(definition_span, def_id),
|
||||
param_env,
|
||||
opaque_ty,
|
||||
definition_ty,
|
||||
err,
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
let mut constraints = MirTypeckRegionConstraints {
|
||||
placeholder_indices: PlaceholderIndices::default(),
|
||||
placeholder_index_to_region: IndexVec::default(),
|
||||
liveness_constraints: LivenessValues::with_specific_points(elements.clone()),
|
||||
liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&elements)),
|
||||
outlives_constraints: OutlivesConstraintSet::default(),
|
||||
member_constraints: MemberConstraintSet::default(),
|
||||
type_tests: Vec::default(),
|
||||
|
|
@ -150,7 +150,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
infcx,
|
||||
param_env,
|
||||
implicit_region_bound,
|
||||
universal_regions.clone(),
|
||||
Rc::clone(&universal_regions),
|
||||
&mut constraints,
|
||||
);
|
||||
|
||||
|
|
@ -1035,7 +1035,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
|
||||
fn unsized_feature_enabled(&self) -> bool {
|
||||
let features = self.tcx().features();
|
||||
features.unsized_locals || features.unsized_fn_params
|
||||
features.unsized_locals() || features.unsized_fn_params()
|
||||
}
|
||||
|
||||
/// Equate the inferred type and the annotated type for user type annotations
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ pub(crate) fn expand_assert<'cx>(
|
|||
// If `generic_assert` is enabled, generates rich captured outputs
|
||||
//
|
||||
// FIXME(c410-f3r) See https://github.com/rust-lang/rust/issues/96949
|
||||
else if cx.ecfg.features.generic_assert {
|
||||
else if cx.ecfg.features.generic_assert() {
|
||||
context::Context::new(cx, call_site_span).build(cond_expr, panic_path())
|
||||
}
|
||||
// If `generic_assert` is not enabled, only outputs a literal "assertion failed: ..."
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ macro_rules! path {
|
|||
($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] }
|
||||
}
|
||||
|
||||
pub(crate) fn expand_deriving_smart_ptr(
|
||||
pub(crate) fn expand_deriving_coerce_pointee(
|
||||
cx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
_mitem: &MetaItem,
|
||||
|
|
@ -41,7 +41,7 @@ pub(crate) fn expand_deriving_smart_ptr(
|
|||
cx.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
"`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`",
|
||||
"`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`",
|
||||
)
|
||||
.emit();
|
||||
return;
|
||||
|
|
@ -54,7 +54,7 @@ pub(crate) fn expand_deriving_smart_ptr(
|
|||
cx.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
"`SmartPointer` can only be derived on `struct`s with at least one field",
|
||||
"`CoercePointee` can only be derived on `struct`s with at least one field",
|
||||
)
|
||||
.emit();
|
||||
return;
|
||||
|
|
@ -64,7 +64,7 @@ pub(crate) fn expand_deriving_smart_ptr(
|
|||
cx.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
"`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`",
|
||||
"`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`",
|
||||
)
|
||||
.emit();
|
||||
return;
|
||||
|
|
@ -94,10 +94,10 @@ pub(crate) fn expand_deriving_smart_ptr(
|
|||
.collect();
|
||||
|
||||
let pointee_param_idx = if type_params.is_empty() {
|
||||
// `#[derive(SmartPointer)]` requires at least one generic type on the target `struct`
|
||||
// `#[derive(CoercePointee)]` requires at least one generic type on the target `struct`
|
||||
cx.dcx().struct_span_err(
|
||||
span,
|
||||
"`SmartPointer` can only be derived on `struct`s that are generic over at least one type",
|
||||
"`CoercePointee` can only be derived on `struct`s that are generic over at least one type",
|
||||
).emit();
|
||||
return;
|
||||
} else if type_params.len() == 1 {
|
||||
|
|
@ -113,7 +113,7 @@ pub(crate) fn expand_deriving_smart_ptr(
|
|||
(None, _) => {
|
||||
cx.dcx().struct_span_err(
|
||||
span,
|
||||
"exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits",
|
||||
"exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits",
|
||||
).emit();
|
||||
return;
|
||||
}
|
||||
|
|
@ -121,7 +121,7 @@ pub(crate) fn expand_deriving_smart_ptr(
|
|||
cx.dcx()
|
||||
.struct_span_err(
|
||||
vec![one, another],
|
||||
"only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits",
|
||||
"only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits",
|
||||
)
|
||||
.emit();
|
||||
return;
|
||||
|
|
@ -185,7 +185,7 @@ pub(crate) fn expand_deriving_smart_ptr(
|
|||
.struct_span_err(
|
||||
pointee_ty_ident.span,
|
||||
format!(
|
||||
"`derive(SmartPointer)` requires {} to be marked `?Sized`",
|
||||
"`derive(CoercePointee)` requires {} to be marked `?Sized`",
|
||||
pointee_ty_ident.name
|
||||
),
|
||||
)
|
||||
|
|
@ -195,7 +195,7 @@ pub(crate) fn expand_deriving_smart_ptr(
|
|||
let arg = GenericArg::Type(s_ty.clone());
|
||||
let unsize = cx.path_all(span, true, path!(span, core::marker::Unsize), vec![arg]);
|
||||
pointee.bounds.push(cx.trait_bound(unsize, false));
|
||||
// Drop `#[pointee]` attribute since it should not be recognized outside `derive(SmartPointer)`
|
||||
// Drop `#[pointee]` attribute since it should not be recognized outside `derive(CoercePointee)`
|
||||
pointee.attrs.retain(|attr| !attr.has_name(sym::pointee));
|
||||
}
|
||||
|
||||
|
|
@ -222,7 +222,7 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, '
|
|||
rustc_ast::visit::walk_attribute(self, attr);
|
||||
}
|
||||
fn visit_variant(&mut self, v: &'a rustc_ast::Variant) {
|
||||
self.visit_ident(v.ident);
|
||||
self.visit_ident(&v.ident);
|
||||
self.visit_vis(&v.vis);
|
||||
self.visit_variant_data(&v.data);
|
||||
visit_opt!(self, visit_anon_const, &v.disr_expr);
|
||||
|
|
|
|||
|
|
@ -22,12 +22,12 @@ macro path_std($($x:tt)*) {
|
|||
|
||||
pub(crate) mod bounds;
|
||||
pub(crate) mod clone;
|
||||
pub(crate) mod coerce_pointee;
|
||||
pub(crate) mod debug;
|
||||
pub(crate) mod decodable;
|
||||
pub(crate) mod default;
|
||||
pub(crate) mod encodable;
|
||||
pub(crate) mod hash;
|
||||
pub(crate) mod smart_ptr;
|
||||
|
||||
#[path = "cmp/eq.rs"]
|
||||
pub(crate) mod eq;
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
|||
PartialOrd: partial_ord::expand_deriving_partial_ord,
|
||||
RustcDecodable: decodable::expand_deriving_rustc_decodable,
|
||||
RustcEncodable: encodable::expand_deriving_rustc_encodable,
|
||||
SmartPointer: smart_ptr::expand_deriving_smart_ptr,
|
||||
CoercePointee: coerce_pointee::expand_deriving_coerce_pointee,
|
||||
}
|
||||
|
||||
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
|
||||
|
|
|
|||
|
|
@ -313,14 +313,23 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
|
|||
match m {
|
||||
ProcMacro::Derive(cd) => {
|
||||
cx.resolver.declare_proc_macro(cd.id);
|
||||
cx.expr_call(span, proc_macro_ty_method_path(cx, custom_derive), thin_vec![
|
||||
cx.expr_str(span, cd.trait_name),
|
||||
cx.expr_array_ref(
|
||||
span,
|
||||
cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::<ThinVec<_>>(),
|
||||
),
|
||||
local_path(cx, cd.function_name),
|
||||
])
|
||||
// The call needs to use `harness_span` so that the const stability checker
|
||||
// accepts it.
|
||||
cx.expr_call(
|
||||
harness_span,
|
||||
proc_macro_ty_method_path(cx, custom_derive),
|
||||
thin_vec![
|
||||
cx.expr_str(span, cd.trait_name),
|
||||
cx.expr_array_ref(
|
||||
span,
|
||||
cd.attrs
|
||||
.iter()
|
||||
.map(|&s| cx.expr_str(span, s))
|
||||
.collect::<ThinVec<_>>(),
|
||||
),
|
||||
local_path(cx, cd.function_name),
|
||||
],
|
||||
)
|
||||
}
|
||||
ProcMacro::Attr(ca) | ProcMacro::Bang(ca) => {
|
||||
cx.resolver.declare_proc_macro(ca.id);
|
||||
|
|
@ -330,7 +339,9 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
|
|||
ProcMacro::Derive(_) => unreachable!(),
|
||||
};
|
||||
|
||||
cx.expr_call(span, proc_macro_ty_method_path(cx, ident), thin_vec![
|
||||
// The call needs to use `harness_span` so that the const stability checker
|
||||
// accepts it.
|
||||
cx.expr_call(harness_span, proc_macro_ty_method_path(cx, ident), thin_vec![
|
||||
cx.expr_str(span, ca.function_name.name),
|
||||
local_path(cx, ca.function_name),
|
||||
])
|
||||
|
|
|
|||
|
|
@ -47,12 +47,12 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
|
|||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
|
||||
|
||||
#[lang = "receiver"]
|
||||
pub trait Receiver {}
|
||||
#[lang = "legacy_receiver"]
|
||||
pub trait LegacyReceiver {}
|
||||
|
||||
impl<T: ?Sized> Receiver for &T {}
|
||||
impl<T: ?Sized> Receiver for &mut T {}
|
||||
impl<T: ?Sized> Receiver for Box<T> {}
|
||||
impl<T: ?Sized> LegacyReceiver for &T {}
|
||||
impl<T: ?Sized> LegacyReceiver for &mut T {}
|
||||
impl<T: ?Sized> LegacyReceiver for Box<T> {}
|
||||
|
||||
#[lang = "copy"]
|
||||
pub unsafe trait Copy {}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
|
|||
index d9de37e..8293fce 100644
|
||||
--- a/library/core/src/sync/atomic.rs
|
||||
+++ b/library/core/src/sync/atomic.rs
|
||||
@@ -2996,42 +2996,6 @@ atomic_int! {
|
||||
@@ -2996,44 +2996,6 @@ atomic_int! {
|
||||
8,
|
||||
u64 AtomicU64
|
||||
}
|
||||
|
|
@ -52,7 +52,8 @@ index d9de37e..8293fce 100644
|
|||
- unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
|
||||
- rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
|
||||
- "i128",
|
||||
- "#![feature(integer_atomics)]\n\n",
|
||||
|
|
@ -70,7 +71,8 @@ index d9de37e..8293fce 100644
|
|||
- unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
|
||||
- rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
|
||||
- "u128",
|
||||
- "#![feature(integer_atomics)]\n\n",
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ pub(super) fn add_local_place_comments<'tcx>(
|
|||
return;
|
||||
}
|
||||
let TyAndLayout { ty, layout } = place.layout();
|
||||
let rustc_target::abi::LayoutS { size, align, .. } = layout.0.0;
|
||||
let rustc_abi::LayoutData { size, align, .. } = layout.0.0;
|
||||
|
||||
let (kind, extra) = place.debug_comment();
|
||||
|
||||
|
|
|
|||
|
|
@ -210,7 +210,6 @@ impl DebugContext {
|
|||
type_names::push_generic_params(
|
||||
tcx,
|
||||
tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args),
|
||||
enclosing_fn_def_id,
|
||||
&mut name,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -44,12 +44,12 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
|
|||
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}
|
||||
|
||||
#[lang = "receiver"]
|
||||
pub trait Receiver {}
|
||||
#[lang = "legacy_receiver"]
|
||||
pub trait LegacyReceiver {}
|
||||
|
||||
impl<T: ?Sized> Receiver for &T {}
|
||||
impl<T: ?Sized> Receiver for &mut T {}
|
||||
impl<T: ?Sized, A: Allocator> Receiver for Box<T, A> {}
|
||||
impl<T: ?Sized> LegacyReceiver for &T {}
|
||||
impl<T: ?Sized> LegacyReceiver for &mut T {}
|
||||
impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
|
||||
|
||||
#[lang = "copy"]
|
||||
pub unsafe trait Copy {}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt};
|
|||
use rustc_span::Span;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_target::abi::call::FnAbi;
|
||||
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi};
|
||||
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, WasmCAbi, X86Abi};
|
||||
|
||||
use crate::common::{SignType, TypeReflection, type_is_pointer};
|
||||
use crate::context::CodegenCx;
|
||||
|
|
@ -1725,16 +1725,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
fn fptosi_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
|
||||
self.fptoint_sat(true, val, dest_ty)
|
||||
}
|
||||
|
||||
fn instrprof_increment(
|
||||
&mut self,
|
||||
_fn_name: RValue<'gcc>,
|
||||
_hash: RValue<'gcc>,
|
||||
_num_counters: RValue<'gcc>,
|
||||
_index: RValue<'gcc>,
|
||||
) {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
||||
|
|
@ -2347,6 +2337,12 @@ impl<'tcx> HasWasmCAbiOpt for Builder<'_, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasX86AbiOpt for Builder<'_, '_, 'tcx> {
|
||||
fn x86_abi_opt(&self) -> X86Abi {
|
||||
self.cx.x86_abi_opt()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToGccComp {
|
||||
fn to_gcc_comparison(&self) -> ComparisonOp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,8 +98,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
|
|||
// whether we are sharing generics or not. The important thing here is
|
||||
// that the visibility we apply to the declaration is the same one that
|
||||
// has been applied to the definition (wherever that definition may be).
|
||||
let is_generic =
|
||||
instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some();
|
||||
let is_generic = instance.args.non_erasable_generics().next().is_some();
|
||||
|
||||
if is_generic {
|
||||
// This is a monomorphization. Its expected visibility depends
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ use rustc_session::Session;
|
|||
use rustc_span::source_map::respan;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
|
||||
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCAbi};
|
||||
use rustc_target::spec::{
|
||||
HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi,
|
||||
};
|
||||
|
||||
use crate::callee::get_fn;
|
||||
use crate::common::SignType;
|
||||
|
|
@ -538,6 +540,12 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
|
||||
fn x86_abi_opt(&self) -> X86Abi {
|
||||
X86Abi { regparm: self.tcx.sess.opts.unstable_opts.regparm }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
#[inline]
|
||||
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
/// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this
|
||||
/// is useful for indexing slices, as `&[T]`'s data pointer is `T*`.
|
||||
/// If the type is an unsized struct, the regular layout is generated,
|
||||
/// with the inner-most trailing unsized field using the "minimal unit"
|
||||
/// with the innermost trailing unsized field using the "minimal unit"
|
||||
/// of that field's type - this is useful for taking the address of
|
||||
/// that field and ensuring the struct has the right alignment.
|
||||
fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
|
||||
|
|
|
|||
|
|
@ -415,7 +415,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
instance: Option<ty::Instance<'tcx>>,
|
||||
) {
|
||||
let mut func_attrs = SmallVec::<[_; 3]>::new();
|
||||
if self.ret.layout.abi.is_uninhabited() {
|
||||
if self.ret.layout.is_uninhabited() {
|
||||
func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx));
|
||||
}
|
||||
if !self.can_unwind {
|
||||
|
|
@ -532,7 +532,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
|
||||
fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value) {
|
||||
let mut func_attrs = SmallVec::<[_; 2]>::new();
|
||||
if self.ret.layout.abi.is_uninhabited() {
|
||||
if self.ret.layout.is_uninhabited() {
|
||||
func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(bx.cx.llcx));
|
||||
}
|
||||
if !self.can_unwind {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use rustc_middle::bug;
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{DebugInfo, OomStrategy};
|
||||
|
||||
use crate::common::AsCCharPtr;
|
||||
use crate::llvm::{self, Context, False, Module, True, Type};
|
||||
use crate::{ModuleLlvm, attributes, debuginfo};
|
||||
|
||||
|
|
@ -76,21 +77,15 @@ pub(crate) unsafe fn codegen(
|
|||
unsafe {
|
||||
// __rust_alloc_error_handler_should_panic
|
||||
let name = OomStrategy::SYMBOL;
|
||||
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
|
||||
llvm::LLVMRustSetVisibility(
|
||||
ll_g,
|
||||
llvm::Visibility::from_generic(tcx.sess.default_visibility()),
|
||||
);
|
||||
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8);
|
||||
llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
|
||||
let val = tcx.sess.opts.unstable_opts.oom.should_panic();
|
||||
let llval = llvm::LLVMConstInt(i8, val as u64, False);
|
||||
llvm::LLVMSetInitializer(ll_g, llval);
|
||||
|
||||
let name = NO_ALLOC_SHIM_IS_UNSTABLE;
|
||||
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
|
||||
llvm::LLVMRustSetVisibility(
|
||||
ll_g,
|
||||
llvm::Visibility::from_generic(tcx.sess.default_visibility()),
|
||||
);
|
||||
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8);
|
||||
llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
|
||||
let llval = llvm::LLVMConstInt(i8, 0, False);
|
||||
llvm::LLVMSetInitializer(ll_g, llval);
|
||||
}
|
||||
|
|
@ -121,7 +116,7 @@ fn create_wrapper_function(
|
|||
);
|
||||
let llfn = llvm::LLVMRustGetOrInsertFunction(
|
||||
llmod,
|
||||
from_name.as_ptr().cast(),
|
||||
from_name.as_c_char_ptr(),
|
||||
from_name.len(),
|
||||
ty,
|
||||
);
|
||||
|
|
@ -134,10 +129,7 @@ fn create_wrapper_function(
|
|||
None
|
||||
};
|
||||
|
||||
llvm::LLVMRustSetVisibility(
|
||||
llfn,
|
||||
llvm::Visibility::from_generic(tcx.sess.default_visibility()),
|
||||
);
|
||||
llvm::set_visibility(llfn, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
|
||||
|
||||
if tcx.sess.must_emit_unwind_tables() {
|
||||
let uwtable =
|
||||
|
|
@ -146,12 +138,12 @@ fn create_wrapper_function(
|
|||
}
|
||||
|
||||
let callee =
|
||||
llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_ptr().cast(), to_name.len(), ty);
|
||||
llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_c_char_ptr(), to_name.len(), ty);
|
||||
if let Some(no_return) = no_return {
|
||||
// -> ! DIFlagNoReturn
|
||||
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
|
||||
}
|
||||
llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
|
||||
llvm::set_visibility(callee, llvm::Visibility::Hidden);
|
||||
|
||||
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr());
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use smallvec::SmallVec;
|
|||
use tracing::debug;
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::common::Funclet;
|
||||
use crate::common::{AsCCharPtr, Funclet};
|
||||
use crate::context::CodegenCx;
|
||||
use crate::type_::Type;
|
||||
use crate::type_of::LayoutLlvmExt;
|
||||
|
|
@ -420,7 +420,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
|||
unsafe {
|
||||
llvm::LLVMAppendModuleInlineAsm(
|
||||
self.llmod,
|
||||
template_str.as_ptr().cast(),
|
||||
template_str.as_c_char_ptr(),
|
||||
template_str.len(),
|
||||
);
|
||||
}
|
||||
|
|
@ -458,14 +458,14 @@ pub(crate) fn inline_asm_call<'ll>(
|
|||
let fty = bx.cx.type_func(&argtys, output);
|
||||
unsafe {
|
||||
// Ask LLVM to verify that the constraints are well-formed.
|
||||
let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr().cast(), cons.len());
|
||||
let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len());
|
||||
debug!("constraint verification result: {:?}", constraints_ok);
|
||||
if constraints_ok {
|
||||
let v = llvm::LLVMRustInlineAsm(
|
||||
fty,
|
||||
asm.as_ptr().cast(),
|
||||
asm.as_c_char_ptr(),
|
||||
asm.len(),
|
||||
cons.as_ptr().cast(),
|
||||
cons.as_c_char_ptr(),
|
||||
cons.len(),
|
||||
volatile,
|
||||
alignstack,
|
||||
|
|
|
|||
|
|
@ -502,9 +502,9 @@ fn thin_lto(
|
|||
// upstream...
|
||||
let data = llvm::LLVMRustCreateThinLTOData(
|
||||
thin_modules.as_ptr(),
|
||||
thin_modules.len() as u32,
|
||||
thin_modules.len(),
|
||||
symbols_below_threshold.as_ptr(),
|
||||
symbols_below_threshold.len() as u32,
|
||||
symbols_below_threshold.len(),
|
||||
)
|
||||
.ok_or_else(|| write::llvm_err(dcx, LlvmError::PrepareThinLtoContext))?;
|
||||
|
||||
|
|
@ -569,7 +569,7 @@ fn thin_lto(
|
|||
|
||||
info!(" - {}: re-compiled", module_name);
|
||||
opt_jobs.push(LtoModuleCodegen::Thin(ThinModule {
|
||||
shared: shared.clone(),
|
||||
shared: Arc::clone(&shared),
|
||||
idx: module_index,
|
||||
}));
|
||||
}
|
||||
|
|
@ -601,23 +601,9 @@ pub(crate) fn run_pass_manager(
|
|||
// This code is based off the code found in llvm's LTO code generator:
|
||||
// llvm/lib/LTO/LTOCodeGenerator.cpp
|
||||
debug!("running the pass manager");
|
||||
unsafe {
|
||||
if !llvm::LLVMRustHasModuleFlag(
|
||||
module.module_llvm.llmod(),
|
||||
"LTOPostLink".as_ptr().cast(),
|
||||
11,
|
||||
) {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
module.module_llvm.llmod(),
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
c"LTOPostLink".as_ptr(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
|
||||
let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
|
||||
write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage)?;
|
||||
}
|
||||
let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
|
||||
let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
|
||||
unsafe { write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) }?;
|
||||
debug!("lto done");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ use crate::back::owned_target_machine::OwnedTargetMachine;
|
|||
use crate::back::profiling::{
|
||||
LlvmSelfProfiler, selfprofile_after_pass_callback, selfprofile_before_pass_callback,
|
||||
};
|
||||
use crate::common::AsCCharPtr;
|
||||
use crate::errors::{
|
||||
CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression,
|
||||
WithLlvmError, WriteBytecode,
|
||||
|
|
@ -596,9 +597,9 @@ pub(crate) unsafe fn llvm_optimize(
|
|||
llvm_selfprofiler,
|
||||
selfprofile_before_pass_callback,
|
||||
selfprofile_after_pass_callback,
|
||||
extra_passes.as_ptr().cast(),
|
||||
extra_passes.as_c_char_ptr(),
|
||||
extra_passes.len(),
|
||||
llvm_plugins.as_ptr().cast(),
|
||||
llvm_plugins.as_c_char_ptr(),
|
||||
llvm_plugins.len(),
|
||||
)
|
||||
};
|
||||
|
|
@ -1042,8 +1043,8 @@ unsafe fn embed_bitcode(
|
|||
llvm::LLVMSetInitializer(llglobal, llconst);
|
||||
|
||||
let section = bitcode_section_name(cgcx);
|
||||
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
|
||||
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::LLVMSetSection(llglobal, section.as_c_char_ptr());
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
|
||||
|
||||
let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
|
||||
|
|
@ -1061,14 +1062,14 @@ unsafe fn embed_bitcode(
|
|||
c".llvmcmd"
|
||||
};
|
||||
llvm::LLVMSetSection(llglobal, section.as_ptr());
|
||||
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
} else {
|
||||
// We need custom section flags, so emit module-level inline assembly.
|
||||
let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
|
||||
let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
|
||||
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
|
||||
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len());
|
||||
let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
|
||||
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
|
||||
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1096,7 +1097,7 @@ fn create_msvc_imps(
|
|||
let ptr_ty = Type::ptr_llcx(llcx);
|
||||
let globals = base::iter_globals(llmod)
|
||||
.filter(|&val| {
|
||||
llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage
|
||||
llvm::get_linkage(val) == llvm::Linkage::ExternalLinkage
|
||||
&& llvm::LLVMIsDeclaration(val) == 0
|
||||
})
|
||||
.filter_map(|val| {
|
||||
|
|
@ -1115,7 +1116,7 @@ fn create_msvc_imps(
|
|||
for (imp_name, val) in globals {
|
||||
let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr());
|
||||
llvm::LLVMSetInitializer(imp, val);
|
||||
llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
|
||||
llvm::set_linkage(imp, llvm::Linkage::ExternalLinkage);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1165,39 +1165,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
|
||||
}
|
||||
|
||||
fn instrprof_increment(
|
||||
&mut self,
|
||||
fn_name: &'ll Value,
|
||||
hash: &'ll Value,
|
||||
num_counters: &'ll Value,
|
||||
index: &'ll Value,
|
||||
) {
|
||||
debug!(
|
||||
"instrprof_increment() with args ({:?}, {:?}, {:?}, {:?})",
|
||||
fn_name, hash, num_counters, index
|
||||
);
|
||||
|
||||
let llfn = unsafe { llvm::LLVMRustGetInstrProfIncrementIntrinsic(self.cx().llmod) };
|
||||
let llty = self.cx.type_func(
|
||||
&[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_i32()],
|
||||
self.cx.type_void(),
|
||||
);
|
||||
let args = &[fn_name, hash, num_counters, index];
|
||||
let args = self.check_call("call", llty, llfn, args);
|
||||
|
||||
unsafe {
|
||||
let _ = llvm::LLVMRustBuildCall(
|
||||
self.llbuilder,
|
||||
llty,
|
||||
llfn,
|
||||
args.as_ptr() as *const &llvm::Value,
|
||||
args.len() as c_uint,
|
||||
[].as_ptr(),
|
||||
0 as c_uint,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn call(
|
||||
&mut self,
|
||||
llty: &'ll Type,
|
||||
|
|
@ -1667,6 +1634,18 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
kcfi_bundle
|
||||
}
|
||||
|
||||
/// Emits a call to `llvm.instrprof.increment`. Used by coverage instrumentation.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn instrprof_increment(
|
||||
&mut self,
|
||||
fn_name: &'ll Value,
|
||||
hash: &'ll Value,
|
||||
num_counters: &'ll Value,
|
||||
index: &'ll Value,
|
||||
) {
|
||||
self.call_intrinsic("llvm.instrprof.increment", &[fn_name, hash, num_counters, index]);
|
||||
}
|
||||
|
||||
/// Emits a call to `llvm.instrprof.mcdc.parameters`.
|
||||
///
|
||||
/// This doesn't produce any code directly, but is used as input by
|
||||
|
|
@ -1676,40 +1655,21 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
///
|
||||
/// [`CodeGenPGO::emitMCDCParameters`]:
|
||||
/// https://github.com/rust-lang/llvm-project/blob/5399a24/clang/lib/CodeGen/CodeGenPGO.cpp#L1124
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn mcdc_parameters(
|
||||
&mut self,
|
||||
fn_name: &'ll Value,
|
||||
hash: &'ll Value,
|
||||
bitmap_bits: &'ll Value,
|
||||
) {
|
||||
debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bits);
|
||||
|
||||
assert!(
|
||||
crate::llvm_util::get_version() >= (19, 0, 0),
|
||||
"MCDC intrinsics require LLVM 19 or later"
|
||||
);
|
||||
|
||||
let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCParametersIntrinsic(self.cx().llmod) };
|
||||
let llty = self.cx.type_func(
|
||||
&[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32()],
|
||||
self.cx.type_void(),
|
||||
);
|
||||
let args = &[fn_name, hash, bitmap_bits];
|
||||
let args = self.check_call("call", llty, llfn, args);
|
||||
|
||||
unsafe {
|
||||
let _ = llvm::LLVMRustBuildCall(
|
||||
self.llbuilder,
|
||||
llty,
|
||||
llfn,
|
||||
args.as_ptr() as *const &llvm::Value,
|
||||
args.len() as c_uint,
|
||||
[].as_ptr(),
|
||||
0 as c_uint,
|
||||
);
|
||||
}
|
||||
self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[fn_name, hash, bitmap_bits]);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn mcdc_tvbitmap_update(
|
||||
&mut self,
|
||||
fn_name: &'ll Value,
|
||||
|
|
@ -1717,39 +1677,21 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
bitmap_index: &'ll Value,
|
||||
mcdc_temp: &'ll Value,
|
||||
) {
|
||||
debug!(
|
||||
"mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?})",
|
||||
fn_name, hash, bitmap_index, mcdc_temp
|
||||
);
|
||||
assert!(
|
||||
crate::llvm_util::get_version() >= (19, 0, 0),
|
||||
"MCDC intrinsics require LLVM 19 or later"
|
||||
);
|
||||
|
||||
let llfn =
|
||||
unsafe { llvm::LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(self.cx().llmod) };
|
||||
let llty = self.cx.type_func(
|
||||
&[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_ptr()],
|
||||
self.cx.type_void(),
|
||||
);
|
||||
let args = &[fn_name, hash, bitmap_index, mcdc_temp];
|
||||
let args = self.check_call("call", llty, llfn, args);
|
||||
unsafe {
|
||||
let _ = llvm::LLVMRustBuildCall(
|
||||
self.llbuilder,
|
||||
llty,
|
||||
llfn,
|
||||
args.as_ptr() as *const &llvm::Value,
|
||||
args.len() as c_uint,
|
||||
[].as_ptr(),
|
||||
0 as c_uint,
|
||||
);
|
||||
}
|
||||
self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", args);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn mcdc_condbitmap_reset(&mut self, mcdc_temp: &'ll Value) {
|
||||
self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn mcdc_condbitmap_update(&mut self, cond_index: &'ll Value, mcdc_temp: &'ll Value) {
|
||||
debug!("mcdc_condbitmap_update() with args ({:?}, {:?})", cond_index, mcdc_temp);
|
||||
assert!(
|
||||
crate::llvm_util::get_version() >= (19, 0, 0),
|
||||
"MCDC intrinsics require LLVM 19 or later"
|
||||
|
|
|
|||
|
|
@ -95,11 +95,10 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
|
|||
// whether we are sharing generics or not. The important thing here is
|
||||
// that the visibility we apply to the declaration is the same one that
|
||||
// has been applied to the definition (wherever that definition may be).
|
||||
unsafe {
|
||||
llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
|
||||
|
||||
let is_generic =
|
||||
instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some();
|
||||
llvm::set_linkage(llfn, llvm::Linkage::ExternalLinkage);
|
||||
unsafe {
|
||||
let is_generic = instance.args.non_erasable_generics().next().is_some();
|
||||
|
||||
let is_hidden = if is_generic {
|
||||
// This is a monomorphization of a generic function.
|
||||
|
|
@ -136,7 +135,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
|
|||
|| !cx.tcx.is_reachable_non_generic(instance_def_id))
|
||||
};
|
||||
if is_hidden {
|
||||
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
|
||||
llvm::set_visibility(llfn, llvm::Visibility::Hidden);
|
||||
}
|
||||
|
||||
// MinGW: For backward compatibility we rely on the linker to decide whether it
|
||||
|
|
|
|||
|
|
@ -219,8 +219,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
llvm::LLVMSetInitializer(g, sc);
|
||||
llvm::LLVMSetGlobalConstant(g, True);
|
||||
llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global);
|
||||
llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
|
||||
}
|
||||
llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
|
||||
(s.to_owned(), g)
|
||||
})
|
||||
.1;
|
||||
|
|
@ -392,3 +392,21 @@ pub(crate) fn get_dllimport<'tcx>(
|
|||
tcx.native_library(id)
|
||||
.and_then(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name))
|
||||
}
|
||||
|
||||
/// Extension trait for explicit casts to `*const c_char`.
|
||||
pub(crate) trait AsCCharPtr {
|
||||
/// Equivalent to `self.as_ptr().cast()`, but only casts to `*const c_char`.
|
||||
fn as_c_char_ptr(&self) -> *const c_char;
|
||||
}
|
||||
|
||||
impl AsCCharPtr for str {
|
||||
fn as_c_char_ptr(&self) -> *const c_char {
|
||||
self.as_ptr().cast()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsCCharPtr for [u8] {
|
||||
fn as_c_char_ptr(&self) -> *const c_char {
|
||||
self.as_ptr().cast()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use rustc_target::abi::{
|
|||
};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::common::CodegenCx;
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::errors::{
|
||||
InvalidMinimumAlignmentNotPowerOfTwo, InvalidMinimumAlignmentTooLarge, SymbolAlreadyDefined,
|
||||
};
|
||||
|
|
@ -172,29 +172,27 @@ fn check_and_apply_linkage<'ll, 'tcx>(
|
|||
if let Some(linkage) = attrs.import_linkage {
|
||||
debug!("get_static: sym={} linkage={:?}", sym, linkage);
|
||||
|
||||
unsafe {
|
||||
// Declare a symbol `foo` with the desired linkage.
|
||||
let g1 = cx.declare_global(sym, cx.type_i8());
|
||||
llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
|
||||
// Declare a symbol `foo` with the desired linkage.
|
||||
let g1 = cx.declare_global(sym, cx.type_i8());
|
||||
llvm::set_linkage(g1, base::linkage_to_llvm(linkage));
|
||||
|
||||
// Declare an internal global `extern_with_linkage_foo` which
|
||||
// is initialized with the address of `foo`. If `foo` is
|
||||
// discarded during linking (for example, if `foo` has weak
|
||||
// linkage and there are no definitions), then
|
||||
// `extern_with_linkage_foo` will instead be initialized to
|
||||
// zero.
|
||||
let mut real_name = "_rust_extern_with_linkage_".to_string();
|
||||
real_name.push_str(sym);
|
||||
let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
|
||||
cx.sess().dcx().emit_fatal(SymbolAlreadyDefined {
|
||||
span: cx.tcx.def_span(def_id),
|
||||
symbol_name: sym,
|
||||
})
|
||||
});
|
||||
llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
|
||||
llvm::LLVMSetInitializer(g2, g1);
|
||||
g2
|
||||
}
|
||||
// Declare an internal global `extern_with_linkage_foo` which
|
||||
// is initialized with the address of `foo`. If `foo` is
|
||||
// discarded during linking (for example, if `foo` has weak
|
||||
// linkage and there are no definitions), then
|
||||
// `extern_with_linkage_foo` will instead be initialized to
|
||||
// zero.
|
||||
let mut real_name = "_rust_extern_with_linkage_".to_string();
|
||||
real_name.push_str(sym);
|
||||
let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
|
||||
cx.sess().dcx().emit_fatal(SymbolAlreadyDefined {
|
||||
span: cx.tcx.def_span(def_id),
|
||||
symbol_name: sym,
|
||||
})
|
||||
});
|
||||
llvm::set_linkage(g2, llvm::Linkage::InternalLinkage);
|
||||
unsafe { llvm::LLVMSetInitializer(g2, g1) };
|
||||
g2
|
||||
} else if cx.tcx.sess.target.arch == "x86"
|
||||
&& let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym)
|
||||
{
|
||||
|
|
@ -224,23 +222,21 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
align: Align,
|
||||
kind: Option<&str>,
|
||||
) -> &'ll Value {
|
||||
unsafe {
|
||||
let gv = match kind {
|
||||
Some(kind) if !self.tcx.sess.fewer_names() => {
|
||||
let name = self.generate_local_symbol_name(kind);
|
||||
let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| {
|
||||
bug!("symbol `{}` is already defined", name);
|
||||
});
|
||||
llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage);
|
||||
gv
|
||||
}
|
||||
_ => self.define_private_global(self.val_ty(cv)),
|
||||
};
|
||||
llvm::LLVMSetInitializer(gv, cv);
|
||||
set_global_alignment(self, gv, align);
|
||||
llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global);
|
||||
gv
|
||||
}
|
||||
let gv = match kind {
|
||||
Some(kind) if !self.tcx.sess.fewer_names() => {
|
||||
let name = self.generate_local_symbol_name(kind);
|
||||
let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| {
|
||||
bug!("symbol `{}` is already defined", name);
|
||||
});
|
||||
llvm::set_linkage(gv, llvm::Linkage::PrivateLinkage);
|
||||
gv
|
||||
}
|
||||
_ => self.define_private_global(self.val_ty(cv)),
|
||||
};
|
||||
unsafe { llvm::LLVMSetInitializer(gv, cv) };
|
||||
set_global_alignment(self, gv, align);
|
||||
llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global);
|
||||
gv
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
|
@ -292,9 +288,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
let g = self.declare_global(sym, llty);
|
||||
|
||||
if !self.tcx.is_reachable_non_generic(def_id) {
|
||||
unsafe {
|
||||
llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden);
|
||||
}
|
||||
llvm::set_visibility(g, llvm::Visibility::Hidden);
|
||||
}
|
||||
|
||||
g
|
||||
|
|
@ -312,7 +306,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
llvm::set_thread_local_mode(g, self.tls_model);
|
||||
}
|
||||
|
||||
let dso_local = unsafe { self.should_assume_dso_local(g, true) };
|
||||
let dso_local = self.should_assume_dso_local(g, true);
|
||||
if dso_local {
|
||||
unsafe {
|
||||
llvm::LLVMRustSetDSOLocal(g, true);
|
||||
|
|
@ -401,18 +395,18 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
let name = llvm::get_value_name(g).to_vec();
|
||||
llvm::set_value_name(g, b"");
|
||||
|
||||
let linkage = llvm::LLVMRustGetLinkage(g);
|
||||
let visibility = llvm::LLVMRustGetVisibility(g);
|
||||
let linkage = llvm::get_linkage(g);
|
||||
let visibility = llvm::get_visibility(g);
|
||||
|
||||
let new_g = llvm::LLVMRustGetOrInsertGlobal(
|
||||
self.llmod,
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
val_llty,
|
||||
);
|
||||
|
||||
llvm::LLVMRustSetLinkage(new_g, linkage);
|
||||
llvm::LLVMRustSetVisibility(new_g, visibility);
|
||||
llvm::set_linkage(new_g, linkage);
|
||||
llvm::set_visibility(new_g, visibility);
|
||||
|
||||
// The old global has had its name removed but is returned by
|
||||
// get_static since it is in the instance cache. Provide an
|
||||
|
|
@ -457,7 +451,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
if let Some(section) = attrs.link_section {
|
||||
let section = llvm::LLVMMDStringInContext2(
|
||||
self.llcx,
|
||||
section.as_str().as_ptr().cast(),
|
||||
section.as_str().as_c_char_ptr(),
|
||||
section.as_str().len(),
|
||||
);
|
||||
assert!(alloc.provenance().ptrs().is_empty());
|
||||
|
|
@ -468,7 +462,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
let bytes =
|
||||
alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len());
|
||||
let alloc =
|
||||
llvm::LLVMMDStringInContext2(self.llcx, bytes.as_ptr().cast(), bytes.len());
|
||||
llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len());
|
||||
let data = [section, alloc];
|
||||
let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len());
|
||||
let val = llvm::LLVMMetadataAsValue(self.llcx, meta);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ use smallvec::SmallVec;
|
|||
|
||||
use crate::back::write::to_llvm_code_model;
|
||||
use crate::callee::get_fn;
|
||||
use crate::common::AsCCharPtr;
|
||||
use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
|
||||
use crate::llvm::{Metadata, MetadataType};
|
||||
use crate::type_::Type;
|
||||
|
|
@ -80,6 +81,7 @@ pub(crate) struct CodegenCx<'ll, 'tcx> {
|
|||
|
||||
pub isize_ty: &'ll Type,
|
||||
|
||||
/// Extra codegen state needed when coverage instrumentation is enabled.
|
||||
pub coverage_cx: Option<coverageinfo::CrateCoverageContext<'ll, 'tcx>>,
|
||||
pub dbg_cx: Option<debuginfo::CodegenUnitDebugContext<'ll, 'tcx>>,
|
||||
|
||||
|
|
@ -208,133 +210,111 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
// If skipping the PLT is enabled, we need to add some module metadata
|
||||
// to ensure intrinsic calls don't use it.
|
||||
if !sess.needs_plt() {
|
||||
let avoid_plt = c"RtLibUseGOT".as_ptr();
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
|
||||
}
|
||||
llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Warning, "RtLibUseGOT", 1);
|
||||
}
|
||||
|
||||
// Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
|
||||
if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
|
||||
let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr();
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
canonical_jump_tables,
|
||||
1,
|
||||
);
|
||||
}
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Override,
|
||||
"CFI Canonical Jump Tables",
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
// If we're normalizing integers with CFI, ensure LLVM generated functions do the same.
|
||||
// See https://github.com/llvm/llvm-project/pull/104826
|
||||
if sess.is_sanitizer_cfi_normalize_integers_enabled() {
|
||||
let cfi_normalize_integers = c"cfi-normalize-integers".as_ptr().cast();
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
cfi_normalize_integers,
|
||||
1,
|
||||
);
|
||||
}
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Override,
|
||||
"cfi-normalize-integers",
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
// Enable LTO unit splitting if specified or if CFI is enabled. (See
|
||||
// https://reviews.llvm.org/D53891.)
|
||||
if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
|
||||
let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr();
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
enable_split_lto_unit,
|
||||
1,
|
||||
);
|
||||
}
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Override,
|
||||
"EnableSplitLTOUnit",
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
|
||||
if sess.is_sanitizer_kcfi_enabled() {
|
||||
let kcfi = c"kcfi".as_ptr();
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
|
||||
}
|
||||
llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Override, "kcfi", 1);
|
||||
|
||||
// Add "kcfi-offset" module flag with -Z patchable-function-entry (See
|
||||
// https://reviews.llvm.org/D141172).
|
||||
let pfe =
|
||||
PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry);
|
||||
if pfe.prefix() > 0 {
|
||||
let kcfi_offset = c"kcfi-offset".as_ptr().cast();
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
kcfi_offset,
|
||||
pfe.prefix().into(),
|
||||
);
|
||||
}
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Override,
|
||||
"kcfi-offset",
|
||||
pfe.prefix().into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
|
||||
if sess.target.is_like_msvc {
|
||||
unsafe {
|
||||
match sess.opts.cg.control_flow_guard {
|
||||
CFGuard::Disabled => {}
|
||||
CFGuard::NoChecks => {
|
||||
// Set `cfguard=1` module flag to emit metadata only.
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"cfguard".as_ptr() as *const _,
|
||||
1,
|
||||
)
|
||||
}
|
||||
CFGuard::Checks => {
|
||||
// Set `cfguard=2` module flag to emit metadata and checks.
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"cfguard".as_ptr() as *const _,
|
||||
2,
|
||||
)
|
||||
}
|
||||
match sess.opts.cg.control_flow_guard {
|
||||
CFGuard::Disabled => {}
|
||||
CFGuard::NoChecks => {
|
||||
// Set `cfguard=1` module flag to emit metadata only.
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Warning,
|
||||
"cfguard",
|
||||
1,
|
||||
);
|
||||
}
|
||||
CFGuard::Checks => {
|
||||
// Set `cfguard=2` module flag to emit metadata and checks.
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Warning,
|
||||
"cfguard",
|
||||
2,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
|
||||
if sess.target.arch == "aarch64" {
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"branch-target-enforcement".as_ptr(),
|
||||
bti.into(),
|
||||
);
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"sign-return-address".as_ptr(),
|
||||
pac_ret.is_some().into(),
|
||||
);
|
||||
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"sign-return-address-all".as_ptr(),
|
||||
pac_opts.leaf.into(),
|
||||
);
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"sign-return-address-with-bkey".as_ptr(),
|
||||
u32::from(pac_opts.key == PAuthKey::B),
|
||||
);
|
||||
}
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Min,
|
||||
"branch-target-enforcement",
|
||||
bti.into(),
|
||||
);
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Min,
|
||||
"sign-return-address",
|
||||
pac_ret.is_some().into(),
|
||||
);
|
||||
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Min,
|
||||
"sign-return-address-all",
|
||||
pac_opts.leaf.into(),
|
||||
);
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Min,
|
||||
"sign-return-address-with-bkey",
|
||||
u32::from(pac_opts.key == PAuthKey::B),
|
||||
);
|
||||
} else {
|
||||
bug!(
|
||||
"branch-protection used on non-AArch64 target; \
|
||||
|
|
@ -345,59 +325,46 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
|
||||
// Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
|
||||
if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
c"cf-protection-branch".as_ptr(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Override,
|
||||
"cf-protection-branch",
|
||||
1,
|
||||
);
|
||||
}
|
||||
if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
c"cf-protection-return".as_ptr(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Override,
|
||||
"cf-protection-return",
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
if sess.opts.unstable_opts.virtual_function_elimination {
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
c"Virtual Function Elim".as_ptr(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Error,
|
||||
"Virtual Function Elim",
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
// Set module flag to enable Windows EHCont Guard (/guard:ehcont).
|
||||
if sess.opts.unstable_opts.ehcont_guard {
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"ehcontguard".as_ptr() as *const _,
|
||||
1,
|
||||
)
|
||||
}
|
||||
llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Warning, "ehcontguard", 1);
|
||||
}
|
||||
|
||||
match sess.opts.unstable_opts.function_return {
|
||||
FunctionReturn::Keep => {}
|
||||
FunctionReturn::ThunkExtern => unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
FunctionReturn::ThunkExtern => {
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
c"function_return_thunk_extern".as_ptr(),
|
||||
llvm::ModuleFlagMergeBehavior::Override,
|
||||
"function_return_thunk_extern",
|
||||
1,
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support())
|
||||
|
|
@ -405,15 +372,12 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
// Set up the small-data optimization limit for architectures that use
|
||||
// an LLVM module flag to control this.
|
||||
(Some(threshold), SmallDataThresholdSupport::LlvmModuleFlag(flag)) => {
|
||||
let flag = SmallCStr::new(flag.as_ref());
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
flag.as_c_str().as_ptr(),
|
||||
threshold as u32,
|
||||
)
|
||||
}
|
||||
llvm::add_module_flag_u32(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Error,
|
||||
&flag,
|
||||
threshold as u32,
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
|
|
@ -428,7 +392,7 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
let name_metadata = unsafe {
|
||||
llvm::LLVMMDStringInContext2(
|
||||
llcx,
|
||||
rustc_producer.as_ptr().cast(),
|
||||
rustc_producer.as_c_char_ptr(),
|
||||
rustc_producer.as_bytes().len(),
|
||||
)
|
||||
};
|
||||
|
|
@ -447,33 +411,29 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
// If llvm_abiname is empty, emit nothing.
|
||||
let llvm_abiname = &sess.target.options.llvm_abiname;
|
||||
if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() {
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagString(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
c"target-abi".as_ptr(),
|
||||
llvm_abiname.as_ptr().cast(),
|
||||
llvm_abiname.len(),
|
||||
);
|
||||
}
|
||||
llvm::add_module_flag_str(
|
||||
llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Error,
|
||||
"target-abi",
|
||||
llvm_abiname,
|
||||
);
|
||||
}
|
||||
|
||||
// Add module flags specified via -Z llvm_module_flag
|
||||
for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag {
|
||||
let key = format!("{key}\0");
|
||||
let behavior = match behavior.as_str() {
|
||||
"error" => llvm::LLVMModFlagBehavior::Error,
|
||||
"warning" => llvm::LLVMModFlagBehavior::Warning,
|
||||
"require" => llvm::LLVMModFlagBehavior::Require,
|
||||
"override" => llvm::LLVMModFlagBehavior::Override,
|
||||
"append" => llvm::LLVMModFlagBehavior::Append,
|
||||
"appendunique" => llvm::LLVMModFlagBehavior::AppendUnique,
|
||||
"max" => llvm::LLVMModFlagBehavior::Max,
|
||||
"min" => llvm::LLVMModFlagBehavior::Min,
|
||||
for (key, value, merge_behavior) in &sess.opts.unstable_opts.llvm_module_flag {
|
||||
let merge_behavior = match merge_behavior.as_str() {
|
||||
"error" => llvm::ModuleFlagMergeBehavior::Error,
|
||||
"warning" => llvm::ModuleFlagMergeBehavior::Warning,
|
||||
"require" => llvm::ModuleFlagMergeBehavior::Require,
|
||||
"override" => llvm::ModuleFlagMergeBehavior::Override,
|
||||
"append" => llvm::ModuleFlagMergeBehavior::Append,
|
||||
"appendunique" => llvm::ModuleFlagMergeBehavior::AppendUnique,
|
||||
"max" => llvm::ModuleFlagMergeBehavior::Max,
|
||||
"min" => llvm::ModuleFlagMergeBehavior::Min,
|
||||
// We already checked this during option parsing
|
||||
_ => unreachable!(),
|
||||
};
|
||||
unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) }
|
||||
llvm::add_module_flag_u32(llmod, merge_behavior, key, *value);
|
||||
}
|
||||
|
||||
llmod
|
||||
|
|
@ -592,11 +552,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
&self.statics_to_rauw
|
||||
}
|
||||
|
||||
/// Extra state that is only available when coverage instrumentation is enabled.
|
||||
#[inline]
|
||||
pub(crate) fn coverage_context(
|
||||
&self,
|
||||
) -> Option<&coverageinfo::CrateCoverageContext<'ll, 'tcx>> {
|
||||
self.coverage_cx.as_ref()
|
||||
pub(crate) fn coverage_cx(&self) -> &coverageinfo::CrateCoverageContext<'ll, 'tcx> {
|
||||
self.coverage_cx.as_ref().expect("only called when coverage instrumentation is enabled")
|
||||
}
|
||||
|
||||
pub(crate) fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
|
||||
|
|
@ -605,7 +564,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
unsafe {
|
||||
let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
|
||||
llvm::LLVMSetInitializer(g, array);
|
||||
llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
|
||||
llvm::set_linkage(g, llvm::Linkage::AppendingLinkage);
|
||||
llvm::LLVMSetSection(g, c"llvm.metadata".as_ptr());
|
||||
}
|
||||
}
|
||||
|
|
@ -1099,6 +1058,10 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
|
||||
if self.sess().instrument_coverage() {
|
||||
ifn!("llvm.instrprof.increment", fn(ptr, t_i64, t_i32, t_i32) -> void);
|
||||
if crate::llvm_util::get_version() >= (19, 0, 0) {
|
||||
ifn!("llvm.instrprof.mcdc.parameters", fn(ptr, t_i64, t_i32) -> void);
|
||||
ifn!("llvm.instrprof.mcdc.tvbitmap.update", fn(ptr, t_i64, t_i32, ptr) -> void);
|
||||
}
|
||||
}
|
||||
|
||||
ifn!("llvm.type.test", fn(ptr, t_metadata) -> i1);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
use rustc_middle::mir::coverage::{
|
||||
ConditionInfo, CounterId, CovTerm, DecisionInfo, ExpressionId, MappingKind, SourceRegion,
|
||||
};
|
||||
use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId, SourceRegion};
|
||||
|
||||
/// Must match the layout of `LLVMRustCounterKind`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub enum CounterKind {
|
||||
pub(crate) enum CounterKind {
|
||||
Zero = 0,
|
||||
CounterValueReference = 1,
|
||||
Expression = 2,
|
||||
|
|
@ -25,9 +23,9 @@ pub enum CounterKind {
|
|||
/// Must match the layout of `LLVMRustCounter`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Counter {
|
||||
pub(crate) struct Counter {
|
||||
// Important: The layout (order and types of fields) must match its C++ counterpart.
|
||||
pub kind: CounterKind,
|
||||
pub(crate) kind: CounterKind,
|
||||
id: u32,
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +34,7 @@ impl Counter {
|
|||
pub(crate) const ZERO: Self = Self { kind: CounterKind::Zero, id: 0 };
|
||||
|
||||
/// Constructs a new `Counter` of kind `CounterValueReference`.
|
||||
pub fn counter_value_reference(counter_id: CounterId) -> Self {
|
||||
pub(crate) fn counter_value_reference(counter_id: CounterId) -> Self {
|
||||
Self { kind: CounterKind::CounterValueReference, id: counter_id.as_u32() }
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +57,7 @@ impl Counter {
|
|||
/// Must match the layout of `LLVMRustCounterExprKind`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub enum ExprKind {
|
||||
pub(crate) enum ExprKind {
|
||||
Subtract = 0,
|
||||
Add = 1,
|
||||
}
|
||||
|
|
@ -69,48 +67,13 @@ pub enum ExprKind {
|
|||
/// Must match the layout of `LLVMRustCounterExpression`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct CounterExpression {
|
||||
pub kind: ExprKind,
|
||||
pub lhs: Counter,
|
||||
pub rhs: Counter,
|
||||
pub(crate) struct CounterExpression {
|
||||
pub(crate) kind: ExprKind,
|
||||
pub(crate) lhs: Counter,
|
||||
pub(crate) rhs: Counter,
|
||||
}
|
||||
|
||||
/// Corresponds to enum `llvm::coverage::CounterMappingRegion::RegionKind`.
|
||||
///
|
||||
/// Must match the layout of `LLVMRustCounterMappingRegionKind`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
enum RegionKind {
|
||||
/// A CodeRegion associates some code with a counter
|
||||
CodeRegion = 0,
|
||||
|
||||
/// An ExpansionRegion represents a file expansion region that associates
|
||||
/// a source range with the expansion of a virtual source file, such as
|
||||
/// for a macro instantiation or #include file.
|
||||
ExpansionRegion = 1,
|
||||
|
||||
/// A SkippedRegion represents a source range with code that was skipped
|
||||
/// by a preprocessor or similar means.
|
||||
SkippedRegion = 2,
|
||||
|
||||
/// A GapRegion is like a CodeRegion, but its count is only set as the
|
||||
/// line execution count when its the only region in the line.
|
||||
GapRegion = 3,
|
||||
|
||||
/// A BranchRegion represents leaf-level boolean expressions and is
|
||||
/// associated with two counters, each representing the number of times the
|
||||
/// expression evaluates to true or false.
|
||||
BranchRegion = 4,
|
||||
|
||||
/// A DecisionRegion represents a top-level boolean expression and is
|
||||
/// associated with a variable length bitmap index and condition number.
|
||||
MCDCDecisionRegion = 5,
|
||||
|
||||
/// A Branch Region can be extended to include IDs to facilitate MC/DC.
|
||||
MCDCBranchRegion = 6,
|
||||
}
|
||||
|
||||
mod mcdc {
|
||||
pub(crate) mod mcdc {
|
||||
use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo};
|
||||
|
||||
/// Must match the layout of `LLVMRustMCDCDecisionParameters`.
|
||||
|
|
@ -121,8 +84,6 @@ mod mcdc {
|
|||
num_conditions: u16,
|
||||
}
|
||||
|
||||
// ConditionId in llvm is `unsigned int` at 18 while `int16_t` at
|
||||
// [19](https://github.com/llvm/llvm-project/pull/81257).
|
||||
type LLVMConditionId = i16;
|
||||
|
||||
/// Must match the layout of `LLVMRustMCDCBranchParameters`.
|
||||
|
|
@ -133,38 +94,6 @@ mod mcdc {
|
|||
condition_ids: [LLVMConditionId; 2],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum ParameterTag {
|
||||
None = 0,
|
||||
Decision = 1,
|
||||
Branch = 2,
|
||||
}
|
||||
/// Same layout with `LLVMRustMCDCParameters`
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) struct Parameters {
|
||||
tag: ParameterTag,
|
||||
decision_params: DecisionParameters,
|
||||
branch_params: BranchParameters,
|
||||
}
|
||||
|
||||
impl Parameters {
|
||||
pub(crate) fn none() -> Self {
|
||||
Self {
|
||||
tag: ParameterTag::None,
|
||||
decision_params: Default::default(),
|
||||
branch_params: Default::default(),
|
||||
}
|
||||
}
|
||||
pub(crate) fn decision(decision_params: DecisionParameters) -> Self {
|
||||
Self { tag: ParameterTag::Decision, decision_params, branch_params: Default::default() }
|
||||
}
|
||||
pub(crate) fn branch(branch_params: BranchParameters) -> Self {
|
||||
Self { tag: ParameterTag::Branch, decision_params: Default::default(), branch_params }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConditionInfo> for BranchParameters {
|
||||
fn from(value: ConditionInfo) -> Self {
|
||||
let to_llvm_cond_id = |cond_id: Option<ConditionId>| {
|
||||
|
|
@ -186,267 +115,68 @@ mod mcdc {
|
|||
}
|
||||
}
|
||||
|
||||
/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
|
||||
/// coverage map, in accordance with the
|
||||
/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
|
||||
/// The struct composes fields representing the `Counter` type and value(s) (injected counter
|
||||
/// ID, or expression type and operands), the source file (an indirect index into a "filenames
|
||||
/// array", encoded separately), and source location (start and end positions of the represented
|
||||
/// code region).
|
||||
/// A span of source code coordinates to be embedded in coverage metadata.
|
||||
///
|
||||
/// Corresponds to struct `llvm::coverage::CounterMappingRegion`.
|
||||
///
|
||||
/// Must match the layout of `LLVMRustCounterMappingRegion`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
/// Must match the layout of `LLVMRustCoverageSpan`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct CounterMappingRegion {
|
||||
/// The counter type and type-dependent counter data, if any.
|
||||
counter: Counter,
|
||||
|
||||
/// If the `RegionKind` is a `BranchRegion`, this represents the counter
|
||||
/// for the false branch of the region.
|
||||
false_counter: Counter,
|
||||
|
||||
mcdc_params: mcdc::Parameters,
|
||||
/// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the
|
||||
/// file_id is an index into a function-specific `virtual_file_mapping` array of indexes
|
||||
/// that, in turn, are used to look up the filename for this region.
|
||||
pub(crate) struct CoverageSpan {
|
||||
/// Local index into the function's local-to-global file ID table.
|
||||
/// The value at that index is itself an index into the coverage filename
|
||||
/// table in the CGU's `__llvm_covmap` section.
|
||||
file_id: u32,
|
||||
|
||||
/// If the `RegionKind` is an `ExpansionRegion`, the `expanded_file_id` can be used to find
|
||||
/// the mapping regions created as a result of macro expansion, by checking if their file id
|
||||
/// matches the expanded file id.
|
||||
expanded_file_id: u32,
|
||||
|
||||
/// 1-based starting line of the mapping region.
|
||||
/// 1-based starting line of the source code span.
|
||||
start_line: u32,
|
||||
|
||||
/// 1-based starting column of the mapping region.
|
||||
/// 1-based starting column of the source code span.
|
||||
start_col: u32,
|
||||
|
||||
/// 1-based ending line of the mapping region.
|
||||
/// 1-based ending line of the source code span.
|
||||
end_line: u32,
|
||||
|
||||
/// 1-based ending column of the mapping region. If the high bit is set, the current
|
||||
/// mapping region is a gap area.
|
||||
/// 1-based ending column of the source code span. High bit must be unset.
|
||||
end_col: u32,
|
||||
|
||||
kind: RegionKind,
|
||||
}
|
||||
|
||||
impl CounterMappingRegion {
|
||||
pub(crate) fn from_mapping(
|
||||
mapping_kind: &MappingKind,
|
||||
local_file_id: u32,
|
||||
source_region: &SourceRegion,
|
||||
) -> Self {
|
||||
let &SourceRegion { file_name: _, start_line, start_col, end_line, end_col } =
|
||||
source_region;
|
||||
match *mapping_kind {
|
||||
MappingKind::Code(term) => Self::code_region(
|
||||
Counter::from_term(term),
|
||||
local_file_id,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
),
|
||||
MappingKind::Branch { true_term, false_term } => Self::branch_region(
|
||||
Counter::from_term(true_term),
|
||||
Counter::from_term(false_term),
|
||||
local_file_id,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
),
|
||||
MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
|
||||
Self::mcdc_branch_region(
|
||||
Counter::from_term(true_term),
|
||||
Counter::from_term(false_term),
|
||||
mcdc_params,
|
||||
local_file_id,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
)
|
||||
}
|
||||
MappingKind::MCDCDecision(decision_info) => Self::decision_region(
|
||||
decision_info,
|
||||
local_file_id,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn code_region(
|
||||
counter: Counter,
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter,
|
||||
false_counter: Counter::ZERO,
|
||||
mcdc_params: mcdc::Parameters::none(),
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::CodeRegion,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn branch_region(
|
||||
counter: Counter,
|
||||
false_counter: Counter,
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter,
|
||||
false_counter,
|
||||
mcdc_params: mcdc::Parameters::none(),
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::BranchRegion,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn mcdc_branch_region(
|
||||
counter: Counter,
|
||||
false_counter: Counter,
|
||||
condition_info: ConditionInfo,
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter,
|
||||
false_counter,
|
||||
mcdc_params: mcdc::Parameters::branch(condition_info.into()),
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::MCDCBranchRegion,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn decision_region(
|
||||
decision_info: DecisionInfo,
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
let mcdc_params = mcdc::Parameters::decision(decision_info.into());
|
||||
|
||||
Self {
|
||||
counter: Counter::ZERO,
|
||||
false_counter: Counter::ZERO,
|
||||
mcdc_params,
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::MCDCDecisionRegion,
|
||||
}
|
||||
}
|
||||
|
||||
// This function might be used in the future; the LLVM API is still evolving, as is coverage
|
||||
// support.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn expansion_region(
|
||||
file_id: u32,
|
||||
expanded_file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter: Counter::ZERO,
|
||||
false_counter: Counter::ZERO,
|
||||
mcdc_params: mcdc::Parameters::none(),
|
||||
file_id,
|
||||
expanded_file_id,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::ExpansionRegion,
|
||||
}
|
||||
}
|
||||
|
||||
// This function might be used in the future; the LLVM API is still evolving, as is coverage
|
||||
// support.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn skipped_region(
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter: Counter::ZERO,
|
||||
false_counter: Counter::ZERO,
|
||||
mcdc_params: mcdc::Parameters::none(),
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::SkippedRegion,
|
||||
}
|
||||
}
|
||||
|
||||
// This function might be used in the future; the LLVM API is still evolving, as is coverage
|
||||
// support.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn gap_region(
|
||||
counter: Counter,
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter,
|
||||
false_counter: Counter::ZERO,
|
||||
mcdc_params: mcdc::Parameters::none(),
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col: (1_u32 << 31) | end_col,
|
||||
kind: RegionKind::GapRegion,
|
||||
}
|
||||
impl CoverageSpan {
|
||||
pub(crate) fn from_source_region(file_id: u32, code_region: &SourceRegion) -> Self {
|
||||
let &SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region;
|
||||
// Internally, LLVM uses the high bit of `end_col` to distinguish between
|
||||
// code regions and gap regions, so it can't be used by the column number.
|
||||
assert!(end_col & (1u32 << 31) == 0, "high bit of `end_col` must be unset: {end_col:#X}");
|
||||
Self { file_id, start_line, start_col, end_line, end_col }
|
||||
}
|
||||
}
|
||||
|
||||
/// Must match the layout of `LLVMRustCoverageCodeRegion`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct CodeRegion {
|
||||
pub(crate) span: CoverageSpan,
|
||||
pub(crate) counter: Counter,
|
||||
}
|
||||
|
||||
/// Must match the layout of `LLVMRustCoverageBranchRegion`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct BranchRegion {
|
||||
pub(crate) span: CoverageSpan,
|
||||
pub(crate) true_counter: Counter,
|
||||
pub(crate) false_counter: Counter,
|
||||
}
|
||||
|
||||
/// Must match the layout of `LLVMRustCoverageMCDCBranchRegion`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct MCDCBranchRegion {
|
||||
pub(crate) span: CoverageSpan,
|
||||
pub(crate) true_counter: Counter,
|
||||
pub(crate) false_counter: Counter,
|
||||
pub(crate) mcdc_branch_params: mcdc::BranchParameters,
|
||||
}
|
||||
|
||||
/// Must match the layout of `LLVMRustCoverageMCDCDecisionRegion`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct MCDCDecisionRegion {
|
||||
pub(crate) span: CoverageSpan,
|
||||
pub(crate) mcdc_decision_params: mcdc::DecisionParameters,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,23 @@
|
|||
use std::ffi::CStr;
|
||||
use std::ffi::CString;
|
||||
|
||||
use itertools::Itertools as _;
|
||||
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods};
|
||||
use rustc_abi::Align;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::coverage::MappingKind;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::{bug, mir};
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::def_id::DefIdSet;
|
||||
use rustc_target::spec::HasTargetSpec;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::common::CodegenCx;
|
||||
use crate::coverageinfo::ffi::CounterMappingRegion;
|
||||
use crate::coverageinfo::ffi;
|
||||
use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector};
|
||||
use crate::{coverageinfo, llvm};
|
||||
|
||||
|
|
@ -49,11 +54,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
add_unused_functions(cx);
|
||||
}
|
||||
|
||||
let function_coverage_map = match cx.coverage_context() {
|
||||
Some(ctx) => ctx.take_function_coverage_map(),
|
||||
None => return,
|
||||
};
|
||||
|
||||
let function_coverage_map = cx.coverage_cx().take_function_coverage_map();
|
||||
if function_coverage_map.is_empty() {
|
||||
// This module has no functions with coverage instrumentation
|
||||
return;
|
||||
|
|
@ -77,11 +78,9 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
|
||||
// Generate the coverage map header, which contains the filenames used by
|
||||
// this CGU's coverage mappings, and store it in a well-known global.
|
||||
let cov_data_val = generate_coverage_map(cx, covmap_version, filenames_size, filenames_val);
|
||||
coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
|
||||
generate_covmap_record(cx, covmap_version, filenames_size, filenames_val);
|
||||
|
||||
let mut unused_function_names = Vec::new();
|
||||
let covfun_section_name = coverageinfo::covfun_section_name(cx);
|
||||
|
||||
// Encode coverage mappings and generate function records
|
||||
for (instance, function_coverage) in function_coverage_entries {
|
||||
|
|
@ -110,9 +109,8 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
unused_function_names.push(mangled_function_name);
|
||||
}
|
||||
|
||||
save_function_record(
|
||||
generate_covfun_record(
|
||||
cx,
|
||||
&covfun_section_name,
|
||||
mangled_function_name,
|
||||
source_hash,
|
||||
filenames_ref,
|
||||
|
|
@ -237,7 +235,10 @@ fn encode_mappings_for_function(
|
|||
let expressions = function_coverage.counter_expressions().collect::<Vec<_>>();
|
||||
|
||||
let mut virtual_file_mapping = VirtualFileMapping::default();
|
||||
let mut mapping_regions = Vec::with_capacity(counter_regions.len());
|
||||
let mut code_regions = vec![];
|
||||
let mut branch_regions = vec![];
|
||||
let mut mcdc_branch_regions = vec![];
|
||||
let mut mcdc_decision_regions = vec![];
|
||||
|
||||
// Group mappings into runs with the same filename, preserving the order
|
||||
// yielded by `FunctionCoverage`.
|
||||
|
|
@ -257,11 +258,36 @@ fn encode_mappings_for_function(
|
|||
// form suitable for FFI.
|
||||
for (mapping_kind, region) in counter_regions_for_file {
|
||||
debug!("Adding counter {mapping_kind:?} to map for {region:?}");
|
||||
mapping_regions.push(CounterMappingRegion::from_mapping(
|
||||
&mapping_kind,
|
||||
local_file_id.as_u32(),
|
||||
region,
|
||||
));
|
||||
let span = ffi::CoverageSpan::from_source_region(local_file_id.as_u32(), region);
|
||||
match mapping_kind {
|
||||
MappingKind::Code(term) => {
|
||||
code_regions
|
||||
.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) });
|
||||
}
|
||||
MappingKind::Branch { true_term, false_term } => {
|
||||
branch_regions.push(ffi::BranchRegion {
|
||||
span,
|
||||
true_counter: ffi::Counter::from_term(true_term),
|
||||
false_counter: ffi::Counter::from_term(false_term),
|
||||
});
|
||||
}
|
||||
MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
|
||||
mcdc_branch_regions.push(ffi::MCDCBranchRegion {
|
||||
span,
|
||||
true_counter: ffi::Counter::from_term(true_term),
|
||||
false_counter: ffi::Counter::from_term(false_term),
|
||||
mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
|
||||
});
|
||||
}
|
||||
MappingKind::MCDCDecision(mcdc_decision_params) => {
|
||||
mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
|
||||
span,
|
||||
mcdc_decision_params: ffi::mcdc::DecisionParameters::from(
|
||||
mcdc_decision_params,
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -270,21 +296,24 @@ fn encode_mappings_for_function(
|
|||
coverageinfo::write_mapping_to_buffer(
|
||||
virtual_file_mapping.into_vec(),
|
||||
expressions,
|
||||
mapping_regions,
|
||||
&code_regions,
|
||||
&branch_regions,
|
||||
&mcdc_branch_regions,
|
||||
&mcdc_decision_regions,
|
||||
buffer,
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
/// Construct coverage map header and the array of function records, and combine them into the
|
||||
/// coverage map. Save the coverage map data into the LLVM IR as a static global using a
|
||||
/// specific, well-known section and name.
|
||||
fn generate_coverage_map<'ll>(
|
||||
/// Generates the contents of the covmap record for this CGU, which mostly
|
||||
/// consists of a header and a list of filenames. The record is then stored
|
||||
/// as a global variable in the `__llvm_covmap` section.
|
||||
fn generate_covmap_record<'ll>(
|
||||
cx: &CodegenCx<'ll, '_>,
|
||||
version: u32,
|
||||
filenames_size: usize,
|
||||
filenames_val: &'ll llvm::Value,
|
||||
) -> &'ll llvm::Value {
|
||||
) {
|
||||
debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
|
||||
|
||||
// Create the coverage data header (Note, fields 0 and 2 are now always zero,
|
||||
|
|
@ -299,15 +328,37 @@ fn generate_coverage_map<'ll>(
|
|||
);
|
||||
|
||||
// Create the complete LLVM coverage data value to add to the LLVM IR
|
||||
cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false)
|
||||
let covmap_data =
|
||||
cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false);
|
||||
|
||||
let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
|
||||
}))
|
||||
.unwrap();
|
||||
debug!("covmap var name: {:?}", covmap_var_name);
|
||||
|
||||
let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
|
||||
}))
|
||||
.expect("covmap section name should not contain NUL");
|
||||
debug!("covmap section name: {:?}", covmap_section_name);
|
||||
|
||||
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(covmap_data), &covmap_var_name);
|
||||
llvm::set_initializer(llglobal, covmap_data);
|
||||
llvm::set_global_constant(llglobal, true);
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_section(llglobal, &covmap_section_name);
|
||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||
// <https://llvm.org/docs/CoverageMappingFormat.html>
|
||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
||||
cx.add_used_global(llglobal);
|
||||
}
|
||||
|
||||
/// Construct a function record and combine it with the function's coverage mapping data.
|
||||
/// Save the function record into the LLVM IR as a static global using a
|
||||
/// specific, well-known section and name.
|
||||
fn save_function_record(
|
||||
/// Generates the contents of the covfun record for this function, which
|
||||
/// contains the function's coverage mapping data. The record is then stored
|
||||
/// as a global variable in the `__llvm_covfun` section.
|
||||
fn generate_covfun_record(
|
||||
cx: &CodegenCx<'_, '_>,
|
||||
covfun_section_name: &CStr,
|
||||
mangled_function_name: &str,
|
||||
source_hash: u64,
|
||||
filenames_ref: u64,
|
||||
|
|
@ -334,13 +385,28 @@ fn save_function_record(
|
|||
/*packed=*/ true,
|
||||
);
|
||||
|
||||
coverageinfo::save_func_record_to_mod(
|
||||
cx,
|
||||
covfun_section_name,
|
||||
func_name_hash,
|
||||
func_record_val,
|
||||
is_used,
|
||||
);
|
||||
// Choose a variable name to hold this function's covfun data.
|
||||
// Functions that are used have a suffix ("u") to distinguish them from
|
||||
// unused copies of the same function (from different CGUs), so that if a
|
||||
// linker sees both it won't discard the used copy's data.
|
||||
let func_record_var_name =
|
||||
CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
|
||||
.unwrap();
|
||||
debug!("function record var name: {:?}", func_record_var_name);
|
||||
|
||||
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
|
||||
llvm::set_initializer(llglobal, func_record_val);
|
||||
llvm::set_global_constant(llglobal, true);
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
|
||||
llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
|
||||
llvm::set_section(llglobal, cx.covfun_section_name());
|
||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||
// <https://llvm.org/docs/CoverageMappingFormat.html>
|
||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
||||
if cx.target_spec().supports_comdat() {
|
||||
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
|
||||
}
|
||||
cx.add_used_global(llglobal);
|
||||
}
|
||||
|
||||
/// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
|
||||
|
|
@ -472,9 +538,5 @@ fn add_unused_function_coverage<'tcx>(
|
|||
// zero, because none of its counters/expressions are marked as seen.
|
||||
let function_coverage = FunctionCoverageCollector::unused(instance, function_coverage_info);
|
||||
|
||||
if let Some(coverage_context) = cx.coverage_context() {
|
||||
coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage);
|
||||
} else {
|
||||
bug!("Could not get the `coverage_context`");
|
||||
}
|
||||
cx.coverage_cx().function_coverage_map.borrow_mut().insert(instance, function_coverage);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,20 @@
|
|||
use std::cell::RefCell;
|
||||
use std::cell::{OnceCell, RefCell};
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
use libc::c_uint;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods,
|
||||
MiscCodegenMethods, StaticCodegenMethods,
|
||||
BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_llvm::RustString;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::coverage::CoverageKind;
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::ty::layout::HasTyCtxt;
|
||||
use rustc_target::abi::{Align, Size};
|
||||
use rustc_target::spec::HasTargetSpec;
|
||||
use rustc_target::abi::Size;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::common::CodegenCx;
|
||||
use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion};
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::coverageinfo::map_data::FunctionCoverageCollector;
|
||||
use crate::llvm;
|
||||
|
||||
|
|
@ -33,6 +29,8 @@ pub(crate) struct CrateCoverageContext<'ll, 'tcx> {
|
|||
RefCell<FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>,
|
||||
pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
|
||||
pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>,
|
||||
|
||||
covfun_section_name: OnceCell<CString>,
|
||||
}
|
||||
|
||||
impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
|
||||
|
|
@ -41,6 +39,7 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
|
|||
function_coverage_map: Default::default(),
|
||||
pgo_func_name_var_map: Default::default(),
|
||||
mcdc_condition_bitmap_map: Default::default(),
|
||||
covfun_section_name: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,27 +66,38 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// These methods used to be part of trait `CoverageInfoMethods`, which no longer
|
||||
// exists after most coverage code was moved out of SSA.
|
||||
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
||||
pub(crate) fn coverageinfo_finalize(&self) {
|
||||
mapgen::finalize(self)
|
||||
}
|
||||
|
||||
/// Returns the section name to use when embedding per-function coverage information
|
||||
/// in the object file, according to the target's object file format. LLVM's coverage
|
||||
/// tools use information from this section when producing coverage reports.
|
||||
///
|
||||
/// Typical values are:
|
||||
/// - `__llvm_covfun` on Linux
|
||||
/// - `__LLVM_COV,__llvm_covfun` on macOS (includes `__LLVM_COV,` segment prefix)
|
||||
/// - `.lcovfun$M` on Windows (includes `$M` sorting suffix)
|
||||
fn covfun_section_name(&self) -> &CStr {
|
||||
self.coverage_cx().covfun_section_name.get_or_init(|| {
|
||||
CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
llvm::LLVMRustCoverageWriteFuncSectionNameToString(self.llmod, s);
|
||||
}))
|
||||
.expect("covfun section name should not contain NUL")
|
||||
})
|
||||
}
|
||||
|
||||
/// For LLVM codegen, returns a function-specific `Value` for a global
|
||||
/// string, to hold the function name passed to LLVM intrinsic
|
||||
/// `instrprof.increment()`. The `Value` is only created once per instance.
|
||||
/// Multiple invocations with the same instance return the same `Value`.
|
||||
fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
|
||||
if let Some(coverage_context) = self.coverage_context() {
|
||||
debug!("getting pgo_func_name_var for instance={:?}", instance);
|
||||
let mut pgo_func_name_var_map = coverage_context.pgo_func_name_var_map.borrow_mut();
|
||||
pgo_func_name_var_map
|
||||
.entry(instance)
|
||||
.or_insert_with(|| create_pgo_func_name_var(self, instance))
|
||||
} else {
|
||||
bug!("Could not get the `coverage_context`");
|
||||
}
|
||||
debug!("getting pgo_func_name_var for instance={:?}", instance);
|
||||
let mut pgo_func_name_var_map = self.coverage_cx().pgo_func_name_var_map.borrow_mut();
|
||||
pgo_func_name_var_map
|
||||
.entry(instance)
|
||||
.or_insert_with(|| create_pgo_func_name_var(self, instance))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -121,11 +131,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
cond_bitmaps.push(cond_bitmap);
|
||||
}
|
||||
|
||||
self.coverage_context()
|
||||
.expect("always present when coverage is enabled")
|
||||
.mcdc_condition_bitmap_map
|
||||
.borrow_mut()
|
||||
.insert(instance, cond_bitmaps);
|
||||
self.coverage_cx().mcdc_condition_bitmap_map.borrow_mut().insert(instance, cond_bitmaps);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
|
@ -146,8 +152,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
return;
|
||||
};
|
||||
|
||||
let Some(coverage_context) = bx.coverage_context() else { return };
|
||||
let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
|
||||
let mut coverage_map = bx.coverage_cx().function_coverage_map.borrow_mut();
|
||||
let func_coverage = coverage_map
|
||||
.entry(instance)
|
||||
.or_insert_with(|| FunctionCoverageCollector::new(instance, function_coverage_info));
|
||||
|
|
@ -189,7 +194,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
}
|
||||
CoverageKind::CondBitmapUpdate { index, decision_depth } => {
|
||||
drop(coverage_map);
|
||||
let cond_bitmap = coverage_context
|
||||
let cond_bitmap = bx
|
||||
.coverage_cx()
|
||||
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
|
||||
.expect("mcdc cond bitmap should have been allocated for updating");
|
||||
let cond_index = bx.const_i32(index as i32);
|
||||
|
|
@ -197,7 +203,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
}
|
||||
CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => {
|
||||
drop(coverage_map);
|
||||
let cond_bitmap = coverage_context
|
||||
let cond_bitmap = bx.coverage_cx()
|
||||
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
|
||||
.expect("mcdc cond bitmap should have been allocated for merging into the global bitmap");
|
||||
assert!(
|
||||
|
|
@ -209,6 +215,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
let hash = bx.const_u64(function_coverage_info.function_source_hash);
|
||||
let bitmap_index = bx.const_u32(bitmap_idx);
|
||||
bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap);
|
||||
bx.mcdc_condbitmap_reset(cond_bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -229,7 +236,7 @@ fn create_pgo_func_name_var<'ll, 'tcx>(
|
|||
unsafe {
|
||||
llvm::LLVMRustCoverageCreatePGOFuncNameVar(
|
||||
llfn,
|
||||
mangled_fn_name.as_ptr().cast(),
|
||||
mangled_fn_name.as_c_char_ptr(),
|
||||
mangled_fn_name.len(),
|
||||
)
|
||||
}
|
||||
|
|
@ -241,7 +248,7 @@ pub(crate) fn write_filenames_section_to_buffer<'a>(
|
|||
) {
|
||||
let (pointers, lengths) = filenames
|
||||
.into_iter()
|
||||
.map(|s: &str| (s.as_ptr().cast(), s.len()))
|
||||
.map(|s: &str| (s.as_c_char_ptr(), s.len()))
|
||||
.unzip::<_, _, Vec<_>, Vec<_>>();
|
||||
|
||||
unsafe {
|
||||
|
|
@ -257,8 +264,11 @@ pub(crate) fn write_filenames_section_to_buffer<'a>(
|
|||
|
||||
pub(crate) fn write_mapping_to_buffer(
|
||||
virtual_file_mapping: Vec<u32>,
|
||||
expressions: Vec<CounterExpression>,
|
||||
mapping_regions: Vec<CounterMappingRegion>,
|
||||
expressions: Vec<ffi::CounterExpression>,
|
||||
code_regions: &[ffi::CodeRegion],
|
||||
branch_regions: &[ffi::BranchRegion],
|
||||
mcdc_branch_regions: &[ffi::MCDCBranchRegion],
|
||||
mcdc_decision_regions: &[ffi::MCDCDecisionRegion],
|
||||
buffer: &RustString,
|
||||
) {
|
||||
unsafe {
|
||||
|
|
@ -267,96 +277,23 @@ pub(crate) fn write_mapping_to_buffer(
|
|||
virtual_file_mapping.len() as c_uint,
|
||||
expressions.as_ptr(),
|
||||
expressions.len() as c_uint,
|
||||
mapping_regions.as_ptr(),
|
||||
mapping_regions.len() as c_uint,
|
||||
code_regions.as_ptr(),
|
||||
code_regions.len() as c_uint,
|
||||
branch_regions.as_ptr(),
|
||||
branch_regions.len() as c_uint,
|
||||
mcdc_branch_regions.as_ptr(),
|
||||
mcdc_branch_regions.len() as c_uint,
|
||||
mcdc_decision_regions.as_ptr(),
|
||||
mcdc_decision_regions.len() as c_uint,
|
||||
buffer,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 {
|
||||
unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_ptr().cast(), bytes.len()) }
|
||||
unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_c_char_ptr(), bytes.len()) }
|
||||
}
|
||||
|
||||
pub(crate) fn mapping_version() -> u32 {
|
||||
unsafe { llvm::LLVMRustCoverageMappingVersion() }
|
||||
}
|
||||
|
||||
pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
cov_data_val: &'ll llvm::Value,
|
||||
) {
|
||||
let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
|
||||
}))
|
||||
.unwrap();
|
||||
debug!("covmap var name: {:?}", covmap_var_name);
|
||||
|
||||
let covmap_section_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
llvm::LLVMRustCoverageWriteMapSectionNameToString(cx.llmod, s);
|
||||
}))
|
||||
.expect("covmap section name should not contain NUL");
|
||||
debug!("covmap section name: {:?}", covmap_section_name);
|
||||
|
||||
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name);
|
||||
llvm::set_initializer(llglobal, cov_data_val);
|
||||
llvm::set_global_constant(llglobal, true);
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_section(llglobal, &covmap_section_name);
|
||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
||||
cx.add_used_global(llglobal);
|
||||
}
|
||||
|
||||
pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
covfun_section_name: &CStr,
|
||||
func_name_hash: u64,
|
||||
func_record_val: &'ll llvm::Value,
|
||||
is_used: bool,
|
||||
) {
|
||||
// Assign a name to the function record. This is used to merge duplicates.
|
||||
//
|
||||
// In LLVM, a "translation unit" (effectively, a `Crate` in Rust) can describe functions that
|
||||
// are included-but-not-used. If (or when) Rust generates functions that are
|
||||
// included-but-not-used, note that a dummy description for a function included-but-not-used
|
||||
// in a Crate can be replaced by full description provided by a different Crate. The two kinds
|
||||
// of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by
|
||||
// appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging.
|
||||
let func_record_var_name =
|
||||
CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
|
||||
.unwrap();
|
||||
debug!("function record var name: {:?}", func_record_var_name);
|
||||
debug!("function record section name: {:?}", covfun_section_name);
|
||||
|
||||
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
|
||||
llvm::set_initializer(llglobal, func_record_val);
|
||||
llvm::set_global_constant(llglobal, true);
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
|
||||
llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
|
||||
llvm::set_section(llglobal, covfun_section_name);
|
||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
||||
if cx.target_spec().supports_comdat() {
|
||||
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
|
||||
}
|
||||
cx.add_used_global(llglobal);
|
||||
}
|
||||
|
||||
/// Returns the section name string to pass through to the linker when embedding
|
||||
/// per-function coverage information in the object file, according to the target
|
||||
/// platform's object file format.
|
||||
///
|
||||
/// LLVM's coverage tools read coverage mapping details from this section when
|
||||
/// producing coverage reports.
|
||||
///
|
||||
/// Typical values are:
|
||||
/// - `__llvm_covfun` on Linux
|
||||
/// - `__LLVM_COV,__llvm_covfun` on macOS (includes `__LLVM_COV,` segment prefix)
|
||||
/// - `.lcovfun$M` on Windows (includes `$M` sorting suffix)
|
||||
pub(crate) fn covfun_section_name(cx: &CodegenCx<'_, '_>) -> CString {
|
||||
CString::new(llvm::build_byte_buffer(|s| unsafe {
|
||||
llvm::LLVMRustCoverageWriteFuncSectionNameToString(cx.llmod, s);
|
||||
}))
|
||||
.expect("covfun section name should not contain NUL")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
|
|||
llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents));
|
||||
llvm::LLVMSetGlobalConstant(section_var, llvm::True);
|
||||
llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global);
|
||||
llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
|
||||
llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
|
||||
// This should make sure that the whole section is not larger than
|
||||
// the string it contains. Otherwise we get a warning from GDB.
|
||||
llvm::LLVMSetAlignment(section_var, 1);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_na
|
|||
use super::utils::{
|
||||
DIB, create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit,
|
||||
};
|
||||
use crate::common::CodegenCx;
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::debuginfo::metadata::type_map::build_type_with_children;
|
||||
use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
|
||||
use crate::llvm::debuginfo::{
|
||||
|
|
@ -190,7 +190,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
|||
data_layout.pointer_size.bits(),
|
||||
data_layout.pointer_align.abi.bits() as u32,
|
||||
0, // Ignore DWARF address space.
|
||||
ptr_type_debuginfo_name.as_ptr().cast(),
|
||||
ptr_type_debuginfo_name.as_c_char_ptr(),
|
||||
ptr_type_debuginfo_name.len(),
|
||||
)
|
||||
};
|
||||
|
|
@ -348,7 +348,7 @@ fn build_subroutine_type_di_node<'ll, 'tcx>(
|
|||
size,
|
||||
align,
|
||||
0, // Ignore DWARF address space.
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
)
|
||||
};
|
||||
|
|
@ -518,7 +518,7 @@ fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll D
|
|||
let name = "<recur_type>";
|
||||
llvm::LLVMRustDIBuilderCreateBasicType(
|
||||
DIB(cx),
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
cx.tcx.data_layout.pointer_size.bits(),
|
||||
DW_ATE_unsigned,
|
||||
|
|
@ -640,14 +640,14 @@ pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFi
|
|||
unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateFile(
|
||||
DIB(cx),
|
||||
file_name.as_ptr().cast(),
|
||||
file_name.as_c_char_ptr(),
|
||||
file_name.len(),
|
||||
directory.as_ptr().cast(),
|
||||
directory.as_c_char_ptr(),
|
||||
directory.len(),
|
||||
hash_kind,
|
||||
hash_value.as_ptr().cast(),
|
||||
hash_value.as_c_char_ptr(),
|
||||
hash_value.len(),
|
||||
source.map_or(ptr::null(), |x| x.as_ptr().cast()),
|
||||
source.map_or(ptr::null(), |x| x.as_c_char_ptr()),
|
||||
source.map_or(0, |x| x.len()),
|
||||
)
|
||||
}
|
||||
|
|
@ -662,12 +662,12 @@ fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
|
|||
|
||||
llvm::LLVMRustDIBuilderCreateFile(
|
||||
DIB(cx),
|
||||
file_name.as_ptr().cast(),
|
||||
file_name.as_c_char_ptr(),
|
||||
file_name.len(),
|
||||
directory.as_ptr().cast(),
|
||||
directory.as_c_char_ptr(),
|
||||
directory.len(),
|
||||
llvm::ChecksumKind::None,
|
||||
hash_value.as_ptr().cast(),
|
||||
hash_value.as_c_char_ptr(),
|
||||
hash_value.len(),
|
||||
ptr::null(),
|
||||
0,
|
||||
|
|
@ -788,7 +788,7 @@ fn build_basic_type_di_node<'ll, 'tcx>(
|
|||
let ty_di_node = unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateBasicType(
|
||||
DIB(cx),
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
cx.size_of(t).bits(),
|
||||
encoding,
|
||||
|
|
@ -810,7 +810,7 @@ fn build_basic_type_di_node<'ll, 'tcx>(
|
|||
llvm::LLVMRustDIBuilderCreateTypedef(
|
||||
DIB(cx),
|
||||
ty_di_node,
|
||||
typedef_name.as_ptr().cast(),
|
||||
typedef_name.as_c_char_ptr(),
|
||||
typedef_name.len(),
|
||||
unknown_file_metadata(cx),
|
||||
0,
|
||||
|
|
@ -861,7 +861,7 @@ fn build_param_type_di_node<'ll, 'tcx>(
|
|||
di_node: unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateBasicType(
|
||||
DIB(cx),
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
Size::ZERO.bits(),
|
||||
DW_ATE_unsigned,
|
||||
|
|
@ -948,9 +948,9 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
|
|||
unsafe {
|
||||
let compile_unit_file = llvm::LLVMRustDIBuilderCreateFile(
|
||||
debug_context.builder,
|
||||
name_in_debuginfo.as_ptr().cast(),
|
||||
name_in_debuginfo.as_c_char_ptr(),
|
||||
name_in_debuginfo.len(),
|
||||
work_dir.as_ptr().cast(),
|
||||
work_dir.as_c_char_ptr(),
|
||||
work_dir.len(),
|
||||
llvm::ChecksumKind::None,
|
||||
ptr::null(),
|
||||
|
|
@ -963,7 +963,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
|
|||
debug_context.builder,
|
||||
DW_LANG_RUST,
|
||||
compile_unit_file,
|
||||
producer.as_ptr().cast(),
|
||||
producer.as_c_char_ptr(),
|
||||
producer.len(),
|
||||
tcx.sess.opts.optimize != config::OptLevel::No,
|
||||
c"".as_ptr(),
|
||||
|
|
@ -971,7 +971,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
|
|||
// NB: this doesn't actually have any perceptible effect, it seems. LLVM will instead
|
||||
// put the path supplied to `MCSplitDwarfFile` into the debug info of the final
|
||||
// output(s).
|
||||
split_name.as_ptr().cast(),
|
||||
split_name.as_c_char_ptr(),
|
||||
split_name.len(),
|
||||
kind,
|
||||
0,
|
||||
|
|
@ -1022,7 +1022,7 @@ fn build_field_di_node<'ll, 'tcx>(
|
|||
llvm::LLVMRustDIBuilderCreateMemberType(
|
||||
DIB(cx),
|
||||
owner,
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
|
|
@ -1306,7 +1306,7 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>(
|
|||
llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
|
||||
DIB(cx),
|
||||
None,
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
actual_type_di_node,
|
||||
)
|
||||
|
|
@ -1382,9 +1382,9 @@ pub(crate) fn build_global_var_di_node<'ll>(
|
|||
llvm::LLVMRustDIBuilderCreateStaticVariable(
|
||||
DIB(cx),
|
||||
Some(var_scope),
|
||||
var_name.as_ptr().cast(),
|
||||
var_name.as_c_char_ptr(),
|
||||
var_name.len(),
|
||||
linkage_name.as_ptr().cast(),
|
||||
linkage_name.as_c_char_ptr(),
|
||||
linkage_name.len(),
|
||||
file_metadata,
|
||||
line_number,
|
||||
|
|
@ -1602,9 +1602,9 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>(
|
|||
llvm::LLVMRustDIBuilderCreateStaticVariable(
|
||||
DIB(cx),
|
||||
NO_SCOPE_METADATA,
|
||||
vtable_name.as_ptr().cast(),
|
||||
vtable_name.as_c_char_ptr(),
|
||||
vtable_name.len(),
|
||||
linkage_name.as_ptr().cast(),
|
||||
linkage_name.as_c_char_ptr(),
|
||||
linkage_name.len(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty};
|
|||
use rustc_target::abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants};
|
||||
use smallvec::smallvec;
|
||||
|
||||
use crate::common::CodegenCx;
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::debuginfo::metadata::enums::DiscrResult;
|
||||
use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
|
||||
use crate::debuginfo::metadata::{
|
||||
|
|
@ -359,7 +359,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
|
|||
llvm::LLVMRustDIBuilderCreateStaticMemberType(
|
||||
DIB(cx),
|
||||
enum_type_di_node,
|
||||
TAG_FIELD_NAME.as_ptr().cast(),
|
||||
TAG_FIELD_NAME.as_c_char_ptr(),
|
||||
TAG_FIELD_NAME.len(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
|
|
@ -537,7 +537,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
|
|||
llvm::LLVMRustDIBuilderCreateStaticMemberType(
|
||||
DIB(cx),
|
||||
wrapper_struct_type_di_node,
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
|
|
@ -785,7 +785,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
|
|||
llvm::LLVMRustDIBuilderCreateMemberType(
|
||||
DIB(cx),
|
||||
enum_type_di_node,
|
||||
field_name.as_ptr().cast(),
|
||||
field_name.as_c_char_ptr(),
|
||||
field_name.len(),
|
||||
file_di_node,
|
||||
line_number,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_target::abi::{FieldIdx, TagEncoding, VariantIdx, Variants};
|
|||
|
||||
use super::type_map::{DINodeCreationResult, UniqueTypeId};
|
||||
use super::{SmallVec, size_and_align_of};
|
||||
use crate::common::CodegenCx;
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::debuginfo::metadata::type_map::{self, Stub};
|
||||
use crate::debuginfo::metadata::{
|
||||
UNKNOWN_LINE_NUMBER, build_field_di_node, build_generic_type_param_di_nodes, type_di_node,
|
||||
|
|
@ -106,7 +106,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>(
|
|||
let value = [value as u64, (value >> 64) as u64];
|
||||
Some(llvm::LLVMRustDIBuilderCreateEnumerator(
|
||||
DIB(cx),
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
value.as_ptr(),
|
||||
size.bits() as libc::c_uint,
|
||||
|
|
@ -119,7 +119,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>(
|
|||
llvm::LLVMRustDIBuilderCreateEnumerationType(
|
||||
DIB(cx),
|
||||
containing_scope,
|
||||
type_name.as_ptr().cast(),
|
||||
type_name.as_c_char_ptr(),
|
||||
type_name.len(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_middle::ty::{self};
|
|||
use rustc_target::abi::{Size, TagEncoding, VariantIdx, Variants};
|
||||
use smallvec::smallvec;
|
||||
|
||||
use crate::common::CodegenCx;
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::debuginfo::metadata::type_map::{self, Stub, StubInfo, UniqueTypeId};
|
||||
use crate::debuginfo::metadata::{
|
||||
DINodeCreationResult, NO_GENERICS, SmallVec, UNKNOWN_LINE_NUMBER, file_metadata,
|
||||
|
|
@ -244,7 +244,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>(
|
|||
llvm::LLVMRustDIBuilderCreateVariantPart(
|
||||
DIB(cx),
|
||||
enum_type_di_node,
|
||||
variant_part_name.as_ptr().cast(),
|
||||
variant_part_name.as_c_char_ptr(),
|
||||
variant_part_name.len(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
|
|
@ -253,7 +253,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>(
|
|||
DIFlags::FlagZero,
|
||||
tag_member_di_node,
|
||||
create_DIArray(DIB(cx), &[]),
|
||||
variant_part_unique_type_id_str.as_ptr().cast(),
|
||||
variant_part_unique_type_id_str.as_c_char_ptr(),
|
||||
variant_part_unique_type_id_str.len(),
|
||||
)
|
||||
},
|
||||
|
|
@ -327,7 +327,7 @@ fn build_discr_member_di_node<'ll, 'tcx>(
|
|||
Some(llvm::LLVMRustDIBuilderCreateMemberType(
|
||||
DIB(cx),
|
||||
containing_scope,
|
||||
tag_name.as_ptr().cast(),
|
||||
tag_name.as_c_char_ptr(),
|
||||
tag_name.len(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
|
|
@ -399,7 +399,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>(
|
|||
llvm::LLVMRustDIBuilderCreateVariantMemberType(
|
||||
DIB(cx),
|
||||
variant_part_di_node,
|
||||
variant_member_info.variant_name.as_ptr().cast(),
|
||||
variant_member_info.variant_name.as_c_char_ptr(),
|
||||
variant_member_info.variant_name.len(),
|
||||
file_di_node,
|
||||
line_number,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_middle::ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
|
|||
use rustc_target::abi::{Align, Size, VariantIdx};
|
||||
|
||||
use super::{SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata};
|
||||
use crate::common::CodegenCx;
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::debuginfo::utils::{DIB, create_DIArray, debug_context};
|
||||
use crate::llvm::debuginfo::{DIFlags, DIScope, DIType};
|
||||
use crate::llvm::{self};
|
||||
|
|
@ -191,7 +191,7 @@ pub(super) fn stub<'ll, 'tcx>(
|
|||
llvm::LLVMRustDIBuilderCreateStructType(
|
||||
DIB(cx),
|
||||
containing_scope,
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
|
|
@ -202,7 +202,7 @@ pub(super) fn stub<'ll, 'tcx>(
|
|||
empty_array,
|
||||
0,
|
||||
vtable_holder,
|
||||
unique_type_id_str.as_ptr().cast(),
|
||||
unique_type_id_str.as_c_char_ptr(),
|
||||
unique_type_id_str.len(),
|
||||
)
|
||||
}
|
||||
|
|
@ -211,7 +211,7 @@ pub(super) fn stub<'ll, 'tcx>(
|
|||
llvm::LLVMRustDIBuilderCreateUnionType(
|
||||
DIB(cx),
|
||||
containing_scope,
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
|
|
@ -220,7 +220,7 @@ pub(super) fn stub<'ll, 'tcx>(
|
|||
flags,
|
||||
Some(empty_array),
|
||||
0,
|
||||
unique_type_id_str.as_ptr().cast(),
|
||||
unique_type_id_str.as_c_char_ptr(),
|
||||
unique_type_id_str.len(),
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ use self::namespace::mangled_name_of_instance;
|
|||
use self::utils::{DIB, create_DIArray, is_node_local_to_unit};
|
||||
use crate::abi::FnAbi;
|
||||
use crate::builder::Builder;
|
||||
use crate::common::CodegenCx;
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::llvm;
|
||||
use crate::llvm::debuginfo::{
|
||||
DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType,
|
||||
|
|
@ -91,45 +91,39 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
|
|||
}
|
||||
|
||||
pub(crate) fn finalize(&self, sess: &Session) {
|
||||
unsafe {
|
||||
llvm::LLVMRustDIBuilderFinalize(self.builder);
|
||||
|
||||
if !sess.target.is_like_msvc {
|
||||
// Debuginfo generation in LLVM by default uses a higher
|
||||
// version of dwarf than macOS currently understands. We can
|
||||
// instruct LLVM to emit an older version of dwarf, however,
|
||||
// for macOS to understand. For more info see #11352
|
||||
// This can be overridden using --llvm-opts -dwarf-version,N.
|
||||
// Android has the same issue (#22398)
|
||||
let dwarf_version = sess
|
||||
.opts
|
||||
.unstable_opts
|
||||
.dwarf_version
|
||||
.unwrap_or(sess.target.default_dwarf_version);
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
self.llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"Dwarf Version".as_ptr(),
|
||||
dwarf_version,
|
||||
);
|
||||
} else {
|
||||
// Indicate that we want CodeView debug information on MSVC
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
self.llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"CodeView".as_ptr(),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
||||
// Prevent bitcode readers from deleting the debug info.
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
unsafe { llvm::LLVMRustDIBuilderFinalize(self.builder) };
|
||||
if !sess.target.is_like_msvc {
|
||||
// Debuginfo generation in LLVM by default uses a higher
|
||||
// version of dwarf than macOS currently understands. We can
|
||||
// instruct LLVM to emit an older version of dwarf, however,
|
||||
// for macOS to understand. For more info see #11352
|
||||
// This can be overridden using --llvm-opts -dwarf-version,N.
|
||||
// Android has the same issue (#22398)
|
||||
let dwarf_version =
|
||||
sess.opts.unstable_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version);
|
||||
llvm::add_module_flag_u32(
|
||||
self.llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"Debug Info Version".as_ptr(),
|
||||
llvm::LLVMRustDebugMetadataVersion(),
|
||||
llvm::ModuleFlagMergeBehavior::Warning,
|
||||
"Dwarf Version",
|
||||
dwarf_version,
|
||||
);
|
||||
} else {
|
||||
// Indicate that we want CodeView debug information on MSVC
|
||||
llvm::add_module_flag_u32(
|
||||
self.llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Warning,
|
||||
"CodeView",
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
// Prevent bitcode readers from deleting the debug info.
|
||||
llvm::add_module_flag_u32(
|
||||
self.llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Warning,
|
||||
"Debug Info Version",
|
||||
unsafe { llvm::LLVMRustDebugMetadataVersion() },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +344,6 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
type_names::push_generic_params(
|
||||
tcx,
|
||||
tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args),
|
||||
enclosing_fn_def_id,
|
||||
&mut name,
|
||||
);
|
||||
|
||||
|
|
@ -365,7 +358,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
|
||||
let mut flags = DIFlags::FlagPrototyped;
|
||||
|
||||
if fn_abi.ret.layout.abi.is_uninhabited() {
|
||||
if fn_abi.ret.layout.is_uninhabited() {
|
||||
flags |= DIFlags::FlagNoReturn;
|
||||
}
|
||||
|
||||
|
|
@ -390,9 +383,9 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
llvm::LLVMRustDIBuilderCreateMethod(
|
||||
DIB(self),
|
||||
containing_scope,
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
linkage_name.as_ptr().cast(),
|
||||
linkage_name.as_c_char_ptr(),
|
||||
linkage_name.len(),
|
||||
file_metadata,
|
||||
loc.line,
|
||||
|
|
@ -407,9 +400,9 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
llvm::LLVMRustDIBuilderCreateFunction(
|
||||
DIB(self),
|
||||
containing_scope,
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
linkage_name.as_ptr().cast(),
|
||||
linkage_name.as_c_char_ptr(),
|
||||
linkage_name.len(),
|
||||
file_metadata,
|
||||
loc.line,
|
||||
|
|
@ -495,7 +488,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
|
||||
DIB(cx),
|
||||
None,
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
actual_type_metadata,
|
||||
))
|
||||
|
|
@ -636,7 +629,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
DIB(self),
|
||||
dwarf_tag,
|
||||
scope_metadata,
|
||||
name.as_ptr().cast(),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
file_metadata,
|
||||
loc.line,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_middle::ty::{self, Instance};
|
||||
|
||||
use super::utils::{DIB, debug_context};
|
||||
use crate::common::CodegenCx;
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::llvm;
|
||||
use crate::llvm::debuginfo::DIScope;
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ pub(crate) fn item_namespace<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'l
|
|||
llvm::LLVMRustDIBuilderCreateNameSpace(
|
||||
DIB(cx),
|
||||
parent_scope,
|
||||
namespace_name_string.as_ptr().cast(),
|
||||
namespace_name_string.as_c_char_ptr(),
|
||||
namespace_name_string.len(),
|
||||
false, // ExportSymbols (only relevant for C++ anonymous namespaces)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use smallvec::SmallVec;
|
|||
use tracing::debug;
|
||||
|
||||
use crate::abi::{FnAbi, FnAbiLlvmExt};
|
||||
use crate::common::AsCCharPtr;
|
||||
use crate::context::CodegenCx;
|
||||
use crate::llvm::AttributePlace::Function;
|
||||
use crate::llvm::Visibility;
|
||||
|
|
@ -41,7 +42,7 @@ fn declare_raw_fn<'ll>(
|
|||
) -> &'ll Value {
|
||||
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
|
||||
let llfn = unsafe {
|
||||
llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_ptr().cast(), name.len(), ty)
|
||||
llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_c_char_ptr(), name.len(), ty)
|
||||
};
|
||||
|
||||
llvm::SetFunctionCallConv(llfn, callconv);
|
||||
|
|
@ -68,7 +69,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
/// return its Value instead.
|
||||
pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value {
|
||||
debug!("declare_global(name={:?})", name);
|
||||
unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_ptr().cast(), name.len(), ty) }
|
||||
unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_c_char_ptr(), name.len(), ty) }
|
||||
}
|
||||
|
||||
/// Declare a C ABI function.
|
||||
|
|
@ -209,7 +210,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
/// Gets declared value by name.
|
||||
pub(crate) fn get_declared_value(&self, name: &str) -> Option<&'ll Value> {
|
||||
debug!("get_declared_value(name={:?})", name);
|
||||
unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_ptr().cast(), name.len()) }
|
||||
unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_c_char_ptr(), name.len()) }
|
||||
}
|
||||
|
||||
/// Gets defined or externally defined (AvailableExternally linkage) value by
|
||||
|
|
|
|||
|
|
@ -785,13 +785,12 @@ fn codegen_msvc_try<'ll>(
|
|||
let type_info =
|
||||
bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_ptr()), type_name], false);
|
||||
let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
|
||||
unsafe {
|
||||
llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
|
||||
if bx.cx.tcx.sess.target.supports_comdat() {
|
||||
llvm::SetUniqueComdat(bx.llmod, tydesc);
|
||||
}
|
||||
llvm::LLVMSetInitializer(tydesc, type_info);
|
||||
|
||||
llvm::set_linkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
|
||||
if bx.cx.tcx.sess.target.supports_comdat() {
|
||||
llvm::SetUniqueComdat(bx.llmod, tydesc);
|
||||
}
|
||||
unsafe { llvm::LLVMSetInitializer(tydesc, type_info) };
|
||||
|
||||
// The flag value of 8 indicates that we are catching the exception by
|
||||
// reference instead of by value. We can't use catch by value because
|
||||
|
|
@ -1064,7 +1063,7 @@ fn gen_fn<'ll, 'tcx>(
|
|||
cx.set_frame_pointer_type(llfn);
|
||||
cx.apply_target_cpu_attr(llfn);
|
||||
// FIXME(eddyb) find a nicer way to do this.
|
||||
unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
|
||||
llvm::set_linkage(llfn, llvm::Linkage::InternalLinkage);
|
||||
let llbb = Builder::append_block(cx, llfn, "entry-block");
|
||||
let bx = Builder::build(cx, llbb);
|
||||
codegen(bx);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
|
||||
use rustc_macros::TryFromU32;
|
||||
use rustc_target::spec::SymbolVisibility;
|
||||
|
||||
use super::RustString;
|
||||
|
|
@ -19,6 +21,30 @@ pub type Bool = c_uint;
|
|||
pub const True: Bool = 1 as Bool;
|
||||
pub const False: Bool = 0 as Bool;
|
||||
|
||||
/// Wrapper for a raw enum value returned from LLVM's C APIs.
|
||||
///
|
||||
/// For C enums returned by LLVM, it's risky to use a Rust enum as the return
|
||||
/// type, because it would be UB if a later version of LLVM adds a new enum
|
||||
/// value and returns it. Instead, return this raw wrapper, then convert to the
|
||||
/// Rust-side enum explicitly.
|
||||
#[repr(transparent)]
|
||||
pub struct RawEnum<T> {
|
||||
value: u32,
|
||||
/// We don't own or consume a `T`, but we can produce one.
|
||||
_rust_side_type: PhantomData<fn() -> T>,
|
||||
}
|
||||
|
||||
impl<T: TryFrom<u32>> RawEnum<T> {
|
||||
#[track_caller]
|
||||
pub(crate) fn to_rust(self) -> T
|
||||
where
|
||||
T::Error: Debug,
|
||||
{
|
||||
// If this fails, the Rust-side enum is out of sync with LLVM's enum.
|
||||
T::try_from(self.value).expect("enum value returned by LLVM should be known")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[repr(C)]
|
||||
#[allow(dead_code)] // Variants constructed by C++.
|
||||
|
|
@ -59,7 +85,7 @@ pub enum LLVMMachineType {
|
|||
ARM = 0x01c0,
|
||||
}
|
||||
|
||||
/// LLVM's Module::ModFlagBehavior, defined in llvm/include/llvm/IR/Module.h.
|
||||
/// Must match the layout of `LLVMRustModuleFlagMergeBehavior`.
|
||||
///
|
||||
/// When merging modules (e.g. during LTO), their metadata flags are combined. Conflicts are
|
||||
/// resolved according to the merge behaviors specified here. Flags differing only in merge
|
||||
|
|
@ -67,9 +93,13 @@ pub enum LLVMMachineType {
|
|||
///
|
||||
/// In order for Rust-C LTO to work, we must specify behaviors compatible with Clang. Notably,
|
||||
/// 'Error' and 'Warning' cannot be mixed for a given flag.
|
||||
///
|
||||
/// There is a stable LLVM-C version of this enum (`LLVMModuleFlagBehavior`),
|
||||
/// but as of LLVM 19 it does not support all of the enum values in the unstable
|
||||
/// C++ API.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub enum LLVMModFlagBehavior {
|
||||
pub enum ModuleFlagMergeBehavior {
|
||||
Error = 1,
|
||||
Warning = 2,
|
||||
Require = 3,
|
||||
|
|
@ -108,26 +138,36 @@ pub enum CallConv {
|
|||
AvrInterrupt = 85,
|
||||
}
|
||||
|
||||
/// LLVMRustLinkage
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
/// Must match the layout of `LLVMLinkage`.
|
||||
#[derive(Copy, Clone, PartialEq, TryFromU32)]
|
||||
#[repr(C)]
|
||||
pub enum Linkage {
|
||||
ExternalLinkage = 0,
|
||||
AvailableExternallyLinkage = 1,
|
||||
LinkOnceAnyLinkage = 2,
|
||||
LinkOnceODRLinkage = 3,
|
||||
WeakAnyLinkage = 4,
|
||||
WeakODRLinkage = 5,
|
||||
AppendingLinkage = 6,
|
||||
InternalLinkage = 7,
|
||||
PrivateLinkage = 8,
|
||||
ExternalWeakLinkage = 9,
|
||||
CommonLinkage = 10,
|
||||
#[deprecated = "marked obsolete by LLVM"]
|
||||
LinkOnceODRAutoHideLinkage = 4,
|
||||
WeakAnyLinkage = 5,
|
||||
WeakODRLinkage = 6,
|
||||
AppendingLinkage = 7,
|
||||
InternalLinkage = 8,
|
||||
PrivateLinkage = 9,
|
||||
#[deprecated = "marked obsolete by LLVM"]
|
||||
DLLImportLinkage = 10,
|
||||
#[deprecated = "marked obsolete by LLVM"]
|
||||
DLLExportLinkage = 11,
|
||||
ExternalWeakLinkage = 12,
|
||||
#[deprecated = "marked obsolete by LLVM"]
|
||||
GhostLinkage = 13,
|
||||
CommonLinkage = 14,
|
||||
LinkerPrivateLinkage = 15,
|
||||
LinkerPrivateWeakLinkage = 16,
|
||||
}
|
||||
|
||||
// LLVMRustVisibility
|
||||
/// Must match the layout of `LLVMVisibility`.
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[derive(Copy, Clone, PartialEq, TryFromU32)]
|
||||
pub enum Visibility {
|
||||
Default = 0,
|
||||
Hidden = 1,
|
||||
|
|
@ -945,7 +985,11 @@ unsafe extern "C" {
|
|||
|
||||
// Operations on global variables, functions, and aliases (globals)
|
||||
pub fn LLVMIsDeclaration(Global: &Value) -> Bool;
|
||||
pub fn LLVMGetLinkage(Global: &Value) -> RawEnum<Linkage>;
|
||||
pub fn LLVMSetLinkage(Global: &Value, RustLinkage: Linkage);
|
||||
pub fn LLVMSetSection(Global: &Value, Section: *const c_char);
|
||||
pub fn LLVMGetVisibility(Global: &Value) -> RawEnum<Visibility>;
|
||||
pub fn LLVMSetVisibility(Global: &Value, Viz: Visibility);
|
||||
pub fn LLVMGetAlignment(Global: &Value) -> c_uint;
|
||||
pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint);
|
||||
pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass);
|
||||
|
|
@ -1521,10 +1565,6 @@ unsafe extern "C" {
|
|||
) -> bool;
|
||||
|
||||
// Operations on global variables, functions, and aliases (globals)
|
||||
pub fn LLVMRustGetLinkage(Global: &Value) -> Linkage;
|
||||
pub fn LLVMRustSetLinkage(Global: &Value, RustLinkage: Linkage);
|
||||
pub fn LLVMRustGetVisibility(Global: &Value) -> Visibility;
|
||||
pub fn LLVMRustSetVisibility(Global: &Value, Viz: Visibility);
|
||||
pub fn LLVMRustSetDSOLocal(Global: &Value, is_dso_local: bool);
|
||||
|
||||
// Operations on global variables
|
||||
|
|
@ -1615,10 +1655,6 @@ unsafe extern "C" {
|
|||
pub fn LLVMRustSetAllowReassoc(Instr: &Value);
|
||||
|
||||
// Miscellaneous instructions
|
||||
pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value;
|
||||
pub fn LLVMRustGetInstrProfMCDCParametersIntrinsic(M: &Module) -> &Value;
|
||||
pub fn LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(M: &Module) -> &Value;
|
||||
|
||||
pub fn LLVMRustBuildCall<'a>(
|
||||
B: &Builder<'a>,
|
||||
Ty: &'a Type,
|
||||
|
|
@ -1744,7 +1780,7 @@ unsafe extern "C" {
|
|||
) -> bool;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustCoverageWriteFilenamesSectionToBuffer(
|
||||
pub(crate) fn LLVMRustCoverageWriteFilenamesSectionToBuffer(
|
||||
Filenames: *const *const c_char,
|
||||
FilenamesLen: size_t,
|
||||
Lengths: *const size_t,
|
||||
|
|
@ -1753,33 +1789,39 @@ unsafe extern "C" {
|
|||
);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustCoverageWriteMappingToBuffer(
|
||||
pub(crate) fn LLVMRustCoverageWriteMappingToBuffer(
|
||||
VirtualFileMappingIDs: *const c_uint,
|
||||
NumVirtualFileMappingIDs: c_uint,
|
||||
Expressions: *const crate::coverageinfo::ffi::CounterExpression,
|
||||
NumExpressions: c_uint,
|
||||
MappingRegions: *const crate::coverageinfo::ffi::CounterMappingRegion,
|
||||
NumMappingRegions: c_uint,
|
||||
CodeRegions: *const crate::coverageinfo::ffi::CodeRegion,
|
||||
NumCodeRegions: c_uint,
|
||||
BranchRegions: *const crate::coverageinfo::ffi::BranchRegion,
|
||||
NumBranchRegions: c_uint,
|
||||
MCDCBranchRegions: *const crate::coverageinfo::ffi::MCDCBranchRegion,
|
||||
NumMCDCBranchRegions: c_uint,
|
||||
MCDCDecisionRegions: *const crate::coverageinfo::ffi::MCDCDecisionRegion,
|
||||
NumMCDCDecisionRegions: c_uint,
|
||||
BufferOut: &RustString,
|
||||
);
|
||||
|
||||
pub fn LLVMRustCoverageCreatePGOFuncNameVar(
|
||||
pub(crate) fn LLVMRustCoverageCreatePGOFuncNameVar(
|
||||
F: &Value,
|
||||
FuncName: *const c_char,
|
||||
FuncNameLen: size_t,
|
||||
) -> &Value;
|
||||
pub fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64;
|
||||
pub(crate) fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustCoverageWriteMapSectionNameToString(M: &Module, Str: &RustString);
|
||||
pub(crate) fn LLVMRustCoverageWriteMapSectionNameToString(M: &Module, Str: &RustString);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustCoverageWriteFuncSectionNameToString(M: &Module, Str: &RustString);
|
||||
pub(crate) fn LLVMRustCoverageWriteFuncSectionNameToString(M: &Module, Str: &RustString);
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
pub fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString);
|
||||
pub(crate) fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString);
|
||||
|
||||
pub fn LLVMRustCoverageMappingVersion() -> u32;
|
||||
pub(crate) fn LLVMRustCoverageMappingVersion() -> u32;
|
||||
pub fn LLVMRustDebugMetadataVersion() -> u32;
|
||||
pub fn LLVMRustVersionMajor() -> u32;
|
||||
pub fn LLVMRustVersionMinor() -> u32;
|
||||
|
|
@ -1791,21 +1833,21 @@ unsafe extern "C" {
|
|||
/// "compatible" means depends on the merge behaviors involved.
|
||||
pub fn LLVMRustAddModuleFlagU32(
|
||||
M: &Module,
|
||||
merge_behavior: LLVMModFlagBehavior,
|
||||
name: *const c_char,
|
||||
value: u32,
|
||||
MergeBehavior: ModuleFlagMergeBehavior,
|
||||
Name: *const c_char,
|
||||
NameLen: size_t,
|
||||
Value: u32,
|
||||
);
|
||||
|
||||
pub fn LLVMRustAddModuleFlagString(
|
||||
M: &Module,
|
||||
merge_behavior: LLVMModFlagBehavior,
|
||||
name: *const c_char,
|
||||
value: *const c_char,
|
||||
value_len: size_t,
|
||||
MergeBehavior: ModuleFlagMergeBehavior,
|
||||
Name: *const c_char,
|
||||
NameLen: size_t,
|
||||
Value: *const c_char,
|
||||
ValueLen: size_t,
|
||||
);
|
||||
|
||||
pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool;
|
||||
|
||||
pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>;
|
||||
|
||||
pub fn LLVMRustDIBuilderDispose<'a>(Builder: &'a mut DIBuilder<'a>);
|
||||
|
|
@ -2347,9 +2389,9 @@ unsafe extern "C" {
|
|||
pub fn LLVMRustThinLTOBufferThinLinkDataLen(M: &ThinLTOBuffer) -> size_t;
|
||||
pub fn LLVMRustCreateThinLTOData(
|
||||
Modules: *const ThinLTOModule,
|
||||
NumModules: c_uint,
|
||||
NumModules: size_t,
|
||||
PreservedSymbols: *const *const c_char,
|
||||
PreservedSymbolsLen: c_uint,
|
||||
PreservedSymbolsLen: size_t,
|
||||
) -> Option<&'static mut ThinLTOData>;
|
||||
pub fn LLVMRustPrepareThinLTORename(
|
||||
Data: &ThinLTOData,
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ pub use self::IntPredicate::*;
|
|||
pub use self::Linkage::*;
|
||||
pub use self::MetadataType::*;
|
||||
pub use self::RealPredicate::*;
|
||||
pub use self::ffi::*;
|
||||
use crate::common::AsCCharPtr;
|
||||
|
||||
pub mod archive_ro;
|
||||
pub mod diagnostic;
|
||||
mod ffi;
|
||||
|
||||
pub use self::ffi::*;
|
||||
|
||||
impl LLVMRustResult {
|
||||
pub fn into_result(self) -> Result<(), ()> {
|
||||
match self {
|
||||
|
|
@ -53,9 +53,9 @@ pub fn CreateAttrStringValue<'ll>(llcx: &'ll Context, attr: &str, value: &str) -
|
|||
unsafe {
|
||||
LLVMCreateStringAttribute(
|
||||
llcx,
|
||||
attr.as_ptr().cast(),
|
||||
attr.as_c_char_ptr(),
|
||||
attr.len().try_into().unwrap(),
|
||||
value.as_ptr().cast(),
|
||||
value.as_c_char_ptr(),
|
||||
value.len().try_into().unwrap(),
|
||||
)
|
||||
}
|
||||
|
|
@ -65,7 +65,7 @@ pub fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &str) -> &'ll Attribute {
|
|||
unsafe {
|
||||
LLVMCreateStringAttribute(
|
||||
llcx,
|
||||
attr.as_ptr().cast(),
|
||||
attr.as_c_char_ptr(),
|
||||
attr.len().try_into().unwrap(),
|
||||
std::ptr::null(),
|
||||
0,
|
||||
|
|
@ -232,15 +232,23 @@ pub fn set_global_constant(llglobal: &Value, is_constant: bool) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_linkage(llglobal: &Value) -> Linkage {
|
||||
unsafe { LLVMGetLinkage(llglobal) }.to_rust()
|
||||
}
|
||||
|
||||
pub fn set_linkage(llglobal: &Value, linkage: Linkage) {
|
||||
unsafe {
|
||||
LLVMRustSetLinkage(llglobal, linkage);
|
||||
LLVMSetLinkage(llglobal, linkage);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_visibility(llglobal: &Value) -> Visibility {
|
||||
unsafe { LLVMGetVisibility(llglobal) }.to_rust()
|
||||
}
|
||||
|
||||
pub fn set_visibility(llglobal: &Value, visibility: Visibility) {
|
||||
unsafe {
|
||||
LLVMRustSetVisibility(llglobal, visibility);
|
||||
LLVMSetVisibility(llglobal, visibility);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -286,7 +294,7 @@ pub fn get_value_name(value: &Value) -> &[u8] {
|
|||
/// Safe wrapper for `LLVMSetValueName2` from a byte slice
|
||||
pub fn set_value_name(value: &Value, name: &[u8]) {
|
||||
unsafe {
|
||||
let data = name.as_ptr().cast();
|
||||
let data = name.as_c_char_ptr();
|
||||
LLVMSetValueName2(value, data, name.len());
|
||||
}
|
||||
}
|
||||
|
|
@ -344,3 +352,32 @@ impl Drop for OperandBundleDef<'_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add_module_flag_u32(
|
||||
module: &Module,
|
||||
merge_behavior: ModuleFlagMergeBehavior,
|
||||
key: &str,
|
||||
value: u32,
|
||||
) {
|
||||
unsafe {
|
||||
LLVMRustAddModuleFlagU32(module, merge_behavior, key.as_c_char_ptr(), key.len(), value);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add_module_flag_str(
|
||||
module: &Module,
|
||||
merge_behavior: ModuleFlagMergeBehavior,
|
||||
key: &str,
|
||||
value: &str,
|
||||
) {
|
||||
unsafe {
|
||||
LLVMRustAddModuleFlagString(
|
||||
module,
|
||||
merge_behavior,
|
||||
key.as_c_char_ptr(),
|
||||
key.len(),
|
||||
value.as_c_char_ptr(),
|
||||
value.len(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -248,6 +248,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
|
|||
("aarch64", "pmuv3") => Some(LLVMFeature::new("perfmon")),
|
||||
("aarch64", "paca") => Some(LLVMFeature::new("pauth")),
|
||||
("aarch64", "pacg") => Some(LLVMFeature::new("pauth")),
|
||||
("aarch64", "pauth-lr") if get_version().0 < 19 => None,
|
||||
// Before LLVM 20 those two features were packaged together as b16b16
|
||||
("aarch64", "sve-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
|
||||
("aarch64", "sme-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
|
||||
|
|
@ -697,12 +698,9 @@ fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> {
|
|||
let feature = s
|
||||
.strip_prefix(&['+', '-'][..])
|
||||
.unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s }));
|
||||
if s.is_empty() {
|
||||
return None;
|
||||
}
|
||||
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
|
||||
// are not passed down to LLVM.
|
||||
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
||||
if s.is_empty() || RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
||||
return None;
|
||||
}
|
||||
Some(feature)
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
|||
.emit_fatal(SymbolAlreadyDefined { span: self.tcx.def_span(def_id), symbol_name })
|
||||
});
|
||||
|
||||
llvm::set_linkage(g, base::linkage_to_llvm(linkage));
|
||||
llvm::set_visibility(g, base::visibility_to_llvm(visibility));
|
||||
unsafe {
|
||||
llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
|
||||
llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
|
||||
if self.should_assume_dso_local(g, false) {
|
||||
llvm::LLVMRustSetDSOLocal(g, true);
|
||||
}
|
||||
|
|
@ -61,7 +61,7 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
|||
|
||||
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
|
||||
let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance));
|
||||
unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
|
||||
llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage));
|
||||
let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
|
||||
base::set_link_section(lldecl, attrs);
|
||||
if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR)
|
||||
|
|
@ -78,21 +78,15 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
|||
&& linkage != Linkage::Private
|
||||
&& self.tcx.is_compiler_builtins(LOCAL_CRATE)
|
||||
{
|
||||
unsafe {
|
||||
llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden);
|
||||
}
|
||||
llvm::set_visibility(lldecl, llvm::Visibility::Hidden);
|
||||
} else {
|
||||
unsafe {
|
||||
llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility));
|
||||
}
|
||||
llvm::set_visibility(lldecl, base::visibility_to_llvm(visibility));
|
||||
}
|
||||
|
||||
debug!("predefine_fn: instance = {:?}", instance);
|
||||
|
||||
unsafe {
|
||||
if self.should_assume_dso_local(lldecl, false) {
|
||||
llvm::LLVMRustSetDSOLocal(lldecl, true);
|
||||
}
|
||||
if self.should_assume_dso_local(lldecl, false) {
|
||||
unsafe { llvm::LLVMRustSetDSOLocal(lldecl, true) };
|
||||
}
|
||||
|
||||
self.instances.borrow_mut().insert(instance, lldecl);
|
||||
|
|
@ -102,13 +96,13 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
|||
impl CodegenCx<'_, '_> {
|
||||
/// Whether a definition or declaration can be assumed to be local to a group of
|
||||
/// libraries that form a single DSO or executable.
|
||||
pub(crate) unsafe fn should_assume_dso_local(
|
||||
pub(crate) fn should_assume_dso_local(
|
||||
&self,
|
||||
llval: &llvm::Value,
|
||||
is_declaration: bool,
|
||||
) -> bool {
|
||||
let linkage = unsafe { llvm::LLVMRustGetLinkage(llval) };
|
||||
let visibility = unsafe { llvm::LLVMRustGetVisibility(llval) };
|
||||
let linkage = llvm::get_linkage(llval);
|
||||
let visibility = llvm::get_visibility(llval);
|
||||
|
||||
if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
|
|||
/// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this
|
||||
/// is useful for indexing slices, as `&[T]`'s data pointer is `T*`.
|
||||
/// If the type is an unsized struct, the regular layout is generated,
|
||||
/// with the inner-most trailing unsized field using the "minimal unit"
|
||||
/// with the innermost trailing unsized field using the "minimal unit"
|
||||
/// of that field's type - this is useful for taking the address of
|
||||
/// that field and ensuring the struct has the right alignment.
|
||||
fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type {
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ fn exported_symbols_provider_local(
|
|||
|
||||
match *mono_item {
|
||||
MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => {
|
||||
if args.non_erasable_generics(tcx, def).next().is_some() {
|
||||
if args.non_erasable_generics().next().is_some() {
|
||||
let symbol = ExportedSymbol::Generic(def, args);
|
||||
symbols.push((symbol, SymbolExportInfo {
|
||||
level: SymbolExportLevel::Rust,
|
||||
|
|
@ -321,12 +321,9 @@ fn exported_symbols_provider_local(
|
|||
}));
|
||||
}
|
||||
}
|
||||
MonoItem::Fn(Instance { def: InstanceKind::DropGlue(def_id, Some(ty)), args }) => {
|
||||
MonoItem::Fn(Instance { def: InstanceKind::DropGlue(_, Some(ty)), args }) => {
|
||||
// A little sanity-check
|
||||
assert_eq!(
|
||||
args.non_erasable_generics(tcx, def_id).next(),
|
||||
Some(GenericArgKind::Type(ty))
|
||||
);
|
||||
assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty)));
|
||||
symbols.push((ExportedSymbol::DropGlue(ty), SymbolExportInfo {
|
||||
level: SymbolExportLevel::Rust,
|
||||
kind: SymbolExportKind::Text,
|
||||
|
|
@ -334,14 +331,11 @@ fn exported_symbols_provider_local(
|
|||
}));
|
||||
}
|
||||
MonoItem::Fn(Instance {
|
||||
def: InstanceKind::AsyncDropGlueCtorShim(def_id, Some(ty)),
|
||||
def: InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)),
|
||||
args,
|
||||
}) => {
|
||||
// A little sanity-check
|
||||
assert_eq!(
|
||||
args.non_erasable_generics(tcx, def_id).next(),
|
||||
Some(GenericArgKind::Type(ty))
|
||||
);
|
||||
assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty)));
|
||||
symbols.push((ExportedSymbol::AsyncDropGlueCtorShim(ty), SymbolExportInfo {
|
||||
level: SymbolExportLevel::Rust,
|
||||
kind: SymbolExportKind::Text,
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
future: Some(coordinator_thread),
|
||||
phantom: PhantomData,
|
||||
},
|
||||
output_filenames: tcx.output_filenames(()).clone(),
|
||||
output_filenames: Arc::clone(tcx.output_filenames(())),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1203,7 +1203,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
coordinator_send,
|
||||
expanded_args: tcx.sess.expanded_args.clone(),
|
||||
diag_emitter: shared_emitter.clone(),
|
||||
output_filenames: tcx.output_filenames(()).clone(),
|
||||
output_filenames: Arc::clone(tcx.output_filenames(())),
|
||||
regular_module_config: regular_config,
|
||||
metadata_module_config: metadata_config,
|
||||
allocator_module_config: allocator_config,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_n
|
|||
use rustc_attr as attr;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
||||
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
|
||||
use rustc_data_structures::sync::par_map;
|
||||
use rustc_data_structures::sync::{Lrc, par_map};
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
|
|
@ -888,7 +888,7 @@ impl CrateInfo {
|
|||
// below.
|
||||
//
|
||||
// In order to get this left-to-right dependency ordering, we use the reverse
|
||||
// postorder of all crates putting the leaves at the right-most positions.
|
||||
// postorder of all crates putting the leaves at the rightmost positions.
|
||||
let mut compiler_builtins = None;
|
||||
let mut used_crates: Vec<_> = tcx
|
||||
.postorder_cnums(())
|
||||
|
|
@ -923,7 +923,7 @@ impl CrateInfo {
|
|||
crate_name: UnordMap::with_capacity(n_crates),
|
||||
used_crates,
|
||||
used_crate_source: UnordMap::with_capacity(n_crates),
|
||||
dependency_formats: tcx.dependency_formats(()).clone(),
|
||||
dependency_formats: Lrc::clone(tcx.dependency_formats(())),
|
||||
windows_subsystem,
|
||||
natvis_debugger_visualizers: Default::default(),
|
||||
};
|
||||
|
|
@ -936,7 +936,7 @@ impl CrateInfo {
|
|||
info.crate_name.insert(cnum, tcx.crate_name(cnum));
|
||||
|
||||
let used_crate_source = tcx.used_crate_source(cnum);
|
||||
info.used_crate_source.insert(cnum, used_crate_source.clone());
|
||||
info.used_crate_source.insert(cnum, Lrc::clone(used_crate_source));
|
||||
if tcx.is_profiler_runtime(cnum) {
|
||||
info.profiler_runtime = Some(cnum);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
let inner = attr.meta_item_list();
|
||||
match inner.as_deref() {
|
||||
Some([item]) if item.has_name(sym::linker) => {
|
||||
if !tcx.features().used_with_arg {
|
||||
if !tcx.features().used_with_arg() {
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
sym::used_with_arg,
|
||||
|
|
@ -149,7 +149,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
|
||||
}
|
||||
Some([item]) if item.has_name(sym::compiler) => {
|
||||
if !tcx.features().used_with_arg {
|
||||
if !tcx.features().used_with_arg() {
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
sym::used_with_arg,
|
||||
|
|
@ -213,7 +213,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
.emit();
|
||||
}
|
||||
if is_closure
|
||||
&& !tcx.features().closure_track_caller
|
||||
&& !tcx.features().closure_track_caller()
|
||||
&& !attr.span.allows_unstable(sym::closure_track_caller)
|
||||
{
|
||||
feature_err(
|
||||
|
|
@ -268,7 +268,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
//
|
||||
// This exception needs to be kept in sync with allowing
|
||||
// `#[target_feature]` on `main` and `start`.
|
||||
} else if !tcx.features().target_feature_11 {
|
||||
} else if !tcx.features().target_feature_11() {
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
sym::target_feature_11,
|
||||
|
|
@ -584,7 +584,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
// its parent function, which effectively inherits the features anyway. Boxing this closure
|
||||
// would result in this closure being compiled without the inherited target features, but this
|
||||
// is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
|
||||
if tcx.features().target_feature_11
|
||||
if tcx.features().target_feature_11()
|
||||
&& tcx.is_closure_like(did.to_def_id())
|
||||
&& codegen_fn_attrs.inline != InlineAttr::Always
|
||||
{
|
||||
|
|
|
|||
|
|
@ -110,14 +110,14 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
ty_and_layout,
|
||||
&|output, visited| {
|
||||
push_item_name(tcx, def.did(), true, output);
|
||||
push_generic_params_internal(tcx, args, def.did(), output, visited);
|
||||
push_generic_params_internal(tcx, args, output, visited);
|
||||
},
|
||||
output,
|
||||
visited,
|
||||
);
|
||||
} else {
|
||||
push_item_name(tcx, def.did(), qualified, output);
|
||||
push_generic_params_internal(tcx, args, def.did(), output, visited);
|
||||
push_generic_params_internal(tcx, args, output, visited);
|
||||
}
|
||||
}
|
||||
ty::Tuple(component_types) => {
|
||||
|
|
@ -251,13 +251,8 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
let principal =
|
||||
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), principal);
|
||||
push_item_name(tcx, principal.def_id, qualified, output);
|
||||
let principal_has_generic_params = push_generic_params_internal(
|
||||
tcx,
|
||||
principal.args,
|
||||
principal.def_id,
|
||||
output,
|
||||
visited,
|
||||
);
|
||||
let principal_has_generic_params =
|
||||
push_generic_params_internal(tcx, principal.args, output, visited);
|
||||
|
||||
let projection_bounds: SmallVec<[_; 4]> = trait_data
|
||||
.projection_bounds()
|
||||
|
|
@ -538,13 +533,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
|
|||
tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref);
|
||||
push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
|
||||
visited.clear();
|
||||
push_generic_params_internal(
|
||||
tcx,
|
||||
trait_ref.args,
|
||||
trait_ref.def_id,
|
||||
&mut vtable_name,
|
||||
&mut visited,
|
||||
);
|
||||
push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited);
|
||||
} else {
|
||||
vtable_name.push('_');
|
||||
}
|
||||
|
|
@ -647,12 +636,11 @@ fn push_unqualified_item_name(
|
|||
fn push_generic_params_internal<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
def_id: DefId,
|
||||
output: &mut String,
|
||||
visited: &mut FxHashSet<Ty<'tcx>>,
|
||||
) -> bool {
|
||||
assert_eq!(args, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args));
|
||||
let mut args = args.non_erasable_generics(tcx, def_id).peekable();
|
||||
let mut args = args.non_erasable_generics().peekable();
|
||||
if args.peek().is_none() {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -736,12 +724,11 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
|
|||
pub fn push_generic_params<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
def_id: DefId,
|
||||
output: &mut String,
|
||||
) {
|
||||
let _prof = tcx.prof.generic_activity("compute_debuginfo_type_name");
|
||||
let mut visited = FxHashSet::default();
|
||||
push_generic_params_internal(tcx, args, def_id, output, &mut visited);
|
||||
push_generic_params_internal(tcx, args, output, &mut visited);
|
||||
}
|
||||
|
||||
fn push_closure_or_coroutine_name<'tcx>(
|
||||
|
|
@ -786,7 +773,7 @@ fn push_closure_or_coroutine_name<'tcx>(
|
|||
// FIXME(async_closures): This is probably not going to be correct w.r.t.
|
||||
// multiple coroutine flavors. Maybe truncate to (parent + 1)?
|
||||
let args = args.truncate_to(tcx, generics);
|
||||
push_generic_params_internal(tcx, args, enclosing_fn_def_id, output, visited);
|
||||
push_generic_params_internal(tcx, args, output, visited);
|
||||
}
|
||||
|
||||
fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
|
||||
|
|
|
|||
|
|
@ -438,7 +438,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
_ => bug!("C-variadic function must have a `VaList` place"),
|
||||
}
|
||||
}
|
||||
if self.fn_abi.ret.layout.abi.is_uninhabited() {
|
||||
if self.fn_abi.ret.layout.is_uninhabited() {
|
||||
// Functions with uninhabited return values are marked `noreturn`,
|
||||
// so we should make sure that we never actually do.
|
||||
// We play it safe by using a well-defined `abort`, but we could go for immediate UB
|
||||
|
|
@ -774,7 +774,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
Some(if do_panic {
|
||||
let msg_str = with_no_visible_paths!({
|
||||
with_no_trimmed_paths!({
|
||||
if layout.abi.is_uninhabited() {
|
||||
if layout.is_uninhabited() {
|
||||
// Use this error even for the other intrinsics as it is more precise.
|
||||
format!("attempted to instantiate uninhabited type `{ty}`")
|
||||
} else if requirement == ValidityRequirement::Zero {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ impl<V: CodegenObject> PlaceValue<V> {
|
|||
/// Creates a `PlaceRef` to this location with the given type.
|
||||
pub fn with_type<'tcx>(self, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
|
||||
assert!(
|
||||
layout.is_unsized() || layout.abi.is_uninhabited() || self.llextra.is_none(),
|
||||
layout.is_unsized() || layout.is_uninhabited() || self.llextra.is_none(),
|
||||
"Had pointer metadata {:?} for sized type {layout:?}",
|
||||
self.llextra,
|
||||
);
|
||||
|
|
@ -239,7 +239,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
let dl = &bx.tcx().data_layout;
|
||||
let cast_to_layout = bx.cx().layout_of(cast_to);
|
||||
let cast_to = bx.cx().immediate_backend_type(cast_to_layout);
|
||||
if self.layout.abi.is_uninhabited() {
|
||||
if self.layout.is_uninhabited() {
|
||||
return bx.cx().const_poison(cast_to);
|
||||
}
|
||||
let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
|
||||
|
|
@ -358,7 +358,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
bx: &mut Bx,
|
||||
variant_index: VariantIdx,
|
||||
) {
|
||||
if self.layout.for_variant(bx.cx(), variant_index).abi.is_uninhabited() {
|
||||
if self.layout.for_variant(bx.cx(), variant_index).is_uninhabited() {
|
||||
// We play it safe by using a well-defined `abort`, but we could go for immediate UB
|
||||
// if that turns out to be helpful.
|
||||
bx.abort();
|
||||
|
|
|
|||
|
|
@ -203,10 +203,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
) -> Option<OperandValue<Bx::Value>> {
|
||||
// Check for transmutes that are always UB.
|
||||
if operand.layout.size != cast.size
|
||||
|| operand.layout.abi.is_uninhabited()
|
||||
|| cast.abi.is_uninhabited()
|
||||
|| operand.layout.is_uninhabited()
|
||||
|| cast.is_uninhabited()
|
||||
{
|
||||
if !operand.layout.abi.is_uninhabited() {
|
||||
if !operand.layout.is_uninhabited() {
|
||||
// Since this is known statically and the input could have existed
|
||||
// without already having hit UB, might as well trap for it.
|
||||
bx.abort();
|
||||
|
|
@ -555,7 +555,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
assert!(bx.cx().is_backend_immediate(cast));
|
||||
let to_backend_ty = bx.cx().immediate_backend_type(cast);
|
||||
if operand.layout.abi.is_uninhabited() {
|
||||
if operand.layout.is_uninhabited() {
|
||||
let val = OperandValue::Immediate(bx.cx().const_poison(to_backend_ty));
|
||||
return OperandRef { val, layout: cast };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
|
@ -61,30 +60,9 @@ pub(crate) fn from_target_feature(
|
|||
return None;
|
||||
};
|
||||
|
||||
// Only allow features whose feature gates have been enabled.
|
||||
// Only allow target features whose feature gates have been enabled.
|
||||
let allowed = match feature_gate.as_ref().copied() {
|
||||
Some(sym::arm_target_feature) => rust_features.arm_target_feature,
|
||||
Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
|
||||
Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
|
||||
Some(sym::mips_target_feature) => rust_features.mips_target_feature,
|
||||
Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
|
||||
Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
|
||||
Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
|
||||
Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
|
||||
Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
|
||||
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
|
||||
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
|
||||
Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
|
||||
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
|
||||
Some(sym::csky_target_feature) => rust_features.csky_target_feature,
|
||||
Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
|
||||
Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature,
|
||||
Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature,
|
||||
Some(sym::sha512_sm_x86) => rust_features.sha512_sm_x86,
|
||||
Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics,
|
||||
Some(sym::xop_target_feature) => rust_features.xop_target_feature,
|
||||
Some(sym::s390x_target_feature) => rust_features.s390x_target_feature,
|
||||
Some(name) => bug!("unknown target feature gate {}", name),
|
||||
Some(name) => rust_features.enabled(name),
|
||||
None => true,
|
||||
};
|
||||
if !allowed {
|
||||
|
|
|
|||
|
|
@ -437,14 +437,6 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
/// Called for `StorageDead`
|
||||
fn lifetime_end(&mut self, ptr: Self::Value, size: Size);
|
||||
|
||||
fn instrprof_increment(
|
||||
&mut self,
|
||||
fn_name: Self::Value,
|
||||
hash: Self::Value,
|
||||
num_counters: Self::Value,
|
||||
index: Self::Value,
|
||||
);
|
||||
|
||||
fn call(
|
||||
&mut self,
|
||||
llty: Self::Type,
|
||||
|
|
|
|||
|
|
@ -41,8 +41,6 @@ const_eval_const_context = {$kind ->
|
|||
*[other] {""}
|
||||
}
|
||||
|
||||
const_eval_const_stable = const-stable functions can only call other const-stable functions
|
||||
|
||||
const_eval_copy_nonoverlapping_overlapping =
|
||||
`copy_nonoverlapping` called on overlapping ranges
|
||||
|
||||
|
|
@ -259,6 +257,9 @@ const_eval_non_const_fn_call =
|
|||
const_eval_non_const_impl =
|
||||
impl defined here, but it is not `const`
|
||||
|
||||
const_eval_non_const_intrinsic =
|
||||
cannot call non-const intrinsic `{$name}` in {const_eval_const_context}s
|
||||
|
||||
const_eval_not_enough_caller_args =
|
||||
calling a function with fewer arguments than it requires
|
||||
|
||||
|
|
@ -397,17 +398,29 @@ const_eval_uninhabited_enum_variant_read =
|
|||
read discriminant of an uninhabited enum variant
|
||||
const_eval_uninhabited_enum_variant_written =
|
||||
writing discriminant of an uninhabited enum variant
|
||||
|
||||
const_eval_unmarked_const_fn_exposed = `{$def_path}` cannot be (indirectly) exposed to stable
|
||||
.help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
|
||||
const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable
|
||||
.help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval)
|
||||
|
||||
const_eval_unreachable = entering unreachable code
|
||||
const_eval_unreachable_unwind =
|
||||
unwinding past a stack frame that does not allow unwinding
|
||||
|
||||
const_eval_unsized_local = unsized locals are not supported
|
||||
const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
|
||||
const_eval_unstable_in_stable_exposed =
|
||||
const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]`
|
||||
.is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
|
||||
.unstable_sugg = if the {$is_function_call2 ->
|
||||
[true] caller
|
||||
*[false] function
|
||||
} is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
||||
.bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
||||
|
||||
const_eval_unstable_in_stable =
|
||||
const-stable function cannot use `#[feature({$gate})]`
|
||||
.unstable_sugg = if the function is not (yet) meant to be stable, make this function unstably const
|
||||
.bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval)
|
||||
const_eval_unstable_intrinsic = `{$name}` is not yet stable as a const intrinsic
|
||||
.help = add `#![feature({$feature})]` to the crate attributes to enable
|
||||
|
||||
const_eval_unterminated_c_string =
|
||||
reading a null-terminated string starting at {$pointer} with no null found before end of allocation
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use std::borrow::Cow;
|
|||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_attr::{ConstStability, StabilityLevel};
|
||||
use rustc_errors::{Diag, ErrorGuaranteed};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
|
|
@ -28,8 +29,8 @@ use super::ops::{self, NonConstOp, Status};
|
|||
use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
|
||||
use super::resolver::FlowSensitiveAnalysis;
|
||||
use super::{ConstCx, Qualif};
|
||||
use crate::const_eval::is_unstable_const_fn;
|
||||
use crate::errors::UnstableInStable;
|
||||
use crate::check_consts::is_safe_to_expose_on_stable_const_fn;
|
||||
use crate::errors;
|
||||
|
||||
type QualifResults<'mir, 'tcx, Q> =
|
||||
rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
|
||||
|
|
@ -274,19 +275,22 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
/// context.
|
||||
pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) {
|
||||
let gate = match op.status_in_item(self.ccx) {
|
||||
Status::Allowed => return,
|
||||
|
||||
Status::Unstable(gate) if self.tcx.features().active(gate) => {
|
||||
let unstable_in_stable = self.ccx.is_const_stable_const_fn()
|
||||
&& !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate);
|
||||
if unstable_in_stable {
|
||||
emit_unstable_in_stable_error(self.ccx, span, gate);
|
||||
Status::Unstable { gate, safe_to_expose_on_stable, is_function_call }
|
||||
if self.tcx.features().enabled(gate) =>
|
||||
{
|
||||
// Generally this is allowed since the feature gate is enabled -- except
|
||||
// if this function wants to be safe-to-expose-on-stable.
|
||||
if !safe_to_expose_on_stable
|
||||
&& self.enforce_recursive_const_stability()
|
||||
&& !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate)
|
||||
{
|
||||
emit_unstable_in_stable_exposed_error(self.ccx, span, gate, is_function_call);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Status::Unstable(gate) => Some(gate),
|
||||
Status::Unstable { gate, .. } => Some(gate),
|
||||
Status::Forbidden => None,
|
||||
};
|
||||
|
||||
|
|
@ -304,7 +308,13 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
self.error_emitted = Some(reported);
|
||||
}
|
||||
|
||||
ops::DiagImportance::Secondary => self.secondary_errors.push(err),
|
||||
ops::DiagImportance::Secondary => {
|
||||
self.secondary_errors.push(err);
|
||||
self.tcx.dcx().span_delayed_bug(
|
||||
span,
|
||||
"compilation must fail when there is a secondary const checker error",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -569,6 +579,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
|
||||
ty::FnPtr(..) => {
|
||||
self.check_op(ops::FnCallIndirect);
|
||||
// We can get here without an error in miri-unleashed mode... might as well
|
||||
// skip the rest of the checks as well then.
|
||||
return;
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -604,14 +616,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
|
||||
let mut is_trait = false;
|
||||
// Attempting to call a trait method?
|
||||
if tcx.trait_of_item(callee).is_some() {
|
||||
if let Some(trait_did) = tcx.trait_of_item(callee) {
|
||||
trace!("attempting to call a trait method");
|
||||
|
||||
let trait_is_const = tcx.is_const_trait(trait_did);
|
||||
// trait method calls are only permitted when `effects` is enabled.
|
||||
// we don't error, since that is handled by typeck. We try to resolve
|
||||
// the trait into the concrete method, and uses that for const stability
|
||||
// checks.
|
||||
// typeck ensures the conditions for calling a const trait method are met,
|
||||
// so we only error if the trait isn't const. We try to resolve the trait
|
||||
// into the concrete method, and uses that for const stability checks.
|
||||
// FIXME(effects) we might consider moving const stability checks to typeck as well.
|
||||
if tcx.features().effects {
|
||||
if tcx.features().effects() && trait_is_const {
|
||||
// This skips the check below that ensures we only call `const fn`.
|
||||
is_trait = true;
|
||||
|
||||
if let Ok(Some(instance)) =
|
||||
|
|
@ -625,18 +640,27 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
callee = def;
|
||||
}
|
||||
} else {
|
||||
// if the trait is const but the user has not enabled the feature(s),
|
||||
// suggest them.
|
||||
let feature = if trait_is_const {
|
||||
Some(if tcx.features().const_trait_impl() {
|
||||
sym::effects
|
||||
} else {
|
||||
sym::const_trait_impl
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
caller,
|
||||
callee,
|
||||
args: fn_args,
|
||||
span: *fn_span,
|
||||
call_source,
|
||||
feature: Some(if tcx.features().const_trait_impl {
|
||||
sym::effects
|
||||
} else {
|
||||
sym::const_trait_impl
|
||||
}),
|
||||
feature,
|
||||
});
|
||||
// If we allowed this, we're in miri-unleashed mode, so we might
|
||||
// as well skip the remaining checks.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -650,29 +674,73 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
// const-eval of the `begin_panic` fn assumes the argument is `&str`
|
||||
if tcx.is_lang_item(callee, LangItem::BeginPanic) {
|
||||
match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() {
|
||||
ty::Ref(_, ty, _) if ty.is_str() => return,
|
||||
ty::Ref(_, ty, _) if ty.is_str() => {}
|
||||
_ => self.check_op(ops::PanicNonStr),
|
||||
}
|
||||
// Allow this call, skip all the checks below.
|
||||
return;
|
||||
}
|
||||
|
||||
// const-eval of `#[rustc_const_panic_str]` functions assumes the argument is `&&str`
|
||||
if tcx.has_attr(callee, sym::rustc_const_panic_str) {
|
||||
match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() {
|
||||
ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
|
||||
{
|
||||
return;
|
||||
{}
|
||||
_ => {
|
||||
self.check_op(ops::PanicNonStr);
|
||||
}
|
||||
_ => self.check_op(ops::PanicNonStr),
|
||||
}
|
||||
// Allow this call, skip all the checks below.
|
||||
return;
|
||||
}
|
||||
|
||||
// This can be called on stable via the `vec!` macro.
|
||||
if tcx.is_lang_item(callee, LangItem::ExchangeMalloc) {
|
||||
self.check_op(ops::HeapAllocation);
|
||||
// Allow this call, skip all the checks below.
|
||||
return;
|
||||
}
|
||||
|
||||
if !tcx.is_const_fn_raw(callee) && !is_trait {
|
||||
// Intrinsics are language primitives, not regular calls, so treat them separately.
|
||||
if let Some(intrinsic) = tcx.intrinsic(callee) {
|
||||
match tcx.lookup_const_stability(callee) {
|
||||
None => {
|
||||
// Non-const intrinsic.
|
||||
self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
|
||||
}
|
||||
Some(ConstStability { feature: None, const_stable_indirect, .. }) => {
|
||||
// Intrinsic does not need a separate feature gate (we rely on the
|
||||
// regular stability checker). However, we have to worry about recursive
|
||||
// const stability.
|
||||
if !const_stable_indirect && self.enforce_recursive_const_stability() {
|
||||
self.dcx().emit_err(errors::UnmarkedIntrinsicExposed {
|
||||
span: self.span,
|
||||
def_path: self.tcx.def_path_str(callee),
|
||||
});
|
||||
}
|
||||
}
|
||||
Some(ConstStability {
|
||||
feature: Some(feature),
|
||||
level: StabilityLevel::Unstable { .. },
|
||||
const_stable_indirect,
|
||||
..
|
||||
}) => {
|
||||
self.check_op(ops::IntrinsicUnstable {
|
||||
name: intrinsic.name,
|
||||
feature,
|
||||
const_stable_indirect,
|
||||
});
|
||||
}
|
||||
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
|
||||
// All good.
|
||||
}
|
||||
}
|
||||
// This completes the checks for intrinsics.
|
||||
return;
|
||||
}
|
||||
|
||||
// Trait functions are not `const fn` so we have to skip them here.
|
||||
if !tcx.is_const_fn(callee) && !is_trait {
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
caller,
|
||||
callee,
|
||||
|
|
@ -681,66 +749,68 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
call_source,
|
||||
feature: None,
|
||||
});
|
||||
// If we allowed this, we're in miri-unleashed mode, so we might
|
||||
// as well skip the remaining checks.
|
||||
return;
|
||||
}
|
||||
|
||||
// If the `const fn` we are trying to call is not const-stable, ensure that we have
|
||||
// the proper feature gate enabled.
|
||||
if let Some((gate, implied_by)) = is_unstable_const_fn(tcx, callee) {
|
||||
trace!(?gate, "calling unstable const fn");
|
||||
if self.span.allows_unstable(gate) {
|
||||
return;
|
||||
// Finally, stability for regular function calls -- this is the big one.
|
||||
match tcx.lookup_const_stability(callee) {
|
||||
Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
|
||||
// All good.
|
||||
}
|
||||
if let Some(implied_by_gate) = implied_by
|
||||
&& self.span.allows_unstable(implied_by_gate)
|
||||
{
|
||||
return;
|
||||
None | Some(ConstStability { feature: None, .. }) => {
|
||||
// This doesn't need a separate const-stability check -- const-stability equals
|
||||
// regular stability, and regular stability is checked separately.
|
||||
// However, we *do* have to worry about *recursive* const stability.
|
||||
if self.enforce_recursive_const_stability()
|
||||
&& !is_safe_to_expose_on_stable_const_fn(tcx, callee)
|
||||
{
|
||||
self.dcx().emit_err(errors::UnmarkedConstFnExposed {
|
||||
span: self.span,
|
||||
def_path: self.tcx.def_path_str(callee),
|
||||
});
|
||||
}
|
||||
}
|
||||
Some(ConstStability {
|
||||
feature: Some(feature),
|
||||
level: StabilityLevel::Unstable { implied_by: implied_feature, .. },
|
||||
..
|
||||
}) => {
|
||||
// An unstable const fn with a feature gate.
|
||||
let callee_safe_to_expose_on_stable =
|
||||
is_safe_to_expose_on_stable_const_fn(tcx, callee);
|
||||
|
||||
// Calling an unstable function *always* requires that the corresponding gate
|
||||
// (or implied gate) be enabled, even if the function has
|
||||
// `#[rustc_allow_const_fn_unstable(the_gate)]`.
|
||||
let gate_declared = |gate| tcx.features().declared(gate);
|
||||
let feature_gate_declared = gate_declared(gate);
|
||||
let implied_gate_declared = implied_by.is_some_and(gate_declared);
|
||||
if !feature_gate_declared && !implied_gate_declared {
|
||||
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
|
||||
return;
|
||||
}
|
||||
// We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
|
||||
// the callee is safe to expose, to avoid bypassing recursive stability.
|
||||
if (self.span.allows_unstable(feature)
|
||||
|| implied_feature.is_some_and(|f| self.span.allows_unstable(f)))
|
||||
&& callee_safe_to_expose_on_stable
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If this crate is not using stability attributes, or the caller is not claiming to be a
|
||||
// stable `const fn`, that is all that is required.
|
||||
if !self.ccx.is_const_stable_const_fn() {
|
||||
trace!("crate not using stability attributes or caller not stably const");
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we are something const-stable calling a const-unstable fn.
|
||||
if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
|
||||
trace!("rustc_allow_const_fn_unstable gate active");
|
||||
return;
|
||||
}
|
||||
|
||||
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME(ecstaticmorse); For compatibility, we consider `unstable` callees that
|
||||
// have no `rustc_const_stable` attributes to be const-unstable as well. This
|
||||
// should be fixed later.
|
||||
let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
|
||||
&& tcx.lookup_stability(callee).is_some_and(|s| s.is_unstable());
|
||||
if callee_is_unstable_unmarked {
|
||||
trace!("callee_is_unstable_unmarked");
|
||||
// We do not use `const` modifiers for intrinsic "functions", as intrinsics are
|
||||
// `extern` functions, and these have no way to get marked `const`. So instead we
|
||||
// use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
|
||||
if self.ccx.is_const_stable_const_fn() || tcx.intrinsic(callee).is_some() {
|
||||
self.check_op(ops::FnCallUnstable(callee, None));
|
||||
return;
|
||||
// We can't use `check_op` to check whether the feature is enabled because
|
||||
// the logic is a bit different than elsewhere: local functions don't need
|
||||
// the feature gate, and there might be an "implied" gate that also suffices
|
||||
// to allow this.
|
||||
let feature_enabled = callee.is_local()
|
||||
|| tcx.features().enabled(feature)
|
||||
|| implied_feature.is_some_and(|f| tcx.features().enabled(f));
|
||||
// We do *not* honor this if we are in the "danger zone": we have to enforce
|
||||
// recursive const-stability and the callee is not safe-to-expose. In that
|
||||
// case we need `check_op` to do the check.
|
||||
let danger_zone = !callee_safe_to_expose_on_stable
|
||||
&& self.enforce_recursive_const_stability();
|
||||
if danger_zone || !feature_enabled {
|
||||
self.check_op(ops::FnCallUnstable {
|
||||
def_id: callee,
|
||||
feature,
|
||||
safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
trace!("permitting call");
|
||||
}
|
||||
|
||||
// Forbid all `Drop` terminators unless the place being dropped is a local with no
|
||||
|
|
@ -785,11 +855,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
|
||||
TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
|
||||
|
||||
TerminatorKind::Yield { .. } => self.check_op(ops::Coroutine(
|
||||
self.tcx
|
||||
.coroutine_kind(self.body.source.def_id())
|
||||
.expect("Only expected to have a yield in a coroutine"),
|
||||
)),
|
||||
TerminatorKind::Yield { .. } => {
|
||||
self.check_op(ops::Coroutine(
|
||||
self.tcx
|
||||
.coroutine_kind(self.body.source.def_id())
|
||||
.expect("Only expected to have a yield in a coroutine"),
|
||||
));
|
||||
}
|
||||
|
||||
TerminatorKind::CoroutineDrop => {
|
||||
span_bug!(
|
||||
|
|
@ -819,8 +891,19 @@ fn is_int_bool_float_or_char(ty: Ty<'_>) -> bool {
|
|||
ty.is_bool() || ty.is_integral() || ty.is_char() || ty.is_floating_point()
|
||||
}
|
||||
|
||||
fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) {
|
||||
fn emit_unstable_in_stable_exposed_error(
|
||||
ccx: &ConstCx<'_, '_>,
|
||||
span: Span,
|
||||
gate: Symbol,
|
||||
is_function_call: bool,
|
||||
) -> ErrorGuaranteed {
|
||||
let attr_span = ccx.tcx.def_span(ccx.def_id()).shrink_to_lo();
|
||||
|
||||
ccx.dcx().emit_err(UnstableInStable { gate: gate.to_string(), span, attr_span });
|
||||
ccx.dcx().emit_err(errors::UnstableInStableExposed {
|
||||
gate: gate.to_string(),
|
||||
span,
|
||||
attr_span,
|
||||
is_function_call,
|
||||
is_function_call2: is_function_call,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,10 +59,12 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
|
|||
self.const_kind.expect("`const_kind` must not be called on a non-const fn")
|
||||
}
|
||||
|
||||
pub fn is_const_stable_const_fn(&self) -> bool {
|
||||
pub fn enforce_recursive_const_stability(&self) -> bool {
|
||||
// We can skip this if `staged_api` is not enabled, since in such crates
|
||||
// `lookup_const_stability` will always be `None`.
|
||||
self.const_kind == Some(hir::ConstContext::ConstFn)
|
||||
&& self.tcx.features().staged_api
|
||||
&& is_const_stable_const_fn(self.tcx, self.def_id().to_def_id())
|
||||
&& self.tcx.features().staged_api()
|
||||
&& is_safe_to_expose_on_stable_const_fn(self.tcx, self.def_id().to_def_id())
|
||||
}
|
||||
|
||||
fn is_async(&self) -> bool {
|
||||
|
|
@ -90,50 +92,38 @@ pub fn rustc_allow_const_fn_unstable(
|
|||
attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate)
|
||||
}
|
||||
|
||||
/// Returns `true` if the given `const fn` is "const-stable".
|
||||
/// Returns `true` if the given `const fn` is "safe to expose on stable".
|
||||
///
|
||||
/// Panics if the given `DefId` does not refer to a `const fn`.
|
||||
///
|
||||
/// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable"
|
||||
/// functions can be called in a const-context by users of the stable compiler. "const-stable"
|
||||
/// functions are subject to more stringent restrictions than "const-unstable" functions: They
|
||||
/// cannot use unstable features and can only call other "const-stable" functions.
|
||||
pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
// A default body in a `#[const_trait]` is not const-stable because const
|
||||
// trait fns currently cannot be const-stable. We shouldn't
|
||||
// restrict default bodies to only call const-stable functions.
|
||||
/// This is relevant within a `staged_api` crate. Unlike with normal features, the use of unstable
|
||||
/// const features *recursively* taints the functions that use them. This is to avoid accidentally
|
||||
/// exposing e.g. the implementation of an unstable const intrinsic on stable. So we partition the
|
||||
/// world into two functions: those that are safe to expose on stable (and hence may not use
|
||||
/// unstable features, not even recursively), and those that are not.
|
||||
pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
// A default body in a `#[const_trait]` is not const-stable because const trait fns currently
|
||||
// cannot be const-stable. These functions can't be called from anything stable, so we shouldn't
|
||||
// restrict them to only call const-stable functions.
|
||||
if tcx.is_const_default_method(def_id) {
|
||||
// FIXME(const_trait_impl): we have to eventually allow some of these if these things can ever be stable.
|
||||
// They should probably behave like regular `const fn` for that...
|
||||
return false;
|
||||
}
|
||||
|
||||
// Const-stability is only relevant for `const fn`.
|
||||
assert!(tcx.is_const_fn_raw(def_id));
|
||||
assert!(tcx.is_const_fn(def_id));
|
||||
|
||||
// A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs
|
||||
// to is const-stable.
|
||||
match tcx.lookup_const_stability(def_id) {
|
||||
Some(stab) => stab.is_const_stable(),
|
||||
None if is_parent_const_stable_trait(tcx, def_id) => {
|
||||
// Remove this when `#![feature(const_trait_impl)]` is stabilized,
|
||||
// returning `true` unconditionally.
|
||||
tcx.dcx().span_delayed_bug(
|
||||
tcx.def_span(def_id),
|
||||
"trait implementations cannot be const stable yet",
|
||||
);
|
||||
true
|
||||
None => {
|
||||
// Only marked functions can be trusted. Note that this may be a function in a
|
||||
// non-staged-API crate where no recursive checks were done!
|
||||
false
|
||||
}
|
||||
Some(stab) => {
|
||||
// We consider things safe-to-expose if they are stable, if they don't have any explicit
|
||||
// const stability attribute, or if they are marked as `const_stable_indirect`.
|
||||
stab.is_const_stable() || stab.feature.is_none() || stab.const_stable_indirect
|
||||
}
|
||||
None => false, // By default, items are not const stable.
|
||||
}
|
||||
}
|
||||
|
||||
fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
let local_def_id = def_id.expect_local();
|
||||
let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
|
||||
|
||||
let parent_owner_id = tcx.parent_hir_id(hir_id).owner;
|
||||
if !tcx.is_const_trait_impl_raw(parent_owner_id.to_def_id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tcx.lookup_const_stability(parent_owner_id).is_some_and(|stab| stab.is_const_stable())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,16 @@ use crate::{errors, fluent_generated};
|
|||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Status {
|
||||
Allowed,
|
||||
Unstable(Symbol),
|
||||
Unstable {
|
||||
/// The feature that must be enabled to use this operation.
|
||||
gate: Symbol,
|
||||
/// Whether it is allowed to use this operation from stable `const fn`.
|
||||
/// This will usually be `false`.
|
||||
safe_to_expose_on_stable: bool,
|
||||
/// We indicate whether this is a function call, since we can use targeted
|
||||
/// diagnostics for "callee is not safe to expose om stable".
|
||||
is_function_call: bool,
|
||||
},
|
||||
Forbidden,
|
||||
}
|
||||
|
||||
|
|
@ -40,9 +48,9 @@ pub enum DiagImportance {
|
|||
Secondary,
|
||||
}
|
||||
|
||||
/// An operation that is not *always* allowed in a const context.
|
||||
/// An operation that is *not allowed* in a const context.
|
||||
pub trait NonConstOp<'tcx>: std::fmt::Debug {
|
||||
/// Returns an enum indicating whether this operation is allowed within the given item.
|
||||
/// Returns an enum indicating whether this operation can be enabled with a feature gate.
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Forbidden
|
||||
}
|
||||
|
|
@ -114,7 +122,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
|
||||
if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
|
||||
// FIXME(effects) revisit this
|
||||
if !tcx.is_const_trait_impl_raw(data.impl_def_id) {
|
||||
if !tcx.is_const_trait_impl(data.impl_def_id) {
|
||||
let span = tcx.def_span(data.impl_def_id);
|
||||
err.subdiagnostic(errors::NonConstImplNote { span });
|
||||
}
|
||||
|
|
@ -166,7 +174,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
let note = match self_ty.kind() {
|
||||
FnDef(def_id, ..) => {
|
||||
let span = tcx.def_span(*def_id);
|
||||
if ccx.tcx.is_const_fn_raw(*def_id) {
|
||||
if ccx.tcx.is_const_fn(*def_id) {
|
||||
span_bug!(span, "calling const FnDef errored when it shouldn't");
|
||||
}
|
||||
|
||||
|
|
@ -298,30 +306,78 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
///
|
||||
/// Contains the name of the feature that would allow the use of this function.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FnCallUnstable(pub DefId, pub Option<Symbol>);
|
||||
pub(crate) struct FnCallUnstable {
|
||||
pub def_id: DefId,
|
||||
pub feature: Symbol,
|
||||
pub safe_to_expose_on_stable: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable {
|
||||
gate: self.feature,
|
||||
safe_to_expose_on_stable: self.safe_to_expose_on_stable,
|
||||
is_function_call: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
let FnCallUnstable(def_id, feature) = *self;
|
||||
|
||||
let mut err = ccx
|
||||
.dcx()
|
||||
.create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) });
|
||||
|
||||
let mut err = ccx.dcx().create_err(errors::UnstableConstFn {
|
||||
span,
|
||||
def_path: ccx.tcx.def_path_str(self.def_id),
|
||||
});
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
if ccx.is_const_stable_const_fn() {
|
||||
err.help(fluent_generated::const_eval_const_stable);
|
||||
} else if ccx.tcx.sess.is_nightly_build() {
|
||||
if let Some(feature) = feature {
|
||||
err.help(format!("add `#![feature({feature})]` to the crate attributes to enable"));
|
||||
}
|
||||
}
|
||||
err.help(format!("add `#![feature({})]` to the crate attributes to enable", self.feature));
|
||||
|
||||
err
|
||||
}
|
||||
}
|
||||
|
||||
/// A call to an intrinsic that is just not const-callable at all.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct IntrinsicNonConst {
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
ccx.dcx().create_err(errors::NonConstIntrinsic {
|
||||
span,
|
||||
name: self.name,
|
||||
kind: ccx.const_kind(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A call to an intrinsic that is just not const-callable at all.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct IntrinsicUnstable {
|
||||
pub name: Symbol,
|
||||
pub feature: Symbol,
|
||||
pub const_stable_indirect: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable {
|
||||
gate: self.feature,
|
||||
safe_to_expose_on_stable: self.const_stable_indirect,
|
||||
// We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`,
|
||||
// that's not a trivial change!
|
||||
is_function_call: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
ccx.dcx().create_err(errors::UnstableIntrinsic {
|
||||
span,
|
||||
name: self.name,
|
||||
feature: self.feature,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Coroutine(pub hir::CoroutineKind);
|
||||
impl<'tcx> NonConstOp<'tcx> for Coroutine {
|
||||
|
|
@ -331,7 +387,11 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
|
|||
hir::CoroutineSource::Block,
|
||||
) = self.0
|
||||
{
|
||||
Status::Unstable(sym::const_async_blocks)
|
||||
Status::Unstable {
|
||||
gate: sym::const_async_blocks,
|
||||
safe_to_expose_on_stable: false,
|
||||
is_function_call: false,
|
||||
}
|
||||
} else {
|
||||
Status::Forbidden
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use crate::check_consts::rustc_allow_const_fn_unstable;
|
|||
/// elaboration.
|
||||
pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool {
|
||||
// Const-stable functions must always use the stable live drop checker...
|
||||
if ccx.is_const_stable_const_fn() {
|
||||
if ccx.enforce_recursive_const_stability() {
|
||||
// ...except if they have the feature flag set via `rustc_allow_const_fn_unstable`.
|
||||
return rustc_allow_const_fn_unstable(
|
||||
ccx.tcx,
|
||||
|
|
@ -24,7 +24,7 @@ pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool {
|
|||
);
|
||||
}
|
||||
|
||||
ccx.tcx.features().const_precise_live_drops
|
||||
ccx.tcx.features().const_precise_live_drops()
|
||||
}
|
||||
|
||||
/// Look for live drops in a const context.
|
||||
|
|
|
|||
|
|
@ -1,25 +1,8 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use {rustc_attr as attr, rustc_hir as hir};
|
||||
|
||||
/// Whether the `def_id` is an unstable const fn and what feature gate(s) are necessary to enable
|
||||
/// it.
|
||||
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<(Symbol, Option<Symbol>)> {
|
||||
if tcx.is_const_fn_raw(def_id) {
|
||||
let const_stab = tcx.lookup_const_stability(def_id)?;
|
||||
match const_stab.level {
|
||||
attr::StabilityLevel::Unstable { implied_by, .. } => {
|
||||
Some((const_stab.feature, implied_by))
|
||||
}
|
||||
attr::StabilityLevel::Stable { .. } => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
let parent_id = tcx.local_parent(def_id);
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
|
|||
}
|
||||
|
||||
/// "Intercept" a function call, because we have something special to do for it.
|
||||
/// All `#[rustc_do_not_const_check]` functions should be hooked here.
|
||||
/// All `#[rustc_do_not_const_check]` functions MUST be hooked here.
|
||||
/// If this returns `Some` function, which may be `instance` or a different function with
|
||||
/// compatible arguments, then evaluation should continue with that function.
|
||||
/// If this returns `None`, the function call has been handled and the function has returned.
|
||||
|
|
@ -395,7 +395,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
|
|||
|
||||
#[inline(always)]
|
||||
fn enforce_validity(ecx: &InterpCx<'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool {
|
||||
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited()
|
||||
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.is_uninhabited()
|
||||
}
|
||||
|
||||
fn load_mir(
|
||||
|
|
@ -431,8 +431,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
|
|||
// sensitive check here. But we can at least rule out functions that are not const at
|
||||
// all. That said, we have to allow calling functions inside a trait marked with
|
||||
// #[const_trait]. These *are* const-checked!
|
||||
// FIXME: why does `is_const_fn_raw` not classify them as const?
|
||||
if (!ecx.tcx.is_const_fn_raw(def) && !ecx.tcx.is_const_default_method(def))
|
||||
// FIXME(effects): why does `is_const_fn` not classify them as const?
|
||||
if (!ecx.tcx.is_const_fn(def) && !ecx.tcx.is_const_default_method(def))
|
||||
|| ecx.tcx.has_attr(def, sym::rustc_do_not_const_check)
|
||||
{
|
||||
// We certainly do *not* want to actually call the fn
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use rustc_middle::mir::interpret::{
|
|||
UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
|
||||
};
|
||||
use rustc_middle::ty::{self, Mutability, Ty};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::abi::WrappingRange;
|
||||
use rustc_target::abi::call::AdjustForForeignAbiError;
|
||||
|
||||
|
|
@ -44,11 +44,15 @@ pub(crate) struct MutablePtrInFinal {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unstable_in_stable)]
|
||||
pub(crate) struct UnstableInStable {
|
||||
#[diag(const_eval_unstable_in_stable_exposed)]
|
||||
pub(crate) struct UnstableInStableExposed {
|
||||
pub gate: String,
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[help(const_eval_is_function_call)]
|
||||
pub is_function_call: bool,
|
||||
/// Need to duplicate the field so that fluent also provides it as a variable...
|
||||
pub is_function_call2: bool,
|
||||
#[suggestion(
|
||||
const_eval_unstable_sugg,
|
||||
code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",
|
||||
|
|
@ -117,6 +121,34 @@ pub(crate) struct UnstableConstFn {
|
|||
pub def_path: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unstable_intrinsic)]
|
||||
#[help]
|
||||
pub(crate) struct UnstableIntrinsic {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
pub feature: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unmarked_const_fn_exposed)]
|
||||
#[help]
|
||||
pub(crate) struct UnmarkedConstFnExposed {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub def_path: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unmarked_intrinsic_exposed)]
|
||||
#[help]
|
||||
pub(crate) struct UnmarkedIntrinsicExposed {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub def_path: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_mutable_ref_escaping, code = E0764)]
|
||||
pub(crate) struct MutableRefEscaping {
|
||||
|
|
@ -153,6 +185,15 @@ pub(crate) struct NonConstFnCall {
|
|||
pub kind: ConstContext,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_non_const_intrinsic)]
|
||||
pub(crate) struct NonConstIntrinsic {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
pub kind: ConstContext,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unallowed_op_in_const_context)]
|
||||
pub(crate) struct UnallowedOpInConstContext {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
// discriminant, so we cannot do anything here.
|
||||
// When evaluating we will always error before even getting here, but ConstProp 'executes'
|
||||
// dead code, so we cannot ICE here.
|
||||
if dest.layout().for_variant(self, variant_index).abi.is_uninhabited() {
|
||||
if dest.layout().for_variant(self, variant_index).is_uninhabited() {
|
||||
throw_ub!(UninhabitedEnumVariantWritten(variant_index))
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
// For consistency with `write_discriminant`, and to make sure that
|
||||
// `project_downcast` cannot fail due to strange layouts, we declare immediate UB
|
||||
// for uninhabited variants.
|
||||
if op.layout().for_variant(self, index).abi.is_uninhabited() {
|
||||
if op.layout().for_variant(self, index).is_uninhabited() {
|
||||
throw_ub!(UninhabitedEnumVariantRead(index))
|
||||
}
|
||||
}
|
||||
|
|
@ -203,7 +203,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
// Reading the discriminant of an uninhabited variant is UB. This is the basis for the
|
||||
// `uninhabited_enum_branching` MIR pass. It also ensures consistency with
|
||||
// `write_discriminant`.
|
||||
if op.layout().for_variant(self, index).abi.is_uninhabited() {
|
||||
if op.layout().for_variant(self, index).is_uninhabited() {
|
||||
throw_ub!(UninhabitedEnumVariantRead(index))
|
||||
}
|
||||
interp_ok(index)
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let msg = match requirement {
|
||||
// For *all* intrinsics we first check `is_uninhabited` to give a more specific
|
||||
// error message.
|
||||
_ if layout.abi.is_uninhabited() => format!(
|
||||
_ if layout.is_uninhabited() => format!(
|
||||
"aborted execution: attempted to instantiate uninhabited type `{ty}`"
|
||||
),
|
||||
ValidityRequirement::Inhabited => bug!("handled earlier"),
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let ptr = left.to_scalar().to_pointer(self)?;
|
||||
let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
|
||||
let pointee_layout = self.layout_of(pointee_ty)?;
|
||||
assert!(pointee_layout.abi.is_sized());
|
||||
assert!(pointee_layout.is_sized());
|
||||
|
||||
// The size always fits in `i64` as it can be at most `isize::MAX`.
|
||||
let pointee_size = i64::try_from(pointee_layout.size.bytes()).unwrap();
|
||||
|
|
@ -518,14 +518,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
|
||||
interp_ok(match null_op {
|
||||
SizeOf => {
|
||||
if !layout.abi.is_sized() {
|
||||
if !layout.is_sized() {
|
||||
span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`");
|
||||
}
|
||||
let val = layout.size.bytes();
|
||||
ImmTy::from_uint(val, usize_layout())
|
||||
}
|
||||
AlignOf => {
|
||||
if !layout.abi.is_sized() {
|
||||
if !layout.is_sized() {
|
||||
span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`");
|
||||
}
|
||||
let val = layout.align.abi.bytes();
|
||||
|
|
|
|||
|
|
@ -542,7 +542,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
|
|||
throw_validation_failure!(self.path, NullPtr { ptr_kind })
|
||||
}
|
||||
// Do not allow references to uninhabited types.
|
||||
if place.layout.abi.is_uninhabited() {
|
||||
if place.layout.is_uninhabited() {
|
||||
let ty = place.layout.ty;
|
||||
throw_validation_failure!(self.path, PtrToUninhabited { ptr_kind, ty })
|
||||
}
|
||||
|
|
@ -867,7 +867,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
|
|||
/// Add the entire given place to the "data" range of this visit.
|
||||
fn add_data_range_place(&mut self, place: &PlaceTy<'tcx, M::Provenance>) {
|
||||
// Only sized places can be added this way.
|
||||
debug_assert!(place.layout.abi.is_sized());
|
||||
debug_assert!(place.layout.is_sized());
|
||||
if let Some(data_bytes) = self.data_bytes.as_mut() {
|
||||
let offset = Self::data_range_offset(self.ecx, place);
|
||||
data_bytes.add_range(offset, place.layout.size);
|
||||
|
|
@ -945,7 +945,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
|
|||
layout: TyAndLayout<'tcx>,
|
||||
) -> Cow<'e, RangeSet> {
|
||||
assert!(layout.ty.is_union());
|
||||
assert!(layout.abi.is_sized(), "there are no unsized unions");
|
||||
assert!(layout.is_sized(), "there are no unsized unions");
|
||||
let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env);
|
||||
return M::cached_union_data_range(ecx, layout.ty, || {
|
||||
let mut out = RangeSet(Vec::new());
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ pub fn check_validity_requirement<'tcx>(
|
|||
|
||||
// There is nothing strict or lax about inhabitedness.
|
||||
if kind == ValidityRequirement::Inhabited {
|
||||
return Ok(!layout.abi.is_uninhabited());
|
||||
return Ok(!layout.is_uninhabited());
|
||||
}
|
||||
|
||||
let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue