Rollup merge of #131984 - dingxiangfei2009:stabilize-if-let-rescope, r=traviscross,lcnr
Stabilize if_let_rescope
Close #131154
Tracked by #124085
diff --git a/Cargo.lock b/Cargo.lock
index 4d54b5a..22b3e82 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3301,6 +3301,7 @@
dependencies = [
"itertools",
"rustc_ast",
+ "rustc_data_structures",
"rustc_lexer",
"rustc_span",
"thin-vec",
@@ -3621,6 +3622,7 @@
dependencies = [
"annotate-snippets 0.11.4",
"derive_setters",
+ "rustc_abi",
"rustc_ast",
"rustc_ast_pretty",
"rustc_data_structures",
@@ -3718,6 +3720,7 @@
version = "0.0.0"
dependencies = [
"itertools",
+ "rustc_abi",
"rustc_arena",
"rustc_ast",
"rustc_attr",
@@ -3906,6 +3909,7 @@
name = "rustc_lint"
version = "0.0.0"
dependencies = [
+ "rustc_abi",
"rustc_ast",
"rustc_ast_pretty",
"rustc_attr",
@@ -3980,6 +3984,7 @@
"bitflags 2.6.0",
"libloading",
"odht",
+ "rustc_abi",
"rustc_ast",
"rustc_attr",
"rustc_data_structures",
@@ -4029,6 +4034,7 @@
"rustc_hir",
"rustc_hir_pretty",
"rustc_index",
+ "rustc_lint_defs",
"rustc_macros",
"rustc_query_system",
"rustc_serialize",
@@ -4073,6 +4079,7 @@
dependencies = [
"polonius-engine",
"regex",
+ "rustc_abi",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
@@ -4094,6 +4101,7 @@
dependencies = [
"either",
"itertools",
+ "rustc_abi",
"rustc_arena",
"rustc_ast",
"rustc_attr",
@@ -4186,6 +4194,7 @@
name = "rustc_passes"
version = "0.0.0"
dependencies = [
+ "rustc_abi",
"rustc_ast",
"rustc_ast_pretty",
"rustc_attr",
@@ -4212,6 +4221,7 @@
version = "0.0.0"
dependencies = [
"rustc-hash 2.0.0",
+ "rustc_abi",
"rustc_apfloat",
"rustc_arena",
"rustc_data_structures",
@@ -4351,6 +4361,7 @@
"bitflags 2.6.0",
"getopts",
"libc",
+ "rustc_abi",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
@@ -4414,6 +4425,7 @@
dependencies = [
"punycode",
"rustc-demangle",
+ "rustc_abi",
"rustc_data_structures",
"rustc_errors",
"rustc_hir",
@@ -4495,6 +4507,7 @@
version = "0.0.0"
dependencies = [
"itertools",
+ "rustc_abi",
"rustc_ast_ir",
"rustc_data_structures",
"rustc_hir",
@@ -4502,7 +4515,6 @@
"rustc_macros",
"rustc_middle",
"rustc_span",
- "rustc_target",
"tracing",
]
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 0340d1b..86de39b 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -7,7 +7,7 @@
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 @@
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 @@
}
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 @@
&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 @@
.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 @@
'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 @@
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 @@
'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 @@
'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 @@
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 @@
'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 @@
'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 @@
// 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 @@
Abi::Aggregate { sized: true }
};
- let layout = LayoutS {
+ let layout = LayoutData {
variants: Variants::Multiple {
tag: niche_scalar,
tag_encoding: TagEncoding::Niche {
@@ -681,7 +681,7 @@
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 @@
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 @@
'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 @@
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 @@
'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();
diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs
index c6812c4..e029e14 100644
--- a/compiler/rustc_abi/src/layout/ty.rs
+++ b/compiler/rustc_abi/src/layout/ty.rs
@@ -58,7 +58,7 @@
}
#[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> 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> 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
}
}
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 8e90130..41922ae 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1485,7 +1485,7 @@
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 @@
// 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 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 @@
}
}
+ /// 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> 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 @@
// 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 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 {
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index b73412a..9311af2 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -223,7 +223,7 @@
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())
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 1d6abbe..3b9edef 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -368,7 +368,7 @@
// 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) },
}
}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 207ec71..eb71ec5 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -135,7 +135,7 @@
/// 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 @@
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_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 @@
}) => {
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 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}) => {
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 {
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 9d2b569..20d3ce6 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -10,17 +10,18 @@
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 }
}
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 3b85f17..70c94f4 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -259,10 +259,11 @@
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);
}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index a1a16d0..b7cf2d2 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -3,6 +3,7 @@
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 @@
_ => (),
}
- 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 @@
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 @@
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 @@
binder,
*capture_clause,
e.id,
- hir_id,
+ expr_hir_id,
*coroutine_kind,
fn_decl,
body,
@@ -223,7 +231,7 @@
binder,
*capture_clause,
e.id,
- hir_id,
+ expr_hir_id,
*constness,
*movability,
fn_decl,
@@ -250,8 +258,16 @@
)
}
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 @@
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 @@
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 @@
/// `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 @@
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 @@
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))
@@ -638,7 +654,7 @@
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);
@@ -724,7 +740,7 @@
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 @@
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 @@
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 @@
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 @@
)
}
- 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 @@
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 @@
}
}
- 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;
@@ -1658,9 +1684,13 @@
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 @@
// 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 @@
// `[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 @@
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 @@
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 @@
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 @@
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))
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index c43106c..d724560 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -57,7 +57,7 @@
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 @@
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 @@
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 @@
);
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
ItemKind::TraitAlias(generics, bounds) => {
let (generics, bounds) = self.lower_generics(
generics,
- Const::No,
- false,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
@@ -604,55 +583,28 @@
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 @@
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 @@
}
}
- 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 @@
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 @@
i.id,
FnDeclKind::Trait,
sig.header.coroutine_kind,
- trait_constness,
);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
}
@@ -829,7 +774,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
);
// 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 @@
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 @@
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,
@@ -1524,30 +1449,6 @@
}
}
- // 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 @@
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),
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 7cd0cd1..dc9c6b7 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -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 @@
/// 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 @@
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 @@
/// 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 @@
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(),
@@ -204,8 +200,6 @@
// 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 @@
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 @@
// 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 @@
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 @@
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 @@
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);
@@ -1874,7 +1878,7 @@
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)))
}
};
@@ -2054,11 +2058,7 @@
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 @@
&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 @@
(
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 },
)
}
}
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 760f845..ace7bfb 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -21,13 +21,20 @@
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 @@
}
};
- self.pat_with_node_id_of(pattern, node)
+ self.pat_with_node_id_of(pattern, node, pat_hir_id)
})
}
@@ -187,10 +194,12 @@
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 @@
// 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 @@
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 @@
}
}
- 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.
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 258655d..133793e 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -34,7 +34,10 @@
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 @@
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 @@
segment,
param_mode,
generic_args_mode,
- itctx,
+ itctx(i),
bound_modifier_allowed_features.clone(),
)
},
@@ -185,7 +198,7 @@
segment,
param_mode,
generic_args_mode,
- itctx,
+ itctx(i),
None,
));
let qpath = hir::QPath::TypeRelative(ty, hir_segment);
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 92acaaa..d81fd53 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -146,8 +146,6 @@
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
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index bf6ebfb..0a4f86d 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -80,10 +80,6 @@
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 @@
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 @@
.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);
@@ -737,10 +696,6 @@
}
}
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 @@
}
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 @@
}
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 @@
}
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 @@
// 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 @@
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 @@
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);
@@ -1521,7 +1476,7 @@
|| 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 @@
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,
};
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 4ca1acd..8c3ac98 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -419,13 +419,6 @@
}
#[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 {
#[primary_span]
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 348a602..d646150 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -623,8 +623,9 @@
let stable_since = features
.enabled_lang_features()
.iter()
- .flat_map(|&(feature, _, since)| if feature == name { since } else { None })
- .next();
+ .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 {
@@ -642,16 +643,15 @@
}
fn check_incompatible_features(sess: &Session, features: &Features) {
- let enabled_features = features
- .enabled_lang_features()
- .iter()
- .copied()
- .map(|(name, span, _)| (name, span))
- .chain(features.enabled_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.enabled(f1) && features.enabled(f2))
+ .filter(|(f1, f2)| features.enabled(*f1) && features.enabled(*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)
@@ -673,10 +673,11 @@
}
// Ban GCE with the new solver, because it does not implement GCE correctly.
- if let Some(&(_, gce_span, _)) = 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],
diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs
index e22e99f..9e7204d 100644
--- a/compiler/rustc_ast_passes/src/node_count.rs
+++ b/compiler/rustc_ast_passes/src/node_count.rs
@@ -16,7 +16,7 @@
}
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) {
diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml
index 9ae5c9b..f290fed 100644
--- a/compiler/rustc_ast_pretty/Cargo.toml
+++ b/compiler/rustc_ast_pretty/Cargo.toml
@@ -7,6 +7,7 @@
# 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"
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 2cdec21..de9f518 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -21,6 +21,7 @@
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 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 @@
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 @@
self.word(token_str);
}
}
+ match item.unsafety {
+ ast::Safety::Unsafe(_) => self.pclose(),
+ ast::Safety::Default | ast::Safety::Safe(_) => {}
+ }
self.end();
}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 8217b6d..8279c66 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -38,7 +38,6 @@
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 @@
ty,
expr.as_deref(),
vis,
+ *safety,
ast::Defaultness::Final,
)
}
@@ -84,10 +84,12 @@
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 @@
ty,
body.as_deref(),
&item.vis,
+ ast::Safety::Default,
ast::Defaultness::Final,
);
}
@@ -192,6 +195,7 @@
ty,
expr.as_deref(),
&item.vis,
+ ast::Safety::Default,
*defaultness,
);
}
@@ -549,6 +553,7 @@
ty,
expr.as_deref(),
vis,
+ ast::Safety::Default,
*defaultness,
);
}
diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl
index adabf18..235ab75 100644
--- a/compiler/rustc_attr/messages.ftl
+++ b/compiler/rustc_attr/messages.ftl
@@ -91,6 +91,9 @@
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
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index e412417..6af75bc 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -16,9 +16,9 @@
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 @@
#[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 @@
/// 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 @@
}
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 @@
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 @@
}
}
}
+ 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 @@
// 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(),
- )),
+ ),
cfg.span(),
sess,
features,
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index 626840a..9d08a9f 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -319,6 +319,13 @@
}
#[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 {
#[primary_span]
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 2437a43..2fa7523 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -65,6 +65,7 @@
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 @@
.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
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index a5f3298..3158517 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -959,13 +959,9 @@
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,
}
};
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 3674053..f76603d 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -107,13 +107,13 @@
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,
);
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index e85f529..d5c2796 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -733,7 +733,7 @@
}
// 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 @@
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];
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index a16c193..abce982 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -360,6 +360,7 @@
.err_ctxt()
.report_mismatched_types(
&ObligationCause::misc(definition_span, def_id),
+ param_env,
opaque_ty,
definition_ty,
err,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index a544d88..26919bf 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -134,7 +134,7 @@
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 @@
infcx,
param_env,
implicit_region_bound,
- universal_regions.clone(),
+ Rc::clone(&universal_regions),
&mut constraints,
);
diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
similarity index 95%
rename from compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
rename to compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
index 731945f..53e938e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
@@ -19,7 +19,7 @@
($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 @@
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 @@
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 @@
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 @@
.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 @@
(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 @@
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 @@
.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 @@
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));
}
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 652e6f7..d4befd1 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -222,7 +222,7 @@
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);
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index e884c0e..681fbd1 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -22,12 +22,12 @@
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;
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 377d7f5..9eee921 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -133,7 +133,7 @@
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);
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index d6603af..707c36d 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -313,14 +313,23 @@
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 @@
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),
])
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 9fc0318..42c7f5f 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -47,12 +47,12 @@
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 {}
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
index 6469288..3c81b04 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
@@ -38,7 +38,7 @@
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 @@
- 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 @@
- 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",
diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
index a318cae..daea789 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
@@ -79,7 +79,7 @@
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();
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index f0b78e5..79d7692 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -210,7 +210,6 @@
type_names::push_generic_params(
tcx,
tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args),
- enclosing_fn_def_id,
&mut name,
);
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index f47bfda..0576b64 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -44,12 +44,12 @@
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 {}
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 4573806..7c52cba 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -1725,16 +1725,6 @@
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> {
diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs
index 9ad2e90..65972a0 100644
--- a/compiler/rustc_codegen_gcc/src/callee.rs
+++ b/compiler/rustc_codegen_gcc/src/callee.rs
@@ -98,8 +98,7 @@
// 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
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index 183e9dd..db874af 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -197,7 +197,7 @@
/// `[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> {
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 2fe5ed3..8a1ee48 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -415,7 +415,7 @@
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 @@
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 {
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 89f5305..a2e6c7e 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -7,6 +7,7 @@
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 @@
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 @@
);
let llfn = llvm::LLVMRustGetOrInsertFunction(
llmod,
- from_name.as_ptr().cast(),
+ from_name.as_c_char_ptr(),
from_name.len(),
ty,
);
@@ -134,10 +129,7 @@
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 @@
}
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());
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index d1d7d0c..3c30822 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -15,7 +15,7 @@
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 @@
unsafe {
llvm::LLVMAppendModuleInlineAsm(
self.llmod,
- template_str.as_ptr().cast(),
+ template_str.as_c_char_ptr(),
template_str.len(),
);
}
@@ -458,14 +458,14 @@
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,
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 1f7a923..352d2e1 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -25,6 +25,7 @@
use crate::back::write::{
self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, save_temp_bitcode,
};
+use crate::common::AsCCharPtr;
use crate::errors::{
DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, LtoProcMacro,
};
@@ -502,9 +503,9 @@
// 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 +570,7 @@
info!(" - {}: re-compiled", module_name);
opt_jobs.push(LtoModuleCodegen::Thin(ThinModule {
- shared: shared.clone(),
+ shared: Arc::clone(&shared),
idx: module_index,
}));
}
@@ -604,7 +605,7 @@
unsafe {
if !llvm::LLVMRustHasModuleFlag(
module.module_llvm.llmod(),
- "LTOPostLink".as_ptr().cast(),
+ "LTOPostLink".as_c_char_ptr(),
11,
) {
llvm::LLVMRustAddModuleFlagU32(
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index afdd2b5..e68ba96 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -34,6 +34,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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);
}
}
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index dbf5298..8702532 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1165,39 +1165,6 @@
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 @@
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 @@
///
/// [`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 @@
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"
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 206a706..25037b9 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -95,11 +95,10 @@
// 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 @@
|| !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
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 0ced37b5..29adc61 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -219,8 +219,8 @@
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 @@
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()
+ }
+}
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 33a85ad..21d996e 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -19,7 +19,7 @@
};
use tracing::{debug, instrument, trace};
-use crate::common::CodegenCx;
+use crate::common::{AsCCharPtr, CodegenCx};
use crate::errors::{
InvalidMinimumAlignmentNotPowerOfTwo, InvalidMinimumAlignmentTooLarge, SymbolAlreadyDefined,
};
@@ -172,29 +172,27 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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);
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 2f830d6..1a21972 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -29,6 +29,7 @@
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 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>>,
@@ -230,7 +232,7 @@
// 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();
+ let cfi_normalize_integers = c"cfi-normalize-integers".as_ptr();
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
@@ -267,7 +269,7 @@
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();
+ let kcfi_offset = c"kcfi-offset".as_ptr();
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
@@ -428,7 +430,7 @@
let name_metadata = unsafe {
llvm::LLVMMDStringInContext2(
llcx,
- rustc_producer.as_ptr().cast(),
+ rustc_producer.as_c_char_ptr(),
rustc_producer.as_bytes().len(),
)
};
@@ -452,7 +454,7 @@
llmod,
llvm::LLVMModFlagBehavior::Error,
c"target-abi".as_ptr(),
- llvm_abiname.as_ptr().cast(),
+ llvm_abiname.as_c_char_ptr(),
llvm_abiname.len(),
);
}
@@ -473,7 +475,7 @@
// We already checked this during option parsing
_ => unreachable!(),
};
- unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) }
+ unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_c_char_ptr(), *value) }
}
llmod
@@ -592,11 +594,10 @@
&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 +606,7 @@
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 +1100,10 @@
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);
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index 90f7dd73..feac97f 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -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 @@
/// 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 @@
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 @@
/// 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 @@
/// 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 @@
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 @@
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 @@
}
}
-/// 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,
- ),
- }
+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 }
}
+}
- 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,
- }
- }
+/// Must match the layout of `LLVMRustCoverageCodeRegion`.
+#[derive(Clone, Debug)]
+#[repr(C)]
+pub(crate) struct CodeRegion {
+ pub(crate) span: CoverageSpan,
+ pub(crate) counter: Counter,
+}
- 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,
- }
- }
+/// 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,
+}
- 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,
- }
- }
+/// 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,
+}
- 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,
- }
- }
+/// 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,
}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index cee704a..8edd788 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
);
// 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 @@
/*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 @@
// 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);
}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 484a4d0..a298ed8 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -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 @@
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 @@
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 @@
}
}
-// 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 @@
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 @@
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 @@
}
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 @@
}
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 @@
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 @@
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 @@
) {
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_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 @@
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")
-}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index f93d3e4..7947c9c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -76,7 +76,7 @@
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);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 15d441a..9064cfa 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -32,7 +32,7 @@
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 @@
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 @@
size,
align,
0, // Ignore DWARF address space.
- name.as_ptr().cast(),
+ name.as_c_char_ptr(),
name.len(),
)
};
@@ -518,7 +518,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
DIB(cx),
None,
- name.as_ptr().cast(),
+ name.as_c_char_ptr(),
name.len(),
actual_type_di_node,
)
@@ -1382,9 +1382,9 @@
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 @@
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,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
index 966788c..5385d3a 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
@@ -11,7 +11,7 @@
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 @@
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 @@
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 @@
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,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index fe16341..4c84802 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -13,7 +13,7 @@
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 @@
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 @@
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,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
index 5e7dbdd..b7400c5 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
@@ -10,7 +10,7 @@
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 @@
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 @@
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 @@
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 @@
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,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index 714e3c0..d050dc9 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -9,7 +9,7 @@
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 @@
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 @@
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 @@
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 @@
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(),
)
},
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 1a8153a..85eb1c8 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -31,7 +31,7 @@
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,
@@ -350,7 +350,6 @@
type_names::push_generic_params(
tcx,
tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args),
- enclosing_fn_def_id,
&mut name,
);
@@ -365,7 +364,7 @@
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 +389,9 @@
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 +406,9 @@
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 +494,7 @@
Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
DIB(cx),
None,
- name.as_ptr().cast(),
+ name.as_c_char_ptr(),
name.len(),
actual_type_metadata,
))
@@ -636,7 +635,7 @@
DIB(self),
dwarf_tag,
scope_metadata,
- name.as_ptr().cast(),
+ name.as_c_char_ptr(),
name.len(),
file_metadata,
loc.line,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
index 3578755..33d9bc2 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
@@ -5,7 +5,7 @@
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 @@
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)
)
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 33258cb..d338c84 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -20,6 +20,7 @@
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 @@
) -> &'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 @@
/// 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 @@
/// 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
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index c9a17c9..d04b525 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -785,13 +785,12 @@
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 @@
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);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index d0034de..30e9758 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -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 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++.
@@ -108,26 +134,36 @@
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 +981,11 @@
// 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 +1561,6 @@
) -> 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 +1651,6 @@
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 +1776,7 @@
) -> 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 +1785,39 @@
);
#[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;
@@ -2347,9 +2385,9 @@
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,
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index e837022..cabe6c0 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -17,13 +17,13 @@
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 @@
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 @@
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 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 @@
/// 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());
}
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 5793621..9adb129 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -248,6 +248,7 @@
("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 @@
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)
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index bf6ef21..ea8857b 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -39,9 +39,9 @@
.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 @@
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 @@
&& 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 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;
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 1af666f..6be4c3f 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -191,7 +191,7 @@
/// `[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 {
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 77c35a1..d966945 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -312,7 +312,7 @@
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 @@
}));
}
}
- 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 @@
}));
}
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,
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index e3d11cf..8445d16 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -514,7 +514,7 @@
future: Some(coordinator_thread),
phantom: PhantomData,
},
- output_filenames: tcx.output_filenames(()).clone(),
+ output_filenames: Arc::clone(tcx.output_filenames(())),
}
}
@@ -1203,7 +1203,7 @@
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,
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index f3d9a7d..b954633 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -7,7 +7,7 @@
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 @@
// 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 @@
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 @@
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);
}
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 526d2b8..1e5b4f3 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -110,14 +110,14 @@
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 @@
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 @@
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_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 @@
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 @@
// 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) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index e3553dc..a17a127 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -438,7 +438,7 @@
_ => 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 @@
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 {
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index a7d5541..15c8e53 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -55,7 +55,7 @@
/// 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 @@
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 @@
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();
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 82fea4c..6e8c193 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -203,10 +203,10 @@
) -> 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 @@
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 };
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index c0c1085..50a5171 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -437,14 +437,6 @@
/// 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,
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 24dbe68..3e4f83c 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -41,8 +41,6 @@
*[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_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 @@
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
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 288798b..004fb12 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -5,6 +5,7 @@
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::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 @@
/// 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().enabled(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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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_enabled = |gate| tcx.features().enabled(gate);
- let feature_gate_enabled = gate_enabled(gate);
- let implied_gate_enabled = implied_by.is_some_and(gate_enabled);
- if !feature_gate_enabled && !implied_gate_enabled {
- 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 enabled");
- 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 @@
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 @@
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,
+ })
}
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index 3720418..56da679 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -59,10 +59,12 @@
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())
+ && 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 @@
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
}
- None => false, // By default, items are not const stable.
+ 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
+ }
}
}
-
-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())
-}
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 5c4a899..3ac06ae 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -26,8 +26,16 @@
#[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 @@
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 @@
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 @@
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 @@
///
/// 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 @@
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
}
diff --git a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
index d04d7b2..0173a52 100644
--- a/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/check_consts/post_drop_elaboration.rs
@@ -15,7 +15,7 @@
/// 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,
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index ca0993f..037fdcb 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -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);
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 2db43a0..5f0bc85 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -219,7 +219,7 @@
}
/// "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 @@
#[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 @@
// 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
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 211668c..38b87b7 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -14,7 +14,7 @@
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 @@
}
#[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",
@@ -118,6 +122,34 @@
}
#[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 {
#[primary_span]
@@ -154,6 +186,15 @@
}
#[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 {
#[primary_span]
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index 81e0b1e..feed086 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -27,7 +27,7 @@
// 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 @@
// 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 @@
// 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)
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 4e603f5..6148123 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -364,7 +364,7 @@
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"),
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index b28ac68..380db90 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -315,7 +315,7 @@
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 @@
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();
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index b6120ce..8b5bb13 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -542,7 +542,7 @@
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 @@
/// 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 @@
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());
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index 649179d..7a8b976 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -29,7 +29,7 @@
// 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);
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index 85b030c..53ff67f 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -2,7 +2,7 @@
//!
//! Algorithm based on Loukas Georgiadis,
//! "Linear-Time Algorithms for Dominators and Related Problems",
-//! <ftp://ftp.cs.princeton.edu/techreports/2005/737.pdf>
+//! <https://www.cs.princeton.edu/techreports/2005/737.pdf>
//!
//! Additionally useful is the original Lengauer-Tarjan paper on this subject,
//! "A Fast Algorithm for Finding Dominators in a Flowgraph"
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index a59dea5..e2585c0 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -1395,7 +1395,7 @@
}
let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default());
- let using_internal_features_hook = using_internal_features.clone();
+ let using_internal_features_hook = Arc::clone(&using_internal_features);
panic::update_hook(Box::new(
move |default_hook: &(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static),
info: &PanicHookInfo<'_>| {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md
index cd28afb..6b2e23b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0539.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0539.md
@@ -45,6 +45,7 @@
#[stable(feature = "stable_struct", since = "1.39.0")] // ok!
struct Stable;
+#[stable(feature = "stable_fn", since = "1.39.0")]
#[rustc_const_stable(feature = "stable_fn", since = "1.39.0")] // ok!
const fn stable_fn() {}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0542.md b/compiler/rustc_error_codes/src/error_codes/E0542.md
index be186db..70590f2 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0542.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0542.md
@@ -30,6 +30,7 @@
#[stable(feature = "_stable_fn", since = "1.0.0")] // ok!
fn _stable_fn() {}
+#[stable(feature = "_stable_const_fn", since = "1.0.0")]
#[rustc_const_stable(feature = "_stable_const_fn", since = "1.0.0")] // ok!
const fn _stable_const_fn() {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0667.md b/compiler/rustc_error_codes/src/error_codes/E0667.md
index 0709a24..339bc06 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0667.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0667.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
`impl Trait` is not allowed in path parameters.
Erroneous code example:
-```compile_fail,E0667
+```ignore (removed error code)
fn some_fn(mut x: impl Iterator) -> <impl Iterator>::Item { // error!
x.next().unwrap()
}
@@ -11,7 +13,7 @@
You cannot use `impl Trait` in path parameters. If you want something
equivalent, you can do this instead:
-```
+```ignore (removed error code)
fn some_fn<T: Iterator>(mut x: T) -> T::Item { // ok!
x.next().unwrap()
}
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index 00eaf4d..41ebe4a 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -7,6 +7,7 @@
# tidy-alphabetical-start
annotate-snippets = "0.11"
derive_setters = "0.1.6"
+rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 335432c..b4a651b 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -173,7 +173,7 @@
source_map.ensure_source_file_source_present(&file);
(
format!("{}", source_map.filename_for_diagnostics(&file.name)),
- source_string(file.clone(), &line),
+ source_string(Lrc::clone(&file), &line),
line.line_index,
line.annotations,
)
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 19529f0..09a608d 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -5,12 +5,12 @@
use std::path::{Path, PathBuf};
use std::process::ExitStatus;
+use rustc_abi::TargetDataLayoutErrors;
use rustc_ast_pretty::pprust;
use rustc_macros::Subdiagnostic;
use rustc_span::Span;
use rustc_span::edition::Edition;
use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
-use rustc_target::abi::TargetDataLayoutErrors;
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
use rustc_type_ir::{ClosureKind, FloatTy};
use {rustc_ast as ast, rustc_hir as hir};
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 1adb6b9..6552cf2 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -58,9 +58,9 @@
struct Margin {
/// The available whitespace in the left that can be consumed when centering.
pub whitespace_left: usize,
- /// The column of the beginning of left-most span.
+ /// The column of the beginning of leftmost span.
pub span_left: usize,
- /// The column of the end of right-most span.
+ /// The column of the end of rightmost span.
pub span_right: usize,
/// The beginning of the line to be displayed.
pub computed_left: usize,
@@ -128,7 +128,7 @@
} else {
0
};
- // We want to show as much as possible, max_line_len is the right-most boundary for the
+ // We want to show as much as possible, max_line_len is the rightmost boundary for the
// relevant code.
self.computed_right = max(max_line_len, self.computed_left);
@@ -685,7 +685,7 @@
buffer.puts(line_offset, code_offset, "...", Style::LineNumber);
}
if margin.was_cut_right(line_len) {
- // We have stripped some code after the right-most span end, make it clear we did so.
+ // We have stripped some code after the rightmost span end, make it clear we did so.
buffer.puts(line_offset, code_offset + taken - 3, "...", Style::LineNumber);
}
buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber);
@@ -1555,7 +1555,7 @@
// Get the left-side margin to remove it
let mut whitespace_margin = usize::MAX;
for line_idx in 0..annotated_file.lines.len() {
- let file = annotated_file.file.clone();
+ let file = Lrc::clone(&annotated_file.file);
let line = &annotated_file.lines[line_idx];
if let Some(source_string) =
line.line_index.checked_sub(1).and_then(|l| file.get_line(l))
@@ -1646,7 +1646,7 @@
let depths = self.render_source_line(
&mut buffer,
- annotated_file.file.clone(),
+ Lrc::clone(&annotated_file.file),
&annotated_file.lines[line_idx],
width_offset,
code_offset,
@@ -2529,7 +2529,12 @@
// | | |
// | |______foo
// | baz
- add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
+ add_annotation_to_file(
+ &mut output,
+ Lrc::clone(&file),
+ ann.line_start,
+ ann.as_start(),
+ );
// 4 is the minimum vertical length of a multiline span when presented: two lines
// of code and two lines of underline. This is not true for the special case where
// the beginning doesn't have an underline, but the current logic seems to be
@@ -2545,11 +2550,11 @@
.unwrap_or(ann.line_start);
for line in ann.line_start + 1..until {
// Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`).
- add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
+ add_annotation_to_file(&mut output, Lrc::clone(&file), line, ann.as_line());
}
let line_end = ann.line_end - 1;
if middle < line_end {
- add_annotation_to_file(&mut output, file.clone(), line_end, ann.as_line());
+ add_annotation_to_file(&mut output, Lrc::clone(&file), line_end, ann.as_line());
}
} else {
end_ann.annotation_type = AnnotationType::Singleline;
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 1534e25..91e2b99 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -367,9 +367,9 @@
ColorConfig::Always | ColorConfig::Auto => dst = Box::new(termcolor::Ansi::new(dst)),
ColorConfig::Never => {}
}
- HumanEmitter::new(dst, je.fallback_bundle.clone())
+ HumanEmitter::new(dst, Lrc::clone(&je.fallback_bundle))
.short_message(short)
- .sm(Some(je.sm.clone()))
+ .sm(Some(Lrc::clone(&je.sm)))
.fluent_bundle(je.fluent_bundle.clone())
.diagnostic_width(je.diagnostic_width)
.macro_backtrace(je.macro_backtrace)
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 57bac9d..fcf3352 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -25,7 +25,7 @@
illegal value for attribute #[collapse_debuginfo(no|external|yes)]
expand_count_repetition_misplaced =
- `count` can not be placed inside the inner-most repetition
+ `count` can not be placed inside the innermost repetition
expand_crate_name_in_cfg_attr =
`crate_name` within an `#![cfg_attr]` attribute is forbidden
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index bed500c..7e4bc50 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -866,7 +866,9 @@
})
.unwrap_or_else(|| (None, helper_attrs));
let stability = attr::find_stability(sess, attrs, span);
- let const_stability = attr::find_const_stability(sess, attrs, span);
+ // We set `is_const_fn` false to avoid getting any implicit const stability.
+ let const_stability =
+ attr::find_const_stability(sess, attrs, span, /* is_const_fn */ false);
let body_stability = attr::find_body_stability(sess, attrs);
if let Some((_, sp)) = const_stability {
sess.dcx().emit_err(errors::MacroConstStability {
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 5bd9e2f..dc6aa11 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -11,8 +11,8 @@
use rustc_attr as attr;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_feature::{
- ACCEPTED_LANG_FEATURES, AttributeSafety, Features, REMOVED_LANG_FEATURES,
- UNSTABLE_LANG_FEATURES,
+ ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features,
+ REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES,
};
use rustc_lint_defs::BuiltinLintDiag;
use rustc_parse::validate_attr;
@@ -88,8 +88,11 @@
// If the enabled feature is stable, record it.
if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name == f.name) {
- let since = Some(Symbol::intern(f.since));
- features.set_enabled_lang_feature(name, mi.span(), since);
+ features.set_enabled_lang_feature(EnabledLangFeature {
+ gate_name: name,
+ attr_sp: mi.span(),
+ stable_since: Some(Symbol::intern(f.since)),
+ });
continue;
}
@@ -115,13 +118,19 @@
{
sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
}
- features.set_enabled_lang_feature(name, mi.span(), None);
+
+ features.set_enabled_lang_feature(EnabledLangFeature {
+ gate_name: name,
+ attr_sp: mi.span(),
+ stable_since: None,
+ });
continue;
}
// Otherwise, the feature is unknown. Enable it as a lib feature.
// It will be checked later whether the feature really exists.
- features.set_enabled_lib_feature(name, mi.span());
+ features
+ .set_enabled_lib_feature(EnabledLibFeature { gate_name: name, attr_sp: mi.span() });
// Similar to above, detect internal lib features to suppress
// the ICE message that asks for a report.
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 3903203..a08db61 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -622,7 +622,7 @@
// possible next positions into `next_mps`. After some post-processing, the contents of
// `next_mps` replenish `cur_mps` and we start over again.
self.cur_mps.clear();
- self.cur_mps.push(MatcherPos { idx: 0, matches: self.empty_matches.clone() });
+ self.cur_mps.push(MatcherPos { idx: 0, matches: Rc::clone(&self.empty_matches) });
loop {
self.next_mps.clear();
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index f40f99b..fcc90c3 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -3,12 +3,11 @@
use std::{mem, slice};
use ast::token::IdentIsRaw;
-use rustc_ast as ast;
use rustc_ast::token::NtPatKind::*;
use rustc_ast::token::TokenKind::*;
use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind};
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
-use rustc_ast::{DUMMY_NODE_ID, NodeId};
+use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, TransparencyError};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
@@ -370,34 +369,32 @@
pub fn compile_declarative_macro(
sess: &Session,
features: &Features,
- def: &ast::Item,
+ macro_def: &ast::MacroDef,
+ ident: Ident,
+ attrs: &[ast::Attribute],
+ span: Span,
+ node_id: NodeId,
edition: Edition,
) -> (SyntaxExtension, Vec<(usize, Span)>) {
- debug!("compile_declarative_macro: {:?}", def);
let mk_syn_ext = |expander| {
SyntaxExtension::new(
sess,
features,
SyntaxExtensionKind::LegacyBang(expander),
- def.span,
+ span,
Vec::new(),
edition,
- def.ident.name,
- &def.attrs,
- def.id != DUMMY_NODE_ID,
+ ident.name,
+ attrs,
+ node_id != DUMMY_NODE_ID,
)
};
let dummy_syn_ext = |guar| (mk_syn_ext(Box::new(DummyExpander(guar))), Vec::new());
let dcx = sess.dcx();
- let lhs_nm = Ident::new(sym::lhs, def.span);
- let rhs_nm = Ident::new(sym::rhs, def.span);
+ let lhs_nm = Ident::new(sym::lhs, span);
+ let rhs_nm = Ident::new(sym::rhs, span);
let tt_spec = Some(NonterminalKind::TT);
-
- let macro_def = match &def.kind {
- ast::ItemKind::MacroDef(def) => def,
- _ => unreachable!(),
- };
let macro_rules = macro_def.macro_rules;
// Parse the macro_rules! invocation
@@ -410,25 +407,22 @@
let argument_gram = vec![
mbe::TokenTree::Sequence(DelimSpan::dummy(), mbe::SequenceRepetition {
tts: vec![
- mbe::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec),
- mbe::TokenTree::token(token::FatArrow, def.span),
- mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec),
+ mbe::TokenTree::MetaVarDecl(span, lhs_nm, tt_spec),
+ mbe::TokenTree::token(token::FatArrow, span),
+ mbe::TokenTree::MetaVarDecl(span, rhs_nm, tt_spec),
],
- separator: Some(Token::new(
- if macro_rules { token::Semi } else { token::Comma },
- def.span,
- )),
- kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span),
+ separator: Some(Token::new(if macro_rules { token::Semi } else { token::Comma }, span)),
+ kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, span),
num_captures: 2,
}),
// to phase into semicolon-termination instead of semicolon-separation
mbe::TokenTree::Sequence(DelimSpan::dummy(), mbe::SequenceRepetition {
tts: vec![mbe::TokenTree::token(
if macro_rules { token::Semi } else { token::Comma },
- def.span,
+ span,
)],
separator: None,
- kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, def.span),
+ kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, span),
num_captures: 0,
}),
];
@@ -460,7 +454,7 @@
};
let s = parse_failure_msg(&token, track.get_expected_token());
- let sp = token.span.substitute_dummy(def.span);
+ let sp = token.span.substitute_dummy(span);
let mut err = sess.dcx().struct_span_err(sp, s);
err.span_label(sp, msg);
annotate_doc_comment(&mut err, sess.source_map(), sp);
@@ -468,7 +462,7 @@
return dummy_syn_ext(guar);
}
Error(sp, msg) => {
- let guar = sess.dcx().span_err(sp.substitute_dummy(def.span), msg);
+ let guar = sess.dcx().span_err(sp.substitute_dummy(span), msg);
return dummy_syn_ext(guar);
}
ErrorReported(guar) => {
@@ -489,7 +483,7 @@
&TokenStream::new(vec![tt.clone()]),
true,
sess,
- def.id,
+ node_id,
features,
edition,
)
@@ -497,13 +491,13 @@
.unwrap();
// We don't handle errors here, the driver will abort
// after parsing/expansion. We can report every error in every macro this way.
- check_emission(check_lhs_nt_follows(sess, def, &tt));
+ check_emission(check_lhs_nt_follows(sess, node_id, &tt));
return tt;
}
- sess.dcx().span_bug(def.span, "wrong-structured lhs")
+ sess.dcx().span_bug(span, "wrong-structured lhs")
})
.collect::<Vec<mbe::TokenTree>>(),
- _ => sess.dcx().span_bug(def.span, "wrong-structured lhs"),
+ _ => sess.dcx().span_bug(span, "wrong-structured lhs"),
};
let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] {
@@ -515,17 +509,17 @@
&TokenStream::new(vec![tt.clone()]),
false,
sess,
- def.id,
+ node_id,
features,
edition,
)
.pop()
.unwrap();
}
- sess.dcx().span_bug(def.span, "wrong-structured rhs")
+ sess.dcx().span_bug(span, "wrong-structured rhs")
})
.collect::<Vec<mbe::TokenTree>>(),
- _ => sess.dcx().span_bug(def.span, "wrong-structured rhs"),
+ _ => sess.dcx().span_bug(span, "wrong-structured rhs"),
};
for rhs in &rhses {
@@ -537,15 +531,9 @@
check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(lhs)));
}
- check_emission(macro_check::check_meta_variables(
- &sess.psess,
- def.id,
- def.span,
- &lhses,
- &rhses,
- ));
+ check_emission(macro_check::check_meta_variables(&sess.psess, node_id, span, &lhses, &rhses));
- let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules);
+ let (transparency, transparency_error) = attr::find_transparency(attrs, macro_rules);
match transparency_error {
Some(TransparencyError::UnknownTransparency(value, span)) => {
dcx.span_err(span, format!("unknown macro transparency: `{value}`"));
@@ -564,7 +552,7 @@
// Compute the spans of the macro rules for unused rule linting.
// Also, we are only interested in non-foreign macros.
- let rule_spans = if def.id != DUMMY_NODE_ID {
+ let rule_spans = if node_id != DUMMY_NODE_ID {
lhses
.iter()
.zip(rhses.iter())
@@ -590,15 +578,15 @@
mbe::TokenTree::Delimited(.., delimited) => {
mbe::macro_parser::compute_locs(&delimited.tts)
}
- _ => sess.dcx().span_bug(def.span, "malformed macro lhs"),
+ _ => sess.dcx().span_bug(span, "malformed macro lhs"),
}
})
.collect();
let expander = Box::new(MacroRulesMacroExpander {
- name: def.ident,
- span: def.span,
- node_id: def.id,
+ name: ident,
+ span,
+ node_id,
transparency,
lhses,
rhses,
@@ -608,13 +596,13 @@
fn check_lhs_nt_follows(
sess: &Session,
- def: &ast::Item,
+ node_id: NodeId,
lhs: &mbe::TokenTree,
) -> Result<(), ErrorGuaranteed> {
// lhs is going to be like TokenTree::Delimited(...), where the
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
if let mbe::TokenTree::Delimited(.., delimited) = lhs {
- check_matcher(sess, def, &delimited.tts)
+ check_matcher(sess, node_id, &delimited.tts)
} else {
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
Err(sess.dcx().span_err(lhs.span(), msg))
@@ -686,12 +674,12 @@
fn check_matcher(
sess: &Session,
- def: &ast::Item,
+ node_id: NodeId,
matcher: &[mbe::TokenTree],
) -> Result<(), ErrorGuaranteed> {
let first_sets = FirstSets::new(matcher);
let empty_suffix = TokenSet::empty();
- check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix)?;
+ check_matcher_core(sess, node_id, &first_sets, matcher, &empty_suffix)?;
Ok(())
}
@@ -1028,7 +1016,7 @@
// see `FirstSets::new`.
fn check_matcher_core<'tt>(
sess: &Session,
- def: &ast::Item,
+ node_id: NodeId,
first_sets: &FirstSets<'tt>,
matcher: &'tt [mbe::TokenTree],
follow: &TokenSet<'tt>,
@@ -1082,7 +1070,7 @@
token::CloseDelim(d.delim),
span.close,
));
- check_matcher_core(sess, def, first_sets, &d.tts, &my_suffix)?;
+ check_matcher_core(sess, node_id, first_sets, &d.tts, &my_suffix)?;
// don't track non NT tokens
last.replace_with_irrelevant();
@@ -1114,7 +1102,7 @@
// At this point, `suffix_first` is built, and
// `my_suffix` is some TokenSet that we can use
// for checking the interior of `seq_rep`.
- let next = check_matcher_core(sess, def, first_sets, &seq_rep.tts, my_suffix)?;
+ let next = check_matcher_core(sess, node_id, first_sets, &seq_rep.tts, my_suffix)?;
if next.maybe_empty {
last.add_all(&next);
} else {
@@ -1144,7 +1132,7 @@
// macro. (See #86567.)
// Macros defined in the current crate have a real node id,
// whereas macros from an external crate have a dummy id.
- if def.id != DUMMY_NODE_ID
+ if node_id != DUMMY_NODE_ID
&& matches!(kind, NonterminalKind::Pat(PatParam { inferred: true }))
&& matches!(
next_token,
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index c4ba98f..810a5d3 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -23,11 +23,11 @@
/// Ignore a meta-variable for repetition without expansion.
Ignore(Ident),
- /// The index of the repetition at a particular depth, where 0 is the inner-most
+ /// The index of the repetition at a particular depth, where 0 is the innermost
/// repetition. The `usize` is the depth.
Index(usize),
- /// The length of the repetition at a particular depth, where 0 is the inner-most
+ /// The length of the repetition at a particular depth, where 0 is the innermost
/// repetition. The `usize` is the depth.
Len(usize),
}
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index fb6fe0b..b77d02e 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -5,6 +5,7 @@
use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, LitKind, Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::Lrc;
use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize};
use rustc_parse::lexer::nfc_normalize;
use rustc_parse::parser::ParseNtResult;
@@ -293,7 +294,7 @@
// `Delimiter::Invisible` to maintain parsing priorities.
// `Interpolated` is currently used for such groups in rustc parser.
marker.visit_span(&mut sp);
- TokenTree::token_alone(token::Interpolated(nt.clone()), sp)
+ TokenTree::token_alone(token::Interpolated(Lrc::clone(nt)), sp)
}
MatchedSeq(..) => {
// We were unable to descend far enough. This is an error.
@@ -570,7 +571,7 @@
}
}
-/// Used solely by the `count` meta-variable expression, counts the outer-most repetitions at a
+/// Used solely by the `count` meta-variable expression, counts the outermost repetitions at a
/// given optional nested depth.
///
/// For example, a macro parameter of `$( { $( $foo:ident ),* } )*` called with `{ a, b } { c }`:
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 95b3389..e910415 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -366,6 +366,8 @@
(accepted, self_in_typedefs, "1.32.0", Some(49303)),
/// Allows `Self` struct constructor (RFC 2302).
(accepted, self_struct_ctor, "1.32.0", Some(51994)),
+ /// Shortern the tail expression lifetime
+ (accepted, shorter_tail_lifetimes, "CURRENT_RUSTC_VERSION", Some(123739)),
/// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`.
(accepted, slice_patterns, "1.42.0", Some(62254)),
/// Allows use of `&foo[a..b]` as a slicing syntax.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 753195b..0069b07 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -618,11 +618,6 @@
"allow_internal_unstable side-steps feature gating and stability checks",
),
gated!(
- rustc_allow_const_fn_unstable, Normal,
- template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No,
- "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
- ),
- gated!(
allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint",
),
@@ -839,8 +834,13 @@
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
),
rustc_attr!(
- rustc_runtime, Normal, template!(Word), WarnFollowing,
- EncodeCrossCrate::No, INTERNAL_UNSTABLE
+ rustc_const_stable_indirect, Normal,
+ template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
+ ),
+ gated!(
+ rustc_allow_const_fn_unstable, Normal,
+ template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No,
+ "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
),
// ==========================================================================
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 2167934..9f42d3e 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -135,4 +135,6 @@
is_valid_for_get_attr,
};
pub use removed::REMOVED_LANG_FEATURES;
-pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_LANG_FEATURES};
+pub use unstable::{
+ EnabledLangFeature, EnabledLibFeature, Features, INCOMPATIBLE_FEATURES, UNSTABLE_LANG_FEATURES,
+};
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index fe3a67f..8d2e1e8 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -85,6 +85,8 @@
/// Allows default type parameters to influence type inference.
(removed, default_type_parameter_fallback, "1.82.0", Some(27336),
Some("never properly implemented; requires significant design work")),
+ /// Allows deriving traits as per `SmartPointer` specification
+ (removed, derive_smart_pointer, "1.79.0", Some(123430), Some("replaced by `CoercePointee`")),
/// Allows using `#[doc(keyword = "...")]`.
(removed, doc_keyword, "1.28.0", Some(51315),
Some("merged into `#![feature(rustdoc_internals)]`")),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 63c43c4..a99d904 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -36,29 +36,54 @@
#[derive(Clone, Default, Debug)]
pub struct Features {
/// `#![feature]` attrs for language features, for error reporting.
- enabled_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
+ enabled_lang_features: Vec<EnabledLangFeature>,
/// `#![feature]` attrs for non-language (library) features.
- enabled_lib_features: Vec<(Symbol, Span)>,
+ enabled_lib_features: Vec<EnabledLibFeature>,
/// `enabled_lang_features` + `enabled_lib_features`.
enabled_features: FxHashSet<Symbol>,
}
+/// Information about an enabled language feature.
+#[derive(Debug, Copy, Clone)]
+pub struct EnabledLangFeature {
+ /// Name of the feature gate guarding the language feature.
+ pub gate_name: Symbol,
+ /// Span of the `#[feature(...)]` attribute.
+ pub attr_sp: Span,
+ /// If the lang feature is stable, the version number when it was stabilized.
+ pub stable_since: Option<Symbol>,
+}
+
+/// Information abhout an enabled library feature.
+#[derive(Debug, Copy, Clone)]
+pub struct EnabledLibFeature {
+ pub gate_name: Symbol,
+ pub attr_sp: Span,
+}
+
impl Features {
- pub fn set_enabled_lang_feature(&mut self, name: Symbol, span: Span, since: Option<Symbol>) {
- self.enabled_lang_features.push((name, span, since));
- self.enabled_features.insert(name);
+ /// `since` should be set for stable features that are nevertheless enabled with a `#[feature]`
+ /// attribute, indicating since when they are stable.
+ pub fn set_enabled_lang_feature(&mut self, lang_feat: EnabledLangFeature) {
+ self.enabled_lang_features.push(lang_feat);
+ self.enabled_features.insert(lang_feat.gate_name);
}
- pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) {
- self.enabled_lib_features.push((name, span));
- self.enabled_features.insert(name);
+ pub fn set_enabled_lib_feature(&mut self, lib_feat: EnabledLibFeature) {
+ self.enabled_lib_features.push(lib_feat);
+ self.enabled_features.insert(lib_feat.gate_name);
}
- pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option<Symbol>)> {
+ /// Returns a list of [`EnabledLangFeature`] with info about:
+ ///
+ /// - Feature gate name.
+ /// - The span of the `#[feature]` attribute.
+ /// - For stable language features, version info for when it was stabilized.
+ pub fn enabled_lang_features(&self) -> &Vec<EnabledLangFeature> {
&self.enabled_lang_features
}
- pub fn enabled_lib_features(&self) -> &Vec<(Symbol, Span)> {
+ pub fn enabled_lib_features(&self) -> &Vec<EnabledLibFeature> {
&self.enabled_lib_features
}
@@ -425,8 +450,6 @@
(unstable, deprecated_suggestion, "1.61.0", Some(94785)),
/// Allows deref patterns.
(incomplete, deref_patterns, "1.79.0", Some(87121)),
- /// Allows deriving `SmartPointer` traits
- (unstable, derive_smart_pointer, "1.79.0", Some(123430)),
/// Controls errors in trait implementations.
(unstable, do_not_recommend, "1.67.0", Some(51992)),
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
@@ -569,8 +592,6 @@
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
/// Allows use of x86 SHA512, SM3 and SM4 target-features and intrinsics
(unstable, sha512_sm_x86, "1.82.0", Some(126624)),
- /// Shortern the tail expression lifetime
- (unstable, shorter_tail_lifetimes, "1.79.0", Some(123739)),
/// Allows the use of SIMD types in functions declared in `extern` blocks.
(unstable, simd_ffi, "1.0.0", Some(27731)),
/// Allows specialization of implementations (RFC 1210).
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 45be04c..1c268c8 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -580,7 +580,6 @@
ty: &'hir Ty<'hir>,
/// Optional default value for the const generic param
default: Option<&'hir ConstArg<'hir>>,
- is_host_effect: bool,
synthetic: bool,
},
}
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index ffe519b..322f8e2 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -935,7 +935,7 @@
match param.kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { ref default, .. } => visit_opt!(visitor, visit_ty, default),
- GenericParamKind::Const { ref ty, ref default, is_host_effect: _, synthetic: _ } => {
+ GenericParamKind::Const { ref ty, ref default, synthetic: _ } => {
try_visit!(visitor.visit_ty(ty));
if let Some(ref default) = default {
try_visit!(visitor.visit_const_param_default(param.hir_id, default));
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index b161e6b..7d81f97 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -241,7 +241,7 @@
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
DerefPure, sym::deref_pure, deref_pure_trait, Target::Trait, GenericRequirement::Exact(0);
DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
- Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
+ LegacyReceiver, sym::legacy_receiver, legacy_receiver_trait, Target::Trait, GenericRequirement::None;
Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
@@ -415,14 +415,6 @@
String, sym::String, string, Target::Struct, GenericRequirement::None;
CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None;
-
- EffectsRuntime, sym::EffectsRuntime, effects_runtime, Target::Struct, GenericRequirement::None;
- EffectsNoRuntime, sym::EffectsNoRuntime, effects_no_runtime, Target::Struct, GenericRequirement::None;
- EffectsMaybe, sym::EffectsMaybe, effects_maybe, Target::Struct, GenericRequirement::None;
- EffectsIntersection, sym::EffectsIntersection, effects_intersection, Target::Trait, GenericRequirement::None;
- EffectsIntersectionOutput, sym::EffectsIntersectionOutput, effects_intersection_output, Target::AssocTy, GenericRequirement::None;
- EffectsCompat, sym::EffectsCompat, effects_compat, Target::Trait, GenericRequirement::Exact(1);
- EffectsTyCompat, sym::EffectsTyCompat, effects_ty_compat, Target::Trait, GenericRequirement::Exact(1);
}
pub enum GenericRequirement {
diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml
index 04ca7f1..3c8887f 100644
--- a/compiler/rustc_hir_analysis/Cargo.toml
+++ b/compiler/rustc_hir_analysis/Cargo.toml
@@ -10,6 +10,7 @@
[dependencies]
# tidy-alphabetical-start
itertools = "0.12"
+rustc_abi = { path = "../rustc_abi" }
rustc_arena = { path = "../rustc_arena" }
rustc_ast = { path = "../rustc_ast" }
rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 507297c..7191c72 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -149,10 +149,6 @@
hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
.label = parameter captured again here
-hir_analysis_effects_without_next_solver = using `#![feature(effects)]` without enabling next trait solver globally
- .note = the next trait solver must be enabled globally for the effects feature to work correctly
- .help = use `-Znext-solver` to enable
-
hir_analysis_empty_specialization = specialization impl does not specialize any associated items
.note = impl is a specialization of this impl
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 77df0cb..09ddc6c 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -1,15 +1,9 @@
//! Bounds are restrictions applied to some types after they've been lowered from the HIR to the
//! [`rustc_middle::ty`] form.
-use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::LangItem;
-use rustc_hir::def::DefKind;
-use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
use rustc_span::Span;
-use rustc_span::def_id::DefId;
-
-use crate::hir_ty_lowering::PredicateFilter;
/// Collects together a list of type bounds. These lists of bounds occur in many places
/// in Rust's syntax:
@@ -30,7 +24,6 @@
#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub(crate) struct Bounds<'tcx> {
clauses: Vec<(ty::Clause<'tcx>, Span)>,
- effects_min_tys: FxIndexMap<Ty<'tcx>, Span>,
}
impl<'tcx> Bounds<'tcx> {
@@ -47,12 +40,9 @@
pub(crate) fn push_trait_bound(
&mut self,
tcx: TyCtxt<'tcx>,
- defining_def_id: DefId,
bound_trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
polarity: ty::PredicatePolarity,
- constness: Option<ty::BoundConstness>,
- predicate_filter: PredicateFilter,
) {
let clause = (
bound_trait_ref
@@ -68,137 +58,6 @@
} else {
self.clauses.push(clause);
}
-
- // FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else.
- // Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated
- // type bounds.
- if !tcx.features().effects() {
- return;
- }
- match predicate_filter {
- PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
- return;
- }
- PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
- // Ok.
- }
- }
-
- // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the
- // associated type of `<T as Tr>` and make sure that the effect is compatible.
- let compat_val = match (tcx.def_kind(defining_def_id), constness) {
- // FIXME(effects): revisit the correctness of this
- (_, Some(ty::BoundConstness::Const)) => tcx.consts.false_,
- // body owners that can have trait bounds
- (
- DefKind::Const | DefKind::Fn | DefKind::AssocFn,
- Some(ty::BoundConstness::ConstIfConst),
- ) => tcx.expected_host_effect_param_for_body(defining_def_id),
-
- (_, None) => {
- if !tcx.is_const_trait(bound_trait_ref.def_id()) {
- return;
- }
- tcx.consts.true_
- }
- (DefKind::Trait, Some(ty::BoundConstness::ConstIfConst)) => {
- // we are in a trait, where `bound_trait_ref` could be:
- // (1) a super trait `trait Foo: ~const Bar`.
- // - This generates `<Self as Foo>::Effects: TyCompat<<Self as Bar>::Effects>`
- //
- // (2) a where clause `where for<..> Something: ~const Bar`.
- // - This generates `for<..> <Self as Foo>::Effects: TyCompat<<Something as Bar>::Effects>`
- let Some(own_fx) = tcx.associated_type_for_effects(defining_def_id) else {
- tcx.dcx().span_delayed_bug(span, "should not have allowed `~const` on a trait that doesn't have `#[const_trait]`");
- return;
- };
- let own_fx_ty = Ty::new_projection(
- tcx,
- own_fx,
- ty::GenericArgs::identity_for_item(tcx, own_fx),
- );
- let Some(their_fx) = tcx.associated_type_for_effects(bound_trait_ref.def_id())
- else {
- tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
- return;
- };
- let their_fx_ty =
- Ty::new_projection(tcx, their_fx, bound_trait_ref.skip_binder().args);
- let compat = tcx.require_lang_item(LangItem::EffectsTyCompat, Some(span));
- let clause = bound_trait_ref
- .map_bound(|_| {
- let trait_ref = ty::TraitRef::new(tcx, compat, [own_fx_ty, their_fx_ty]);
- ty::ClauseKind::Trait(ty::TraitPredicate {
- trait_ref,
- polarity: ty::PredicatePolarity::Positive,
- })
- })
- .upcast(tcx);
-
- self.clauses.push((clause, span));
- return;
- }
-
- (DefKind::Impl { of_trait: true }, Some(ty::BoundConstness::ConstIfConst)) => {
- // this is a where clause on an impl header.
- // push `<T as Tr>::Effects` into the set for the `Min` bound.
- let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
- tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
- return;
- };
-
- let ty = bound_trait_ref
- .map_bound(|trait_ref| Ty::new_projection(tcx, assoc, trait_ref.args));
-
- // When the user has written `for<'a, T> X<'a, T>: ~const Foo`, replace the
- // binders to dummy ones i.e. `X<'static, ()>` so they can be referenced in
- // the `Min` associated type properly (which doesn't allow using `for<>`)
- // This should work for any bound variables as long as they don't have any
- // bounds e.g. `for<T: Trait>`.
- // FIXME(effects) reconsider this approach to allow compatibility with `for<T: Tr>`
- let ty = tcx.replace_bound_vars_uncached(ty, FnMutDelegate {
- regions: &mut |_| tcx.lifetimes.re_static,
- types: &mut |_| tcx.types.unit,
- consts: &mut |_| unimplemented!("`~const` does not support const binders"),
- });
-
- self.effects_min_tys.insert(ty, span);
- return;
- }
- // for
- // ```
- // trait Foo { type Bar: ~const Trait }
- // ```
- // ensure that `<Self::Bar as Trait>::Effects: TyCompat<Self::Effects>`.
- //
- // FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor
- // that uses a `Bar` that implements `Trait` with `Maybe` effects.
- (DefKind::AssocTy, Some(ty::BoundConstness::ConstIfConst)) => {
- // FIXME(effects): implement this
- return;
- }
- // probably illegal in this position.
- (_, Some(ty::BoundConstness::ConstIfConst)) => {
- tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered");
- return;
- }
- };
- // create a new projection type `<T as Tr>::Effects`
- let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
- tcx.dcx().span_delayed_bug(
- span,
- "`~const` trait bound has no effect assoc yet no errors encountered?",
- );
- return;
- };
- let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args);
- // make `<T as Tr>::Effects: Compat<runtime>`
- let new_trait_ref =
- ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::EffectsCompat, Some(span)), [
- ty::GenericArg::from(self_ty),
- compat_val.into(),
- ]);
- self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span));
}
pub(crate) fn push_projection_bound(
@@ -220,15 +79,22 @@
self.clauses.insert(0, (trait_ref.upcast(tcx), span));
}
- pub(crate) fn clauses(
- &self,
- // FIXME(effects): remove tcx
- _tcx: TyCtxt<'tcx>,
- ) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
- self.clauses.iter().cloned()
+ /// Push a `const` or `~const` bound as a `HostEffect` predicate.
+ pub(crate) fn push_const_bound(
+ &mut self,
+ tcx: TyCtxt<'tcx>,
+ bound_trait_ref: ty::PolyTraitRef<'tcx>,
+ host: ty::HostPolarity,
+ span: Span,
+ ) {
+ if tcx.is_const_trait(bound_trait_ref.def_id()) {
+ self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, host), span));
+ } else {
+ tcx.dcx().span_delayed_bug(span, "tried to lower {host:?} bound for non-const trait");
+ }
}
- pub(crate) fn effects_min_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
- self.effects_min_tys.keys().copied()
+ pub(crate) fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
+ self.clauses.iter().cloned()
}
}
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 97f3f1c..6d04bdf 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,6 +1,7 @@
use std::cell::LazyCell;
use std::ops::ControlFlow;
+use rustc_abi::FieldIdx;
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::MultiSpan;
use rustc_errors::codes::*;
@@ -23,7 +24,6 @@
TypeVisitableExt,
};
use rustc_session::lint::builtin::UNINHABITED_STATIC;
-use rustc_target::abi::FieldIdx;
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective;
use rustc_trait_selection::traits;
@@ -172,7 +172,7 @@
return;
}
};
- if layout.abi.is_uninhabited() {
+ if layout.is_uninhabited() {
tcx.node_span_lint(
UNINHABITED_STATIC,
tcx.local_def_id_to_hir_id(def_id),
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 7595616..9de96b7 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -43,14 +43,13 @@
/// - `impl_m`: type of the method we are checking
/// - `trait_m`: the method in the trait
/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
+#[instrument(level = "debug", skip(tcx))]
pub(super) fn compare_impl_method<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: ty::AssocItem,
trait_m: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
) {
- debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
-
let _: Result<_, ErrorGuaranteed> = try {
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?;
compare_method_predicate_entailment(tcx, impl_m, trait_m, impl_trait_ref)?;
@@ -167,8 +166,6 @@
trait_m: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorGuaranteed> {
- let trait_to_impl_args = impl_trait_ref.args;
-
// This node-id should be used for the `body_id` field on each
// `ObligationCause` (and the `FnCtxt`).
//
@@ -183,27 +180,18 @@
kind: impl_m.kind,
});
- // Create mapping from impl to placeholder.
- let impl_to_placeholder_args = GenericArgs::identity_for_item(tcx, impl_m.def_id);
-
- // Create mapping from trait to placeholder.
- let trait_to_placeholder_args =
- impl_to_placeholder_args.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_args);
- debug!("compare_impl_method: trait_to_placeholder_args={:?}", trait_to_placeholder_args);
+ // Create mapping from trait method to impl method.
+ let impl_def_id = impl_m.container_id(tcx);
+ let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto(
+ tcx,
+ impl_m.container_id(tcx),
+ impl_trait_ref.args,
+ );
+ debug!(?trait_to_impl_args);
let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
- // Create obligations for each predicate declared by the impl
- // definition in the context of the trait's parameter
- // environment. We can't just use `impl_env.caller_bounds`,
- // however, because we want to replace all late-bound regions with
- // region variables.
- let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
- let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
-
- debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
-
// This is the only tricky bit of the new way we check implementation methods
// We need to build a set of predicates where only the method-level bounds
// are from the trait and we assume all other bounds from the implementation
@@ -211,25 +199,43 @@
//
// We then register the obligations from the impl_m and check to see
// if all constraints hold.
- hybrid_preds.predicates.extend(
- trait_m_predicates
- .instantiate_own(tcx, trait_to_placeholder_args)
- .map(|(predicate, _)| predicate),
+ let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
+ let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates;
+ hybrid_preds.extend(
+ trait_m_predicates.instantiate_own(tcx, trait_to_impl_args).map(|(predicate, _)| predicate),
);
- // Construct trait parameter environment and then shift it into the placeholder viewpoint.
- // The key step here is to update the caller_bounds's predicates to be
- // the new hybrid bounds we computed.
+ // FIXME(effects): This should be replaced with a more dedicated method.
+ let is_conditionally_const = tcx.is_conditionally_const(impl_def_id);
+ if is_conditionally_const {
+ // Augment the hybrid param-env with the const conditions
+ // of the impl header and the trait method.
+ hybrid_preds.extend(
+ tcx.const_conditions(impl_def_id)
+ .instantiate_identity(tcx)
+ .into_iter()
+ .chain(
+ tcx.const_conditions(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args),
+ )
+ .map(|(trait_ref, _)| {
+ trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)
+ }),
+ );
+ }
+
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
- let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
+ let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
+ debug!(caller_bounds=?param_env.caller_bounds());
let infcx = &tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
- debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
-
- let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_args);
+ // Create obligations for each predicate declared by the impl
+ // definition in the context of the hybrid param-env. This makes
+ // sure that the impl's method's where clauses are not more
+ // restrictive than the trait's method (and the impl itself).
+ let impl_m_own_bounds = impl_m_predicates.instantiate_own_identity();
for (predicate, span) in impl_m_own_bounds {
let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);
let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
@@ -243,6 +249,34 @@
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
}
+ // If we're within a const implementation, we need to make sure that the method
+ // does not assume stronger `~const` bounds than the trait definition.
+ //
+ // This registers the `~const` bounds of the impl method, which we will prove
+ // using the hybrid param-env that we earlier augmented with the const conditions
+ // from the impl header and trait method declaration.
+ if is_conditionally_const {
+ for (const_condition, span) in
+ tcx.const_conditions(impl_m.def_id).instantiate_own_identity()
+ {
+ let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);
+ let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
+
+ let cause =
+ ObligationCause::new(span, impl_m_def_id, ObligationCauseCode::CompareImplItem {
+ impl_item_def_id: impl_m_def_id,
+ trait_item_def_id: trait_m.def_id,
+ kind: impl_m.kind,
+ });
+ ocx.register_obligation(traits::Obligation::new(
+ tcx,
+ cause,
+ param_env,
+ const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
+ ));
+ }
+ }
+
// We now need to check that the signature of the impl method is
// compatible with that of the trait method. We do this by
// checking that `impl_fty <: trait_fty`.
@@ -256,7 +290,6 @@
// any associated types appearing in the fn arguments or return
// type.
- // Compute placeholder form of impl and trait method tys.
let mut wf_tys = FxIndexSet::default();
let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars(
@@ -267,9 +300,9 @@
let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id);
let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig);
- debug!("compare_impl_method: impl_fty={:?}", impl_sig);
+ debug!(?impl_sig);
- let trait_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_placeholder_args);
+ let trait_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args);
let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
// Next, add all inputs and output as well-formed tys. Importantly,
@@ -280,9 +313,7 @@
// We also have to add the normalized trait signature
// as we don't normalize during implied bounds computation.
wf_tys.extend(trait_sig.inputs_and_output.iter());
- let trait_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(trait_sig));
-
- debug!("compare_impl_method: trait_fty={:?}", trait_fty);
+ debug!(?trait_sig);
// FIXME: We'd want to keep more accurate spans than "the method signature" when
// processing the comparison between the trait and impl fn, but we sadly lose them
@@ -298,6 +329,7 @@
let emitted = report_trait_method_mismatch(
infcx,
cause,
+ param_env,
terr,
(trait_m, trait_sig),
(impl_m, impl_sig),
@@ -455,8 +487,6 @@
// just so we don't ICE during instantiation later.
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
- let trait_to_impl_args = impl_trait_ref.args;
-
let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id);
let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
let cause =
@@ -466,18 +496,18 @@
kind: impl_m.kind,
});
- // Create mapping from impl to placeholder.
- let impl_to_placeholder_args = GenericArgs::identity_for_item(tcx, impl_m.def_id);
-
- // Create mapping from trait to placeholder.
- let trait_to_placeholder_args =
- impl_to_placeholder_args.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_args);
+ // Create mapping from trait to impl (i.e. impl trait header + impl method identity args).
+ let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto(
+ tcx,
+ impl_m.container_id(tcx),
+ impl_trait_ref.args,
+ );
let hybrid_preds = tcx
.predicates_of(impl_m.container_id(tcx))
.instantiate_identity(tcx)
.into_iter()
- .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_placeholder_args))
+ .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args))
.map(|(clause, _)| clause);
let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing);
let param_env = traits::normalize_param_env_or_error(
@@ -511,7 +541,7 @@
.instantiate_binder_with_fresh_vars(
return_span,
infer::HigherRankedType,
- tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_placeholder_args),
+ tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args),
)
.fold_with(&mut collector);
@@ -581,7 +611,7 @@
Err(terr) => {
let mut diag = struct_span_code_err!(
tcx.dcx(),
- cause.span(),
+ cause.span,
E0053,
"method `{}` has an incompatible return type for trait",
trait_m.name
@@ -593,10 +623,10 @@
hir.get_if_local(impl_m.def_id)
.and_then(|node| node.fn_decl())
.map(|decl| (decl.output.span(), Cow::from("return type in trait"), false)),
- Some(infer::ValuePairs::Terms(ExpectedFound {
+ Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound {
expected: trait_return_ty.into(),
found: impl_return_ty.into(),
- })),
+ }))),
terr,
false,
);
@@ -620,6 +650,7 @@
let emitted = report_trait_method_mismatch(
infcx,
cause,
+ param_env,
terr,
(trait_m, trait_sig),
(impl_m, impl_sig),
@@ -705,7 +736,7 @@
// Also, we only need to account for a difference in trait and impl args,
// since we previously enforce that the trait method and impl method have the
// same generics.
- let num_trait_args = trait_to_impl_args.len();
+ let num_trait_args = impl_trait_ref.args.len();
let num_impl_args = tcx.generics_of(impl_m.container_id(tcx)).own_params.len();
let ty = match ty.try_fold_with(&mut RemapHiddenTyRegions {
tcx,
@@ -933,6 +964,7 @@
fn report_trait_method_mismatch<'tcx>(
infcx: &InferCtxt<'tcx>,
mut cause: ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
terr: TypeError<'tcx>,
(trait_m, trait_sig): (ty::AssocItem, ty::FnSig<'tcx>),
(impl_m, impl_sig): (ty::AssocItem, ty::FnSig<'tcx>),
@@ -1018,10 +1050,10 @@
&mut diag,
&cause,
trait_err_span.map(|sp| (sp, Cow::from("type in trait"), false)),
- Some(infer::ValuePairs::PolySigs(ExpectedFound {
+ Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
expected: ty::Binder::dummy(trait_sig),
found: ty::Binder::dummy(impl_sig),
- })),
+ }))),
terr,
false,
);
@@ -1041,12 +1073,7 @@
let trait_generics = tcx.generics_of(trait_m.def_id);
let trait_params = trait_generics.own_counts().lifetimes;
- debug!(
- "check_region_bounds_on_impl_item: \
- trait_generics={:?} \
- impl_generics={:?}",
- trait_generics, impl_generics
- );
+ debug!(?trait_generics, ?impl_generics);
// Must have same number of early-bound lifetime parameters.
// Unfortunately, if the user screws up the bounds, then this
@@ -1142,7 +1169,7 @@
TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
(impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
}
- _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)),
+ _ => (cause.span, tcx.hir().span_if_local(trait_m.def_id)),
}
}
@@ -1710,8 +1737,7 @@
let trait_const_item = tcx.associated_item(trait_const_item_def);
let impl_trait_ref =
tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().instantiate_identity();
-
- debug!("compare_impl_const(impl_trait_ref={:?})", impl_trait_ref);
+ debug!(?impl_trait_ref);
compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?;
compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?;
@@ -1722,6 +1748,7 @@
/// The equivalent of [compare_method_predicate_entailment], but for associated constants
/// instead of associated functions.
// FIXME(generic_const_items): If possible extract the common parts of `compare_{type,const}_predicate_entailment`.
+#[instrument(level = "debug", skip(tcx))]
fn compare_const_predicate_entailment<'tcx>(
tcx: TyCtxt<'tcx>,
impl_ct: ty::AssocItem,
@@ -1736,13 +1763,14 @@
// because we shouldn't really have to deal with lifetimes or
// predicates. In fact some of this should probably be put into
// shared functions because of DRY violations...
- let impl_args = GenericArgs::identity_for_item(tcx, impl_ct.def_id);
- let trait_to_impl_args =
- impl_args.rebase_onto(tcx, impl_ct.container_id(tcx), impl_trait_ref.args);
+ let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_ct.def_id).rebase_onto(
+ tcx,
+ impl_ct.container_id(tcx),
+ impl_trait_ref.args,
+ );
// Create a parameter environment that represents the implementation's
- // method.
- // Compute placeholder form of impl and trait const tys.
+ // associated const.
let impl_ty = tcx.type_of(impl_ct_def_id).instantiate_identity();
let trait_ty = tcx.type_of(trait_ct.def_id).instantiate(tcx, trait_to_impl_args);
@@ -1759,14 +1787,14 @@
// The predicates declared by the impl definition, the trait and the
// associated const in the trait are assumed.
let impl_predicates = tcx.predicates_of(impl_ct_predicates.parent.unwrap());
- let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
- hybrid_preds.predicates.extend(
+ let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates;
+ hybrid_preds.extend(
trait_ct_predicates
.instantiate_own(tcx, trait_to_impl_args)
.map(|(predicate, _)| predicate),
);
- let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
+ let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
let param_env = traits::normalize_param_env_or_error(
tcx,
param_env,
@@ -1776,7 +1804,7 @@
let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
- let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args);
+ let impl_ct_own_bounds = impl_ct_predicates.instantiate_own_identity();
for (predicate, span) in impl_ct_own_bounds {
let cause = ObligationCause::misc(span, impl_ct_def_id);
let predicate = ocx.normalize(&cause, param_env, predicate);
@@ -1787,20 +1815,15 @@
// There is no "body" here, so just pass dummy id.
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
-
- debug!("compare_const_impl: impl_ty={:?}", impl_ty);
+ debug!(?impl_ty);
let trait_ty = ocx.normalize(&cause, param_env, trait_ty);
-
- debug!("compare_const_impl: trait_ty={:?}", trait_ty);
+ debug!(?trait_ty);
let err = ocx.sup(&cause, param_env, trait_ty, impl_ty);
if let Err(terr) = err {
- debug!(
- "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
- impl_ty, trait_ty
- );
+ debug!(?impl_ty, ?trait_ty);
// Locate the Span containing just the type of the offending impl
let (ty, _) = tcx.hir().expect_impl_item(impl_ct_def_id).expect_const();
@@ -1824,10 +1847,10 @@
&mut diag,
&cause,
trait_c_span.map(|span| (span, Cow::from("type in trait"), false)),
- Some(infer::ValuePairs::Terms(ExpectedFound {
+ Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound {
expected: trait_ty.into(),
found: impl_ty.into(),
- })),
+ }))),
terr,
false,
);
@@ -1845,14 +1868,13 @@
ocx.resolve_regions_and_report_errors(impl_ct_def_id, &outlives_env)
}
+#[instrument(level = "debug", skip(tcx))]
pub(super) fn compare_impl_ty<'tcx>(
tcx: TyCtxt<'tcx>,
impl_ty: ty::AssocItem,
trait_ty: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
) {
- debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
-
let _: Result<(), ErrorGuaranteed> = try {
compare_number_of_generics(tcx, impl_ty, trait_ty, false)?;
compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
@@ -1864,20 +1886,25 @@
/// The equivalent of [compare_method_predicate_entailment], but for associated types
/// instead of associated functions.
+#[instrument(level = "debug", skip(tcx))]
fn compare_type_predicate_entailment<'tcx>(
tcx: TyCtxt<'tcx>,
impl_ty: ty::AssocItem,
trait_ty: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorGuaranteed> {
- let impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id);
- let trait_to_impl_args =
- impl_args.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.args);
+ let impl_def_id = impl_ty.container_id(tcx);
+ let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id).rebase_onto(
+ tcx,
+ impl_def_id,
+ impl_trait_ref.args,
+ );
let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
- let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_args);
+ let impl_ty_own_bounds = impl_ty_predicates.instantiate_own_identity();
+ // If there are no bounds, then there are no const conditions, so no need to check that here.
if impl_ty_own_bounds.len() == 0 {
// Nothing to check.
return Ok(());
@@ -1887,29 +1914,46 @@
// `ObligationCause` (and the `FnCtxt`). This is what
// `regionck_item` expects.
let impl_ty_def_id = impl_ty.def_id.expect_local();
- debug!("compare_type_predicate_entailment: trait_to_impl_args={:?}", trait_to_impl_args);
+ debug!(?trait_to_impl_args);
// The predicates declared by the impl definition, the trait and the
// associated type in the trait are assumed.
let impl_predicates = tcx.predicates_of(impl_ty_predicates.parent.unwrap());
- let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
- hybrid_preds.predicates.extend(
+ let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates;
+ hybrid_preds.extend(
trait_ty_predicates
.instantiate_own(tcx, trait_to_impl_args)
.map(|(predicate, _)| predicate),
);
-
- debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
+ debug!(?hybrid_preds);
let impl_ty_span = tcx.def_span(impl_ty_def_id);
let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id);
- let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
+
+ let is_conditionally_const = tcx.is_conditionally_const(impl_ty.def_id);
+ if is_conditionally_const {
+ // Augment the hybrid param-env with the const conditions
+ // of the impl header and the trait assoc type.
+ hybrid_preds.extend(
+ tcx.const_conditions(impl_ty_predicates.parent.unwrap())
+ .instantiate_identity(tcx)
+ .into_iter()
+ .chain(
+ tcx.const_conditions(trait_ty.def_id).instantiate_own(tcx, trait_to_impl_args),
+ )
+ .map(|(trait_ref, _)| {
+ trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)
+ }),
+ );
+ }
+
+ let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
+ debug!(caller_bounds=?param_env.caller_bounds());
+
let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
- debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
-
for (predicate, span) in impl_ty_own_bounds {
let cause = ObligationCause::misc(span, impl_ty_def_id);
let predicate = ocx.normalize(&cause, param_env, predicate);
@@ -1923,6 +1967,29 @@
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
}
+ if is_conditionally_const {
+ // Validate the const conditions of the impl associated type.
+ let impl_ty_own_const_conditions =
+ tcx.const_conditions(impl_ty.def_id).instantiate_own_identity();
+ for (const_condition, span) in impl_ty_own_const_conditions {
+ let normalize_cause = traits::ObligationCause::misc(span, impl_ty_def_id);
+ let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
+
+ let cause =
+ ObligationCause::new(span, impl_ty_def_id, ObligationCauseCode::CompareImplItem {
+ impl_item_def_id: impl_ty_def_id,
+ trait_item_def_id: trait_ty.def_id,
+ kind: impl_ty.kind,
+ });
+ ocx.register_obligation(traits::Obligation::new(
+ tcx,
+ cause,
+ param_env,
+ const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
+ ));
+ }
+ }
+
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
@@ -2005,15 +2072,31 @@
ObligationCause::new(impl_ty_span, impl_ty_def_id, code)
};
- let obligations: Vec<_> = tcx
+ let mut obligations: Vec<_> = tcx
.explicit_item_bounds(trait_ty.def_id)
.iter_instantiated_copied(tcx, rebased_args)
.map(|(concrete_ty_bound, span)| {
- debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
+ debug!(?concrete_ty_bound);
traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
})
.collect();
- debug!("check_type_bounds: item_bounds={:?}", obligations);
+
+ // Only in a const implementation do we need to check that the `~const` item bounds hold.
+ if tcx.is_conditionally_const(impl_ty_def_id) {
+ obligations.extend(
+ tcx.implied_const_bounds(trait_ty.def_id)
+ .iter_instantiated_copied(tcx, rebased_args)
+ .map(|(c, span)| {
+ traits::Obligation::new(
+ tcx,
+ mk_cause(span),
+ param_env,
+ c.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
+ )
+ }),
+ );
+ }
+ debug!(item_bounds=?obligations);
// Normalize predicates with the assumption that the GAT may always normalize
// to its definition type. This should be the param-env we use to *prove* the
@@ -2032,7 +2115,7 @@
} else {
ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate)
};
- debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
+ debug!(?normalized_predicate);
obligation.predicate = normalized_predicate;
ocx.register_obligation(obligation);
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 06317a3..c75bdce 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -58,15 +58,9 @@
// the host effect param should be invisible as it shouldn't matter
// whether effects is enabled for the intrinsic provider crate.
- let consts_count = if generics.host_effect_index.is_some() {
- own_counts.consts - 1
- } else {
- own_counts.consts
- };
-
if gen_count_ok(own_counts.lifetimes, n_lts, "lifetime")
&& gen_count_ok(own_counts.types, n_tps, "type")
- && gen_count_ok(consts_count, n_cts, "const")
+ && gen_count_ok(own_counts.consts, n_cts, "const")
{
let _ = check_function_signature(
tcx,
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index bbff00c..e95669c 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -1,5 +1,6 @@
use std::assert_matches::debug_assert_matches;
+use rustc_abi::FieldIdx;
use rustc_ast::InlineAsmTemplatePiece;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::{self as hir, LangItem};
@@ -8,7 +9,6 @@
use rustc_session::lint;
use rustc_span::Symbol;
use rustc_span::def_id::LocalDefId;
-use rustc_target::abi::FieldIdx;
use rustc_target::asm::{
InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo,
};
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 959b17b..ec5a89e 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -74,6 +74,7 @@
use std::num::NonZero;
pub use check::{check_abi, check_abi_fn_ptr};
+use rustc_abi::VariantIdx;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -90,7 +91,6 @@
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::symbol::{Ident, kw, sym};
use rustc_span::{BytePos, DUMMY_SP, Span, Symbol};
-use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _;
@@ -612,7 +612,7 @@
match err {
TypeError::ArgumentMutability(i)
| TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
- _ => cause.span(),
+ _ => cause.span,
}
}
@@ -646,10 +646,10 @@
&mut diag,
&cause,
None,
- Some(infer::ValuePairs::PolySigs(ExpectedFound {
+ Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
expected: expected_sig,
found: actual_sig,
- })),
+ }))),
err,
false,
);
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index e37a7ed..679f6cc 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -167,9 +167,7 @@
}
}
if let Some(tail_expr) = blk.expr {
- if visitor.tcx.features().shorter_tail_lifetimes()
- && blk.span.edition().at_least_rust_2024()
- {
+ if blk.span.edition().at_least_rust_2024() {
visitor.terminating_scopes.insert(tail_expr.hir_id.local_id);
}
visitor.visit_expr(tail_expr);
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 3170c0a..499e42d 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -32,7 +32,8 @@
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
- self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
+ self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
+ WellFormedLoc,
};
use rustc_type_ir::TypeFlags;
use rustc_type_ir::solve::NoSolution;
@@ -86,7 +87,7 @@
self.body_def_id,
ObligationCauseCode::WellFormed(loc),
);
- self.ocx.register_obligation(traits::Obligation::new(
+ self.ocx.register_obligation(Obligation::new(
self.tcx(),
cause,
self.param_env,
@@ -913,12 +914,7 @@
hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()),
// Const parameters are well formed if their type is structural match.
- hir::GenericParamKind::Const {
- ty: hir_ty,
- default: _,
- is_host_effect: _,
- synthetic: _,
- } => {
+ hir::GenericParamKind::Const { ty: hir_ty, default: _, synthetic: _ } => {
let ty = tcx.type_of(param.def_id).instantiate_identity();
if tcx.features().unsized_const_params() {
@@ -1178,7 +1174,7 @@
wfcx.body_def_id,
ObligationCauseCode::Misc,
);
- wfcx.register_obligation(traits::Obligation::new(
+ wfcx.register_obligation(Obligation::new(
tcx,
cause,
wfcx.param_env,
@@ -1374,6 +1370,30 @@
obligation.cause.span = hir_self_ty.span;
}
}
+
+ // Ensure that the `~const` where clauses of the trait hold for the impl.
+ if tcx.is_conditionally_const(item.owner_id.def_id) {
+ for (bound, _) in
+ tcx.const_conditions(trait_ref.def_id).instantiate(tcx, trait_ref.args)
+ {
+ let bound = wfcx.normalize(
+ item.span,
+ Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
+ bound,
+ );
+ wfcx.register_obligation(Obligation::new(
+ tcx,
+ ObligationCause::new(
+ hir_self_ty.span,
+ wfcx.body_def_id,
+ ObligationCauseCode::WellFormed(None),
+ ),
+ wfcx.param_env,
+ bound.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
+ ))
+ }
+ }
+
debug!(?obligations);
wfcx.register_obligations(obligations);
}
@@ -1566,7 +1586,7 @@
wfcx.body_def_id,
ObligationCauseCode::WhereClause(def_id.to_def_id(), DUMMY_SP),
);
- traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
+ Obligation::new(tcx, cause, wfcx.param_env, pred)
});
let predicates = predicates.instantiate_identity(tcx);
@@ -1801,7 +1821,7 @@
autoderef = autoderef.include_raw_pointers();
}
- let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, Some(span));
+ let receiver_trait_def_id = tcx.require_lang_item(LangItem::LegacyReceiver, Some(span));
// Keep dereferencing `receiver_ty` until we get to `self_ty`.
while let Some((potential_self_ty, _)) = autoderef.next() {
@@ -1857,7 +1877,7 @@
let tcx = wfcx.tcx();
let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]);
- let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
+ let obligation = Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) {
true
@@ -2193,7 +2213,7 @@
.unwrap_or(obligation_span);
}
- let obligation = traits::Obligation::new(
+ let obligation = Obligation::new(
tcx,
traits::ObligationCause::new(
span,
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 76c75d9..b4f6b5a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -364,6 +364,7 @@
.err_ctxt()
.report_mismatched_types(
&cause,
+ param_env,
mk_ptr(mt_b.ty),
target,
ty::error::TypeError::Mutability,
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index acc21d0..3add801 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -77,6 +77,8 @@
explicit_supertraits_containing_assoc_item:
predicates_of::explicit_supertraits_containing_assoc_item,
trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
+ const_conditions: predicates_of::const_conditions,
+ implied_const_bounds: predicates_of::implied_const_bounds,
type_param_predicates: predicates_of::type_param_predicates,
trait_def,
adt_def,
@@ -1595,7 +1597,7 @@
impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id).instantiate_identity();
- check_impl_constness(tcx, tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref);
+ check_impl_constness(tcx, tcx.is_const_trait_impl(def_id.to_def_id()), ast_trait_ref);
let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty);
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 348b226..3eec0e1 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -53,7 +53,6 @@
param_def_id_to_index,
has_self: opaque_ty_generics.has_self,
has_late_bound_regions: opaque_ty_generics.has_late_bound_regions,
- host_effect_index: parent_generics.host_effect_index,
};
}
@@ -161,7 +160,6 @@
param_def_id_to_index,
has_self: generics.has_self,
has_late_bound_regions: generics.has_late_bound_regions,
- host_effect_index: None,
};
} else {
// HACK(eddyb) this provides the correct generics when
@@ -292,12 +290,10 @@
let has_self = opt_self.is_some();
let mut parent_has_self = false;
let mut own_start = has_self as u32;
- let mut host_effect_index = None;
let parent_count = parent_def_id.map_or(0, |def_id| {
let generics = tcx.generics_of(def_id);
assert!(!has_self);
parent_has_self = generics.has_self;
- host_effect_index = generics.host_effect_index;
own_start = generics.count() as u32;
generics.parent_count + generics.own_params.len()
});
@@ -361,12 +357,8 @@
kind,
})
}
- GenericParamKind::Const { ty: _, default, is_host_effect, synthetic } => {
- if !matches!(allow_defaults, Defaults::Allowed)
- && default.is_some()
- // `host` effect params are allowed to have defaults.
- && !is_host_effect
- {
+ GenericParamKind::Const { ty: _, default, synthetic } => {
+ if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
tcx.dcx().span_err(
param.span,
"defaults for const parameters are only allowed in \
@@ -376,27 +368,12 @@
let index = next_index();
- if is_host_effect {
- if let Some(idx) = host_effect_index {
- tcx.dcx().span_delayed_bug(
- param.span,
- format!("parent also has host effect param? index: {idx}, def: {def_id:?}"),
- );
- }
-
- host_effect_index = Some(index as usize);
- }
-
Some(ty::GenericParamDef {
index,
name: param.name.ident().name,
def_id: param.def_id.to_def_id(),
pure_wrt_drop: param.pure_wrt_drop,
- kind: ty::GenericParamDefKind::Const {
- has_default: default.is_some(),
- is_host_effect,
- synthetic,
- },
+ kind: ty::GenericParamDefKind::Const { has_default: default.is_some(), synthetic },
})
}
}));
@@ -459,7 +436,6 @@
param_def_id_to_index,
has_self: has_self || parent_has_self,
has_late_bound_regions: has_late_bound_regions(tcx, node),
- host_effect_index,
}
}
@@ -540,8 +516,7 @@
type Result = ControlFlow<()>;
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result {
- if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind
- {
+ if let GenericParamKind::Const { ty, default: _, synthetic: _ } = p.kind {
let prev = self.in_param_ty;
self.in_param_ty = true;
let res = self.visit_ty(ty);
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 69ebd3a..5c4cecc 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -40,7 +40,16 @@
let mut bounds = Bounds::default();
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
// Associated types are implicitly sized unless a `?Sized` bound is found
- icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
+ match filter {
+ PredicateFilter::All
+ | PredicateFilter::SelfOnly
+ | PredicateFilter::SelfThatDefines(_)
+ | PredicateFilter::SelfAndAssociatedTypeBounds => {
+ icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
+ }
+ // `ConstIfConst` is only interested in `~const` bounds.
+ PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
+ }
let trait_def_id = tcx.local_parent(assoc_item_def_id);
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
@@ -58,7 +67,7 @@
)
});
- let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent));
+ let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent));
debug!(
"associated_type_bounds({}) = {:?}",
tcx.def_path_str(assoc_item_def_id.to_def_id()),
@@ -109,10 +118,19 @@
} else {
// Only collect *self* type bounds if the filter is for self.
match filter {
- PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
+ PredicateFilter::All => {}
+ PredicateFilter::SelfOnly => {
return None;
}
- PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {}
+ PredicateFilter::SelfThatDefines(_)
+ | PredicateFilter::SelfConstIfConst
+ | PredicateFilter::SelfAndAssociatedTypeBounds
+ | PredicateFilter::ConstIfConst => {
+ unreachable!(
+ "invalid predicate filter for \
+ `remap_gat_vars_and_recurse_into_nested_projections`"
+ )
+ }
}
clause_ty = alias_ty.self_ty();
@@ -308,10 +326,20 @@
let mut bounds = Bounds::default();
icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
// Opaque types are implicitly sized unless a `?Sized` bound is found
- icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
+ match filter {
+ PredicateFilter::All
+ | PredicateFilter::SelfOnly
+ | PredicateFilter::SelfThatDefines(_)
+ | PredicateFilter::SelfAndAssociatedTypeBounds => {
+ // Associated types are implicitly sized unless a `?Sized` bound is found
+ icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
+ }
+ //`ConstIfConst` is only interested in `~const` bounds.
+ PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
+ }
debug!(?bounds);
- tcx.arena.alloc_from_iter(bounds.clauses(tcx))
+ tcx.arena.alloc_from_iter(bounds.clauses())
})
}
@@ -339,20 +367,8 @@
// a projection self type.
Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
let opaque_ty = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_opaque_ty();
- let item_ty = Ty::new_projection_from_args(
- tcx,
- def_id.to_def_id(),
- ty::GenericArgs::identity_for_item(tcx, def_id),
- );
- let bounds = opaque_type_bounds(
- tcx,
- opaque_def_id.expect_local(),
- opaque_ty.bounds,
- item_ty,
- opaque_ty.span,
- filter,
- );
- assert_only_contains_predicates_from(filter, bounds, item_ty);
+ let bounds =
+ associated_type_bounds(tcx, def_id, opaque_ty.bounds, opaque_ty.span, filter);
return ty::EarlyBinder::bind(bounds);
}
Some(ty::ImplTraitInTraitData::Impl { .. }) => span_bug!(
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 097a1fb..644ff0c 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -12,6 +12,7 @@
use rustc_span::{DUMMY_SP, Span};
use tracing::{debug, instrument, trace};
+use super::item_bounds::explicit_item_bounds_with_filter;
use crate::bounds::Bounds;
use crate::collect::ItemCtxt;
use crate::constrained_generic_params as cgp;
@@ -78,7 +79,6 @@
#[instrument(level = "trace", skip(tcx), ret)]
fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> {
use rustc_hir::*;
- use rustc_middle::ty::Ty;
match tcx.opt_rpitit_info(def_id.to_def_id()) {
Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) => {
@@ -106,7 +106,6 @@
return ty::GenericPredicates {
parent: Some(tcx.parent(def_id.to_def_id())),
predicates: tcx.arena.alloc_from_iter(predicates),
- effects_min_tys: ty::List::empty(),
};
}
@@ -128,7 +127,6 @@
return ty::GenericPredicates {
parent: Some(impl_def_id),
predicates: tcx.arena.alloc_from_iter(impl_predicates),
- effects_min_tys: ty::List::empty(),
};
}
@@ -154,7 +152,6 @@
// We use an `IndexSet` to preserve order of insertion.
// Preserving the order of insertion is important here so as not to break UI tests.
let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default();
- let mut effects_min_tys = Vec::new();
let hir_generics = node.generics().unwrap_or(NO_GENERICS);
if let Node::Item(item) = node {
@@ -189,8 +186,7 @@
ty::List::empty(),
PredicateFilter::All,
);
- predicates.extend(bounds.clauses(tcx));
- effects_min_tys.extend(bounds.effects_min_tys());
+ predicates.extend(bounds.clauses());
}
// In default impls, we can assume that the self type implements
@@ -223,7 +219,7 @@
param.span,
);
trace!(?bounds);
- predicates.extend(bounds.clauses(tcx));
+ predicates.extend(bounds.clauses());
trace!(?predicates);
}
hir::GenericParamKind::Const { .. } => {
@@ -275,8 +271,7 @@
bound_vars,
PredicateFilter::All,
);
- predicates.extend(bounds.clauses(tcx));
- effects_min_tys.extend(bounds.effects_min_tys());
+ predicates.extend(bounds.clauses());
}
hir::WherePredicate::RegionPredicate(region_pred) => {
@@ -345,30 +340,9 @@
debug!(?predicates);
}
- // add `Self::Effects: Compat<HOST>` to ensure non-const impls don't get called
- // in const contexts.
- if let Node::TraitItem(&TraitItem { kind: TraitItemKind::Fn(..), .. }) = node
- && let Some(host_effect_index) = generics.host_effect_index
- {
- let parent = generics.parent.unwrap();
- let Some(assoc_def_id) = tcx.associated_type_for_effects(parent) else {
- bug!("associated_type_for_effects returned None when there is host effect in generics");
- };
- let effects =
- Ty::new_projection(tcx, assoc_def_id, ty::GenericArgs::identity_for_item(tcx, parent));
- let param = generics.param_at(host_effect_index, tcx);
- let span = tcx.def_span(param.def_id);
- let host = ty::Const::new_param(tcx, ty::ParamConst::for_def(param));
- let compat = tcx.require_lang_item(LangItem::EffectsCompat, Some(span));
- let trait_ref =
- ty::TraitRef::new(tcx, compat, [ty::GenericArg::from(effects), host.into()]);
- predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span));
- }
-
ty::GenericPredicates {
parent: generics.parent,
predicates: tcx.arena.alloc_from_iter(predicates),
- effects_min_tys: tcx.mk_type_list(&effects_min_tys),
}
}
@@ -519,7 +493,6 @@
ty::GenericPredicates {
parent: predicates_and_bounds.parent,
predicates: tcx.arena.alloc_slice(&predicates),
- effects_min_tys: predicates_and_bounds.effects_min_tys,
}
}
} else {
@@ -571,7 +544,6 @@
return GenericPredicates {
parent: parent_preds.parent,
predicates: { tcx.arena.alloc_from_iter(filtered_predicates) },
- effects_min_tys: parent_preds.effects_min_tys,
};
}
gather_explicit_predicates_of(tcx, def_id)
@@ -650,7 +622,7 @@
// Combine the two lists to form the complete set of superbounds:
let implied_bounds =
- &*tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(where_bounds_that_match));
+ &*tcx.arena.alloc_from_iter(bounds.clauses().chain(where_bounds_that_match));
debug!(?implied_bounds);
// Now require that immediate supertraits are lowered, which will, in
@@ -706,29 +678,76 @@
assert_eq!(
trait_predicate.self_ty(),
ty,
- "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}"
+ "expected `Self` predicate when computing \
+ `{filter:?}` implied bounds: {clause:?}"
);
}
ty::ClauseKind::Projection(projection_predicate) => {
assert_eq!(
projection_predicate.self_ty(),
ty,
- "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}"
+ "expected `Self` predicate when computing \
+ `{filter:?}` implied bounds: {clause:?}"
);
}
ty::ClauseKind::TypeOutlives(outlives_predicate) => {
assert_eq!(
outlives_predicate.0, ty,
- "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}"
+ "expected `Self` predicate when computing \
+ `{filter:?}` implied bounds: {clause:?}"
);
}
ty::ClauseKind::RegionOutlives(_)
| ty::ClauseKind::ConstArgHasType(_, _)
| ty::ClauseKind::WellFormed(_)
- | ty::ClauseKind::ConstEvaluatable(_) => {
+ | ty::ClauseKind::ConstEvaluatable(_)
+ | ty::ClauseKind::HostEffect(..) => {
bug!(
- "unexpected non-`Self` predicate when computing `{filter:?}` implied bounds: {clause:?}"
+ "unexpected non-`Self` predicate when computing \
+ `{filter:?}` implied bounds: {clause:?}"
+ );
+ }
+ }
+ }
+ }
+ PredicateFilter::ConstIfConst => {
+ for (clause, _) in bounds {
+ match clause.kind().skip_binder() {
+ ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
+ trait_ref: _,
+ host: ty::HostPolarity::Maybe,
+ }) => {}
+ _ => {
+ bug!(
+ "unexpected non-`HostEffect` predicate when computing \
+ `{filter:?}` implied bounds: {clause:?}"
+ );
+ }
+ }
+ }
+ }
+ PredicateFilter::SelfConstIfConst => {
+ for (clause, _) in bounds {
+ match clause.kind().skip_binder() {
+ ty::ClauseKind::HostEffect(pred) => {
+ assert_eq!(
+ pred.host,
+ ty::HostPolarity::Maybe,
+ "expected `~const` predicate when computing `{filter:?}` \
+ implied bounds: {clause:?}",
+ );
+ assert_eq!(
+ pred.trait_ref.self_ty(),
+ ty,
+ "expected `Self` predicate when computing `{filter:?}` \
+ implied bounds: {clause:?}"
+ );
+ }
+ _ => {
+ bug!(
+ "unexpected non-`HostEffect` predicate when computing \
+ `{filter:?}` implied bounds: {clause:?}"
);
}
}
@@ -847,6 +866,147 @@
);
}
- bounds.clauses(self.tcx).collect()
+ bounds.clauses().collect()
}
}
+
+/// Compute the conditions that need to hold for a conditionally-const item to be const.
+/// That is, compute the set of `~const` where clauses for a given item.
+///
+/// This query also computes the `~const` where clauses for associated types, which are
+/// not "const", but which have item bounds which may be `~const`. These must hold for
+/// the `~const` item bound to hold.
+pub(super) fn const_conditions<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: LocalDefId,
+) -> ty::ConstConditions<'tcx> {
+ if !tcx.is_conditionally_const(def_id) {
+ bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}");
+ }
+
+ let (generics, trait_def_id_and_supertraits, has_parent) = match tcx.hir_node_by_def_id(def_id)
+ {
+ Node::Item(item) => match item.kind {
+ hir::ItemKind::Impl(impl_) => (impl_.generics, None, false),
+ hir::ItemKind::Fn(_, generics, _) => (generics, None, false),
+ hir::ItemKind::Trait(_, _, generics, supertraits, _) => {
+ (generics, Some((item.owner_id.def_id, supertraits)), false)
+ }
+ _ => bug!("const_conditions called on wrong item: {def_id:?}"),
+ },
+ // While associated types are not really const, we do allow them to have `~const`
+ // bounds and where clauses. `const_conditions` is responsible for gathering
+ // these up so we can check them in `compare_type_predicate_entailment`, and
+ // in `HostEffect` goal computation.
+ Node::TraitItem(item) => match item.kind {
+ hir::TraitItemKind::Fn(_, _) | hir::TraitItemKind::Type(_, _) => {
+ (item.generics, None, true)
+ }
+ _ => bug!("const_conditions called on wrong item: {def_id:?}"),
+ },
+ Node::ImplItem(item) => match item.kind {
+ hir::ImplItemKind::Fn(_, _) | hir::ImplItemKind::Type(_) => {
+ (item.generics, None, tcx.is_conditionally_const(tcx.local_parent(def_id)))
+ }
+ _ => bug!("const_conditions called on wrong item: {def_id:?}"),
+ },
+ Node::ForeignItem(item) => match item.kind {
+ hir::ForeignItemKind::Fn(_, _, generics) => (generics, None, false),
+ _ => bug!("const_conditions called on wrong item: {def_id:?}"),
+ },
+ // N.B. Tuple ctors are unconditionally constant.
+ Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(),
+ _ => bug!("const_conditions called on wrong item: {def_id:?}"),
+ };
+
+ let icx = ItemCtxt::new(tcx, def_id);
+ let mut bounds = Bounds::default();
+
+ for pred in generics.predicates {
+ match pred {
+ hir::WherePredicate::BoundPredicate(bound_pred) => {
+ let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty);
+ let bound_vars = tcx.late_bound_vars(bound_pred.hir_id);
+ icx.lowerer().lower_bounds(
+ ty,
+ bound_pred.bounds.iter(),
+ &mut bounds,
+ bound_vars,
+ PredicateFilter::ConstIfConst,
+ );
+ }
+ _ => {}
+ }
+ }
+
+ if let Some((def_id, supertraits)) = trait_def_id_and_supertraits {
+ bounds.push_const_bound(
+ tcx,
+ ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())),
+ ty::HostPolarity::Maybe,
+ DUMMY_SP,
+ );
+
+ icx.lowerer().lower_bounds(
+ tcx.types.self_param,
+ supertraits.into_iter(),
+ &mut bounds,
+ ty::List::empty(),
+ PredicateFilter::ConstIfConst,
+ );
+ }
+
+ ty::ConstConditions {
+ parent: has_parent.then(|| tcx.local_parent(def_id).to_def_id()),
+ predicates: tcx.arena.alloc_from_iter(bounds.clauses().map(|(clause, span)| {
+ (
+ clause.kind().map_bound(|clause| match clause {
+ ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
+ trait_ref,
+ host: ty::HostPolarity::Maybe,
+ }) => trait_ref,
+ _ => bug!("converted {clause:?}"),
+ }),
+ span,
+ )
+ })),
+ }
+}
+
+pub(super) fn implied_const_bounds<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: LocalDefId,
+) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
+ if !tcx.is_conditionally_const(def_id) {
+ bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}");
+ }
+
+ let bounds = match tcx.hir_node_by_def_id(def_id) {
+ Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => {
+ implied_predicates_with_filter(
+ tcx,
+ def_id.to_def_id(),
+ PredicateFilter::SelfConstIfConst,
+ )
+ }
+ Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. }) => {
+ explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst)
+ }
+ _ => bug!("implied_const_bounds called on wrong item: {def_id:?}"),
+ };
+
+ bounds.map_bound(|bounds| {
+ &*tcx.arena.alloc_from_iter(bounds.iter().copied().map(|(clause, span)| {
+ (
+ clause.kind().map_bound(|clause| match clause {
+ ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
+ trait_ref,
+ host: ty::HostPolarity::Maybe,
+ }) => trait_ref,
+ _ => bug!("converted {clause:?}"),
+ }),
+ span,
+ )
+ }))
+ })
+}
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 95e0724..f7daef3 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -33,18 +33,12 @@
#[extension(trait RegionExt)]
impl ResolvedArg {
- fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
- debug!("ResolvedArg::early: def_id={:?}", param.def_id);
- (param.def_id, ResolvedArg::EarlyBound(param.def_id))
+ fn early(param: &GenericParam<'_>) -> ResolvedArg {
+ ResolvedArg::EarlyBound(param.def_id)
}
- fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
- let depth = ty::INNERMOST;
- debug!(
- "ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
- idx, param, depth, param.def_id,
- );
- (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id))
+ fn late(idx: u32, param: &GenericParam<'_>) -> ResolvedArg {
+ ResolvedArg::LateBound(ty::INNERMOST, idx, param.def_id)
}
fn id(&self) -> Option<LocalDefId> {
@@ -282,24 +276,33 @@
fn late_arg_as_bound_arg<'tcx>(
tcx: TyCtxt<'tcx>,
- arg: &ResolvedArg,
param: &GenericParam<'tcx>,
) -> ty::BoundVariableKind {
- match arg {
- ResolvedArg::LateBound(_, _, def_id) => {
- let def_id = def_id.to_def_id();
- let name = tcx.item_name(def_id);
- match param.kind {
- GenericParamKind::Lifetime { .. } => {
- ty::BoundVariableKind::Region(ty::BrNamed(def_id, name))
- }
- GenericParamKind::Type { .. } => {
- ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name))
- }
- GenericParamKind::Const { .. } => ty::BoundVariableKind::Const,
- }
+ let def_id = param.def_id.to_def_id();
+ let name = tcx.item_name(def_id);
+ match param.kind {
+ GenericParamKind::Lifetime { .. } => {
+ ty::BoundVariableKind::Region(ty::BrNamed(def_id, name))
}
- _ => bug!("{:?} is not a late argument", arg),
+ GenericParamKind::Type { .. } => {
+ ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name))
+ }
+ GenericParamKind::Const { .. } => ty::BoundVariableKind::Const,
+ }
+}
+
+/// Turn a [`ty::GenericParamDef`] into a bound arg. Generally, this should only
+/// be used when turning early-bound vars into late-bound vars when lowering
+/// return type notation.
+fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVariableKind {
+ match param.kind {
+ ty::GenericParamDefKind::Lifetime => {
+ ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(param.def_id, param.name))
+ }
+ ty::GenericParamDefKind::Type { .. } => {
+ ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name))
+ }
+ ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
}
}
@@ -360,10 +363,9 @@
let mut bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = FxIndexMap::default();
let binders_iter =
trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| {
- let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param);
- let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
- bound_vars.insert(pair.0, pair.1);
- r
+ let arg = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param);
+ bound_vars.insert(param.def_id, arg);
+ late_arg_as_bound_arg(self.tcx, param)
});
binders.extend(binders_iter);
@@ -458,9 +460,10 @@
.iter()
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = ResolvedArg::late(late_bound_idx as u32, param);
- let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
- (pair, r)
+ (
+ (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
+ late_arg_as_bound_arg(self.tcx, param),
+ )
})
.unzip();
@@ -492,8 +495,8 @@
let mut bound_vars = FxIndexMap::default();
debug!(?opaque.generics.params);
for param in opaque.generics.params {
- let (def_id, reg) = ResolvedArg::early(param);
- bound_vars.insert(def_id, reg);
+ let arg = ResolvedArg::early(param);
+ bound_vars.insert(param.def_id, arg);
}
let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id);
@@ -618,9 +621,10 @@
.iter()
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = ResolvedArg::late(late_bound_idx as u32, param);
- let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
- (pair, r)
+ (
+ (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
+ late_arg_as_bound_arg(self.tcx, param),
+ )
})
.unzip();
@@ -870,9 +874,10 @@
.iter()
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair = ResolvedArg::late(late_bound_idx as u32, param);
- let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
- (pair, r)
+ (
+ (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
+ late_arg_as_bound_arg(self.tcx, param),
+ )
})
.unzip();
@@ -1052,19 +1057,21 @@
let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = generics
.params
.iter()
- .map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => {
- if self.tcx.is_late_bound(param.hir_id) {
- let late_bound_idx = named_late_bound_vars;
- named_late_bound_vars += 1;
- ResolvedArg::late(late_bound_idx, param)
- } else {
+ .map(|param| {
+ (param.def_id, match param.kind {
+ GenericParamKind::Lifetime { .. } => {
+ if self.tcx.is_late_bound(param.hir_id) {
+ let late_bound_idx = named_late_bound_vars;
+ named_late_bound_vars += 1;
+ ResolvedArg::late(late_bound_idx, param)
+ } else {
+ ResolvedArg::early(param)
+ }
+ }
+ GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
ResolvedArg::early(param)
}
- }
- GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
- ResolvedArg::early(param)
- }
+ })
})
.collect();
@@ -1075,11 +1082,7 @@
matches!(param.kind, GenericParamKind::Lifetime { .. })
&& self.tcx.is_late_bound(param.hir_id)
})
- .enumerate()
- .map(|(late_bound_idx, param)| {
- let pair = ResolvedArg::late(late_bound_idx as u32, param);
- late_arg_as_bound_arg(self.tcx, &pair.1, param)
- })
+ .map(|param| late_arg_as_bound_arg(self.tcx, param))
.collect();
self.record_late_bound_vars(hir_id, binders);
let scope = Scope::Binder {
@@ -1096,7 +1099,8 @@
where
F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>),
{
- let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
+ let bound_vars =
+ generics.params.iter().map(|param| (param.def_id, ResolvedArg::early(param))).collect();
self.record_late_bound_vars(hir_id, vec![]);
let scope = Scope::Binder {
hir_id,
@@ -1639,17 +1643,13 @@
constraint.ident,
ty::AssocKind::Fn,
) {
- bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).own_params.iter().map(
- |param| match param.kind {
- ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
- ty::BoundRegionKind::BrNamed(param.def_id, param.name),
- ),
- ty::GenericParamDefKind::Type { .. } => ty::BoundVariableKind::Ty(
- ty::BoundTyKind::Param(param.def_id, param.name),
- ),
- ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
- },
- ));
+ bound_vars.extend(
+ self.tcx
+ .generics_of(assoc_fn.def_id)
+ .own_params
+ .iter()
+ .map(|param| generic_param_def_as_bound_arg(param)),
+ );
bound_vars.extend(
self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars(),
);
@@ -1968,17 +1968,13 @@
// Append the early-bound vars on the function, and then the late-bound ones.
// We actually turn type parameters into higher-ranked types here, but we
// deny them later in HIR lowering.
- bound_vars.extend(self.tcx.generics_of(item_def_id).own_params.iter().map(|param| {
- match param.kind {
- ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
- ty::BoundRegionKind::BrNamed(param.def_id, param.name),
- ),
- ty::GenericParamDefKind::Type { .. } => {
- ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name))
- }
- ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
- }
- }));
+ bound_vars.extend(
+ self.tcx
+ .generics_of(item_def_id)
+ .own_params
+ .iter()
+ .map(|param| generic_param_def_as_bound_arg(param)),
+ );
bound_vars.extend(self.tcx.fn_sig(item_def_id).instantiate_identity().bound_vars());
// SUBTLE: Stash the old bound vars onto the *item segment* before appending
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs
index 1ccb7fa..e65420e 100644
--- a/compiler/rustc_hir_analysis/src/delegation.rs
+++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -186,7 +186,6 @@
param_def_id_to_index,
has_self,
has_late_bound_regions: sig_generics.has_late_bound_regions,
- host_effect_index: sig_generics.host_effect_index,
}
}
}
@@ -279,8 +278,6 @@
ty::GenericPredicates {
parent: self.parent,
predicates: self.tcx.arena.alloc_from_iter(preds),
- // FIXME(fn_delegation): Support effects.
- effects_min_tys: ty::List::empty(),
}
}
}
@@ -472,10 +469,6 @@
}));
};
- if tcx.has_host_param(sig_id) {
- emit("delegation to a function with effect parameter is not supported yet");
- }
-
if let Some(local_sig_id) = sig_id.as_local()
&& tcx.hir().opt_delegation_sig_id(local_sig_id).is_some()
{
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 77e81af..7fa9dfe 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1624,12 +1624,6 @@
}
#[derive(Diagnostic)]
-#[diag(hir_analysis_effects_without_next_solver)]
-#[note]
-#[help]
-pub(crate) struct EffectsWithoutNextSolver;
-
-#[derive(Diagnostic)]
#[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)]
#[note]
pub(crate) struct CmseInputsStackSpill {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 2b0e135..a570908 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -154,7 +154,6 @@
for hir_bound in hir_bounds {
// In order to avoid cycles, when we're lowering `SelfThatDefines`,
// we skip over any traits that don't define the given associated type.
-
if let PredicateFilter::SelfThatDefines(assoc_name) = predicate_filter {
if let Some(trait_ref) = hir_bound.trait_ref()
&& let Some(trait_did) = trait_ref.trait_def_id()
@@ -169,13 +168,6 @@
match hir_bound {
hir::GenericBound::Trait(poly_trait_ref) => {
let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers;
- // FIXME: We could pass these directly into `lower_poly_trait_ref`
- // so that we could use these spans in diagnostics within that function...
- let constness = match constness {
- hir::BoundConstness::Never => None,
- hir::BoundConstness::Always(_) => Some(ty::BoundConstness::Const),
- hir::BoundConstness::Maybe(_) => Some(ty::BoundConstness::ConstIfConst),
- };
let polarity = match polarity {
rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive,
rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative,
@@ -193,6 +185,14 @@
);
}
hir::GenericBound::Outlives(lifetime) => {
+ // `ConstIfConst` is only interested in `~const` bounds.
+ if matches!(
+ predicate_filter,
+ PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst
+ ) {
+ continue;
+ }
+
let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound);
bounds.push_region_bound(
self.tcx(),
@@ -392,21 +392,31 @@
},
);
- bounds.push_projection_bound(
- tcx,
- projection_term.map_bound(|projection_term| ty::ProjectionPredicate {
- projection_term,
- term,
- }),
- constraint.span,
- );
+ match predicate_filter {
+ PredicateFilter::All
+ | PredicateFilter::SelfOnly
+ | PredicateFilter::SelfThatDefines(_)
+ | PredicateFilter::SelfAndAssociatedTypeBounds => {
+ bounds.push_projection_bound(
+ tcx,
+ projection_term.map_bound(|projection_term| ty::ProjectionPredicate {
+ projection_term,
+ term,
+ }),
+ constraint.span,
+ );
+ }
+ // `ConstIfConst` is only interested in `~const` bounds.
+ PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {}
+ }
}
// Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator<Item: Debug>`
// to a bound involving a projection: `<T as Iterator>::Item: Debug`.
hir::AssocItemConstraintKind::Bound { bounds: hir_bounds } => {
match predicate_filter {
- PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {}
- PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
+ PredicateFilter::All
+ | PredicateFilter::SelfAndAssociatedTypeBounds
+ | PredicateFilter::ConstIfConst => {
let projection_ty = projection_term
.map_bound(|projection_term| projection_term.expect_ty(self.tcx()));
// Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty`
@@ -421,6 +431,9 @@
predicate_filter,
);
}
+ PredicateFilter::SelfOnly
+ | PredicateFilter::SelfThatDefines(_)
+ | PredicateFilter::SelfConstIfConst => {}
}
}
}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 2cee7c7..f2ee4b0 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -50,7 +50,7 @@
} = self.lower_poly_trait_ref(
&trait_bound.trait_ref,
trait_bound.span,
- None,
+ hir::BoundConstness::Never,
ty::PredicatePolarity::Positive,
dummy_self,
&mut bounds,
@@ -62,7 +62,7 @@
let mut trait_bounds = vec![];
let mut projection_bounds = vec![];
- for (pred, span) in bounds.clauses(tcx) {
+ for (pred, span) in bounds.clauses() {
let bound_pred = pred.kind();
match bound_pred.skip_binder() {
ty::ClauseKind::Trait(trait_pred) => {
@@ -78,7 +78,8 @@
ty::ClauseKind::RegionOutlives(_)
| ty::ClauseKind::ConstArgHasType(..)
| ty::ClauseKind::WellFormed(_)
- | ty::ClauseKind::ConstEvaluatable(_) => {
+ | ty::ClauseKind::ConstEvaluatable(_)
+ | ty::ClauseKind::HostEffect(..) => {
span_bug!(span, "did not expect {pred} clause in object bounds");
}
}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index a73a2f9..0891642 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -81,6 +81,12 @@
/// For example, given `Self: Tr<A: B>`, this would expand to `Self: Tr`
/// and `<Self as Tr>::A: B`.
SelfAndAssociatedTypeBounds,
+
+ /// Filter only the `~const` bounds, which are lowered into `HostEffect` clauses.
+ ConstIfConst,
+
+ /// Filter only the `~const` bounds which are *also* in the supertrait position.
+ SelfConstIfConst,
}
#[derive(Debug)]
@@ -652,7 +658,7 @@
&self,
trait_ref: &hir::TraitRef<'tcx>,
span: Span,
- constness: Option<ty::BoundConstness>,
+ constness: hir::BoundConstness,
polarity: ty::PredicatePolarity,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
@@ -675,11 +681,11 @@
Some(self_ty),
);
- if let Some(constness) = constness
+ if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness
&& !self.tcx().is_const_trait(trait_def_id)
{
self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
- span: trait_ref.path.span,
+ span,
modifier: constness.as_str(),
});
}
@@ -693,16 +699,49 @@
bound_vars,
);
- debug!(?poly_trait_ref);
- bounds.push_trait_bound(
- tcx,
- self.item_def_id().to_def_id(),
- poly_trait_ref,
- span,
- polarity,
- constness,
- predicate_filter,
- );
+ match predicate_filter {
+ PredicateFilter::All
+ | PredicateFilter::SelfOnly
+ | PredicateFilter::SelfThatDefines(..)
+ | PredicateFilter::SelfAndAssociatedTypeBounds => {
+ debug!(?poly_trait_ref);
+ bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
+
+ match constness {
+ hir::BoundConstness::Always(span) => {
+ if polarity == ty::PredicatePolarity::Positive {
+ bounds.push_const_bound(
+ tcx,
+ poly_trait_ref,
+ ty::HostPolarity::Const,
+ span,
+ );
+ }
+ }
+ hir::BoundConstness::Maybe(_) => {
+ // We don't emit a const bound here, since that would mean that we
+ // unconditionally need to prove a `HostEffect` predicate, even when
+ // the predicates are being instantiated in a non-const context. This
+ // is instead handled in the `const_conditions` query.
+ }
+ hir::BoundConstness::Never => {}
+ }
+ }
+ // On the flip side, when filtering `ConstIfConst` bounds, we only need to convert
+ // `~const` bounds. All other predicates are handled in their respective queries.
+ //
+ // Note that like `PredicateFilter::SelfOnly`, we don't need to do any filtering
+ // here because we only call this on self bounds, and deal with the recursive case
+ // in `lower_assoc_item_constraint`.
+ PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => match constness {
+ hir::BoundConstness::Maybe(span) => {
+ if polarity == ty::PredicatePolarity::Positive {
+ bounds.push_const_bound(tcx, poly_trait_ref, ty::HostPolarity::Maybe, span);
+ }
+ }
+ hir::BoundConstness::Always(_) | hir::BoundConstness::Never => {}
+ },
+ }
let mut dup_constraints = FxIndexMap::default();
for constraint in trait_segment.args().constraints {
@@ -1164,15 +1203,6 @@
err.emit()
} else if let Err(reported) = qself_ty.error_reported() {
reported
- } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
- // `<impl Trait as OtherTrait>::Assoc` makes no sense.
- struct_span_code_err!(
- self.dcx(),
- tcx.def_span(alias_ty.def_id),
- E0667,
- "`impl Trait` is not allowed in path parameters"
- )
- .emit() // Already reported in an earlier stage.
} else {
self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?;
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 0355adf..a394fc2 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -530,6 +530,7 @@
| ty::ClauseKind::Projection(_)
| ty::ClauseKind::ConstArgHasType(..)
| ty::ClauseKind::WellFormed(_)
- | ty::ClauseKind::ConstEvaluatable(..) => None,
+ | ty::ClauseKind::ConstEvaluatable(..)
+ | ty::ClauseKind::HostEffect(..) => None,
}
}
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 3ad3516..339edde 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -153,12 +153,6 @@
pub fn check_crate(tcx: TyCtxt<'_>) {
let _prof_timer = tcx.sess.timer("type_check_crate");
- // FIXME(effects): remove once effects is implemented in old trait solver
- // or if the next solver is stabilized.
- if tcx.features().effects() && !tcx.next_trait_solver_globally() {
- tcx.dcx().emit_err(errors::EffectsWithoutNextSolver);
- }
-
tcx.sess.time("coherence_checking", || {
tcx.hir().par_for_each_module(|module| {
let _ = tcx.ensure().check_mod_type_wf(module);
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index f576499..2c1d443 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -53,7 +53,8 @@
| ty::ClauseKind::Projection(_)
| ty::ClauseKind::ConstArgHasType(_, _)
| ty::ClauseKind::WellFormed(_)
- | ty::ClauseKind::ConstEvaluatable(_) => {}
+ | ty::ClauseKind::ConstEvaluatable(_)
+ | ty::ClauseKind::HostEffect(..) => {}
}
}
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 3ba9c76..61214b9 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -2134,7 +2134,7 @@
self.print_type(default);
}
}
- GenericParamKind::Const { ty, ref default, is_host_effect: _, synthetic: _ } => {
+ GenericParamKind::Const { ty, ref default, synthetic: _ } => {
self.word_space(":");
self.print_type(ty);
if let Some(default) = default {
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index e68caa3..3372cae 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -94,14 +94,11 @@
(None, arm.body.span)
};
- let (span, code) = match prior_arm {
+ let code = match prior_arm {
// The reason for the first arm to fail is not that the match arms diverge,
// but rather that there's a prior obligation that doesn't hold.
- None => {
- (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src))
- }
- Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => (
- expr.span,
+ None => ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src),
+ Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => {
ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause {
arm_block_id,
arm_span,
@@ -110,13 +107,14 @@
prior_arm_ty,
prior_arm_span,
scrut_span: scrut.span,
+ expr_span: expr.span,
source: match_src,
prior_non_diverging_arms: prior_non_diverging_arms.clone(),
tail_defines_return_position_impl_trait,
- })),
- ),
+ }))
+ }
};
- let cause = self.cause(span, code);
+ let cause = self.cause(arm_span, code);
// This is the moral equivalent of `coercion.coerce(self, cause, arm.body, arm_ty)`.
// We use it this way to be able to expand on the potential error and detect when a
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index fa6a86c..ed56bb9 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -20,7 +20,7 @@
use rustc_trait_selection::error_reporting::traits::DefIdOrName;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use tracing::{debug, instrument, trace};
+use tracing::{debug, instrument};
use super::method::MethodCallee;
use super::method::probe::ProbeScope;
@@ -537,7 +537,7 @@
//
// This check is here because there is currently no way to express a trait bound for `FnDef` types only.
if let ty::FnDef(def_id, _args) = *arg_ty.kind() {
- if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
+ if idx == 0 && !self.tcx.is_const_fn(def_id) {
self.dcx().emit_err(errors::ConstSelectMustBeConst { span });
}
} else {
@@ -843,27 +843,38 @@
callee_did: DefId,
callee_args: GenericArgsRef<'tcx>,
) {
- let tcx = self.tcx;
+ // FIXME(effects): We should be enforcing these effects unconditionally.
+ // This can be done as soon as we convert the standard library back to
+ // using const traits, since if we were to enforce these conditions now,
+ // we'd fail on basically every builtin trait call (i.e. `1 + 2`).
+ if !self.tcx.features().effects() {
+ return;
+ }
- // fast-reject if callee doesn't have the host effect param (non-const)
- let generics = tcx.generics_of(callee_did);
- let Some(host_effect_index) = generics.host_effect_index else { return };
-
- let effect = tcx.expected_host_effect_param_for_body(self.body_id);
-
- trace!(?effect, ?generics, ?callee_args);
-
- let param = callee_args.const_at(host_effect_index);
- let cause = self.misc(span);
- // We know the type of `effect` to be `bool`, there will be no opaque type inference.
- match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::Yes, effect, param) {
- Ok(infer::InferOk { obligations, value: () }) => {
- self.register_predicates(obligations);
+ let host = match self.tcx.hir().body_const_context(self.body_id) {
+ Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => {
+ ty::HostPolarity::Const
}
- Err(e) => {
- // FIXME(effects): better diagnostic
- self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit();
+ Some(hir::ConstContext::ConstFn) => ty::HostPolarity::Maybe,
+ None => return,
+ };
+
+ // FIXME(effects): Should this be `is_const_fn_raw`? It depends on if we move
+ // const stability checking here too, I guess.
+ if self.tcx.is_conditionally_const(callee_did) {
+ let q = self.tcx.const_conditions(callee_did);
+ // FIXME(effects): Use this span with a better cause code.
+ for (cond, _) in q.instantiate(self.tcx, callee_args) {
+ self.register_predicate(Obligation::new(
+ self.tcx,
+ self.misc(span),
+ self.param_env,
+ cond.to_host_effect_clause(self.tcx, host),
+ ));
}
+ } else {
+ // FIXME(effects): This should eventually be caught here.
+ // For now, though, we defer some const checking to MIR.
}
}
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index f7306063..483a8d1 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -876,20 +876,14 @@
// A<dyn Src<...> + SrcAuto> -> B<dyn Dst<...> + DstAuto>. need to make sure
// - `Src` and `Dst` traits are the same
// - traits have the same generic arguments
- // - `SrcAuto` is a superset of `DstAuto`
- (Some(src_principal), Some(dst_principal)) => {
+ // - projections are the same
+ // - `SrcAuto` (+auto traits implied by `Src`) is a superset of `DstAuto`
+ //
+ // Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
+ // and is unaffected by this check.
+ (Some(src_principal), Some(_)) => {
let tcx = fcx.tcx;
- // Check that the traits are actually the same.
- // The `dyn Src = dyn Dst` check below would suffice,
- // but this may produce a better diagnostic.
- //
- // Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
- // and is unaffected by this check.
- if src_principal.def_id() != dst_principal.def_id() {
- return Err(CastError::DifferingKinds { src_kind, dst_kind });
- }
-
// We need to reconstruct trait object types.
// `m_src` and `m_dst` won't work for us here because they will potentially
// contain wrappers, which we do not care about.
@@ -912,8 +906,8 @@
ty::Dyn,
));
- // `dyn Src = dyn Dst`, this checks for matching traits/generics
- // This is `demand_eqtype`, but inlined to give a better error.
+ // `dyn Src = dyn Dst`, this checks for matching traits/generics/projections
+ // This is `fcx.demand_eqtype`, but inlined to give a better error.
let cause = fcx.misc(self.span);
if fcx
.at(&cause, fcx.param_env)
@@ -965,8 +959,35 @@
// dyn Auto -> dyn Auto'? ok.
(None, None) => Ok(CastKind::PtrPtrCast),
- // dyn Trait -> dyn Auto? should be ok, but we used to not allow it.
- // FIXME: allow this
+ // dyn Trait -> dyn Auto? not ok (for now).
+ //
+ // Although dropping the principal is already allowed for unsizing coercions
+ // (e.g. `*const (dyn Trait + Auto)` to `*const dyn Auto`), dropping it is
+ // currently **NOT** allowed for (non-coercion) ptr-to-ptr casts (e.g
+ // `*const Foo` to `*const Bar` where `Foo` has a `dyn Trait + Auto` tail
+ // and `Bar` has a `dyn Auto` tail), because the underlying MIR operations
+ // currently work very differently:
+ //
+ // * A MIR unsizing coercion on raw pointers to trait objects (`*const dyn Src`
+ // to `*const dyn Dst`) is currently equivalent to downcasting the source to
+ // the concrete sized type that it was originally unsized from first (via a
+ // ptr-to-ptr cast from `*const Src` to `*const T` with `T: Sized`) and then
+ // unsizing this thin pointer to the target type (unsizing `*const T` to
+ // `*const Dst`). In particular, this means that the pointer's metadata
+ // (vtable) will semantically change, e.g. for const eval and miri, even
+ // though the vtables will always be merged for codegen.
+ //
+ // * A MIR ptr-to-ptr cast is currently equivalent to a transmute and does not
+ // change the pointer metadata (vtable) at all.
+ //
+ // In addition to this potentially surprising difference between coercion and
+ // non-coercion casts, casting away the principal with a MIR ptr-to-ptr cast
+ // is currently considered undefined behavior:
+ //
+ // As a validity invariant of pointers to trait objects, we currently require
+ // that the principal of the vtable in the pointer metadata exactly matches
+ // the principal of the pointee type, where "no principal" is also considered
+ // a kind of principal.
(Some(_), None) => Err(CastError::DifferingKinds { src_kind, dst_kind }),
// dyn Auto -> dyn Trait? not ok.
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index de80ccf..6fa958d 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1723,6 +1723,7 @@
}) => {
err = fcx.err_ctxt().report_mismatched_types(
cause,
+ fcx.param_env,
expected,
found,
coercion_error,
@@ -1752,6 +1753,7 @@
}) => {
err = fcx.err_ctxt().report_mismatched_types(
cause,
+ fcx.param_env,
expected,
found,
coercion_error,
@@ -1787,6 +1789,7 @@
_ => {
err = fcx.err_ctxt().report_mismatched_types(
cause,
+ fcx.param_env,
expected,
found,
coercion_error,
@@ -1897,7 +1900,8 @@
block_or_return_id: hir::HirId,
expression: Option<&'tcx hir::Expr<'tcx>>,
) -> Diag<'infcx> {
- let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
+ let mut err =
+ fcx.err_ctxt().report_mismatched_types(cause, fcx.param_env, expected, found, ty_err);
let due_to_block = matches!(fcx.tcx.hir_node(block_or_return_id), hir::Node::Block(..));
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 777248f..3399a9f 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -191,7 +191,9 @@
self.at(cause, self.param_env)
.sup(DefineOpaqueTypes::Yes, expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
- .map_err(|e| self.err_ctxt().report_mismatched_types(cause, expected, actual, e))
+ .map_err(|e| {
+ self.err_ctxt().report_mismatched_types(cause, self.param_env, expected, actual, e)
+ })
}
pub(crate) fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
@@ -218,7 +220,9 @@
self.at(cause, self.param_env)
.eq(DefineOpaqueTypes::Yes, expected, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
- .map_err(|e| self.err_ctxt().report_mismatched_types(cause, expected, actual, e))
+ .map_err(|e| {
+ self.err_ctxt().report_mismatched_types(cause, self.param_env, expected, actual, e)
+ })
}
pub(crate) fn demand_coerce(
@@ -271,7 +275,8 @@
let expr = expr.peel_drop_temps();
let cause = self.misc(expr.span);
let expr_ty = self.resolve_vars_if_possible(checked_ty);
- let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e);
+ let mut err =
+ self.err_ctxt().report_mismatched_types(&cause, self.param_env, expected, expr_ty, e);
self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, Some(e));
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index da231ac..d6e5fab 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1751,7 +1751,7 @@
// to tell them that in the diagnostic. Does not affect typeck.
let is_constable = match element.kind {
hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
- ty::FnDef(def_id, _) if tcx.is_const_fn(def_id) => traits::IsConstable::Fn,
+ ty::FnDef(def_id, _) if tcx.is_stable_const_fn(def_id) => traits::IsConstable::Fn,
_ => traits::IsConstable::No,
},
hir::ExprKind::Path(qpath) => {
@@ -2027,7 +2027,7 @@
}
Err(_) => {
span_bug!(
- cause.span(),
+ cause.span,
"subtyping remaining fields of type changing FRU failed: {target_ty} != {fru_ty}: {}::{}",
variant.name,
ident.name,
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 4fd508a..68776c5 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -7,8 +7,6 @@
use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_hir::intravisit::Visitor;
-use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
-use rustc_middle::bug;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
@@ -48,7 +46,7 @@
self.fulfillment_cx.borrow_mut().pending_obligations()
);
- let fallback_occurred = self.fallback_types() | self.fallback_effects();
+ let fallback_occurred = self.fallback_types();
if !fallback_occurred {
return;
@@ -103,31 +101,6 @@
fallback_occurred
}
- fn fallback_effects(&self) -> bool {
- let unsolved_effects = self.unsolved_effects();
-
- if unsolved_effects.is_empty() {
- return false;
- }
-
- // not setting the `fallback_has_occurred` field here because
- // that field is only used for type fallback diagnostics.
- for effect in unsolved_effects {
- let expected = self.tcx.consts.true_;
- let cause = self.misc(DUMMY_SP);
- match self.at(&cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, effect) {
- Ok(InferOk { obligations, value: () }) => {
- self.register_predicates(obligations);
- }
- Err(e) => {
- bug!("cannot eq unsolved effect: {e:?}")
- }
- }
- }
-
- true
- }
-
// Tries to apply a fallback to `ty` if it is an unsolved variable.
//
// - Unconstrained ints are replaced with `i32`.
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index d2d311e..0fc566c 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1262,15 +1262,8 @@
(GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
self.fcx.ty_infer(Some(param), inf.span).into()
}
- (
- &GenericParamDefKind::Const { has_default, is_host_effect, .. },
- GenericArg::Infer(inf),
- ) => {
- if has_default && is_host_effect {
- self.fcx.var_for_effect(param)
- } else {
- self.fcx.ct_infer(Some(param), inf.span).into()
- }
+ (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
+ self.fcx.ct_infer(Some(param), inf.span).into()
}
_ => unreachable!(),
}
@@ -1305,20 +1298,9 @@
self.fcx.var_for_def(self.span, param)
}
}
- GenericParamDefKind::Const { has_default, is_host_effect, .. } => {
+ GenericParamDefKind::Const { has_default, .. } => {
if has_default {
- // N.B. this is a bit of a hack. `infer_args` is passed depending on
- // whether the user has provided generic args. E.g. for `Vec::new`
- // we would have to infer the generic types. However, for `Vec::<T>::new`
- // where the allocator param `A` has a default we will *not* infer. But
- // for effect params this is a different story: if the user has not written
- // anything explicit for the effect param, we always need to try to infer
- // it before falling back to default, such that a `const fn` such as
- // `needs_drop::<()>` can still be called in const contexts. (if we defaulted
- // instead of inferred, typeck would error)
- if is_host_effect {
- return self.fcx.var_for_effect(param);
- } else if !infer_args {
+ if !infer_args {
return tcx
.const_param_default(param.def_id)
.instantiate(tcx, preceding_args)
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index f29d619..a6c249d 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -827,6 +827,7 @@
formal_and_expected_inputs[mismatch_idx.into()],
provided_arg_tys[mismatch_idx.into()].0,
),
+ self.param_env,
terr,
);
err.span_label(
@@ -912,7 +913,8 @@
let trace =
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
- let mut err = self.err_ctxt().report_and_explain_type_error(trace, *e);
+ let mut err =
+ self.err_ctxt().report_and_explain_type_error(trace, self.param_env, *e);
suggest_confusable(&mut err);
reported = Some(err.emit());
return false;
@@ -940,7 +942,8 @@
let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx];
let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty);
- let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
+ let mut err =
+ self.err_ctxt().report_and_explain_type_error(trace, self.param_env, *err);
self.emit_coerce_suggestions(
&mut err,
provided_args[*provided_idx],
@@ -1113,7 +1116,7 @@
&mut err,
&trace.cause,
None,
- Some(trace.values),
+ Some(self.param_env.and(trace.values)),
e,
true,
);
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
index 693cb44..eb5fe3a 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
@@ -52,6 +52,7 @@
| ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
| ty::PredicateKind::Ambiguous => false,
}
}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 4123fee..3940d13 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -247,12 +247,6 @@
fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
// FIXME ideally this shouldn't use unwrap
match param {
- Some(
- param @ ty::GenericParamDef {
- kind: ty::GenericParamDefKind::Const { is_host_effect: true, .. },
- ..
- },
- ) => self.var_for_effect(param).as_const().unwrap(),
Some(param) => self.var_for_def(span, param).as_const().unwrap(),
None => self.next_const_var(span),
}
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index f468572..f2b55d3 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -538,13 +538,19 @@
// to the feature, like the self type can't reference method args.
if self.tcx.features().arbitrary_self_types() {
self.err_ctxt()
- .report_mismatched_types(&cause, method_self_ty, self_ty, terr)
+ .report_mismatched_types(
+ &cause,
+ self.param_env,
+ method_self_ty,
+ self_ty,
+ terr,
+ )
.emit();
} else {
// This has/will have errored in wfcheck, which we cannot depend on from here, as typeck on functions
// may run before wfcheck if the function is used in const eval.
self.dcx().span_delayed_bug(
- cause.span(),
+ cause.span,
format!("{self_ty} was a subtype of {method_self_ty} but now is not?"),
);
}
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 69b9be0..e20a0cb 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -369,17 +369,6 @@
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
let (obligation, args) =
self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types);
- // FIXME(effects) find a better way to do this
- // Operators don't have generic methods, but making them `#[const_trait]` gives them
- // `const host: bool`.
- let args = if self.tcx.is_const_trait(trait_def_id) {
- self.tcx.mk_args_from_iter(
- args.iter()
- .chain([self.tcx.expected_host_effect_param_for_body(self.body_id).into()]),
- )
- } else {
- args
- };
self.construct_obligation_for_trait(m_name, trait_def_id, obligation, args)
}
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index b60fa8b..569fdea 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -813,7 +813,8 @@
| ty::ClauseKind::Projection(_)
| ty::ClauseKind::ConstArgHasType(_, _)
| ty::ClauseKind::WellFormed(_)
- | ty::ClauseKind::ConstEvaluatable(_) => None,
+ | ty::ClauseKind::ConstEvaluatable(_)
+ | ty::ClauseKind::HostEffect(..) => None,
}
});
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 9dd5954..eaf40a1 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -537,7 +537,7 @@
&& binding_id != self.binding_id
{
if self.check_and_add_sugg_binding(LetStmt {
- ty_hir_id_opt: if let Some(ty) = ty { Some(ty.hir_id) } else { None },
+ ty_hir_id_opt: ty.map(|ty| ty.hir_id),
binding_id,
span: pat.span,
init_hir_id: init.hir_id,
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 9e8a314..8898266 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -2457,7 +2457,7 @@
) -> (Place<'_>, ty::UpvarCapture) {
let is_shared_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not));
- // Find the right-most deref (if any). All the projections that come after this
+ // Find the rightmost deref (if any). All the projections that come after this
// are fields or other "in-place pointer adjustments"; these refer therefore to
// data owned by whatever pointer is being dereferenced here.
let idx = place.projections.iter().rposition(|proj| ProjectionKind::Deref == proj.kind);
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index e3519df..90d0796 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -489,17 +489,6 @@
}
}
}
- ty::ConstKind::Infer(InferConst::EffectVar(vid)) => {
- match self.infcx.unwrap().probe_effect_var(vid) {
- Some(value) => return self.fold_const(value),
- None => {
- return self.canonicalize_const_var(
- CanonicalVarInfo { kind: CanonicalVarKind::Effect },
- ct,
- );
- }
- }
- }
ty::ConstKind::Infer(InferConst::Fresh(_)) => {
bug!("encountered a fresh const during canonicalization")
}
@@ -700,8 +689,7 @@
.iter()
.map(|v| CanonicalVarInfo {
kind: match v.kind {
- CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
- | CanonicalVarKind::Effect => {
+ CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
return *v;
}
CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 8caedcd..fb5fc3a 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -24,7 +24,6 @@
pub use instantiate::CanonicalExt;
use rustc_index::IndexVec;
pub use rustc_middle::infer::canonical::*;
-use rustc_middle::infer::unify_key::EffectVarValue;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, GenericArg, List, Ty, TyCtxt};
use rustc_span::Span;
@@ -145,15 +144,6 @@
CanonicalVarKind::Const(ui) => {
self.next_const_var_in_universe(span, universe_map(ui)).into()
}
- CanonicalVarKind::Effect => {
- let vid = self
- .inner
- .borrow_mut()
- .effect_unification_table()
- .new_key(EffectVarValue::Unknown)
- .vid;
- ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid)).into()
- }
CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }) => {
let universe_mapped = universe_map(universe);
let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound };
diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs
index 5700775..0c151a1 100644
--- a/compiler/rustc_infer/src/infer/context.rs
+++ b/compiler/rustc_infer/src/infer/context.rs
@@ -1,6 +1,5 @@
///! Definition of `InferCtxtLike` from the librarified type layer.
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::infer::unify_key::EffectVarValue;
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::solve::SolverMode;
use rustc_middle::ty::fold::TypeFoldable;
@@ -88,15 +87,6 @@
}
}
- fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> {
- match self.probe_effect_var(vid) {
- Some(ct) => ct,
- None => {
- ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(self.root_effect_var(vid)))
- }
- }
- }
-
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
}
@@ -152,10 +142,6 @@
self.inner.borrow_mut().const_unification_table().union(a, b);
}
- fn equate_effect_vids_raw(&self, a: rustc_type_ir::EffectVid, b: rustc_type_ir::EffectVid) {
- self.inner.borrow_mut().effect_unification_table().union(a, b);
- }
-
fn instantiate_ty_var_raw<R: PredicateEmittingRelation<Self>>(
&self,
relation: &mut R,
@@ -189,13 +175,6 @@
self.inner.borrow_mut().float_unification_table().union_value(vid, value);
}
- fn instantiate_effect_var_raw(&self, vid: rustc_type_ir::EffectVid, value: ty::Const<'tcx>) {
- self.inner
- .borrow_mut()
- .effect_unification_table()
- .union_value(vid, EffectVarValue::Known(value));
- }
-
fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>(
&self,
relation: &mut R,
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index c429411..28eac5b 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -153,15 +153,6 @@
drop(inner);
self.freshen_const(input, ty::InferConst::Fresh)
}
- ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
- let mut inner = self.infcx.inner.borrow_mut();
- let input =
- inner.effect_unification_table().probe_value(v).known().ok_or_else(|| {
- ty::InferConst::EffectVar(inner.effect_unification_table().find(v).vid)
- });
- drop(inner);
- self.freshen_const(input, ty::InferConst::Fresh)
- }
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
if i >= self.const_freshen_count {
bug!(
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 5afdf3c..be43cba 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -26,9 +26,7 @@
use rustc_macros::extension;
pub use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
-use rustc_middle::infer::unify_key::{
- ConstVariableOrigin, ConstVariableValue, ConstVidKey, EffectVarValue, EffectVidKey,
-};
+use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
use rustc_middle::traits::select;
@@ -39,7 +37,7 @@
};
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{
- self, ConstVid, EffectVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
+ self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid,
};
use rustc_middle::{bug, span_bug};
@@ -117,9 +115,6 @@
/// Map from floating variable to the kind of float it represents.
float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
- /// Map from effect variable to the effect param it represents.
- effect_unification_storage: ut::UnificationTableStorage<EffectVidKey<'tcx>>,
-
/// Tracks the set of region variables and the constraints between them.
///
/// This is initially `Some(_)` but when
@@ -176,7 +171,6 @@
const_unification_storage: Default::default(),
int_unification_storage: Default::default(),
float_unification_storage: Default::default(),
- effect_unification_storage: Default::default(),
region_constraint_storage: Some(Default::default()),
region_obligations: vec![],
opaque_type_storage: Default::default(),
@@ -228,10 +222,6 @@
self.const_unification_storage.with_log(&mut self.undo_log)
}
- fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, EffectVidKey<'tcx>> {
- self.effect_unification_storage.with_log(&mut self.undo_log)
- }
-
#[inline]
pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> {
self.region_constraint_storage
@@ -524,7 +514,6 @@
),
Ty(_) => write!(f, "unconstrained type"),
Const(_) => write!(f, "unconstrained const value"),
- Effect(_) => write!(f, "unconstrained effect value"),
}
}
}
@@ -726,17 +715,6 @@
vars
}
- pub fn unsolved_effects(&self) -> Vec<ty::Const<'tcx>> {
- let mut inner = self.inner.borrow_mut();
- let mut table = inner.effect_unification_table();
-
- (0..table.len())
- .map(|i| ty::EffectVid::from_usize(i))
- .filter(|&vid| table.probe_value(vid).is_unknown())
- .map(|v| ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v)))
- .collect()
- }
-
#[instrument(skip(self), level = "debug")]
pub fn sub_regions(
&self,
@@ -899,13 +877,6 @@
ty::Const::new_var(self.tcx, vid)
}
- fn next_effect_var(&self) -> ty::Const<'tcx> {
- let effect_vid =
- self.inner.borrow_mut().effect_unification_table().new_key(EffectVarValue::Unknown).vid;
-
- ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid))
- }
-
pub fn next_int_var(&self) -> Ty<'tcx> {
let next_int_var_id =
self.inner.borrow_mut().int_unification_table().new_key(ty::IntVarValue::Unknown);
@@ -991,10 +962,7 @@
Ty::new_var(self.tcx, ty_var_id).into()
}
- GenericParamDefKind::Const { is_host_effect, .. } => {
- if is_host_effect {
- return self.var_for_effect(param);
- }
+ GenericParamDefKind::Const { .. } => {
let origin = ConstVariableOrigin { param_def_id: Some(param.def_id), span };
let const_var_id = self
.inner
@@ -1007,16 +975,6 @@
}
}
- pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
- let ty = self
- .tcx
- .type_of(param.def_id)
- .no_bound_vars()
- .expect("const parameter types cannot be generic");
- debug_assert_eq!(self.tcx.types.bool, ty);
- self.next_effect_var().into()
- }
-
/// Given a set of generics defined on a type or impl, returns the generic parameters mapping
/// each type/region parameter to a fresh inference variable.
pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> {
@@ -1142,13 +1100,6 @@
.probe_value(vid)
.known()
.unwrap_or(ct),
- InferConst::EffectVar(vid) => self
- .inner
- .borrow_mut()
- .effect_unification_table()
- .probe_value(vid)
- .known()
- .unwrap_or(ct),
InferConst::Fresh(_) => ct,
},
ty::ConstKind::Param(_)
@@ -1169,10 +1120,6 @@
self.inner.borrow_mut().const_unification_table().find(var).vid
}
- pub fn root_effect_var(&self, var: ty::EffectVid) -> ty::EffectVid {
- self.inner.borrow_mut().effect_unification_table().find(var).vid
- }
-
/// Resolves an int var to a rigid int type, if it was constrained to one,
/// or else the root int var in the unification table.
pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
@@ -1238,10 +1185,6 @@
}
}
- pub fn probe_effect_var(&self, vid: EffectVid) -> Option<ty::Const<'tcx>> {
- self.inner.borrow_mut().effect_unification_table().probe_value(vid).known()
- }
-
/// Attempts to resolve all type/region/const variables in
/// `value`. Region inference must have been run already (e.g.,
/// by calling `resolve_regions_and_report_errors`). If some
@@ -1511,14 +1454,6 @@
ConstVariableValue::Known { .. } => true,
}
}
-
- TyOrConstInferVar::Effect(v) => {
- // If `probe_value` returns `Some`, it never equals
- // `ty::ConstKind::Infer(ty::InferConst::Effect(v))`.
- //
- // Not `inlined_probe_value(v)` because this call site is colder.
- self.probe_effect_var(v).is_some()
- }
}
}
@@ -1545,8 +1480,6 @@
/// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
Const(ConstVid),
- /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`.
- Effect(EffectVid),
}
impl<'tcx> TyOrConstInferVar {
@@ -1577,7 +1510,6 @@
fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
match ct.kind() {
ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
- ty::ConstKind::Infer(InferConst::EffectVar(v)) => Some(TyOrConstInferVar::Effect(v)),
_ => None,
}
}
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index 853ae6d..c38b711 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -364,7 +364,7 @@
span,
concrete_ty,
r,
- choice_regions.clone(),
+ Lrc::clone(&choice_regions),
)
},
});
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index e23bb1a..1afe50e 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -24,19 +24,9 @@
param_env
.caller_bounds()
.into_iter()
- .map(ty::Clause::kind)
+ .filter_map(ty::Clause::as_region_outlives_clause)
.filter_map(ty::Binder::no_bound_vars)
- .filter_map(move |kind| match kind {
- ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
- Some(OutlivesBound::RegionSubRegion(r_b, r_a))
- }
- ty::ClauseKind::Trait(_)
- | ty::ClauseKind::TypeOutlives(_)
- | ty::ClauseKind::Projection(_)
- | ty::ClauseKind::ConstArgHasType(_, _)
- | ty::ClauseKind::WellFormed(_)
- | ty::ClauseKind::ConstEvaluatable(_) => None,
- })
+ .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a))
}
impl<'tcx> InferCtxt<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 7049444..32817db 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -660,7 +660,6 @@
}
}
}
- ty::ConstKind::Infer(InferConst::EffectVar(_)) => Ok(c),
// FIXME: Unevaluated constants are also not rigid, so the current
// approach of always relating them structurally is incomplete.
//
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 64cc76f..6ec2e01 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -176,9 +176,6 @@
ty::ConstKind::Infer(InferConst::Fresh(_)) => {
bug!("Unexpected const in full const resolver: {:?}", c);
}
- ty::ConstKind::Infer(InferConst::EffectVar(evid)) => {
- return Err(FixupError { unresolved: super::TyOrConstInferVar::Effect(evid) });
- }
_ => {}
}
c.try_super_fold_with(self)
diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
index 613cebc2..394e07a 100644
--- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
@@ -4,7 +4,6 @@
use rustc_middle::infer::unify_key::{ConstVariableValue, ConstVidKey};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
-use rustc_type_ir::EffectVid;
use rustc_type_ir::visit::TypeVisitableExt;
use tracing::instrument;
use ut::UnifyKey;
@@ -129,7 +128,6 @@
int_vars: Range<IntVid>,
float_vars: Range<FloatVid>,
const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>),
- effect_vars: Range<EffectVid>,
}
impl SnapshotVarData {
@@ -148,30 +146,16 @@
&mut inner.const_unification_table(),
vars_pre_snapshot.const_var_len,
);
- let effect_vars = vars_since_snapshot(
- &inner.effect_unification_table(),
- vars_pre_snapshot.effect_var_len,
- );
- let effect_vars = effect_vars.start.vid..effect_vars.end.vid;
-
- SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars, effect_vars }
+ SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars }
}
fn is_empty(&self) -> bool {
- let SnapshotVarData {
- region_vars,
- type_vars,
- int_vars,
- float_vars,
- const_vars,
- effect_vars,
- } = self;
+ let SnapshotVarData { region_vars, type_vars, int_vars, float_vars, const_vars } = self;
region_vars.0.is_empty()
&& type_vars.0.is_empty()
&& int_vars.is_empty()
&& float_vars.is_empty()
&& const_vars.0.is_empty()
- && effect_vars.is_empty()
}
}
@@ -258,13 +242,6 @@
ct
}
}
- ty::InferConst::EffectVar(vid) => {
- if self.snapshot_vars.effect_vars.contains(&vid) {
- self.infcx.next_effect_var()
- } else {
- ct
- }
- }
ty::InferConst::Fresh(_) => {
unreachable!("unexpected fresh infcx var")
}
diff --git a/compiler/rustc_infer/src/infer/snapshot/mod.rs b/compiler/rustc_infer/src/infer/snapshot/mod.rs
index fa81350..b16c80c 100644
--- a/compiler/rustc_infer/src/infer/snapshot/mod.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/mod.rs
@@ -23,7 +23,6 @@
int_var_len: usize,
float_var_len: usize,
const_var_len: usize,
- effect_var_len: usize,
}
impl<'tcx> InferCtxt<'tcx> {
@@ -35,7 +34,6 @@
int_var_len: inner.int_unification_table().len(),
float_var_len: inner.float_unification_table().len(),
const_var_len: inner.const_unification_table().len(),
- effect_var_len: inner.effect_unification_table().len(),
}
}
diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
index 79ea091..713389f 100644
--- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
@@ -2,7 +2,7 @@
use rustc_data_structures::undo_log::{Rollback, UndoLogs};
use rustc_data_structures::{snapshot_vec as sv, unify as ut};
-use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey, RegionVidKey};
+use rustc_middle::infer::unify_key::{ConstVidKey, RegionVidKey};
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey};
use tracing::debug;
@@ -22,7 +22,6 @@
ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
- EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
ProjectionCache(traits::UndoLog<'tcx>),
@@ -50,7 +49,6 @@
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
- EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
ProjectionCache(traits::UndoLog<'tcx>),
@@ -65,7 +63,6 @@
UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo),
- UndoLog::EffectUnificationTable(undo) => self.effect_unification_storage.reverse(undo),
UndoLog::RegionConstraintCollector(undo) => {
self.region_constraint_storage.as_mut().unwrap().reverse(undo)
}
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 779ce97..2086483 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -187,10 +187,7 @@
value_count: usize,
) -> (Range<TyVid>, Vec<TypeVariableOrigin>) {
let range = TyVid::from_usize(value_count)..TyVid::from_usize(self.num_vars());
- (
- range.start..range.end,
- (range.start..range.end).map(|index| self.var_origin(index)).collect(),
- )
+ (range.clone(), range.map(|index| self.var_origin(index)).collect())
}
/// Returns indices of all variables that are not yet
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 3a18334..b6837ec 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -142,7 +142,7 @@
Ok(Linker {
dep_graph: tcx.dep_graph.clone(),
- output_filenames: tcx.output_filenames(()).clone(),
+ output_filenames: Arc::clone(tcx.output_filenames(())),
crate_hash: if tcx.needs_crate_hash() {
Some(tcx.crate_hash(LOCAL_CRATE))
} else {
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 232d4c1..dd7b40d 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -5,6 +5,7 @@
[dependencies]
# tidy-alphabetical-start
+rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index c4d709aa..3fa4329 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -203,14 +203,14 @@
.current_use = this identifier can be confused with `{$existing_sym}`
.other_use = other identifier used here
-lint_cstring_ptr = getting the inner pointer of a temporary `CString`
- .as_ptr_label = this pointer will be invalid
- .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
- .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
- .help = for more information, see https://doc.rust-lang.org/reference/destructors.html
-
lint_custom_inner_attribute_unstable = custom inner attributes are unstable
+lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped
+ .label_ptr = this pointer will immediately be invalid
+ .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ .help = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
.note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 71c667b..dbb8c66 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -4,21 +4,14 @@
//! AST visitor. Also see `rustc_session::lint::builtin`, which contains the
//! definitions of lints that are emitted directly inside the main compiler.
//!
-//! To add a new lint to rustc, declare it here using `declare_lint!()`.
+//! To add a new lint to rustc, declare it here using [`declare_lint!`].
//! Then add code to emit the new lint in the appropriate circumstances.
-//! You can do that in an existing `LintPass` if it makes sense, or in a
-//! new `LintPass`, or using `Session::add_lint` elsewhere in the
-//! compiler. Only do the latter if the check can't be written cleanly as a
-//! `LintPass` (also, note that such lints will need to be defined in
-//! `rustc_session::lint::builtin`, not here).
//!
-//! If you define a new `EarlyLintPass`, you will also need to add it to the
-//! `add_early_builtin!` or `add_early_builtin_with_new!` invocation in
-//! `lib.rs`. Use the former for unit-like structs and the latter for structs
-//! with a `pub fn new()`.
+//! If you define a new [`EarlyLintPass`], you will also need to add it to the
+//! [`crate::early_lint_methods!`] invocation in `lib.rs`.
//!
-//! If you define a new `LateLintPass`, you will also need to add it to the
-//! `late_lint_methods!` invocation in `lib.rs`.
+//! If you define a new [`LateLintPass`], you will also need to add it to the
+//! [`crate::late_lint_methods!`] invocation in `lib.rs`.
use std::fmt::Write;
@@ -73,7 +66,6 @@
EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
fluent_generated as fluent,
};
-
declare_lint! {
/// The `while_true` lint detects `while true { }`.
///
@@ -241,7 +233,8 @@
/// behavior.
UNSAFE_CODE,
Allow,
- "usage of `unsafe` code and other potentially unsound constructs"
+ "usage of `unsafe` code and other potentially unsound constructs",
+ @eval_always = true
}
declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);
@@ -389,6 +382,7 @@
report_in_external_macro
}
+#[derive(Default)]
pub struct MissingDoc;
impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
@@ -819,8 +813,8 @@
impl_lint_pass!(DeprecatedAttr => []);
-impl DeprecatedAttr {
- pub fn new() -> DeprecatedAttr {
+impl Default for DeprecatedAttr {
+ fn default() -> Self {
DeprecatedAttr { depr_attrs: deprecated_attributes() }
}
}
@@ -1554,7 +1548,9 @@
// Ignore bounds that a user can't type
| ClauseKind::WellFormed(..)
// FIXME(generic_const_exprs): `ConstEvaluatable` can be written
- | ClauseKind::ConstEvaluatable(..) => continue,
+ | ClauseKind::ConstEvaluatable(..)
+ // Users don't write this directly, only via another trait ref.
+ | ty::ClauseKind::HostEffect(..) => continue,
};
if predicate.is_global() {
cx.emit_span_lint(TRIVIAL_BOUNDS, span, BuiltinTrivialBounds {
@@ -1892,11 +1888,11 @@
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
self.check_tokens(cx, &mac.args.tokens);
}
- fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
+ fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: &Ident) {
if ident.name.as_str().starts_with('\'') {
self.check_ident_token(cx, UnderMacro(false), ident.without_first_quote(), "'");
} else {
- self.check_ident_token(cx, UnderMacro(false), ident, "");
+ self.check_ident_token(cx, UnderMacro(false), *ident, "");
}
}
}
@@ -2287,13 +2283,15 @@
impl EarlyLintPass for IncompleteInternalFeatures {
fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
let features = cx.builder.features();
- features
- .enabled_lang_features()
- .iter()
- .map(|(name, span, _)| (name, span))
- .chain(features.enabled_lib_features().iter().map(|(name, span)| (name, span)))
- .filter(|(&name, _)| features.incomplete(name) || features.internal(name))
- .for_each(|(&name, &span)| {
+ let lang_features =
+ features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
+ let lib_features =
+ features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
+
+ lang_features
+ .chain(lib_features)
+ .filter(|(name, _)| features.incomplete(*name) || features.internal(*name))
+ .for_each(|(name, span)| {
if features.incomplete(name) {
let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
.map(|n| BuiltinFeatureIssueNote { n });
@@ -2657,8 +2655,8 @@
///
/// ### Explanation
///
- /// Dereferencing a null pointer causes [undefined behavior] even as a place expression,
- /// like `&*(0 as *const i32)` or `addr_of!(*(0 as *const i32))`.
+ /// Dereferencing a null pointer causes [undefined behavior] if it is accessed
+ /// (loaded from or stored to).
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
pub DEREF_NULLPTR,
@@ -2673,14 +2671,14 @@
/// test if expression is a null ptr
fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
match &expr.kind {
- rustc_hir::ExprKind::Cast(expr, ty) => {
- if let rustc_hir::TyKind::Ptr(_) = ty.kind {
+ hir::ExprKind::Cast(expr, ty) => {
+ if let hir::TyKind::Ptr(_) = ty.kind {
return is_zero(expr) || is_null_ptr(cx, expr);
}
}
// check for call to `core::ptr::null` or `core::ptr::null_mut`
- rustc_hir::ExprKind::Call(path, _) => {
- if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
+ hir::ExprKind::Call(path, _) => {
+ if let hir::ExprKind::Path(ref qpath) = path.kind {
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
return matches!(
cx.tcx.get_diagnostic_name(def_id),
@@ -2697,7 +2695,7 @@
/// test if expression is the literal `0`
fn is_zero(expr: &hir::Expr<'_>) -> bool {
match &expr.kind {
- rustc_hir::ExprKind::Lit(lit) => {
+ hir::ExprKind::Lit(lit) => {
if let LitKind::Int(a, _) = lit.node {
return a == 0;
}
@@ -2707,8 +2705,16 @@
false
}
- if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
- if is_null_ptr(cx, expr_deref) {
+ if let hir::ExprKind::Unary(hir::UnOp::Deref, expr_deref) = expr.kind
+ && is_null_ptr(cx, expr_deref)
+ {
+ if let hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::AddrOf(hir::BorrowKind::Raw, ..),
+ ..
+ }) = cx.tcx.parent_hir_node(expr.hir_id)
+ {
+ // `&raw *NULL` is ok.
+ } else {
cx.emit_span_lint(DEREF_NULLPTR, expr.span, BuiltinDerefNullptr {
label: expr.span,
});
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 39f90a8..6990889 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -1,18 +1,7 @@
-//! Implementation of lint checking.
+//! Basic types for managing and implementing lints.
//!
-//! The lint checking is mostly consolidated into one pass which runs
-//! after all other analyses. Throughout compilation, lint warnings
-//! can be added via the `add_lint` method on the Session structure. This
-//! requires a span and an ID of the node that the lint is being added to. The
-//! lint isn't actually emitted at that time because it is unknown what the
-//! actual lint level at that location is.
-//!
-//! To actually emit lint warnings/errors, a separate pass is used.
-//! A context keeps track of the current state of all lint levels.
-//! Upon entering a node of the ast which can modify the lint settings, the
-//! previous lint state is pushed onto a stack and the ast is then recursed
-//! upon. As the ast is traversed, this keeps track of the current lint level
-//! for all lint attributes.
+//! See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for an
+//! overview of how lints are implemented.
use std::cell::Cell;
use std::{iter, slice};
@@ -22,7 +11,6 @@
use rustc_data_structures::unord::UnordMap;
use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
use rustc_feature::Features;
-use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
@@ -38,8 +26,8 @@
use rustc_span::Span;
use rustc_span::edit_distance::find_best_match_for_names;
use rustc_span::symbol::{Ident, Symbol, sym};
-use rustc_target::abi;
use tracing::debug;
+use {rustc_abi as abi, rustc_hir as hir};
use self::TargetLint::*;
use crate::levels::LintLevelsBuilder;
@@ -52,9 +40,6 @@
dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
/// Information about the registered lints.
-///
-/// This is basically the subset of `Context` that we can
-/// build early in the compile pipeline.
pub struct LintStore {
/// Registered lints.
lints: Vec<&'static Lint>,
diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs
new file mode 100644
index 0000000..a34c3e2
--- /dev/null
+++ b/compiler/rustc_lint/src/dangling.rs
@@ -0,0 +1,223 @@
+use rustc_ast::visit::{visit_opt, walk_list};
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
+use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem};
+use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_session::{declare_lint, impl_lint_pass};
+use rustc_span::Span;
+use rustc_span::symbol::sym;
+
+use crate::lints::DanglingPointersFromTemporaries;
+use crate::{LateContext, LateLintPass};
+
+declare_lint! {
+ /// The `dangling_pointers_from_temporaries` lint detects getting a pointer to data
+ /// of a temporary that will immediately get dropped.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// # #![allow(unused)]
+ /// # unsafe fn use_data(ptr: *const u8) { }
+ /// fn gather_and_use(bytes: impl Iterator<Item = u8>) {
+ /// let x: *const u8 = bytes.collect::<Vec<u8>>().as_ptr();
+ /// unsafe { use_data(x) }
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Getting a pointer from a temporary value will not prolong its lifetime,
+ /// which means that the value can be dropped and the allocation freed
+ /// while the pointer still exists, making the pointer dangling.
+ /// This is not an error (as far as the type system is concerned)
+ /// but probably is not what the user intended either.
+ ///
+ /// If you need stronger guarantees, consider using references instead,
+ /// as they are statically verified by the borrow-checker to never dangle.
+ pub DANGLING_POINTERS_FROM_TEMPORARIES,
+ Warn,
+ "detects getting a pointer from a temporary"
+}
+
+/// FIXME: false negatives (i.e. the lint is not emitted when it should be)
+/// 1. Method calls that are not checked for:
+/// - [`temporary_unsafe_cell.get()`][`core::cell::UnsafeCell::get()`]
+/// - [`temporary_sync_unsafe_cell.get()`][`core::cell::SyncUnsafeCell::get()`]
+/// 2. Ways to get a temporary that are not recognized:
+/// - `owning_temporary.field`
+/// - `owning_temporary[index]`
+/// 3. No checks for ref-to-ptr conversions:
+/// - `&raw [mut] temporary`
+/// - `&temporary as *(const|mut) _`
+/// - `ptr::from_ref(&temporary)` and friends
+#[derive(Clone, Copy, Default)]
+pub(crate) struct DanglingPointers;
+
+impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]);
+
+// This skips over const blocks, but they cannot use or return a dangling pointer anyways.
+impl<'tcx> LateLintPass<'tcx> for DanglingPointers {
+ fn check_fn(
+ &mut self,
+ cx: &LateContext<'tcx>,
+ _: FnKind<'tcx>,
+ _: &'tcx FnDecl<'tcx>,
+ body: &'tcx Body<'tcx>,
+ _: Span,
+ _: LocalDefId,
+ ) {
+ DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body)
+ }
+}
+
+/// This produces a dangling pointer:
+/// ```ignore (example)
+/// let ptr = CString::new("hello").unwrap().as_ptr();
+/// foo(ptr)
+/// ```
+///
+/// But this does not:
+/// ```ignore (example)
+/// foo(CString::new("hello").unwrap().as_ptr())
+/// ```
+///
+/// But this does:
+/// ```ignore (example)
+/// foo({ let ptr = CString::new("hello").unwrap().as_ptr(); ptr })
+/// ```
+///
+/// So we have to keep track of when we are inside of a function/method call argument.
+struct DanglingPointerSearcher<'lcx, 'tcx> {
+ cx: &'lcx LateContext<'tcx>,
+ /// Keeps track of whether we are inside of function/method call arguments,
+ /// where this lint should not be emitted.
+ ///
+ /// See [the main doc][`Self`] for examples.
+ inside_call_args: bool,
+}
+
+impl Visitor<'_> for DanglingPointerSearcher<'_, '_> {
+ fn visit_expr(&mut self, expr: &Expr<'_>) -> Self::Result {
+ if !self.inside_call_args {
+ lint_expr(self.cx, expr)
+ }
+ match expr.kind {
+ ExprKind::Call(lhs, args) | ExprKind::MethodCall(_, lhs, args, _) => {
+ self.visit_expr(lhs);
+ self.with_inside_call_args(true, |this| walk_list!(this, visit_expr, args))
+ }
+ ExprKind::Block(&Block { stmts, expr, .. }, _) => {
+ self.with_inside_call_args(false, |this| walk_list!(this, visit_stmt, stmts));
+ visit_opt!(self, visit_expr, expr)
+ }
+ _ => walk_expr(self, expr),
+ }
+ }
+}
+
+impl DanglingPointerSearcher<'_, '_> {
+ fn with_inside_call_args<R>(
+ &mut self,
+ inside_call_args: bool,
+ callback: impl FnOnce(&mut Self) -> R,
+ ) -> R {
+ let old = core::mem::replace(&mut self.inside_call_args, inside_call_args);
+ let result = callback(self);
+ self.inside_call_args = old;
+ result
+ }
+}
+
+fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind
+ && matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr)
+ && is_temporary_rvalue(receiver)
+ && let ty = cx.typeck_results().expr_ty(receiver)
+ && is_interesting(cx.tcx, ty)
+ {
+ // FIXME: use `emit_node_lint` when `#[primary_span]` is added.
+ cx.tcx.emit_node_span_lint(
+ DANGLING_POINTERS_FROM_TEMPORARIES,
+ expr.hir_id,
+ method.ident.span,
+ DanglingPointersFromTemporaries {
+ callee: method.ident.name,
+ ty,
+ ptr_span: method.ident.span,
+ temporary_span: receiver.span,
+ },
+ )
+ }
+}
+
+fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
+ match expr.kind {
+ // Const is not temporary.
+ ExprKind::ConstBlock(..) | ExprKind::Repeat(..) | ExprKind::Lit(..) => false,
+
+ // This is literally lvalue.
+ ExprKind::Path(..) => false,
+
+ // Calls return rvalues.
+ ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) => true,
+
+ // Inner blocks are rvalues.
+ ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => true,
+
+ // FIXME: these should probably recurse and typecheck along the way.
+ // Some false negatives are possible for now.
+ ExprKind::Index(..) | ExprKind::Field(..) | ExprKind::Unary(..) => false,
+
+ ExprKind::Struct(..) => true,
+
+ // FIXME: this has false negatives, but I do not want to deal with 'static/const promotion just yet.
+ ExprKind::Array(..) => false,
+
+ // These typecheck to `!`
+ ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) | ExprKind::Become(..) => {
+ false
+ }
+
+ // These typecheck to `()`
+ ExprKind::Assign(..) | ExprKind::AssignOp(..) | ExprKind::Yield(..) => false,
+
+ // Compiler-magic macros
+ ExprKind::AddrOf(..) | ExprKind::OffsetOf(..) | ExprKind::InlineAsm(..) => false,
+
+ // We are not interested in these
+ ExprKind::Cast(..)
+ | ExprKind::Closure(..)
+ | ExprKind::Tup(..)
+ | ExprKind::DropTemps(..)
+ | ExprKind::Let(..) => false,
+
+ // Not applicable
+ ExprKind::Type(..) | ExprKind::Err(..) => false,
+ }
+}
+
+// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>,
+// or any of the above in arbitrary many nested Box'es.
+fn is_interesting(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
+ if ty.is_array() {
+ true
+ } else if let Some(inner) = ty.boxed_ty() {
+ inner.is_slice()
+ || inner.is_str()
+ || inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr))
+ || is_interesting(tcx, inner)
+ } else if let Some(def) = ty.ty_adt_def() {
+ for lang_item in [LangItem::String, LangItem::MaybeUninit] {
+ if tcx.is_lang_item(def.did(), lang_item) {
+ return true;
+ }
+ }
+ tcx.get_diagnostic_name(def.did())
+ .is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell))
+ } else {
+ false
+ }
+}
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 2285877..acccff7 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -1,18 +1,8 @@
-//! Implementation of lint checking.
+//! Implementation of the early lint pass.
//!
-//! The lint checking is mostly consolidated into one pass which runs
-//! after all other analyses. Throughout compilation, lint warnings
-//! can be added via the `add_lint` method on the Session structure. This
-//! requires a span and an ID of the node that the lint is being added to. The
-//! lint isn't actually emitted at that time because it is unknown what the
-//! actual lint level at that location is.
-//!
-//! To actually emit lint warnings/errors, a separate pass is used.
-//! A context keeps track of the current state of all lint levels.
-//! Upon entering a node of the ast which can modify the lint settings, the
-//! previous lint state is pushed onto a stack and the ast is then recursed
-//! upon. As the ast is traversed, this keeps track of the current lint level
-//! for all lint attributes.
+//! The early lint pass works on AST nodes after macro expansion and name
+//! resolution, just before AST lowering. These lints are for purely
+//! syntactical lints.
use rustc_ast::ptr::P;
use rustc_ast::visit::{self as ast_visit, Visitor, walk_list};
@@ -121,6 +111,18 @@
self.with_lint_attrs(e.id, &e.attrs, |cx| {
lint_callback!(cx, check_expr, e);
ast_visit::walk_expr(cx, e);
+ // Explicitly check for lints associated with 'closure_id', since
+ // it does not have a corresponding AST node
+ match e.kind {
+ ast::ExprKind::Closure(box ast::Closure {
+ coroutine_kind: Some(coroutine_kind),
+ ..
+ }) => {
+ cx.check_id(coroutine_kind.closure_id());
+ }
+ _ => {}
+ }
+ lint_callback!(cx, check_expr_post, e);
})
}
@@ -190,7 +192,7 @@
ast_visit::walk_ty(self, t);
}
- fn visit_ident(&mut self, ident: Ident) {
+ fn visit_ident(&mut self, ident: &Ident) {
lint_callback!(self, check_ident, ident);
}
@@ -214,21 +216,6 @@
})
}
- fn visit_expr_post(&mut self, e: &'a ast::Expr) {
- // Explicitly check for lints associated with 'closure_id', since
- // it does not have a corresponding AST node
- match e.kind {
- ast::ExprKind::Closure(box ast::Closure {
- coroutine_kind: Some(coroutine_kind),
- ..
- }) => {
- self.check_id(coroutine_kind.closure_id());
- }
- _ => {}
- }
- lint_callback!(self, check_expr_post, e);
- }
-
fn visit_generic_arg(&mut self, arg: &'a ast::GenericArg) {
lint_callback!(self, check_generic_arg, arg);
ast_visit::walk_generic_arg(self, arg);
@@ -312,6 +299,9 @@
fn name(&self) -> &'static str {
panic!()
}
+ fn get_lints(&self) -> crate::LintVec {
+ panic!()
+ }
}
macro_rules! impl_early_lint_pass {
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index 8168829..abe4e3e 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -1,3 +1,4 @@
+use rustc_abi::FIRST_VARIANT;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir as hir;
@@ -6,7 +7,6 @@
use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt};
use rustc_session::declare_lint;
use rustc_span::{Span, Symbol, sym};
-use rustc_target::abi::FIRST_VARIANT;
use tracing::{debug, instrument};
use crate::lints::{BuiltinClashingExtern, BuiltinClashingExternSub};
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 94cc58e..2f338f4 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -427,9 +427,10 @@
/// More details on translatable diagnostics can be found
/// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html).
pub rustc::UNTRANSLATABLE_DIAGNOSTIC,
- Deny,
+ Allow,
"prevent creation of diagnostics which cannot be translated",
- report_in_external_macro: true
+ report_in_external_macro: true,
+ @eval_always = true
}
declare_tool_lint! {
@@ -440,9 +441,10 @@
/// More details on diagnostics implementations can be found
/// [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html).
pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL,
- Deny,
+ Allow,
"prevent diagnostic creation outside of `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls",
- report_in_external_macro: true
+ report_in_external_macro: true,
+ @eval_always = true
}
declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]);
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 6d5903a..9d35ce1 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -1,18 +1,7 @@
-//! Implementation of lint checking.
+//! Implementation of the late lint pass.
//!
-//! The lint checking is mostly consolidated into one pass which runs
-//! after all other analyses. Throughout compilation, lint warnings
-//! can be added via the `add_lint` method on the Session structure. This
-//! requires a span and an ID of the node that the lint is being added to. The
-//! lint isn't actually emitted at that time because it is unknown what the
-//! actual lint level at that location is.
-//!
-//! To actually emit lint warnings/errors, a separate pass is used.
-//! A context keeps track of the current state of all lint levels.
-//! Upon entering a node of the ast which can modify the lint settings, the
-//! previous lint state is pushed onto a stack and the ast is then recursed
-//! upon. As the ast is traversed, this keeps track of the current lint level
-//! for all lint attributes.
+//! The late lint pass Works on HIR nodes, towards the end of analysis (after
+//! borrow checking, etc.). These lints have full type information available.
use std::any::Any;
use std::cell::Cell;
@@ -26,11 +15,12 @@
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::Session;
use rustc_session::lint::LintPass;
+use rustc_session::lint::builtin::HardwiredLints;
use rustc_span::Span;
use tracing::debug;
use crate::passes::LateLintPassObject;
-use crate::{LateContext, LateLintPass, LintStore};
+use crate::{LateContext, LateLintPass, LintId, LintStore};
/// Extract the [`LintStore`] from [`Session`].
///
@@ -326,6 +316,9 @@
fn name(&self) -> &'static str {
panic!()
}
+ fn get_lints(&self) -> crate::LintVec {
+ panic!()
+ }
}
macro_rules! impl_late_lint_pass {
@@ -361,13 +354,20 @@
// Note: `passes` is often empty. In that case, it's faster to run
// `builtin_lints` directly rather than bundling it up into the
// `RuntimeCombinedLateLintPass`.
- let late_module_passes = &unerased_lint_store(tcx.sess).late_module_passes;
- if late_module_passes.is_empty() {
+ let store = unerased_lint_store(tcx.sess);
+
+ if store.late_module_passes.is_empty() {
late_lint_mod_inner(tcx, module_def_id, context, builtin_lints);
} else {
- let mut passes: Vec<_> = late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
- passes.push(Box::new(builtin_lints));
- let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
+ let builtin_lints = Box::new(builtin_lints) as Box<dyn LateLintPass<'tcx>>;
+ let mut binding = store
+ .late_module_passes
+ .iter()
+ .map(|mk_pass| (mk_pass)(tcx))
+ .chain(std::iter::once(builtin_lints))
+ .collect::<Vec<_>>();
+
+ let pass = RuntimeCombinedLateLintPass { passes: binding.as_mut_slice() };
late_lint_mod_inner(tcx, module_def_id, context, pass);
}
}
@@ -398,7 +398,7 @@
fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
// Note: `passes` is often empty.
- let mut passes: Vec<_> =
+ let passes: Vec<_> =
unerased_lint_store(tcx.sess).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
if passes.is_empty() {
@@ -416,7 +416,18 @@
only_module: false,
};
- let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
+ let lints_that_dont_need_to_run = tcx.lints_that_dont_need_to_run(());
+
+ let mut filtered_passes: Vec<Box<dyn LateLintPass<'tcx>>> = passes
+ .into_iter()
+ .filter(|pass| {
+ let lints = (**pass).get_lints();
+ !lints.iter().all(|lint| lints_that_dont_need_to_run.contains(&LintId::of(lint)))
+ })
+ .collect();
+
+ filtered_passes.push(Box::new(HardwiredLints));
+ let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] };
late_lint_crate_inner(tcx, context, pass);
}
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index ff2ae69..97a9578 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1,9 +1,9 @@
use rustc_ast_pretty::pprust;
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
use rustc_feature::{Features, GateIssue};
-use rustc_hir::HirId;
use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::{CRATE_HIR_ID, HirId};
use rustc_index::IndexVec;
use rustc_middle::bug;
use rustc_middle::hir::nested_filter;
@@ -115,6 +115,38 @@
}
}
+fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
+ let store = unerased_lint_store(&tcx.sess);
+
+ let map = tcx.shallow_lint_levels_on(rustc_hir::CRATE_OWNER_ID);
+
+ let dont_need_to_run: FxIndexSet<LintId> = store
+ .get_lints()
+ .into_iter()
+ .filter_map(|lint| {
+ if !lint.eval_always {
+ let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID);
+ if matches!(lint_level, (Level::Allow, ..))
+ || (matches!(lint_level, (.., LintLevelSource::Default)))
+ && lint.default_level(tcx.sess.edition()) == Level::Allow
+ {
+ Some(LintId::of(lint))
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ let mut visitor = LintLevelMaximum { tcx, dont_need_to_run };
+ visitor.process_opts();
+ tcx.hir().walk_attributes(&mut visitor);
+
+ visitor.dont_need_to_run
+}
+
#[instrument(level = "trace", skip(tcx), ret)]
fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap {
let store = unerased_lint_store(tcx.sess);
@@ -301,6 +333,83 @@
}
}
+/// Visitor with the only function of visiting every item-like in a crate and
+/// computing the highest level that every lint gets put to.
+///
+/// E.g., if a crate has a global #![allow(lint)] attribute, but a single item
+/// uses #[warn(lint)], this visitor will set that lint level as `Warn`
+struct LintLevelMaximum<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ /// The actual list of detected lints.
+ dont_need_to_run: FxIndexSet<LintId>,
+}
+
+impl<'tcx> LintLevelMaximum<'tcx> {
+ fn process_opts(&mut self) {
+ let store = unerased_lint_store(self.tcx.sess);
+ for (lint_group, level) in &self.tcx.sess.opts.lint_opts {
+ if *level != Level::Allow {
+ let Ok(lints) = store.find_lints(lint_group) else {
+ return;
+ };
+ for lint in lints {
+ self.dont_need_to_run.swap_remove(&lint);
+ }
+ }
+ }
+ }
+}
+
+impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> {
+ type NestedFilter = nested_filter::All;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
+ }
+
+ /// FIXME(blyxyas): In a future revision, we should also graph #![allow]s,
+ /// but that is handled with more care
+ fn visit_attribute(&mut self, attribute: &'tcx ast::Attribute) {
+ if matches!(
+ Level::from_attr(attribute),
+ Some(
+ Level::Warn
+ | Level::Deny
+ | Level::Forbid
+ | Level::Expect(..)
+ | Level::ForceWarn(..),
+ )
+ ) {
+ let store = unerased_lint_store(self.tcx.sess);
+ let Some(meta) = attribute.meta() else { return };
+ // Lint attributes are always a metalist inside a
+ // metalist (even with just one lint).
+ let Some(meta_item_list) = meta.meta_item_list() else { return };
+
+ for meta_list in meta_item_list {
+ // Convert Path to String
+ let Some(meta_item) = meta_list.meta_item() else { return };
+ let ident: &str = &meta_item
+ .path
+ .segments
+ .iter()
+ .map(|segment| segment.ident.as_str())
+ .collect::<Vec<&str>>()
+ .join("::");
+ let Ok(lints) = store.find_lints(
+ // Lint attributes can only have literals
+ ident,
+ ) else {
+ return;
+ };
+ for lint in lints {
+ self.dont_need_to_run.swap_remove(&lint);
+ }
+ }
+ }
+ }
+}
+
pub struct LintLevelsBuilder<'s, P> {
sess: &'s Session,
features: &'s Features,
@@ -934,7 +1043,7 @@
}
pub(crate) fn provide(providers: &mut Providers) {
- *providers = Providers { shallow_lint_levels_on, ..*providers };
+ *providers = Providers { shallow_lint_levels_on, lints_that_dont_need_to_run, ..*providers };
}
pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index a7faab0..8611227 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -6,20 +6,14 @@
//! other phases of the compiler, which are generally required to hold in order
//! to compile the program at all.
//!
-//! Most lints can be written as [LintPass] instances. These run after
+//! Most lints can be written as [`LintPass`] instances. These run after
//! all other analyses. The `LintPass`es built into rustc are defined
//! within [rustc_session::lint::builtin],
//! which has further comments on how to add such a lint.
//! rustc can also load external lint plugins, as is done for Clippy.
//!
-//! Some of rustc's lints are defined elsewhere in the compiler and work by
-//! calling `add_lint()` on the overall `Session` object. This works when
-//! it happens before the main lint pass, which emits the lints stored by
-//! `add_lint()`. To emit lints after the main lint pass (from codegen, for
-//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
-//! in `context.rs`.
-//!
-//! Some code also exists in [rustc_session::lint], [rustc_middle::lint].
+//! See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for an
+//! overview of how lints are implemented.
//!
//! ## Note
//!
@@ -46,6 +40,7 @@
mod async_fn_in_trait;
pub mod builtin;
mod context;
+mod dangling;
mod deref_into_dyn_supertrait;
mod drop_forget_useless;
mod early;
@@ -65,7 +60,6 @@
mod lints;
mod macro_expr_fragment_specifier_2024_migration;
mod map_unit_fn;
-mod methods;
mod multiple_supertrait_upcastable;
mod non_ascii_idents;
mod non_fmt_panic;
@@ -91,6 +85,7 @@
use async_closures::AsyncClosureUsage;
use async_fn_in_trait::AsyncFnInTrait;
use builtin::*;
+use dangling::*;
use deref_into_dyn_supertrait::*;
use drop_forget_useless::*;
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
@@ -103,7 +98,6 @@
use let_underscore::*;
use macro_expr_fragment_specifier_2024_migration::*;
use map_unit_fn::*;
-use methods::*;
use multiple_supertrait_upcastable::*;
use non_ascii_idents::*;
use non_fmt_panic::NonPanicFmt;
@@ -170,7 +164,7 @@
[
pub BuiltinCombinedEarlyLintPass,
[
- UnusedParens: UnusedParens::new(),
+ UnusedParens: UnusedParens::default(),
UnusedBraces: UnusedBraces,
UnusedImportBraces: UnusedImportBraces,
UnsafeCode: UnsafeCode,
@@ -178,7 +172,7 @@
AnonymousParameters: AnonymousParameters,
EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
NonCamelCaseTypes: NonCamelCaseTypes,
- DeprecatedAttr: DeprecatedAttr::new(),
+ DeprecatedAttr: DeprecatedAttr::default(),
WhileTrue: WhileTrue,
NonAsciiIdents: NonAsciiIdents,
HiddenUnicodeCodepoints: HiddenUnicodeCodepoints,
@@ -199,7 +193,6 @@
ForLoopsOverFallibles: ForLoopsOverFallibles,
DerefIntoDynSupertrait: DerefIntoDynSupertrait,
DropForgetUseless: DropForgetUseless,
- HardwiredLints: HardwiredLints,
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
InvalidFromUtf8: InvalidFromUtf8,
@@ -232,7 +225,7 @@
UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller,
ShadowedIntoIter: ShadowedIntoIter,
DropTraitConstraints: DropTraitConstraints,
- TemporaryCStringAsPtr: TemporaryCStringAsPtr,
+ DanglingPointers: DanglingPointers,
NonPanicFmt: NonPanicFmt,
NoopMethodCall: NoopMethodCall,
EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
@@ -280,6 +273,7 @@
store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints());
store.register_lints(&foreign_modules::get_lints());
+ store.register_lints(&HardwiredLints::lint_vec());
add_lint_group!(
"nonstandard_style",
@@ -356,6 +350,7 @@
store.register_renamed("non_fmt_panic", "non_fmt_panics");
store.register_renamed("unused_tuple_struct_fields", "dead_code");
store.register_renamed("static_mut_ref", "static_mut_refs");
+ store.register_renamed("temporary_cstring_as_ptr", "dangling_pointers_from_temporaries");
// These were moved to tool lints, but rustc still sees them when compiling normally, before
// tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use
@@ -602,25 +597,25 @@
}
fn register_internals(store: &mut LintStore) {
- store.register_lints(&LintPassImpl::get_lints());
+ store.register_lints(&LintPassImpl::lint_vec());
store.register_early_pass(|| Box::new(LintPassImpl));
- store.register_lints(&DefaultHashTypes::get_lints());
+ store.register_lints(&DefaultHashTypes::lint_vec());
store.register_late_mod_pass(|_| Box::new(DefaultHashTypes));
- store.register_lints(&QueryStability::get_lints());
+ store.register_lints(&QueryStability::lint_vec());
store.register_late_mod_pass(|_| Box::new(QueryStability));
- store.register_lints(&ExistingDocKeyword::get_lints());
+ store.register_lints(&ExistingDocKeyword::lint_vec());
store.register_late_mod_pass(|_| Box::new(ExistingDocKeyword));
- store.register_lints(&TyTyKind::get_lints());
+ store.register_lints(&TyTyKind::lint_vec());
store.register_late_mod_pass(|_| Box::new(TyTyKind));
- store.register_lints(&TypeIr::get_lints());
+ store.register_lints(&TypeIr::lint_vec());
store.register_late_mod_pass(|_| Box::new(TypeIr));
- store.register_lints(&Diagnostics::get_lints());
+ store.register_lints(&Diagnostics::lint_vec());
store.register_late_mod_pass(|_| Box::new(Diagnostics));
- store.register_lints(&BadOptAccess::get_lints());
+ store.register_lints(&BadOptAccess::lint_vec());
store.register_late_mod_pass(|_| Box::new(BadOptAccess));
- store.register_lints(&PassByValue::get_lints());
+ store.register_lints(&PassByValue::lint_vec());
store.register_late_mod_pass(|_| Box::new(PassByValue));
- store.register_lints(&SpanUseEqCtxt::get_lints());
+ store.register_lints(&SpanUseEqCtxt::lint_vec());
store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt));
// FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and
// `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 16cfae1..000f4b6 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1137,16 +1137,19 @@
pub name: Symbol,
}
-// methods.rs
+// dangling.rs
#[derive(LintDiagnostic)]
-#[diag(lint_cstring_ptr)]
+#[diag(lint_dangling_pointers_from_temporaries)]
#[note]
#[help]
-pub(crate) struct CStringPtr {
- #[label(lint_as_ptr_label)]
- pub as_ptr: Span,
- #[label(lint_unwrap_label)]
- pub unwrap: Span,
+// FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts
+pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
+ pub callee: Symbol,
+ pub ty: Ty<'tcx>,
+ #[label(lint_label_ptr)]
+ pub ptr_span: Span,
+ #[label(lint_label_temporary)]
+ pub temporary_span: Span,
}
// multiple_supertrait_upcastable.rs
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
deleted file mode 100644
index df22bf0..0000000
--- a/compiler/rustc_lint/src/methods.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-use rustc_hir::{Expr, ExprKind};
-use rustc_middle::ty;
-use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::Span;
-use rustc_span::symbol::sym;
-
-use crate::lints::CStringPtr;
-use crate::{LateContext, LateLintPass, LintContext};
-
-declare_lint! {
- /// The `temporary_cstring_as_ptr` lint detects getting the inner pointer of
- /// a temporary `CString`.
- ///
- /// ### Example
- ///
- /// ```rust
- /// # #![allow(unused)]
- /// # use std::ffi::CString;
- /// let c_str = CString::new("foo").unwrap().as_ptr();
- /// ```
- ///
- /// {{produces}}
- ///
- /// ### Explanation
- ///
- /// The inner pointer of a `CString` lives only as long as the `CString` it
- /// points to. Getting the inner pointer of a *temporary* `CString` allows the `CString`
- /// to be dropped at the end of the statement, as it is not being referenced as far as the
- /// typesystem is concerned. This means outside of the statement the pointer will point to
- /// freed memory, which causes undefined behavior if the pointer is later dereferenced.
- pub TEMPORARY_CSTRING_AS_PTR,
- Warn,
- "detects getting the inner pointer of a temporary `CString`"
-}
-
-declare_lint_pass!(TemporaryCStringAsPtr => [TEMPORARY_CSTRING_AS_PTR]);
-
-impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if let ExprKind::MethodCall(as_ptr_path, as_ptr_receiver, ..) = expr.kind
- && as_ptr_path.ident.name == sym::as_ptr
- && let ExprKind::MethodCall(unwrap_path, unwrap_receiver, ..) = as_ptr_receiver.kind
- && (unwrap_path.ident.name == sym::unwrap || unwrap_path.ident.name == sym::expect)
- {
- lint_cstring_as_ptr(cx, as_ptr_path.ident.span, unwrap_receiver, as_ptr_receiver);
- }
- }
-}
-
-fn lint_cstring_as_ptr(
- cx: &LateContext<'_>,
- as_ptr_span: Span,
- source: &rustc_hir::Expr<'_>,
- unwrap: &rustc_hir::Expr<'_>,
-) {
- let source_type = cx.typeck_results().expr_ty(source);
- if let ty::Adt(def, args) = source_type.kind() {
- if cx.tcx.is_diagnostic_item(sym::Result, def.did()) {
- if let ty::Adt(adt, _) = args.type_at(0).kind() {
- if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
- cx.emit_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, CStringPtr {
- as_ptr: as_ptr_span,
- unwrap: unwrap.span,
- });
- }
- }
- }
- }
-}
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 83a8ca4..1c27e1d 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -542,11 +542,7 @@
}
fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) {
- if let GenericParamKind::Const { is_host_effect, .. } = param.kind {
- // `host` params are explicitly allowed to be lowercase.
- if is_host_effect {
- return;
- }
+ if let GenericParamKind::Const { .. } = param.kind {
NonUpperCaseGlobals::check_upper_case(cx, "const parameter", ¶m.name.ident());
}
}
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index a1d436e..9d84d36 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -110,7 +110,7 @@
$v fn get_lints() -> $crate::LintVec {
let mut lints = Vec::new();
- $(lints.extend_from_slice(&$pass::get_lints());)*
+ $(lints.extend_from_slice(&$pass::lint_vec());)*
lints
}
}
@@ -124,6 +124,9 @@
fn name(&self) -> &'static str {
panic!()
}
+ fn get_lints(&self) -> LintVec {
+ panic!()
+ }
}
)
}
@@ -133,7 +136,7 @@
($macro:path, $args:tt) => (
$macro!($args, [
fn check_param(a: &rustc_ast::Param);
- fn check_ident(a: rustc_span::symbol::Ident);
+ fn check_ident(a: &rustc_span::symbol::Ident);
fn check_crate(a: &rustc_ast::Crate);
fn check_crate_post(a: &rustc_ast::Crate);
fn check_item(a: &rustc_ast::Item);
@@ -222,7 +225,7 @@
$v fn get_lints() -> $crate::LintVec {
let mut lints = Vec::new();
- $(lints.extend_from_slice(&$pass::get_lints());)*
+ $(lints.extend_from_slice(&$pass::lint_vec());)*
lints
}
}
@@ -236,6 +239,9 @@
fn name(&self) -> &'static str {
panic!()
}
+ fn get_lints(&self) -> LintVec {
+ panic!()
+ }
}
)
}
diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs
index 04f769b..8976305 100644
--- a/compiler/rustc_lint/src/tail_expr_drop_order.rs
+++ b/compiler/rustc_lint/src/tail_expr_drop_order.rs
@@ -14,15 +14,14 @@
use crate::{LateContext, LateLintPass};
declare_lint! {
- /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, that of type
- /// with a significant `Drop` implementation, such as locks.
- /// In case there are also local variables of type with significant `Drop` implementation as well,
- /// this lint warns you of a potential transposition in the drop order.
- /// Your discretion on the new drop order introduced by Edition 2024 is required.
+ /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location,
+ /// that runs a custom `Drop` destructor.
+ /// Some of them may be dropped earlier in Edition 2024 that they used to in Edition 2021 and prior.
+ /// This lint detects those cases and provides you information on those values and their custom destructor implementations.
+ /// Your discretion on this information is required.
///
/// ### Example
- /// ```rust,edition2024
- /// #![feature(shorter_tail_lifetimes)]
+ /// ```rust,edition2021
/// #![warn(tail_expr_drop_order)]
/// struct Droppy(i32);
/// impl Droppy {
@@ -37,12 +36,12 @@
/// println!("loud drop {}", self.0);
/// }
/// }
- /// fn edition_2024() -> i32 {
+ /// fn edition_2021() -> i32 {
/// let another_droppy = Droppy(0);
/// Droppy(1).get()
/// }
/// fn main() {
- /// edition_2024();
+ /// edition_2021();
/// }
/// ```
///
@@ -137,7 +136,7 @@
_: Span,
def_id: rustc_span::def_id::LocalDefId,
) {
- if cx.tcx.sess.at_least_rust_2024() && cx.tcx.features().shorter_tail_lifetimes() {
+ if !body.value.span.edition().at_least_rust_2024() {
Self::check_fn_or_closure(cx, fn_kind, body, def_id);
}
}
@@ -185,8 +184,8 @@
impl<'a, 'tcx> LintVisitor<'a, 'tcx> {
fn check_block_inner(&mut self, block: &Block<'tcx>) {
- if !block.span.at_least_rust_2024() {
- // We only lint for Edition 2024 onwards
+ if block.span.at_least_rust_2024() {
+ // We only lint up to Edition 2021
return;
}
let Some(tail_expr) = block.expr else { return };
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 60ff925..0751d35 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -167,7 +167,7 @@
"detects ambiguous wide pointer comparisons"
}
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Default)]
pub(crate) struct TypeLimits {
/// Id of the last visited negated expression
negated_expr_id: Option<hir::HirId>,
diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs
index d1e8509..dca42fe 100644
--- a/compiler/rustc_lint/src/types/literal.rs
+++ b/compiler/rustc_lint/src/types/literal.rs
@@ -1,8 +1,8 @@
use hir::{ExprKind, Node, is_range_literal};
+use rustc_abi::{Integer, Size};
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::{bug, ty};
-use rustc_target::abi::{Integer, Size};
use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
use crate::LateContext;
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index ddc18c7..bbb290c 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1025,8 +1025,8 @@
parens_in_cast_in_lt: Vec<ast::NodeId>,
}
-impl UnusedParens {
- pub(crate) fn new() -> Self {
+impl Default for UnusedParens {
+ fn default() -> Self {
Self { with_self_ty_parens: false, parens_in_cast_in_lt: Vec::new() }
}
}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index a4c49a1..06a3e4a6 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -377,7 +377,8 @@
/// will not overflow.
pub ARITHMETIC_OVERFLOW,
Deny,
- "arithmetic operation overflows"
+ "arithmetic operation overflows",
+ @eval_always = true
}
declare_lint! {
@@ -401,7 +402,8 @@
/// `panic!` or `unreachable!` macro instead in case the panic is intended.
pub UNCONDITIONAL_PANIC,
Deny,
- "operation will cause a panic at runtime"
+ "operation will cause a panic at runtime",
+ @eval_always = true
}
declare_lint! {
@@ -632,7 +634,8 @@
/// is only available in a newer version.
pub UNKNOWN_LINTS,
Warn,
- "unrecognized lint attribute"
+ "unrecognized lint attribute",
+ @eval_always = true
}
declare_lint! {
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index c01fa5c..601784f 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -312,6 +312,10 @@
pub feature_gate: Option<Symbol>,
pub crate_level_only: bool,
+
+ /// `true` if this lint should not be filtered out under any circustamces
+ /// (e.g. the unknown_attributes lint)
+ pub eval_always: bool,
}
/// Extra information for a future incompatibility lint.
@@ -456,6 +460,7 @@
future_incompatible: None,
feature_gate: None,
crate_level_only: false,
+ eval_always: false,
}
}
@@ -864,6 +869,7 @@
);
);
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
+ $(@eval_always = $eval_always:literal)?
$(@feature_gate = $gate:ident;)?
$(@future_incompatible = FutureIncompatibleInfo {
reason: $reason:expr,
@@ -885,6 +891,7 @@
..$crate::FutureIncompatibleInfo::default_fields_for_macro()
}),)?
$(edition_lint_opts: Some(($crate::Edition::$lint_edition, $crate::$edition_level)),)?
+ $(eval_always: $eval_always,)?
..$crate::Lint::default_fields_for_macro()
};
);
@@ -894,20 +901,23 @@
macro_rules! declare_tool_lint {
(
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
+ $(, @eval_always = $eval_always:literal)?
$(, @feature_gate = $gate:ident;)?
) => (
- $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @feature_gate = $gate;)?}
+ $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @eval_always = $eval_always)? $(, @feature_gate = $gate;)?}
);
(
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
report_in_external_macro: $rep:expr
+ $(, @eval_always = $eval_always: literal)?
$(, @feature_gate = $gate:ident;)?
) => (
- $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?}
+ $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @eval_always = $eval_always)? $(, @feature_gate = $gate;)?}
);
(
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
$external:expr
+ $(, @eval_always = $eval_always: literal)?
$(, @feature_gate = $gate:ident;)?
) => (
$(#[$attr])*
@@ -921,6 +931,7 @@
is_externally_loaded: true,
$(feature_gate: Some(rustc_span::symbol::sym::$gate),)?
crate_level_only: false,
+ $(eval_always: $eval_always,)?
..$crate::Lint::default_fields_for_macro()
};
);
@@ -930,6 +941,7 @@
pub trait LintPass {
fn name(&self) -> &'static str;
+ fn get_lints(&self) -> LintVec;
}
/// Implements `LintPass for $ty` with the given list of `Lint` statics.
@@ -938,9 +950,11 @@
($ty:ty => [$($lint:expr),* $(,)?]) => {
impl $crate::LintPass for $ty {
fn name(&self) -> &'static str { stringify!($ty) }
+ fn get_lints(&self) -> $crate::LintVec { vec![$($lint),*] }
}
impl $ty {
- pub fn get_lints() -> $crate::LintVec { vec![$($lint),*] }
+ #[allow(unused)]
+ pub fn lint_vec() -> $crate::LintVec { vec![$($lint),*] }
}
};
}
diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
index cda81d4..b32af5e 100644
--- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
@@ -33,45 +33,6 @@
report_fatal_error("Bad LLVMRustCounterKind!");
}
-// FFI equivalent of enum `llvm::coverage::CounterMappingRegion::RegionKind`
-// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L213-L234
-enum class LLVMRustCounterMappingRegionKind {
- CodeRegion = 0,
- ExpansionRegion = 1,
- SkippedRegion = 2,
- GapRegion = 3,
- BranchRegion = 4,
- MCDCDecisionRegion = 5,
- MCDCBranchRegion = 6
-};
-
-static coverage::CounterMappingRegion::RegionKind
-fromRust(LLVMRustCounterMappingRegionKind Kind) {
- switch (Kind) {
- case LLVMRustCounterMappingRegionKind::CodeRegion:
- return coverage::CounterMappingRegion::CodeRegion;
- case LLVMRustCounterMappingRegionKind::ExpansionRegion:
- return coverage::CounterMappingRegion::ExpansionRegion;
- case LLVMRustCounterMappingRegionKind::SkippedRegion:
- return coverage::CounterMappingRegion::SkippedRegion;
- case LLVMRustCounterMappingRegionKind::GapRegion:
- return coverage::CounterMappingRegion::GapRegion;
- case LLVMRustCounterMappingRegionKind::BranchRegion:
- return coverage::CounterMappingRegion::BranchRegion;
- case LLVMRustCounterMappingRegionKind::MCDCDecisionRegion:
- return coverage::CounterMappingRegion::MCDCDecisionRegion;
- case LLVMRustCounterMappingRegionKind::MCDCBranchRegion:
- return coverage::CounterMappingRegion::MCDCBranchRegion;
- }
- report_fatal_error("Bad LLVMRustCounterMappingRegionKind!");
-}
-
-enum LLVMRustMCDCParametersTag {
- None = 0,
- Decision = 1,
- Branch = 2,
-};
-
struct LLVMRustMCDCDecisionParameters {
uint32_t BitmapIdx;
uint16_t NumConditions;
@@ -82,47 +43,58 @@
int16_t ConditionIDs[2];
};
-struct LLVMRustMCDCParameters {
- LLVMRustMCDCParametersTag Tag;
- LLVMRustMCDCDecisionParameters DecisionParameters;
- LLVMRustMCDCBranchParameters BranchParameters;
-};
-
#if LLVM_VERSION_GE(19, 0)
-static coverage::mcdc::Parameters fromRust(LLVMRustMCDCParameters Params) {
- switch (Params.Tag) {
- case LLVMRustMCDCParametersTag::None:
- return std::monostate();
- case LLVMRustMCDCParametersTag::Decision:
- return coverage::mcdc::DecisionParameters(
- Params.DecisionParameters.BitmapIdx,
- Params.DecisionParameters.NumConditions);
- case LLVMRustMCDCParametersTag::Branch:
- return coverage::mcdc::BranchParameters(
- static_cast<coverage::mcdc::ConditionID>(
- Params.BranchParameters.ConditionID),
- {static_cast<coverage::mcdc::ConditionID>(
- Params.BranchParameters.ConditionIDs[0]),
- static_cast<coverage::mcdc::ConditionID>(
- Params.BranchParameters.ConditionIDs[1])});
- }
- report_fatal_error("Bad LLVMRustMCDCParametersTag!");
+static coverage::mcdc::BranchParameters
+fromRust(LLVMRustMCDCBranchParameters Params) {
+ return coverage::mcdc::BranchParameters(
+ Params.ConditionID, {Params.ConditionIDs[0], Params.ConditionIDs[1]});
+}
+
+static coverage::mcdc::DecisionParameters
+fromRust(LLVMRustMCDCDecisionParameters Params) {
+ return coverage::mcdc::DecisionParameters(Params.BitmapIdx,
+ Params.NumConditions);
}
#endif
-// FFI equivalent of struct `llvm::coverage::CounterMappingRegion`
-// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L211-L304
-struct LLVMRustCounterMappingRegion {
- LLVMRustCounter Count;
- LLVMRustCounter FalseCount;
- LLVMRustMCDCParameters MCDCParameters;
+// Must match the layout of
+// `rustc_codegen_llvm::coverageinfo::ffi::CoverageSpan`.
+struct LLVMRustCoverageSpan {
uint32_t FileID;
- uint32_t ExpandedFileID;
uint32_t LineStart;
uint32_t ColumnStart;
uint32_t LineEnd;
uint32_t ColumnEnd;
- LLVMRustCounterMappingRegionKind Kind;
+};
+
+// Must match the layout of `rustc_codegen_llvm::coverageinfo::ffi::CodeRegion`.
+struct LLVMRustCoverageCodeRegion {
+ LLVMRustCoverageSpan Span;
+ LLVMRustCounter Count;
+};
+
+// Must match the layout of
+// `rustc_codegen_llvm::coverageinfo::ffi::BranchRegion`.
+struct LLVMRustCoverageBranchRegion {
+ LLVMRustCoverageSpan Span;
+ LLVMRustCounter TrueCount;
+ LLVMRustCounter FalseCount;
+};
+
+// Must match the layout of
+// `rustc_codegen_llvm::coverageinfo::ffi::MCDCBranchRegion`.
+struct LLVMRustCoverageMCDCBranchRegion {
+ LLVMRustCoverageSpan Span;
+ LLVMRustCounter TrueCount;
+ LLVMRustCounter FalseCount;
+ LLVMRustMCDCBranchParameters MCDCBranchParams;
+};
+
+// Must match the layout of
+// `rustc_codegen_llvm::coverageinfo::ffi::MCDCDecisionRegion`.
+struct LLVMRustCoverageMCDCDecisionRegion {
+ LLVMRustCoverageSpan Span;
+ LLVMRustMCDCDecisionParameters MCDCDecisionParams;
};
// FFI equivalent of enum `llvm::coverage::CounterExpression::ExprKind`
@@ -174,28 +146,16 @@
extern "C" void LLVMRustCoverageWriteMappingToBuffer(
const unsigned *VirtualFileMappingIDs, unsigned NumVirtualFileMappingIDs,
const LLVMRustCounterExpression *RustExpressions, unsigned NumExpressions,
- const LLVMRustCounterMappingRegion *RustMappingRegions,
- unsigned NumMappingRegions, RustStringRef BufferOut) {
+ const LLVMRustCoverageCodeRegion *CodeRegions, unsigned NumCodeRegions,
+ const LLVMRustCoverageBranchRegion *BranchRegions,
+ unsigned NumBranchRegions,
+ const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions,
+ unsigned NumMCDCBranchRegions,
+ const LLVMRustCoverageMCDCDecisionRegion *MCDCDecisionRegions,
+ unsigned NumMCDCDecisionRegions, RustStringRef BufferOut) {
// Convert from FFI representation to LLVM representation.
- SmallVector<coverage::CounterMappingRegion, 0> MappingRegions;
- MappingRegions.reserve(NumMappingRegions);
- for (const auto &Region : ArrayRef<LLVMRustCounterMappingRegion>(
- RustMappingRegions, NumMappingRegions)) {
- MappingRegions.emplace_back(
- fromRust(Region.Count), fromRust(Region.FalseCount),
-#if LLVM_VERSION_LT(19, 0)
- coverage::CounterMappingRegion::MCDCParameters{},
-#endif
- Region.FileID, Region.ExpandedFileID, // File IDs, then region info.
- Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd,
- fromRust(Region.Kind)
-#if LLVM_VERSION_GE(19, 0)
- ,
- fromRust(Region.MCDCParameters)
-#endif
- );
- }
+ // Expressions:
std::vector<coverage::CounterExpression> Expressions;
Expressions.reserve(NumExpressions);
for (const auto &Expression :
@@ -205,6 +165,46 @@
fromRust(Expression.RHS));
}
+ std::vector<coverage::CounterMappingRegion> MappingRegions;
+ MappingRegions.reserve(NumCodeRegions + NumBranchRegions +
+ NumMCDCBranchRegions + NumMCDCDecisionRegions);
+
+ // Code regions:
+ for (const auto &Region : ArrayRef(CodeRegions, NumCodeRegions)) {
+ MappingRegions.push_back(coverage::CounterMappingRegion::makeRegion(
+ fromRust(Region.Count), Region.Span.FileID, Region.Span.LineStart,
+ Region.Span.ColumnStart, Region.Span.LineEnd, Region.Span.ColumnEnd));
+ }
+
+ // Branch regions:
+ for (const auto &Region : ArrayRef(BranchRegions, NumBranchRegions)) {
+ MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion(
+ fromRust(Region.TrueCount), fromRust(Region.FalseCount),
+ Region.Span.FileID, Region.Span.LineStart, Region.Span.ColumnStart,
+ Region.Span.LineEnd, Region.Span.ColumnEnd));
+ }
+
+#if LLVM_VERSION_GE(19, 0)
+ // MC/DC branch regions:
+ for (const auto &Region : ArrayRef(MCDCBranchRegions, NumMCDCBranchRegions)) {
+ MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion(
+ fromRust(Region.TrueCount), fromRust(Region.FalseCount),
+ Region.Span.FileID, Region.Span.LineStart, Region.Span.ColumnStart,
+ Region.Span.LineEnd, Region.Span.ColumnEnd,
+ fromRust(Region.MCDCBranchParams)));
+ }
+
+ // MC/DC decision regions:
+ for (const auto &Region :
+ ArrayRef(MCDCDecisionRegions, NumMCDCDecisionRegions)) {
+ MappingRegions.push_back(coverage::CounterMappingRegion::makeDecisionRegion(
+ fromRust(Region.MCDCDecisionParams), Region.Span.FileID,
+ Region.Span.LineStart, Region.Span.ColumnStart, Region.Span.LineEnd,
+ Region.Span.ColumnEnd));
+ }
+#endif
+
+ // Write the converted expressions and mappings to a byte buffer.
auto CoverageMappingWriter = coverage::CoverageMappingWriter(
ArrayRef<unsigned>(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
Expressions, MappingRegions);
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 4b30351..20bf32d 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1251,12 +1251,12 @@
// here is basically the same as before threads are spawned in the `run`
// function of `lib/LTO/ThinLTOCodeGenerator.cpp`.
extern "C" LLVMRustThinLTOData *
-LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, int num_modules,
- const char **preserved_symbols, int num_symbols) {
+LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, size_t num_modules,
+ const char **preserved_symbols, size_t num_symbols) {
auto Ret = std::make_unique<LLVMRustThinLTOData>();
// Load each module's summary and merge it into one combined index
- for (int i = 0; i < num_modules; i++) {
+ for (size_t i = 0; i < num_modules; i++) {
auto module = &modules[i];
auto buffer = StringRef(module->data, module->len);
auto mem_buffer = MemoryBufferRef(buffer, module->identifier);
@@ -1275,7 +1275,7 @@
// Convert the preserved symbols set from string to GUID, this is then needed
// for internalization.
- for (int i = 0; i < num_symbols; i++) {
+ for (size_t i = 0; i < num_symbols; i++) {
auto GUID = GlobalValue::getGUID(preserved_symbols[i]);
Ret->GUIDPreservedSymbols.insert(GUID);
}
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 910c27d..4a2e078 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1231,7 +1231,7 @@
return dwarf::DW_OP_plus_uconst;
}
-extern "C" int64_t LLVMRustDIBuilderCreateOpLLVMFragment() {
+extern "C" uint64_t LLVMRustDIBuilderCreateOpLLVMFragment() {
return dwarf::DW_OP_LLVM_fragment;
}
@@ -1531,45 +1531,6 @@
ArrayRef<OperandBundleDef>(OpBundles)));
}
-extern "C" LLVMValueRef
-LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) {
-#if LLVM_VERSION_GE(20, 0)
- return wrap(llvm::Intrinsic::getOrInsertDeclaration(
- unwrap(M), llvm::Intrinsic::instrprof_increment));
-#else
- return wrap(llvm::Intrinsic::getDeclaration(
- unwrap(M), llvm::Intrinsic::instrprof_increment));
-#endif
-}
-
-extern "C" LLVMValueRef
-LLVMRustGetInstrProfMCDCParametersIntrinsic(LLVMModuleRef M) {
-#if LLVM_VERSION_LT(19, 0)
- report_fatal_error("LLVM 19.0 is required for mcdc intrinsic functions");
-#endif
-#if LLVM_VERSION_GE(20, 0)
- return wrap(llvm::Intrinsic::getOrInsertDeclaration(
- unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters));
-#else
- return wrap(llvm::Intrinsic::getDeclaration(
- unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters));
-#endif
-}
-
-extern "C" LLVMValueRef
-LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(LLVMModuleRef M) {
-#if LLVM_VERSION_LT(19, 0)
- report_fatal_error("LLVM 19.0 is required for mcdc intrinsic functions");
-#endif
-#if LLVM_VERSION_GE(20, 0)
- return wrap(llvm::Intrinsic::getOrInsertDeclaration(
- unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update));
-#else
- return wrap(llvm::Intrinsic::getDeclaration(
- unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update));
-#endif
-}
-
extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst,
unsigned DstAlign, LLVMValueRef Src,
unsigned SrcAlign,
@@ -1658,86 +1619,6 @@
unwrap(B)->SetInsertPoint(unwrap(BB), Point);
}
-enum class LLVMRustLinkage {
- ExternalLinkage = 0,
- AvailableExternallyLinkage = 1,
- LinkOnceAnyLinkage = 2,
- LinkOnceODRLinkage = 3,
- WeakAnyLinkage = 4,
- WeakODRLinkage = 5,
- AppendingLinkage = 6,
- InternalLinkage = 7,
- PrivateLinkage = 8,
- ExternalWeakLinkage = 9,
- CommonLinkage = 10,
-};
-
-static LLVMRustLinkage toRust(LLVMLinkage Linkage) {
- switch (Linkage) {
- case LLVMExternalLinkage:
- return LLVMRustLinkage::ExternalLinkage;
- case LLVMAvailableExternallyLinkage:
- return LLVMRustLinkage::AvailableExternallyLinkage;
- case LLVMLinkOnceAnyLinkage:
- return LLVMRustLinkage::LinkOnceAnyLinkage;
- case LLVMLinkOnceODRLinkage:
- return LLVMRustLinkage::LinkOnceODRLinkage;
- case LLVMWeakAnyLinkage:
- return LLVMRustLinkage::WeakAnyLinkage;
- case LLVMWeakODRLinkage:
- return LLVMRustLinkage::WeakODRLinkage;
- case LLVMAppendingLinkage:
- return LLVMRustLinkage::AppendingLinkage;
- case LLVMInternalLinkage:
- return LLVMRustLinkage::InternalLinkage;
- case LLVMPrivateLinkage:
- return LLVMRustLinkage::PrivateLinkage;
- case LLVMExternalWeakLinkage:
- return LLVMRustLinkage::ExternalWeakLinkage;
- case LLVMCommonLinkage:
- return LLVMRustLinkage::CommonLinkage;
- default:
- report_fatal_error("Invalid LLVMRustLinkage value!");
- }
-}
-
-static LLVMLinkage fromRust(LLVMRustLinkage Linkage) {
- switch (Linkage) {
- case LLVMRustLinkage::ExternalLinkage:
- return LLVMExternalLinkage;
- case LLVMRustLinkage::AvailableExternallyLinkage:
- return LLVMAvailableExternallyLinkage;
- case LLVMRustLinkage::LinkOnceAnyLinkage:
- return LLVMLinkOnceAnyLinkage;
- case LLVMRustLinkage::LinkOnceODRLinkage:
- return LLVMLinkOnceODRLinkage;
- case LLVMRustLinkage::WeakAnyLinkage:
- return LLVMWeakAnyLinkage;
- case LLVMRustLinkage::WeakODRLinkage:
- return LLVMWeakODRLinkage;
- case LLVMRustLinkage::AppendingLinkage:
- return LLVMAppendingLinkage;
- case LLVMRustLinkage::InternalLinkage:
- return LLVMInternalLinkage;
- case LLVMRustLinkage::PrivateLinkage:
- return LLVMPrivateLinkage;
- case LLVMRustLinkage::ExternalWeakLinkage:
- return LLVMExternalWeakLinkage;
- case LLVMRustLinkage::CommonLinkage:
- return LLVMCommonLinkage;
- }
- report_fatal_error("Invalid LLVMRustLinkage value!");
-}
-
-extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) {
- return toRust(LLVMGetLinkage(V));
-}
-
-extern "C" void LLVMRustSetLinkage(LLVMValueRef V,
- LLVMRustLinkage RustLinkage) {
- LLVMSetLinkage(V, fromRust(RustLinkage));
-}
-
extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) {
auto C = unwrap<llvm::ConstantInt>(CV);
if (C->getBitWidth() > 64)
@@ -1765,45 +1646,6 @@
return true;
}
-enum class LLVMRustVisibility {
- Default = 0,
- Hidden = 1,
- Protected = 2,
-};
-
-static LLVMRustVisibility toRust(LLVMVisibility Vis) {
- switch (Vis) {
- case LLVMDefaultVisibility:
- return LLVMRustVisibility::Default;
- case LLVMHiddenVisibility:
- return LLVMRustVisibility::Hidden;
- case LLVMProtectedVisibility:
- return LLVMRustVisibility::Protected;
- }
- report_fatal_error("Invalid LLVMRustVisibility value!");
-}
-
-static LLVMVisibility fromRust(LLVMRustVisibility Vis) {
- switch (Vis) {
- case LLVMRustVisibility::Default:
- return LLVMDefaultVisibility;
- case LLVMRustVisibility::Hidden:
- return LLVMHiddenVisibility;
- case LLVMRustVisibility::Protected:
- return LLVMProtectedVisibility;
- }
- report_fatal_error("Invalid LLVMRustVisibility value!");
-}
-
-extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef V) {
- return toRust(LLVMGetVisibility(V));
-}
-
-extern "C" void LLVMRustSetVisibility(LLVMValueRef V,
- LLVMRustVisibility RustVisibility) {
- LLVMSetVisibility(V, fromRust(RustVisibility));
-}
-
extern "C" void LLVMRustSetDSOLocal(LLVMValueRef Global, bool is_dso_local) {
unwrap<GlobalValue>(Global)->setDSOLocal(is_dso_local);
}
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 72f1e59..1055f27 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -253,7 +253,10 @@
let mut field_binding = binding_info.binding.clone();
field_binding.set_span(field.ty.span());
- let ident = field.ident.as_ref().unwrap();
+ let Some(ident) = field.ident.as_ref() else {
+ span_err(field.span().unwrap(), "tuple structs are not supported").emit();
+ return TokenStream::new();
+ };
let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
quote! {
diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs
index 9cdb9fb..a78cf2b 100644
--- a/compiler/rustc_macros/src/diagnostics/error.rs
+++ b/compiler/rustc_macros/src/diagnostics/error.rs
@@ -56,7 +56,7 @@
/// Returns an error diagnostic on span `span` with msg `msg`.
#[must_use]
pub(crate) fn span_err<T: Into<String>>(span: impl MultiSpan, msg: T) -> Diagnostic {
- Diagnostic::spanned(span, Level::Error, msg)
+ Diagnostic::spanned(span, Level::Error, format!("derive(Diagnostic): {}", msg.into()))
}
/// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 5946b11..612a36b 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -243,7 +243,7 @@
*self = Some((value, span));
}
Some((_, prev_span)) => {
- span_err(span, "specified multiple times")
+ span_err(span, "attribute specified multiple times")
.span_note(*prev_span, "previously specified here")
.emit();
}
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index f46c795..0df674e 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -20,6 +20,7 @@
mod query;
mod serialize;
mod symbols;
+mod try_from;
mod type_foldable;
mod type_visitable;
@@ -165,3 +166,12 @@
suggestion_part,
applicability)] => diagnostics::subdiagnostic_derive
);
+
+decl_derive! {
+ [TryFromU32] =>
+ /// Derives `TryFrom<u32>` for the annotated `enum`, which must have no fields.
+ /// Each variant maps to the value it would produce under an `as u32` cast.
+ ///
+ /// The error type is `u32`.
+ try_from::try_from_u32
+}
diff --git a/compiler/rustc_macros/src/try_from.rs b/compiler/rustc_macros/src/try_from.rs
new file mode 100644
index 0000000..9338c1c
--- /dev/null
+++ b/compiler/rustc_macros/src/try_from.rs
@@ -0,0 +1,55 @@
+use proc_macro2::TokenStream;
+use quote::{quote, quote_spanned};
+use syn::Data;
+use syn::spanned::Spanned;
+use synstructure::Structure;
+
+pub(crate) fn try_from_u32(s: Structure<'_>) -> TokenStream {
+ let span_error = |span, message: &str| {
+ quote_spanned! { span => const _: () = ::core::compile_error!(#message); }
+ };
+
+ // Must be applied to an enum type.
+ if let Some(span) = match &s.ast().data {
+ Data::Enum(_) => None,
+ Data::Struct(s) => Some(s.struct_token.span()),
+ Data::Union(u) => Some(u.union_token.span()),
+ } {
+ return span_error(span, "type is not an enum (TryFromU32)");
+ }
+
+ // The enum's variants must not have fields.
+ let variant_field_errors = s
+ .variants()
+ .iter()
+ .filter_map(|v| v.ast().fields.iter().map(|f| f.span()).next())
+ .map(|span| span_error(span, "enum variant cannot have fields (TryFromU32)"))
+ .collect::<TokenStream>();
+ if !variant_field_errors.is_empty() {
+ return variant_field_errors;
+ }
+
+ let ctor = s
+ .variants()
+ .iter()
+ .map(|v| v.construct(|_, _| -> TokenStream { unreachable!() }))
+ .collect::<Vec<_>>();
+ // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here?
+ #[allow(keyword_idents_2024)]
+ s.gen_impl(quote! {
+ // The surrounding code might have shadowed these identifiers.
+ use ::core::convert::TryFrom;
+ use ::core::primitive::u32;
+ use ::core::result::Result::{self, Ok, Err};
+
+ gen impl TryFrom<u32> for @Self {
+ type Error = u32;
+
+ #[allow(deprecated)] // Don't warn about deprecated variants.
+ fn try_from(value: u32) -> Result<Self, Self::Error> {
+ #( if value == const { #ctor as u32 } { return Ok(#ctor) } )*
+ Err(value)
+ }
+ }
+ })
+}
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 79d3482..3b0151b 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -8,6 +8,7 @@
bitflags = "2.4.1"
libloading = "0.8.0"
odht = { version = "0.3.1", features = ["nightly"] }
+rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 8adec75..1662391 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -28,7 +28,7 @@
use rustc_session::output::validate_crate_name;
use rustc_session::search_paths::PathKind;
use rustc_span::edition::Edition;
-use rustc_span::symbol::{Symbol, sym};
+use rustc_span::symbol::{Ident, Symbol, sym};
use rustc_span::{DUMMY_SP, Span};
use rustc_target::spec::{PanicStrategy, Target, TargetTriple};
use tracing::{debug, info, trace};
@@ -97,7 +97,7 @@
}
pub enum LoadedMacro {
- MacroDef(ast::Item, Edition),
+ MacroDef { def: MacroDef, ident: Ident, attrs: AttrVec, span: Span, edition: Edition },
ProcMacro(SyntaxExtension),
}
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 7bb4099..926eb4f 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -1,7 +1,6 @@
use std::any::Any;
use std::mem;
-use rustc_ast as ast;
use rustc_attr::Deprecation;
use rustc_data_structures::sync::Lrc;
use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -275,6 +274,8 @@
impl_parent => { table }
defaultness => { table_direct }
constness => { table_direct }
+ const_conditions => { table }
+ implied_const_bounds => { table_defaulted_array }
coerce_unsized_info => {
Ok(cdata
.root
@@ -330,7 +331,6 @@
.process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys")))
}
- associated_type_for_effects => { table }
associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array }
visibility => { cdata.get_visibility(def_id.index) }
@@ -591,27 +591,16 @@
let data = self.get_crate_data(id.krate);
if data.root.is_proc_macro_crate() {
- return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, tcx));
- }
-
- let span = data.get_span(id.index, sess);
-
- LoadedMacro::MacroDef(
- ast::Item {
+ LoadedMacro::ProcMacro(data.load_proc_macro(id.index, tcx))
+ } else {
+ LoadedMacro::MacroDef {
+ def: data.get_macro(id.index, sess),
ident: data.item_ident(id.index, sess),
- id: ast::DUMMY_NODE_ID,
- span,
attrs: data.get_item_attrs(id.index, sess).collect(),
- kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)),
- vis: ast::Visibility {
- span: span.shrink_to_lo(),
- kind: ast::VisibilityKind::Inherited,
- tokens: None,
- },
- tokens: None,
- },
- data.root.edition,
- )
+ span: data.get_span(id.index, sess),
+ edition: data.root.edition,
+ }
+ }
}
pub fn def_span_untracked(&self, def_id: DefId, sess: &Session) -> Span {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index ec678c7..b5ac302 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -278,7 +278,7 @@
let source_map = s.tcx.sess.source_map();
let source_file_index = source_map.lookup_source_file_idx(self.lo);
s.source_file_cache =
- (source_map.files()[source_file_index].clone(), source_file_index);
+ (Lrc::clone(&source_map.files()[source_file_index]), source_file_index);
}
let (ref source_file, source_file_index) = s.source_file_cache;
debug_assert!(source_file.contains(self.lo));
@@ -1081,7 +1081,7 @@
&& (generics.requires_monomorphization(tcx)
|| tcx.cross_crate_inlinable(def_id)));
// The function has a `const` modifier or is in a `#[const_trait]`.
- let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
+ let is_const_fn = tcx.is_const_fn(def_id.to_def_id())
|| tcx.is_const_default_method(def_id.to_def_id());
(is_const_fn, opt)
}
@@ -1433,6 +1433,9 @@
}
}
}
+ if tcx.is_conditionally_const(def_id) {
+ record!(self.tables.const_conditions[def_id] <- self.tcx.const_conditions(def_id));
+ }
if should_encode_type(tcx, local_id, def_kind) {
record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id));
}
@@ -1456,10 +1459,13 @@
self.tcx.explicit_super_predicates_of(def_id).skip_binder());
record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <-
self.tcx.explicit_implied_predicates_of(def_id).skip_binder());
-
let module_children = self.tcx.module_children_local(local_id);
record_array!(self.tables.module_children_non_reexports[def_id] <-
module_children.iter().map(|child| child.res.def_id().index));
+ if self.tcx.is_const_trait(def_id) {
+ record_defaulted_array!(self.tables.implied_const_bounds[def_id]
+ <- self.tcx.implied_const_bounds(def_id).skip_binder());
+ }
}
if let DefKind::TraitAlias = def_kind {
record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
@@ -1479,9 +1485,6 @@
for &def_id in associated_item_def_ids {
self.encode_info_for_assoc_item(def_id);
}
- if let Some(assoc_def_id) = self.tcx.associated_type_for_effects(def_id) {
- record!(self.tables.associated_type_for_effects[def_id] <- assoc_def_id);
- }
}
if let DefKind::Closure | DefKind::SyntheticCoroutineBody = def_kind
&& let Some(coroutine_kind) = self.tcx.coroutine_kind(def_id)
@@ -1652,6 +1655,10 @@
if let ty::AssocKind::Type = item.kind {
self.encode_explicit_item_bounds(def_id);
self.encode_explicit_item_super_predicates(def_id);
+ if tcx.is_conditionally_const(def_id) {
+ record_defaulted_array!(self.tables.implied_const_bounds[def_id]
+ <- self.tcx.implied_const_bounds(def_id).skip_binder());
+ }
}
}
AssocItemContainer::ImplContainer => {
@@ -2268,7 +2275,7 @@
encoder.emit_raw_bytes(&0u64.to_le_bytes());
let source_map_files = tcx.sess.source_map().files();
- let source_file_cache = (source_map_files[0].clone(), 0);
+ let source_file_cache = (Lrc::clone(&source_map_files[0]), 0);
let required_source_files = Some(FxIndexSet::default());
drop(source_map_files);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 79bd1c1..f184404 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -6,6 +6,7 @@
use def_path_hash_map::DefPathHashMapRef;
use encoder::EncodeContext;
pub use encoder::{EncodedMetadata, encode_metadata, rendered_const};
+use rustc_abi::{FieldIdx, VariantIdx};
use rustc_ast::expand::StrippedCfgItem;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::svh::Svh;
@@ -37,7 +38,6 @@
use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData};
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span};
-use rustc_target::abi::{FieldIdx, VariantIdx};
use rustc_target::spec::{PanicStrategy, TargetTriple};
use table::TableBuilder;
use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
@@ -392,9 +392,9 @@
inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
+ implied_const_bounds: Table<DefIndex, LazyArray<(ty::PolyTraitRef<'static>, Span)>>,
inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
- associated_type_for_effects: Table<DefIndex, Option<LazyValue<DefId>>>,
opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>,
is_effects_desugaring: Table<DefIndex, bool>,
unused_generic_params: Table<DefIndex, UnusedGenericParams>,
@@ -436,6 +436,7 @@
thir_abstract_const: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::Const<'static>>>>,
impl_parent: Table<DefIndex, RawDefId>,
constness: Table<DefIndex, hir::Constness>,
+ const_conditions: Table<DefIndex, LazyValue<ty::ConstConditions<'static>>>,
defaultness: Table<DefIndex, hir::Defaultness>,
// FIXME(eddyb) perhaps compute this on the fly if cheap enough?
coerce_unsized_info: Table<DefIndex, LazyValue<ty::adjustment::CoerceUnsizedInfo>>,
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 8cb602d9..485d1c1 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -27,6 +27,7 @@
rustc_hir = { path = "../rustc_hir" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_index = { path = "../rustc_index" }
+rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" }
rustc_query_system = { path = "../rustc_query_system" }
rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 52fe995..7e77923 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -8,7 +8,7 @@
macro_rules! arena_types {
($macro:path) => (
$macro!([
- [] layout: rustc_target::abi::LayoutS<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>,
+ [] layout: rustc_abi::LayoutData<rustc_abi::FieldIdx, rustc_abi::VariantIdx>,
[] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>,
// AdtDef are interned and compared by address
[decode] adt_def: rustc_middle::ty::AdtDefData,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 8fd5ff1..9266910 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -329,7 +329,7 @@
BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability),
BodyOwnerKind::Fn if self.tcx.is_constructor(def_id) => return None,
- BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn_raw(def_id) => {
+ BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn(def_id) => {
ConstContext::ConstFn
}
BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id) => ConstContext::ConstFn,
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index cf692b1..7f92110 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -172,70 +172,3 @@
}
}
}
-
-/// values for the effect inference variable
-#[derive(Clone, Copy, Debug)]
-pub enum EffectVarValue<'tcx> {
- Unknown,
- Known(ty::Const<'tcx>),
-}
-
-impl<'tcx> EffectVarValue<'tcx> {
- pub fn known(self) -> Option<ty::Const<'tcx>> {
- match self {
- EffectVarValue::Unknown => None,
- EffectVarValue::Known(value) => Some(value),
- }
- }
-
- pub fn is_unknown(self) -> bool {
- match self {
- EffectVarValue::Unknown => true,
- EffectVarValue::Known(_) => false,
- }
- }
-}
-
-impl<'tcx> UnifyValue for EffectVarValue<'tcx> {
- type Error = NoError;
-
- fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
- match (*value1, *value2) {
- (EffectVarValue::Unknown, EffectVarValue::Unknown) => Ok(EffectVarValue::Unknown),
- (EffectVarValue::Unknown, EffectVarValue::Known(val))
- | (EffectVarValue::Known(val), EffectVarValue::Unknown) => {
- Ok(EffectVarValue::Known(val))
- }
- (EffectVarValue::Known(_), EffectVarValue::Known(_)) => {
- bug!("equating known inference variables: {value1:?} {value2:?}")
- }
- }
- }
-}
-
-#[derive(PartialEq, Copy, Clone, Debug)]
-pub struct EffectVidKey<'tcx> {
- pub vid: ty::EffectVid,
- pub phantom: PhantomData<ty::Const<'tcx>>,
-}
-
-impl<'tcx> From<ty::EffectVid> for EffectVidKey<'tcx> {
- fn from(vid: ty::EffectVid) -> Self {
- EffectVidKey { vid, phantom: PhantomData }
- }
-}
-
-impl<'tcx> UnifyKey for EffectVidKey<'tcx> {
- type Value = EffectVarValue<'tcx>;
- #[inline]
- fn index(&self) -> u32 {
- self.vid.as_u32()
- }
- #[inline]
- fn from_index(i: u32) -> Self {
- EffectVidKey::from(ty::EffectVid::from_u32(i))
- }
- fn tag() -> &'static str {
- "EffectVidKey"
- }
-}
diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
index 615a740..c241c06 100644
--- a/compiler/rustc_middle/src/middle/debugger_visualizer.rs
+++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
@@ -32,7 +32,7 @@
pub fn path_erased(&self) -> Self {
DebuggerVisualizerFile {
- src: self.src.clone(),
+ src: Lrc::clone(&self.src),
visualizer_type: self.visualizer_type,
path: None,
}
diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs
index a3fe8f9..7bb4119 100644
--- a/compiler/rustc_middle/src/mir/graphviz.rs
+++ b/compiler/rustc_middle/src/mir/graphviz.rs
@@ -17,7 +17,7 @@
let mirs = def_ids
.iter()
.flat_map(|def_id| {
- if tcx.is_const_fn_raw(*def_id) {
+ if tcx.is_const_fn(*def_id) {
vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]
} else {
vec![tcx.instance_mir(ty::InstanceKind::Item(*def_id))]
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 56ca916..d8d99de 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -86,11 +86,9 @@
}
}
- pub fn is_generic_fn(&self, tcx: TyCtxt<'tcx>) -> bool {
+ pub fn is_generic_fn(&self) -> bool {
match self {
- MonoItem::Fn(instance) => {
- instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some()
- }
+ MonoItem::Fn(instance) => instance.args.non_erasable_generics().next().is_some(),
MonoItem::Static(..) | MonoItem::GlobalAsm(..) => false,
}
}
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 2a3a070..e690bf7 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -277,9 +277,9 @@
)
})?;
}
- Ok(fs::File::create_buffered(&file_path).map_err(|e| {
+ fs::File::create_buffered(&file_path).map_err(|e| {
io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}"))
- })?)
+ })
}
///////////////////////////////////////////////////////////////////////////
@@ -317,7 +317,7 @@
};
// For `const fn` we want to render both the optimized MIR and the MIR for ctfe.
- if tcx.is_const_fn_raw(def_id) {
+ if tcx.is_const_fn(def_id) {
render_body(w, tcx.optimized_mir(def_id))?;
writeln!(w)?;
writeln!(w, "// MIR FOR CTFE")?;
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 48bf4ff..5f8427b 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -370,6 +370,7 @@
rustc_middle::ty::FnSig,
rustc_middle::ty::GenericArg,
rustc_middle::ty::GenericPredicates,
+ rustc_middle::ty::ConstConditions,
rustc_middle::ty::inhabitedness::InhabitedPredicate,
rustc_middle::ty::Instance,
rustc_middle::ty::InstanceKind,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index f8ba606..d7a60a8 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -29,6 +29,7 @@
use rustc_hir::lang_items::{LangItem, LanguageItems};
use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate};
use rustc_index::IndexVec;
+use rustc_lint_defs::LintId;
use rustc_macros::rustc_queries;
use rustc_query_system::ich::StableHashingContext;
use rustc_query_system::query::{QueryCache, QueryMode, QueryState, try_get_cached};
@@ -422,6 +423,11 @@
desc { "computing `#[expect]`ed lints in this crate" }
}
+ query lints_that_dont_need_to_run(_: ()) -> &'tcx FxIndexSet<LintId> {
+ arena_cache
+ desc { "Computing all lints that are explicitly enabled or with a default level greater than Allow" }
+ }
+
query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
desc { |tcx| "getting the expansion that defined `{}`", tcx.def_path_str(key) }
separate_provide_extern
@@ -683,6 +689,24 @@
}
}
+ query const_conditions(
+ key: DefId
+ ) -> ty::ConstConditions<'tcx> {
+ desc { |tcx| "computing the conditions for `{}` to be considered const",
+ tcx.def_path_str(key)
+ }
+ separate_provide_extern
+ }
+
+ query implied_const_bounds(
+ key: DefId
+ ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> {
+ desc { |tcx| "computing the implied `~const` bounds for `{}`",
+ tcx.def_path_str(key)
+ }
+ separate_provide_extern
+ }
+
/// To avoid cycles within the predicates of a single item we compute
/// per-type-parameter predicates for resolving `T::AssocTy`.
query type_param_predicates(
@@ -723,12 +747,11 @@
desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) }
}
- /// Returns `true` if this is a const fn, use the `is_const_fn` to know whether your crate
- /// actually sees it as const fn (e.g., the const-fn-ness might be unstable and you might
- /// not have the feature gate active).
+ /// Returns `true` if this is a const fn / const impl.
///
/// **Do not call this function manually.** It is only meant to cache the base data for the
- /// `is_const_fn` function. Consider using `is_const_fn` or `is_const_fn_raw` instead.
+ /// higher-level functions. Consider using `is_const_fn` or `is_const_trait_impl` instead.
+ /// Also note that neither of them takes into account feature gates and stability.
query constness(key: DefId) -> hir::Constness {
desc { |tcx| "checking if item is const: `{}`", tcx.def_path_str(key) }
separate_provide_extern
@@ -854,12 +877,6 @@
separate_provide_extern
}
- query associated_type_for_effects(def_id: DefId) -> Option<DefId> {
- desc { |tcx| "creating associated items for effects in `{}`", tcx.def_path_str(def_id) }
- cache_on_disk_if { def_id.is_local() }
- separate_provide_extern
- }
-
/// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding
/// associated item.
query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId {
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 35a1668..8b77a4a 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -472,32 +472,27 @@
let CacheDecoder { tcx, file_index_to_file, file_index_to_stable_id, source_map, .. } =
*self;
- file_index_to_file
- .borrow_mut()
- .entry(index)
- .or_insert_with(|| {
- let source_file_id = &file_index_to_stable_id[&index];
- let source_file_cnum =
- tcx.stable_crate_id_to_crate_num(source_file_id.stable_crate_id);
+ Lrc::clone(file_index_to_file.borrow_mut().entry(index).or_insert_with(|| {
+ let source_file_id = &file_index_to_stable_id[&index];
+ let source_file_cnum = tcx.stable_crate_id_to_crate_num(source_file_id.stable_crate_id);
- // If this `SourceFile` is from a foreign crate, then make sure
- // that we've imported all of the source files from that crate.
- // This has usually already been done during macro invocation.
- // However, when encoding query results like `TypeckResults`,
- // we might encode an `AdtDef` for a foreign type (because it
- // was referenced in the body of the function). There is no guarantee
- // that we will load the source files from that crate during macro
- // expansion, so we use `import_source_files` to ensure that the foreign
- // source files are actually imported before we call `source_file_by_stable_id`.
- if source_file_cnum != LOCAL_CRATE {
- self.tcx.import_source_files(source_file_cnum);
- }
+ // If this `SourceFile` is from a foreign crate, then make sure
+ // that we've imported all of the source files from that crate.
+ // This has usually already been done during macro invocation.
+ // However, when encoding query results like `TypeckResults`,
+ // we might encode an `AdtDef` for a foreign type (because it
+ // was referenced in the body of the function). There is no guarantee
+ // that we will load the source files from that crate during macro
+ // expansion, so we use `import_source_files` to ensure that the foreign
+ // source files are actually imported before we call `source_file_by_stable_id`.
+ if source_file_cnum != LOCAL_CRATE {
+ self.tcx.import_source_files(source_file_cnum);
+ }
- source_map
- .source_file_by_stable_id(source_file_id.stable_source_file_id)
- .expect("failed to lookup `SourceFile` in new context")
- })
- .clone()
+ source_map
+ .source_file_by_stable_id(source_file_id.stable_source_file_id)
+ .expect("failed to lookup `SourceFile` in new context")
+ }))
}
}
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 8ee8b4c..40e5ec4 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -92,16 +92,6 @@
ObligationCause { span, body_id: CRATE_DEF_ID, code: Default::default() }
}
- pub fn span(&self) -> Span {
- match *self.code() {
- ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
- arm_span,
- ..
- }) => arm_span,
- _ => self.span,
- }
- }
-
#[inline]
pub fn code(&self) -> &ObligationCauseCode<'tcx> {
&self.code
@@ -517,10 +507,17 @@
pub prior_arm_block_id: Option<HirId>,
pub prior_arm_ty: Ty<'tcx>,
pub prior_arm_span: Span,
+ /// Span of the scrutinee of the match (the matched value).
pub scrut_span: Span,
+ /// Source of the match, i.e. `match` or a desugaring.
pub source: hir::MatchSource,
+ /// Span of the *whole* match expr.
+ pub expr_span: Span,
+ /// Spans of the previous arms except for those that diverge (i.e. evaluate to `!`).
+ ///
+ /// These are used for pointing out errors that may affect several arms.
pub prior_non_diverging_arms: Vec<Span>,
- // Is the expectation of this match expression an RPIT?
+ /// Is the expectation of this match expression an RPIT?
pub tail_defines_return_position_impl_trait: Option<LocalDefId>,
}
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 7e533bc..ef9dfdd 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -387,6 +387,17 @@
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+ for [(ty::PolyTraitRef<'tcx>, Span)]
+{
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ decoder
+ .interner()
+ .arena
+ .alloc_from_iter((0..decoder.read_usize()).map(|_| Decodable::decode(decoder)))
+ }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
for ty::List<ty::BoundVariableKind>
{
fn decode(decoder: &mut D) -> &'tcx Self {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index b682524..5ae9c58 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -12,7 +12,7 @@
use std::ops::{Bound, Deref};
use std::{fmt, iter, mem};
-use rustc_abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
+use rustc_abi::{FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx};
use rustc_ast::{self as ast, attr};
use rustc_data_structures::defer;
use rustc_data_structures::fingerprint::Fingerprint;
@@ -78,10 +78,10 @@
use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
use crate::ty::{
self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericArg, GenericArgs,
- GenericArgsRef, GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst,
- ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind,
- PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid,
- Visibility,
+ GenericArgsRef, GenericParamDefKind, HostPolarity, ImplPolarity, List, ListWithCachedTypeInfo,
+ ParamConst, ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate,
+ PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty,
+ TyKind, TyVid, Visibility,
};
#[allow(rustc::usage_of_ty_tykind)]
@@ -383,6 +383,28 @@
self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied())
}
+ fn is_const_impl(self, def_id: DefId) -> bool {
+ self.is_conditionally_const(def_id)
+ }
+
+ fn const_conditions(
+ self,
+ def_id: DefId,
+ ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> {
+ ty::EarlyBinder::bind(
+ self.const_conditions(def_id).instantiate_identity(self).into_iter().map(|(c, _)| c),
+ )
+ }
+
+ fn implied_const_bounds(
+ self,
+ def_id: DefId,
+ ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>>> {
+ ty::EarlyBinder::bind(
+ self.implied_const_bounds(def_id).iter_identity_copied().map(|(c, _)| c),
+ )
+ }
+
fn has_target_features(self, def_id: DefId) -> bool {
!self.codegen_fn_attrs(def_id).target_features.is_empty()
}
@@ -646,13 +668,6 @@
Destruct,
DiscriminantKind,
DynMetadata,
- EffectsCompat,
- EffectsIntersection,
- EffectsIntersectionOutput,
- EffectsMaybe,
- EffectsNoRuntime,
- EffectsRuntime,
- EffectsTyCompat,
Fn,
FnMut,
FnOnce,
@@ -751,7 +766,7 @@
pat: InternedSet<'tcx, PatternKind<'tcx>>,
const_allocation: InternedSet<'tcx, Allocation>,
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
- layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>,
+ layout: InternedSet<'tcx, LayoutData<FieldIdx, VariantIdx>>,
adt_def: InternedSet<'tcx, AdtDefData>,
external_constraints: InternedSet<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>,
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<TyCtxt<'tcx>>>,
@@ -2196,7 +2211,7 @@
nop_slice_lift! {ty::ValTree<'a> => ty::ValTree<'tcx>}
TrivialLiftImpls! {
- ImplPolarity, PredicatePolarity, Promoted
+ ImplPolarity, PredicatePolarity, Promoted, HostPolarity,
}
macro_rules! sty_debug_print {
@@ -2454,7 +2469,7 @@
region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>,
pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>,
const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
- layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
+ layout: pub mk_layout(LayoutData<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
external_constraints: pub mk_external_constraints(ExternalConstraintsData<TyCtxt<'tcx>>):
ExternalConstraints -> ExternalConstraints<'tcx>,
@@ -3105,38 +3120,24 @@
}
}
- /// Whether the `def_id` counts as const fn in the current crate, considering all active
- /// feature gates
- pub fn is_const_fn(self, def_id: DefId) -> bool {
- if self.is_const_fn_raw(def_id) {
- match self.lookup_const_stability(def_id) {
- Some(stability) if stability.is_const_unstable() => {
- // has a `rustc_const_unstable` attribute, check whether the user enabled the
- // corresponding feature gate.
- self.features().enabled(stability.feature)
- }
- // functions without const stability are either stable user written
- // const fn or the user is using feature gates and we thus don't
- // care what they do
- _ => true,
+ /// Whether `def_id` is a stable const fn (i.e., doesn't need any feature gates to be called).
+ ///
+ /// When this is `false`, the function may still be callable as a `const fn` due to features
+ /// being enabled!
+ pub fn is_stable_const_fn(self, def_id: DefId) -> bool {
+ self.is_const_fn(def_id)
+ && match self.lookup_const_stability(def_id) {
+ None => true, // a fn in a non-staged_api crate
+ Some(stability) if stability.is_const_stable() => true,
+ _ => false,
}
- } else {
- false
- }
}
+ // FIXME(effects): Please remove this. It's a footgun.
/// Whether the trait impl is marked const. This does not consider stability or feature gates.
- pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool {
- let Some(local_def_id) = def_id.as_local() else { return false };
- let node = self.hir_node_by_def_id(local_def_id);
-
- matches!(
- node,
- hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
- ..
- }) if matches!(constness, hir::Constness::Const)
- )
+ pub fn is_const_trait_impl(self, def_id: DefId) -> bool {
+ self.def_kind(def_id) == DefKind::Impl { of_trait: true }
+ && self.constness(def_id) == hir::Constness::Const
}
pub fn intrinsic(self, def_id: impl IntoQueryParam<DefId> + Copy) -> Option<ty::IntrinsicDef> {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 8bd2ae9..84f52bf 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -70,7 +70,7 @@
/// ADTs with no type arguments.
pub fn is_simple_text(self, tcx: TyCtxt<'tcx>) -> bool {
match self.kind() {
- Adt(def, args) => args.non_erasable_generics(tcx, def.did()).next().is_none(),
+ Adt(_, args) => args.non_erasable_generics().next().is_none(),
Ref(_, ty, _) => ty.is_simple_text(tcx),
_ => self.is_simple_ty(),
}
@@ -592,9 +592,6 @@
match c.kind() {
ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {}
- // effect variables are always suggestable, because they are not visible
- ConstKind::Infer(InferConst::EffectVar(_)) => {}
-
ConstKind::Infer(..)
| ConstKind::Bound(..)
| ConstKind::Placeholder(..)
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 92a975c..704a197 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -265,6 +265,12 @@
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
self.add_args(trait_pred.trait_ref.args);
}
+ ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
+ trait_ref,
+ host: _,
+ })) => {
+ self.add_args(trait_ref.args);
+ }
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
a,
b,
@@ -354,9 +360,7 @@
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
match infer {
InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
- InferConst::Var(_) | InferConst::EffectVar(_) => {
- self.add_flags(TypeFlags::HAS_CT_INFER)
- }
+ InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
}
}
ty::ConstKind::Bound(debruijn, _) => {
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index daf1362..737f136 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -501,12 +501,8 @@
#[inline]
pub fn non_erasable_generics(
&'tcx self,
- tcx: TyCtxt<'tcx>,
- def_id: DefId,
) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> + 'tcx {
- let generics = tcx.generics_of(def_id);
- self.iter().enumerate().filter_map(|(i, k)| match k.unpack() {
- _ if Some(i) == generics.host_effect_index => None,
+ self.iter().filter_map(|k| match k.unpack() {
ty::GenericArgKind::Lifetime(_) => None,
generic => Some(generic),
})
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 660686f..1977974 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -14,7 +14,7 @@
pub enum GenericParamDefKind {
Lifetime,
Type { has_default: bool, synthetic: bool },
- Const { has_default: bool, is_host_effect: bool, synthetic: bool },
+ Const { has_default: bool, synthetic: bool },
}
impl GenericParamDefKind {
@@ -81,10 +81,6 @@
}
}
- pub fn is_host_effect(&self) -> bool {
- matches!(self.kind, GenericParamDefKind::Const { is_host_effect: true, .. })
- }
-
pub fn default_value<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
@@ -133,9 +129,6 @@
pub has_self: bool,
pub has_late_bound_regions: Option<Span>,
-
- // The index of the host effect when instantiated. (i.e. might be index to parent args)
- pub host_effect_index: Option<usize>,
}
impl<'tcx> rustc_type_ir::inherent::GenericsOf<TyCtxt<'tcx>> for &'tcx Generics {
@@ -216,12 +209,10 @@
pub fn own_requires_monomorphization(&self) -> bool {
for param in &self.own_params {
match param.kind {
- GenericParamDefKind::Type { .. }
- | GenericParamDefKind::Const { is_host_effect: false, .. } => {
+ GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
return true;
}
- GenericParamDefKind::Lifetime
- | GenericParamDefKind::Const { is_host_effect: true, .. } => {}
+ GenericParamDefKind::Lifetime => {}
}
}
false
@@ -300,8 +291,6 @@
own_params.start = 1;
}
- let verbose = tcx.sess.verbose_internals();
-
// Filter the default arguments.
//
// This currently uses structural equality instead
@@ -316,8 +305,6 @@
param.default_value(tcx).is_some_and(|default| {
default.instantiate(tcx, args) == args[param.index as usize]
})
- // filter out trailing effect params, if we're not in `-Zverbose-internals`.
- || (!verbose && matches!(param.kind, GenericParamDefKind::Const { is_host_effect: true, .. }))
})
.count();
@@ -373,7 +360,6 @@
pub struct GenericPredicates<'tcx> {
pub parent: Option<DefId>,
pub predicates: &'tcx [(Clause<'tcx>, Span)],
- pub effects_min_tys: &'tcx ty::List<Ty<'tcx>>,
}
impl<'tcx> GenericPredicates<'tcx> {
@@ -395,7 +381,9 @@
EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args)
}
- pub fn instantiate_own_identity(self) -> impl Iterator<Item = (Clause<'tcx>, Span)> {
+ pub fn instantiate_own_identity(
+ self,
+ ) -> impl Iterator<Item = (Clause<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator {
EarlyBinder::bind(self.predicates).iter_identity_copied()
}
@@ -433,3 +421,73 @@
instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s));
}
}
+
+/// `~const` bounds for a given item. This is represented using a struct much like
+/// `GenericPredicates`, where you can either choose to only instantiate the "own"
+/// bounds or all of the bounds including those from the parent. This distinction
+/// is necessary for code like `compare_method_predicate_entailment`.
+#[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct ConstConditions<'tcx> {
+ pub parent: Option<DefId>,
+ pub predicates: &'tcx [(ty::PolyTraitRef<'tcx>, Span)],
+}
+
+impl<'tcx> ConstConditions<'tcx> {
+ pub fn instantiate(
+ self,
+ tcx: TyCtxt<'tcx>,
+ args: GenericArgsRef<'tcx>,
+ ) -> Vec<(ty::PolyTraitRef<'tcx>, Span)> {
+ let mut instantiated = vec![];
+ self.instantiate_into(tcx, &mut instantiated, args);
+ instantiated
+ }
+
+ pub fn instantiate_own(
+ self,
+ tcx: TyCtxt<'tcx>,
+ args: GenericArgsRef<'tcx>,
+ ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
+ {
+ EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args)
+ }
+
+ pub fn instantiate_own_identity(
+ self,
+ ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
+ {
+ EarlyBinder::bind(self.predicates).iter_identity_copied()
+ }
+
+ #[instrument(level = "debug", skip(self, tcx))]
+ fn instantiate_into(
+ self,
+ tcx: TyCtxt<'tcx>,
+ instantiated: &mut Vec<(ty::PolyTraitRef<'tcx>, Span)>,
+ args: GenericArgsRef<'tcx>,
+ ) {
+ if let Some(def_id) = self.parent {
+ tcx.const_conditions(def_id).instantiate_into(tcx, instantiated, args);
+ }
+ instantiated.extend(
+ self.predicates.iter().map(|&(p, s)| (EarlyBinder::bind(p).instantiate(tcx, args), s)),
+ );
+ }
+
+ pub fn instantiate_identity(self, tcx: TyCtxt<'tcx>) -> Vec<(ty::PolyTraitRef<'tcx>, Span)> {
+ let mut instantiated = vec![];
+ self.instantiate_identity_into(tcx, &mut instantiated);
+ instantiated
+ }
+
+ fn instantiate_identity_into(
+ self,
+ tcx: TyCtxt<'tcx>,
+ instantiated: &mut Vec<(ty::PolyTraitRef<'tcx>, Span)>,
+ ) {
+ if let Some(def_id) = self.parent {
+ tcx.const_conditions(def_id).instantiate_identity_into(tcx, instantiated);
+ }
+ instantiated.extend(self.predicates.iter().copied());
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index b1c5ff5..e237d38 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -204,7 +204,7 @@
}
// If this a non-generic instance, it cannot be a shared monomorphization.
- self.args.non_erasable_generics(tcx, self.def_id()).next()?;
+ self.args.non_erasable_generics().next()?;
// compiler_builtins cannot use upstream monomorphizations.
if tcx.is_compiler_builtins(LOCAL_CRATE) {
@@ -476,7 +476,6 @@
pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> {
let args = GenericArgs::for_item(tcx, def_id, |param, _| match param.kind {
ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
- ty::GenericParamDefKind::Const { is_host_effect: true, .. } => tcx.consts.true_.into(),
ty::GenericParamDefKind::Type { .. } => {
bug!("Instance::mono: {:?} has type parameters", def_id)
}
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 7e65df6..2c7a3ff 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -4,7 +4,7 @@
use rustc_abi::Primitive::{self, Float, Int, Pointer};
use rustc_abi::{
- Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutS,
+ Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutData,
PointeeInfo, PointerKind, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, Variants,
};
use rustc_error_messages::DiagMessage;
@@ -346,7 +346,7 @@
// First try computing a static layout.
let err = match tcx.layout_of(param_env.and(ty)) {
Ok(layout) => {
- if layout.abi.is_sized() {
+ if layout.is_sized() {
return Ok(SizeSkeleton::Known(layout.size, Some(layout.align.abi)));
} else {
// Just to be safe, don't claim a known layout for unsized types.
@@ -751,7 +751,7 @@
ty::Adt(def, _) => def.variant(variant_index).fields.len(),
_ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty),
};
- tcx.mk_layout(LayoutS {
+ tcx.mk_layout(LayoutData {
variants: Variants::Single { index: variant_index },
fields: match NonZero::new(fields) {
Some(fields) => FieldsShape::Union(fields),
@@ -788,7 +788,7 @@
let tcx = cx.tcx();
let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
TyAndLayout {
- layout: tcx.mk_layout(LayoutS::scalar(cx, tag)),
+ layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
ty: tag.primitive().to_ty(tcx),
}
};
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ed24fcc..b92fc86 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -84,12 +84,13 @@
pub use self::pattern::{Pattern, PatternKind};
pub use self::predicate::{
AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate,
- ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, NormalizesTo,
- OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection,
- PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate,
- PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate,
- PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef,
- TraitPredicate, TraitRef, TypeOutlivesPredicate,
+ ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef,
+ HostEffectPredicate, NormalizesTo, OutlivesPredicate, PolyCoercePredicate,
+ PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef,
+ PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate,
+ PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate,
+ RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, TraitPredicate, TraitRef,
+ TypeOutlivesPredicate,
};
pub use self::region::BoundRegionKind::*;
pub use self::region::{
@@ -1994,14 +1995,82 @@
(ident, scope)
}
+ /// Checks whether this is a `const fn`. Returns `false` for non-functions.
+ ///
+ /// Even if this returns `true`, constness may still be unstable!
#[inline]
- pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
+ pub fn is_const_fn(self, def_id: DefId) -> bool {
matches!(
self.def_kind(def_id),
- DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Closure
+ DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Closure
) && self.constness(def_id) == hir::Constness::Const
}
+ /// Whether this item is conditionally constant for the purposes of the
+ /// effects implementation.
+ ///
+ /// This roughly corresponds to all const functions and other callable
+ /// items, along with const impls and traits, and associated types within
+ /// those impls and traits.
+ pub fn is_conditionally_const(self, def_id: impl Into<DefId>) -> bool {
+ let def_id: DefId = def_id.into();
+ match self.def_kind(def_id) {
+ DefKind::Impl { of_trait: true } => {
+ self.constness(def_id) == hir::Constness::Const
+ && self.is_const_trait(
+ self.trait_id_of_impl(def_id)
+ .expect("expected trait for trait implementation"),
+ )
+ }
+ DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => {
+ self.constness(def_id) == hir::Constness::Const
+ }
+ DefKind::Trait => self.is_const_trait(def_id),
+ DefKind::AssocTy | DefKind::AssocFn => {
+ let parent_def_id = self.parent(def_id);
+ match self.def_kind(parent_def_id) {
+ DefKind::Impl { of_trait: false } => {
+ self.constness(def_id) == hir::Constness::Const
+ }
+ DefKind::Impl { of_trait: true } | DefKind::Trait => {
+ self.is_conditionally_const(parent_def_id)
+ }
+ _ => bug!("unexpected parent item of associated item: {parent_def_id:?}"),
+ }
+ }
+ DefKind::Closure | DefKind::OpaqueTy => {
+ // Closures and RPITs will eventually have const conditions
+ // for `~const` bounds.
+ false
+ }
+ DefKind::Ctor(_, CtorKind::Const)
+ | DefKind::Impl { of_trait: false }
+ | DefKind::Mod
+ | DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::Variant
+ | DefKind::TyAlias
+ | DefKind::ForeignTy
+ | DefKind::TraitAlias
+ | DefKind::TyParam
+ | DefKind::Const
+ | DefKind::ConstParam
+ | DefKind::Static { .. }
+ | DefKind::AssocConst
+ | DefKind::Macro(_)
+ | DefKind::ExternCrate
+ | DefKind::Use
+ | DefKind::ForeignMod
+ | DefKind::AnonConst
+ | DefKind::InlineConst
+ | DefKind::Field
+ | DefKind::LifetimeParam
+ | DefKind::GlobalAsm
+ | DefKind::SyntheticCoroutineBody => false,
+ }
+ }
+
#[inline]
pub fn is_const_trait(self, def_id: DefId) -> bool {
self.trait_def(def_id).constness == hir::Constness::Const
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 7e1255f..43bdce5 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -132,6 +132,7 @@
ty::Ty,
ty::FnSig,
ty::GenericPredicates,
+ ty::ConstConditions,
ty::TraitRef,
ty::Const,
ty::Predicate,
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index d20cb36..3ecaa3e 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -19,6 +19,7 @@
pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef<TyCtxt<'tcx>>;
pub type ExistentialProjection<'tcx> = ir::ExistentialProjection<TyCtxt<'tcx>>;
pub type TraitPredicate<'tcx> = ir::TraitPredicate<TyCtxt<'tcx>>;
+pub type HostEffectPredicate<'tcx> = ir::HostEffectPredicate<TyCtxt<'tcx>>;
pub type ClauseKind<'tcx> = ir::ClauseKind<TyCtxt<'tcx>>;
pub type PredicateKind<'tcx> = ir::PredicateKind<TyCtxt<'tcx>>;
pub type NormalizesTo<'tcx> = ir::NormalizesTo<TyCtxt<'tcx>>;
@@ -143,6 +144,7 @@
| PredicateKind::AliasRelate(..)
| PredicateKind::NormalizesTo(..) => false,
PredicateKind::Clause(ClauseKind::Trait(_))
+ | PredicateKind::Clause(ClauseKind::HostEffect(..))
| PredicateKind::Clause(ClauseKind::RegionOutlives(_))
| PredicateKind::Clause(ClauseKind::TypeOutlives(_))
| PredicateKind::Clause(ClauseKind::Projection(_))
@@ -644,6 +646,7 @@
match predicate.skip_binder() {
PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)),
PredicateKind::Clause(ClauseKind::Projection(..))
+ | PredicateKind::Clause(ClauseKind::HostEffect(..))
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
| PredicateKind::NormalizesTo(..)
| PredicateKind::AliasRelate(..)
@@ -664,6 +667,7 @@
match predicate.skip_binder() {
PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)),
PredicateKind::Clause(ClauseKind::Trait(..))
+ | PredicateKind::Clause(ClauseKind::HostEffect(..))
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
| PredicateKind::NormalizesTo(..)
| PredicateKind::AliasRelate(..)
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 10c3522..0248aad 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -3075,6 +3075,15 @@
p!(print(self.trait_ref.print_trait_sugared()))
}
+ ty::HostEffectPredicate<'tcx> {
+ let constness = match self.host {
+ ty::HostPolarity::Const => { "const" }
+ ty::HostPolarity::Maybe => { "~const" }
+ };
+ p!(print(self.trait_ref.self_ty()), ": {constness} ");
+ p!(print(self.trait_ref.print_trait_sugared()))
+ }
+
ty::TypeAndMut<'tcx> {
p!(write("{}", self.mutbl.prefix_str()), print(self.ty))
}
@@ -3087,6 +3096,7 @@
ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)),
ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)),
ty::ClauseKind::Projection(predicate) => p!(print(predicate)),
+ ty::ClauseKind::HostEffect(predicate) => p!(print(predicate)),
ty::ClauseKind::ConstArgHasType(ct, ty) => {
p!("the constant `", print(ct), "` has type `", print(ty), "`")
},
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 06cbb6c..7fd7e46 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -17,10 +17,10 @@
use rustc_target::abi::{Float, Integer, IntegerType, Size};
use rustc_target::spec::abi::Abi;
use smallvec::{SmallVec, smallvec};
-use tracing::{debug, instrument, trace};
+use tracing::{debug, instrument};
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use crate::query::{IntoQueryParam, Providers};
+use crate::query::Providers;
use crate::ty::layout::{FloatExt, IntegerExt};
use crate::ty::{
self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable,
@@ -865,48 +865,6 @@
|| self.extern_crate(key).is_some_and(|e| e.is_direct())
}
- /// Whether the item has a host effect param. This is different from `TyCtxt::is_const`,
- /// because the item must also be "maybe const", and the crate where the item is
- /// defined must also have the effects feature enabled.
- pub fn has_host_param(self, def_id: impl IntoQueryParam<DefId>) -> bool {
- self.generics_of(def_id).host_effect_index.is_some()
- }
-
- pub fn expected_host_effect_param_for_body(self, def_id: impl Into<DefId>) -> ty::Const<'tcx> {
- let def_id = def_id.into();
- // FIXME(effects): This is suspicious and should probably not be done,
- // especially now that we enforce host effects and then properly handle
- // effect vars during fallback.
- let mut host_always_on = !self.features().effects()
- || self.sess.opts.unstable_opts.unleash_the_miri_inside_of_you;
-
- // Compute the constness required by the context.
- let const_context = self.hir().body_const_context(def_id);
-
- let kind = self.def_kind(def_id);
- debug_assert_ne!(kind, DefKind::ConstParam);
-
- if self.has_attr(def_id, sym::rustc_do_not_const_check) {
- trace!("do not const check this context");
- host_always_on = true;
- }
-
- match const_context {
- _ if host_always_on => self.consts.true_,
- Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => {
- self.consts.false_
- }
- Some(hir::ConstContext::ConstFn) => {
- let host_idx = self
- .generics_of(def_id)
- .host_effect_index
- .expect("ConstContext::Maybe must have host effect param");
- ty::GenericArgs::identity_for_item(self, def_id).const_at(host_idx)
- }
- None => self.consts.true_,
- }
- }
-
/// Expand any [weak alias types][weak] contained within the given `value`.
///
/// This should be used over other normalization routines in situations where
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index dfc82f7..a7e56b8 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -1048,8 +1048,8 @@
// | +------------|outer_scope cache|--+ |
// +------------------------------|middle_scope cache|------+
//
- // Now, a new, inner-most scope is added along with a new drop into
- // both inner-most and outer-most scopes:
+ // Now, a new, innermost scope is added along with a new drop into
+ // both innermost and outermost scopes:
//
// +------------------------------------------------------------+
// | +----------------------------------+ |
@@ -1061,11 +1061,11 @@
// +----=----------------|invalid middle_scope cache|-----------+
//
// If, when adding `drop(new)` we do not invalidate the cached blocks for both
- // outer_scope and middle_scope, then, when building drops for the inner (right-most)
+ // outer_scope and middle_scope, then, when building drops for the inner (rightmost)
// scope, the old, cached blocks, without `drop(new)` will get used, producing the
// wrong results.
//
- // Note that this code iterates scopes from the inner-most to the outer-most,
+ // Note that this code iterates scopes from the innermost to the outermost,
// invalidating caches of each scope visited. This way bare minimum of the
// caches gets invalidated. i.e., if a new drop is added into the middle scope, the
// cache of outer scope stays intact.
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 8512763..f3e6301 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -509,20 +509,12 @@
}
ExprKind::RawBorrow { arg, .. } => {
if let ExprKind::Scope { value: arg, .. } = self.thir[arg].kind
- // THIR desugars UNSAFE_STATIC into *UNSAFE_STATIC_REF, where
- // UNSAFE_STATIC_REF holds the addr of the UNSAFE_STATIC, so: take two steps
&& let ExprKind::Deref { arg } = self.thir[arg].kind
- // FIXME(workingjubiee): we lack a clear reason to reject ThreadLocalRef here,
- // but we also have no conclusive reason to allow it either!
- && let ExprKind::StaticRef { .. } = self.thir[arg].kind
{
- // A raw ref to a place expr, even an "unsafe static", is okay!
- // We short-circuit to not recursively traverse this expression.
+ // Taking a raw ref to a deref place expr is always safe.
+ // Make sure the expression we're deref'ing is safe, though.
+ visit::walk_expr(self, &self.thir[arg]);
return;
- // note: const_mut_refs enables this code, and it currently remains unsafe:
- // static mut BYTE: u8 = 0;
- // static mut BYTE_PTR: *mut u8 = unsafe { addr_of_mut!(BYTE) };
- // static mut DEREF_BYTE_PTR: *mut u8 = unsafe { addr_of_mut!(*BYTE_PTR) };
}
}
ExprKind::Deref { arg } => {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 24c914d..d20e5fc 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -281,7 +281,14 @@
.unwrap_or_else(|e| panic!("could not compute layout for {param_env_ty:?}: {e:?}"))
.size;
- let lit = ScalarInt::try_from_uint(discr_offset as u128, size).unwrap();
+ let (lit, overflowing) = ScalarInt::truncate_from_uint(discr_offset as u128, size);
+ if overflowing {
+ // An erroneous enum with too many variants for its repr will emit E0081 and E0370
+ self.tcx.dcx().span_delayed_bug(
+ source.span,
+ "overflowing enum wasn't rejected by hir analysis",
+ );
+ }
let kind = ExprKind::NonHirLiteral { lit, user_ty: None };
let offset = self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind });
diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml
index 7199db6..62a69b3 100644
--- a/compiler/rustc_mir_dataflow/Cargo.toml
+++ b/compiler/rustc_mir_dataflow/Cargo.toml
@@ -7,6 +7,7 @@
# tidy-alphabetical-start
polonius-engine = "0.13.0"
regex = "1"
+rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
index bb53eaf..e5cddd0 100644
--- a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
+++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
@@ -1,5 +1,5 @@
+use rustc_abi::VariantIdx;
use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind};
-use rustc_target::abi::VariantIdx;
use tracing::debug;
use super::move_paths::{InitKind, LookupResult, MoveData, MovePathIndex};
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 7f2a07e..9a1f000 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -1,5 +1,6 @@
use std::{fmt, iter};
+use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
use rustc_hir::lang_items::LangItem;
use rustc_index::Idx;
use rustc_middle::mir::patch::MirPatch;
@@ -10,7 +11,6 @@
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt};
use rustc_span::DUMMY_SP;
use rustc_span::source_map::Spanned;
-use rustc_target::abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
use tracing::{debug, instrument};
/// The value of an inserted drop flag.
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index faee40f..f7d4a08 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -36,6 +36,7 @@
use std::fmt::{Debug, Formatter};
use std::ops::Range;
+use rustc_abi::{FieldIdx, VariantIdx};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry};
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -46,7 +47,6 @@
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_target::abi::{FieldIdx, VariantIdx};
use tracing::debug;
use crate::fmt::DebugWithContext;
@@ -1177,7 +1177,7 @@
/// The projection used to go from parent to this node (only None for root).
proj_elem: Option<TrackElem>,
- /// The left-most child.
+ /// The leftmost child.
first_child: Option<PlaceIndex>,
/// Index of the sibling to the right of this node.
diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml
index 07ca51a..4b648d2 100644
--- a/compiler/rustc_mir_transform/Cargo.toml
+++ b/compiler/rustc_mir_transform/Cargo.toml
@@ -7,6 +7,7 @@
# tidy-alphabetical-start
either = "1"
itertools = "0.12"
+rustc_abi = { path = "../rustc_abi" }
rustc_arena = { path = "../rustc_arena" }
rustc_ast = { path = "../rustc_ast" }
rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 9a533ea..cf9f698 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -280,13 +280,12 @@
//
// The traversal tries to ensure that, when a loop is encountered, all
// nodes within the loop are visited before visiting any nodes outside
- // the loop. It also keeps track of which loop(s) the traversal is
- // currently inside.
+ // the loop.
let mut traversal = TraverseCoverageGraphWithLoops::new(self.graph);
while let Some(bcb) = traversal.next() {
let _span = debug_span!("traversal", ?bcb).entered();
if self.bcb_needs_counter.contains(bcb) {
- self.make_node_counter_and_out_edge_counters(&traversal, bcb);
+ self.make_node_counter_and_out_edge_counters(bcb);
}
}
@@ -299,12 +298,8 @@
/// Make sure the given node has a node counter, and then make sure each of
/// its out-edges has an edge counter (if appropriate).
- #[instrument(level = "debug", skip(self, traversal))]
- fn make_node_counter_and_out_edge_counters(
- &mut self,
- traversal: &TraverseCoverageGraphWithLoops<'_>,
- from_bcb: BasicCoverageBlock,
- ) {
+ #[instrument(level = "debug", skip(self))]
+ fn make_node_counter_and_out_edge_counters(&mut self, from_bcb: BasicCoverageBlock) {
// First, ensure that this node has a counter of some kind.
// We might also use that counter to compute one of the out-edge counters.
let node_counter = self.get_or_make_node_counter(from_bcb);
@@ -337,8 +332,7 @@
// If there are out-edges without counters, choose one to be given an expression
// (computed from this node and the other out-edges) instead of a physical counter.
- let Some(target_bcb) =
- self.choose_out_edge_for_expression(traversal, &candidate_successors)
+ let Some(target_bcb) = self.choose_out_edge_for_expression(from_bcb, &candidate_successors)
else {
return;
};
@@ -462,12 +456,12 @@
/// choose one to be given a counter expression instead of a physical counter.
fn choose_out_edge_for_expression(
&self,
- traversal: &TraverseCoverageGraphWithLoops<'_>,
+ from_bcb: BasicCoverageBlock,
candidate_successors: &[BasicCoverageBlock],
) -> Option<BasicCoverageBlock> {
// Try to find a candidate that leads back to the top of a loop,
// because reloop edges tend to be executed more times than loop-exit edges.
- if let Some(reloop_target) = self.find_good_reloop_edge(traversal, &candidate_successors) {
+ if let Some(reloop_target) = self.find_good_reloop_edge(from_bcb, &candidate_successors) {
debug!("Selecting reloop target {reloop_target:?} to get an expression");
return Some(reloop_target);
}
@@ -486,7 +480,7 @@
/// for them to be able to avoid a physical counter increment.
fn find_good_reloop_edge(
&self,
- traversal: &TraverseCoverageGraphWithLoops<'_>,
+ from_bcb: BasicCoverageBlock,
candidate_successors: &[BasicCoverageBlock],
) -> Option<BasicCoverageBlock> {
// If there are no candidates, avoid iterating over the loop stack.
@@ -495,14 +489,15 @@
}
// Consider each loop on the current traversal context stack, top-down.
- for reloop_bcbs in traversal.reloop_bcbs_per_loop() {
+ for loop_header_node in self.graph.loop_headers_containing(from_bcb) {
// Try to find a candidate edge that doesn't exit this loop.
for &target_bcb in candidate_successors {
// An edge is a reloop edge if its target dominates any BCB that has
// an edge back to the loop header. (Otherwise it's an exit edge.)
- let is_reloop_edge = reloop_bcbs
- .iter()
- .any(|&reloop_bcb| self.graph.dominates(target_bcb, reloop_bcb));
+ let is_reloop_edge = self
+ .graph
+ .reloop_predecessors(loop_header_node)
+ .any(|reloop_bcb| self.graph.dominates(target_bcb, reloop_bcb));
if is_reloop_edge {
// We found a good out-edge to be given an expression.
return Some(target_bcb);
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 930fa12..168262b 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -1,10 +1,11 @@
use std::cmp::Ordering;
use std::collections::VecDeque;
+use std::iter;
use std::ops::{Index, IndexMut};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::graph::dominators::{self, Dominators};
+use rustc_data_structures::graph::dominators::Dominators;
use rustc_data_structures::graph::{self, DirectedGraph, StartNode};
use rustc_index::IndexVec;
use rustc_index::bit_set::BitSet;
@@ -20,11 +21,17 @@
bb_to_bcb: IndexVec<BasicBlock, Option<BasicCoverageBlock>>,
pub(crate) successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
pub(crate) predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
+
dominators: Option<Dominators<BasicCoverageBlock>>,
/// Allows nodes to be compared in some total order such that _if_
/// `a` dominates `b`, then `a < b`. If neither node dominates the other,
/// their relative order is consistent but arbitrary.
dominator_order_rank: IndexVec<BasicCoverageBlock, u32>,
+ /// A loop header is a node that dominates one or more of its predecessors.
+ is_loop_header: BitSet<BasicCoverageBlock>,
+ /// For each node, the loop header node of its nearest enclosing loop.
+ /// This forms a linked list that can be traversed to find all enclosing loops.
+ enclosing_loop_header: IndexVec<BasicCoverageBlock, Option<BasicCoverageBlock>>,
}
impl CoverageGraph {
@@ -66,17 +73,38 @@
predecessors,
dominators: None,
dominator_order_rank: IndexVec::from_elem_n(0, num_nodes),
+ is_loop_header: BitSet::new_empty(num_nodes),
+ enclosing_loop_header: IndexVec::from_elem_n(None, num_nodes),
};
assert_eq!(num_nodes, this.num_nodes());
- this.dominators = Some(dominators::dominators(&this));
+ // Set the dominators first, because later init steps rely on them.
+ this.dominators = Some(graph::dominators::dominators(&this));
- // The dominator rank of each node is just its index in a reverse-postorder traversal.
- let reverse_post_order = graph::iterate::reverse_post_order(&this, this.start_node());
+ // Iterate over all nodes, such that dominating nodes are visited before
+ // the nodes they dominate. Either preorder or reverse postorder is fine.
+ let dominator_order = graph::iterate::reverse_post_order(&this, this.start_node());
// The coverage graph is created by traversal, so all nodes are reachable.
- assert_eq!(reverse_post_order.len(), this.num_nodes());
- for (rank, bcb) in (0u32..).zip(reverse_post_order) {
+ assert_eq!(dominator_order.len(), this.num_nodes());
+ for (rank, bcb) in (0u32..).zip(dominator_order) {
+ // The dominator rank of each node is its index in a dominator-order traversal.
this.dominator_order_rank[bcb] = rank;
+
+ // A node is a loop header if it dominates any of its predecessors.
+ if this.reloop_predecessors(bcb).next().is_some() {
+ this.is_loop_header.insert(bcb);
+ }
+
+ // If the immediate dominator is a loop header, that's our enclosing loop.
+ // Otherwise, inherit the immediate dominator's enclosing loop.
+ // (Dominator order ensures that we already processed the dominator.)
+ if let Some(dom) = this.dominators().immediate_dominator(bcb) {
+ this.enclosing_loop_header[bcb] = this
+ .is_loop_header
+ .contains(dom)
+ .then_some(dom)
+ .or_else(|| this.enclosing_loop_header[dom]);
+ }
}
// The coverage graph's entry-point node (bcb0) always starts with bb0,
@@ -173,8 +201,13 @@
}
#[inline(always)]
+ fn dominators(&self) -> &Dominators<BasicCoverageBlock> {
+ self.dominators.as_ref().unwrap()
+ }
+
+ #[inline(always)]
pub(crate) fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool {
- self.dominators.as_ref().unwrap().dominates(dom, node)
+ self.dominators().dominates(dom, node)
}
#[inline(always)]
@@ -214,6 +247,36 @@
None
}
}
+
+ /// For each loop that contains the given node, yields the "loop header"
+ /// node representing that loop, from innermost to outermost. If the given
+ /// node is itself a loop header, it is yielded first.
+ pub(crate) fn loop_headers_containing(
+ &self,
+ bcb: BasicCoverageBlock,
+ ) -> impl Iterator<Item = BasicCoverageBlock> + Captures<'_> {
+ let self_if_loop_header = self.is_loop_header.contains(bcb).then_some(bcb).into_iter();
+
+ let mut curr = Some(bcb);
+ let strictly_enclosing = iter::from_fn(move || {
+ let enclosing = self.enclosing_loop_header[curr?];
+ curr = enclosing;
+ enclosing
+ });
+
+ self_if_loop_header.chain(strictly_enclosing)
+ }
+
+ /// For the given node, yields the subset of its predecessor nodes that
+ /// it dominates. If that subset is non-empty, the node is a "loop header",
+ /// and each of those predecessors represents an in-edge that jumps back to
+ /// the top of its loop.
+ pub(crate) fn reloop_predecessors(
+ &self,
+ to_bcb: BasicCoverageBlock,
+ ) -> impl Iterator<Item = BasicCoverageBlock> + Captures<'_> {
+ self.predecessors[to_bcb].iter().copied().filter(move |&pred| self.dominates(to_bcb, pred))
+ }
}
impl Index<BasicCoverageBlock> for CoverageGraph {
@@ -439,15 +502,12 @@
pub(crate) struct TraverseCoverageGraphWithLoops<'a> {
basic_coverage_blocks: &'a CoverageGraph,
- backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
context_stack: Vec<TraversalContext>,
visited: BitSet<BasicCoverageBlock>,
}
impl<'a> TraverseCoverageGraphWithLoops<'a> {
pub(crate) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self {
- let backedges = find_loop_backedges(basic_coverage_blocks);
-
let worklist = VecDeque::from([basic_coverage_blocks.start_node()]);
let context_stack = vec![TraversalContext { loop_header: None, worklist }];
@@ -456,17 +516,7 @@
// of the stack as loops are entered, and popped off of the stack when a loop's worklist is
// exhausted.
let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes());
- Self { basic_coverage_blocks, backedges, context_stack, visited }
- }
-
- /// For each loop on the loop context stack (top-down), yields a list of BCBs
- /// within that loop that have an outgoing edge back to the loop header.
- pub(crate) fn reloop_bcbs_per_loop(&self) -> impl Iterator<Item = &[BasicCoverageBlock]> {
- self.context_stack
- .iter()
- .rev()
- .filter_map(|context| context.loop_header)
- .map(|header_bcb| self.backedges[header_bcb].as_slice())
+ Self { basic_coverage_blocks, context_stack, visited }
}
pub(crate) fn next(&mut self) -> Option<BasicCoverageBlock> {
@@ -488,7 +538,7 @@
}
debug!("Visiting {bcb:?}");
- if self.backedges[bcb].len() > 0 {
+ if self.basic_coverage_blocks.is_loop_header.contains(bcb) {
debug!("{bcb:?} is a loop header! Start a new TraversalContext...");
self.context_stack
.push(TraversalContext { loop_header: Some(bcb), worklist: VecDeque::new() });
@@ -566,29 +616,6 @@
}
}
-fn find_loop_backedges(
- basic_coverage_blocks: &CoverageGraph,
-) -> IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>> {
- let num_bcbs = basic_coverage_blocks.num_nodes();
- let mut backedges = IndexVec::from_elem_n(Vec::<BasicCoverageBlock>::new(), num_bcbs);
-
- // Identify loops by their backedges.
- for (bcb, _) in basic_coverage_blocks.iter_enumerated() {
- for &successor in &basic_coverage_blocks.successors[bcb] {
- if basic_coverage_blocks.dominates(successor, bcb) {
- let loop_header = successor;
- let backedge_from_bcb = bcb;
- debug!(
- "Found BCB backedge: {:?} -> loop_header: {:?}",
- backedge_from_bcb, loop_header
- );
- backedges[loop_header].push(backedge_from_bcb);
- }
- }
- }
- backedges
-}
-
fn short_circuit_preorder<'a, 'tcx, F, Iter>(
body: &'a mir::Body<'tcx>,
filtered_successors: F,
diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs
index bc86ae2..2db7c6c 100644
--- a/compiler/rustc_mir_transform/src/coverage/mappings.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs
@@ -363,7 +363,7 @@
let ConditionInfo { condition_id, true_next_id, false_next_id } = branch.condition_info;
[true_next_id, false_next_id]
.into_iter()
- .filter_map(std::convert::identity)
+ .flatten()
.for_each(|next_id| indegree_stats[next_id] += 1);
(condition_id, branch)
})
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index da7d20c..085c738 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -87,7 +87,7 @@
covspans.retain(|covspan| {
match covspan.expn_kind {
// Retain only the first await-related or macro-expanded covspan with this span.
- Some(ExpnKind::Desugaring(kind)) if kind == DesugaringKind::Await => {
+ Some(ExpnKind::Desugaring(DesugaringKind::Await)) => {
deduplicated_spans.insert(covspan.span)
}
Some(ExpnKind::Macro(MacroKind::Bang, _)) => deduplicated_spans.insert(covspan.span),
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index c9f2476..42d6bdf 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -439,12 +439,7 @@
// Reachability pass defines which functions are eligible for inlining. Generally inlining
// other functions is incorrect because they could reference symbols that aren't exported.
- let is_generic = callsite
- .callee
- .args
- .non_erasable_generics(self.tcx, callsite.callee.def_id())
- .next()
- .is_some();
+ let is_generic = callsite.callee.args.non_erasable_generics().next().is_some();
if !is_generic && !cross_crate_inlinable {
return Err("not exported");
}
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 86c4b24..fa9a6bf 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -673,7 +673,7 @@
}
// Make sure the callee is a `const fn`.
let is_const_fn = match *fn_ty.kind() {
- ty::FnDef(def_id, _) => self.tcx.is_const_fn_raw(def_id),
+ ty::FnDef(def_id, _) => self.tcx.is_const_fn(def_id),
_ => false,
};
if !is_const_fn {
diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
index 5612e77..3011af4 100644
--- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
@@ -1,5 +1,6 @@
//! A pass that eliminates branches on uninhabited or unreachable enum variants.
+use rustc_abi::Variants;
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::bug;
use rustc_middle::mir::patch::MirPatch;
@@ -9,7 +10,6 @@
};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{Ty, TyCtxt};
-use rustc_target::abi::{Abi, Variants};
use tracing::trace;
pub(super) struct UnreachableEnumBranching;
@@ -65,7 +65,7 @@
Variants::Multiple { variants, .. } => variants
.iter_enumerated()
.filter_map(|(idx, layout)| {
- (layout.abi != Abi::Uninhabited)
+ (!layout.is_uninhabited())
.then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
})
.collect(),
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index b4d084d..8df6e63 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -504,7 +504,7 @@
// Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the
// mono item graph.
if tcx.dcx().err_count() > error_count
- && starting_item.node.is_generic_fn(tcx)
+ && starting_item.node.is_generic_fn()
&& starting_item.node.is_user_defined()
{
let formatted_item = with_no_trimmed_paths!(starting_item.node.to_string());
@@ -1522,7 +1522,6 @@
// it, to validate whether or not the impl is legal to instantiate at all.
let only_region_params = |param: &ty::GenericParamDef, _: &_| match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
- GenericParamDefKind::Const { is_host_effect: true, .. } => tcx.consts.true_.into(),
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
unreachable!(
"`own_requires_monomorphization` check means that \
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 9bf7e67..e2a6d39 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -229,7 +229,7 @@
}
let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item);
- let is_volatile = is_incremental_build && mono_item.is_generic_fn(cx.tcx);
+ let is_volatile = is_incremental_build && mono_item.is_generic_fn();
let cgu_name = match characteristic_def_id {
Some(def_id) => compute_codegen_unit_name(
@@ -822,7 +822,7 @@
return Visibility::Hidden;
}
- let is_generic = instance.args.non_erasable_generics(tcx, def_id).next().is_some();
+ let is_generic = instance.args.non_erasable_generics().next().is_some();
// Upstream `DefId` instances get different handling than local ones.
let Some(def_id) = def_id.as_local() else {
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 23634d3..63608f9 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -431,7 +431,6 @@
);
CanonicalVarKind::Const(self.delegate.universe_of_ct(vid).unwrap())
}
- ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect,
ty::InferConst::Fresh(_) => todo!(),
},
ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs
index f2654f7..71c8771 100644
--- a/compiler/rustc_next_trait_solver/src/resolve.rs
+++ b/compiler/rustc_next_trait_solver/src/resolve.rs
@@ -76,9 +76,6 @@
resolved
}
}
- ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
- self.delegate.opportunistic_resolve_effect_var(vid)
- }
_ => {
if c.has_infer() {
c.super_fold_with(self)
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index c9c0d63..f6a5f20 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -100,6 +100,15 @@
})
}
+ /// Assemble additional assumptions for an alias that are not included
+ /// in the item bounds of the alias. For now, this is limited to the
+ /// `implied_const_bounds` for an associated type.
+ fn consider_additional_alias_assumptions(
+ ecx: &mut EvalCtxt<'_, D>,
+ goal: Goal<I, Self>,
+ alias_ty: ty::AliasTy<I>,
+ ) -> Vec<Candidate<I>>;
+
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
@@ -270,11 +279,6 @@
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
) -> Vec<Candidate<I>>;
-
- fn consider_builtin_effects_intersection_candidate(
- ecx: &mut EvalCtxt<'_, D>,
- goal: Goal<I, Self>,
- ) -> Result<Candidate<I>, NoSolution>;
}
impl<D, I> EvalCtxt<'_, D>
@@ -481,9 +485,6 @@
Some(TraitSolverLangItem::TransmuteTrait) => {
G::consider_builtin_transmute_candidate(self, goal)
}
- Some(TraitSolverLangItem::EffectsIntersection) => {
- G::consider_builtin_effects_intersection_candidate(self, goal)
- }
_ => Err(NoSolution),
}
};
@@ -602,6 +603,8 @@
));
}
+ candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty));
+
if kind != ty::Projection {
return;
}
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
new file mode 100644
index 0000000..8d57ad8
--- /dev/null
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -0,0 +1,345 @@
+//! Dealing with host effect goals, i.e. enforcing the constness in
+//! `T: const Trait` or `T: ~const Trait`.
+
+use rustc_type_ir::fast_reject::DeepRejectCtxt;
+use rustc_type_ir::inherent::*;
+use rustc_type_ir::{self as ty, Interner, elaborate};
+use tracing::instrument;
+
+use super::assembly::Candidate;
+use crate::delegate::SolverDelegate;
+use crate::solve::assembly::{self};
+use crate::solve::{
+ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution,
+ QueryResult,
+};
+
+impl<D, I> assembly::GoalKind<D> for ty::HostEffectPredicate<I>
+where
+ D: SolverDelegate<Interner = I>,
+ I: Interner,
+{
+ fn self_ty(self) -> I::Ty {
+ self.self_ty()
+ }
+
+ fn trait_ref(self, _: I) -> ty::TraitRef<I> {
+ self.trait_ref
+ }
+
+ fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self {
+ self.with_self_ty(cx, self_ty)
+ }
+
+ fn trait_def_id(self, _: I) -> I::DefId {
+ self.def_id()
+ }
+
+ fn probe_and_match_goal_against_assumption(
+ ecx: &mut EvalCtxt<'_, D>,
+ source: rustc_type_ir::solve::CandidateSource<I>,
+ goal: Goal<I, Self>,
+ assumption: <I as Interner>::Clause,
+ then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ if let Some(host_clause) = assumption.as_host_effect_clause() {
+ if host_clause.def_id() == goal.predicate.def_id()
+ && host_clause.host().satisfies(goal.predicate.host)
+ {
+ if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
+ goal.predicate.trait_ref.args,
+ host_clause.skip_binder().trait_ref.args,
+ ) {
+ return Err(NoSolution);
+ }
+
+ ecx.probe_trait_candidate(source).enter(|ecx| {
+ let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause);
+ ecx.eq(
+ goal.param_env,
+ goal.predicate.trait_ref,
+ assumption_trait_pred.trait_ref,
+ )?;
+ then(ecx)
+ })
+ } else {
+ Err(NoSolution)
+ }
+ } else {
+ Err(NoSolution)
+ }
+ }
+
+ /// Register additional assumptions for aliases corresponding to `~const` item bounds.
+ ///
+ /// Unlike item bounds, they are not simply implied by the well-formedness of the alias.
+ /// Instead, they only hold if the const conditons on the alias also hold. This is why
+ /// we also register the const conditions of the alias after matching the goal against
+ /// the assumption.
+ fn consider_additional_alias_assumptions(
+ ecx: &mut EvalCtxt<'_, D>,
+ goal: Goal<I, Self>,
+ alias_ty: ty::AliasTy<I>,
+ ) -> Vec<Candidate<I>> {
+ let cx = ecx.cx();
+ let mut candidates = vec![];
+
+ // FIXME(effects): We elaborate here because the implied const bounds
+ // aren't necessarily elaborated. We probably should prefix this query
+ // with `explicit_`...
+ for clause in elaborate::elaborate(
+ cx,
+ cx.implied_const_bounds(alias_ty.def_id)
+ .iter_instantiated(cx, alias_ty.args)
+ .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.host)),
+ ) {
+ candidates.extend(Self::probe_and_match_goal_against_assumption(
+ ecx,
+ CandidateSource::AliasBound,
+ goal,
+ clause,
+ |ecx| {
+ // Const conditions must hold for the implied const bound to hold.
+ ecx.add_goals(
+ GoalSource::Misc,
+ cx.const_conditions(alias_ty.def_id)
+ .iter_instantiated(cx, alias_ty.args)
+ .map(|trait_ref| {
+ goal.with(
+ cx,
+ trait_ref.to_host_effect_clause(cx, goal.predicate.host),
+ )
+ }),
+ );
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ },
+ ));
+ }
+
+ candidates
+ }
+
+ fn consider_impl_candidate(
+ ecx: &mut EvalCtxt<'_, D>,
+ goal: Goal<I, Self>,
+ impl_def_id: <I as Interner>::DefId,
+ ) -> Result<Candidate<I>, NoSolution> {
+ let cx = ecx.cx();
+
+ let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
+ if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
+ .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
+ {
+ return Err(NoSolution);
+ }
+
+ let impl_polarity = cx.impl_polarity(impl_def_id);
+ match impl_polarity {
+ ty::ImplPolarity::Negative => return Err(NoSolution),
+ ty::ImplPolarity::Reservation => {
+ unimplemented!("reservation impl for const trait: {:?}", goal)
+ }
+ ty::ImplPolarity::Positive => {}
+ };
+
+ if !cx.is_const_impl(impl_def_id) {
+ return Err(NoSolution);
+ }
+
+ ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
+ let impl_args = ecx.fresh_args_for_item(impl_def_id);
+ ecx.record_impl_args(impl_args);
+ let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
+
+ ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
+ let where_clause_bounds = cx
+ .predicates_of(impl_def_id)
+ .iter_instantiated(cx, impl_args)
+ .map(|pred| goal.with(cx, pred));
+ ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
+
+ // For this impl to be `const`, we need to check its `~const` bounds too.
+ let const_conditions = cx
+ .const_conditions(impl_def_id)
+ .iter_instantiated(cx, impl_args)
+ .map(|bound_trait_ref| {
+ goal.with(cx, bound_trait_ref.to_host_effect_clause(cx, goal.predicate.host))
+ });
+ ecx.add_goals(GoalSource::ImplWhereBound, const_conditions);
+
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ })
+ }
+
+ fn consider_error_guaranteed_candidate(
+ ecx: &mut EvalCtxt<'_, D>,
+ _guar: <I as Interner>::ErrorGuaranteed,
+ ) -> Result<Candidate<I>, NoSolution> {
+ ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
+ .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
+ }
+
+ fn consider_auto_trait_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("auto traits are never const")
+ }
+
+ fn consider_trait_alias_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("trait aliases are never const")
+ }
+
+ fn consider_builtin_sized_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("Sized is never const")
+ }
+
+ fn consider_builtin_copy_clone_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ todo!("Copy/Clone is not yet const")
+ }
+
+ fn consider_builtin_pointer_like_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("PointerLike is not const")
+ }
+
+ fn consider_builtin_fn_ptr_trait_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ todo!("Fn* are not yet const")
+ }
+
+ fn consider_builtin_fn_trait_candidates(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ _kind: rustc_type_ir::ClosureKind,
+ ) -> Result<Candidate<I>, NoSolution> {
+ todo!("Fn* are not yet const")
+ }
+
+ fn consider_builtin_async_fn_trait_candidates(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ _kind: rustc_type_ir::ClosureKind,
+ ) -> Result<Candidate<I>, NoSolution> {
+ todo!("AsyncFn* are not yet const")
+ }
+
+ fn consider_builtin_async_fn_kind_helper_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("AsyncFnKindHelper is not const")
+ }
+
+ fn consider_builtin_tuple_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("Tuple trait is not const")
+ }
+
+ fn consider_builtin_pointee_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("Pointee is not const")
+ }
+
+ fn consider_builtin_future_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("Future is not const")
+ }
+
+ fn consider_builtin_iterator_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ todo!("Iterator is not yet const")
+ }
+
+ fn consider_builtin_fused_iterator_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("FusedIterator is not const")
+ }
+
+ fn consider_builtin_async_iterator_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("AsyncIterator is not const")
+ }
+
+ fn consider_builtin_coroutine_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("Coroutine is not const")
+ }
+
+ fn consider_builtin_discriminant_kind_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("DiscriminantKind is not const")
+ }
+
+ fn consider_builtin_async_destruct_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("AsyncDestruct is not const")
+ }
+
+ fn consider_builtin_destruct_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("Destruct is not const")
+ }
+
+ fn consider_builtin_transmute_candidate(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Result<Candidate<I>, NoSolution> {
+ unreachable!("TransmuteFrom is not const")
+ }
+
+ fn consider_structural_builtin_unsize_candidates(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ ) -> Vec<Candidate<I>> {
+ unreachable!("Unsize is not const")
+ }
+}
+
+impl<D, I> EvalCtxt<'_, D>
+where
+ D: SolverDelegate<Interner = I>,
+ I: Interner,
+{
+ #[instrument(level = "trace", skip(self))]
+ pub(super) fn compute_host_effect_goal(
+ &mut self,
+ goal: Goal<I, ty::HostEffectPredicate<I>>,
+ ) -> QueryResult<I> {
+ let candidates = self.assemble_and_evaluate_candidates(goal);
+ self.merge_candidates(candidates)
+ }
+}
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 250174e..7608253 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -443,6 +443,9 @@
ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
self.compute_trait_goal(Goal { param_env, predicate })
}
+ ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
+ self.compute_host_effect_goal(Goal { param_env, predicate })
+ }
ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => {
self.compute_projection_goal(Goal { param_env, predicate })
}
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index a475a58..6793779 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -13,6 +13,7 @@
mod alias_relate;
mod assembly;
+mod effect_goals;
mod eval_ctxt;
pub mod inspect;
mod normalizes_to;
@@ -182,12 +183,6 @@
let (ct, ty) = goal.predicate;
let ct_ty = match ct.kind() {
- // FIXME: Ignore effect vars because canonicalization doesn't handle them correctly
- // and if we stall on the var then we wind up creating ambiguity errors in a probe
- // for this goal which contains an effect var. Which then ends up ICEing.
- ty::ConstKind::Infer(ty::InferConst::EffectVar(_)) => {
- return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
- }
ty::ConstKind::Infer(_) => {
return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
}
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 4d8b193..7287cdf 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -193,6 +193,14 @@
}
}
+ fn consider_additional_alias_assumptions(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ _alias_ty: ty::AliasTy<I>,
+ ) -> Vec<Candidate<I>> {
+ vec![]
+ }
+
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, NormalizesTo<I>>,
@@ -911,68 +919,6 @@
) -> Result<Candidate<I>, NoSolution> {
panic!("`TransmuteFrom` does not have an associated type: {:?}", goal)
}
-
- fn consider_builtin_effects_intersection_candidate(
- ecx: &mut EvalCtxt<'_, D>,
- goal: Goal<I, Self>,
- ) -> Result<Candidate<I>, NoSolution> {
- let ty::Tuple(types) = goal.predicate.self_ty().kind() else {
- return Err(NoSolution);
- };
-
- let cx = ecx.cx();
-
- let mut first_non_maybe = None;
- let mut non_maybe_count = 0;
- for ty in types.iter() {
- if !matches!(ty::EffectKind::try_from_ty(cx, ty), Some(ty::EffectKind::Maybe)) {
- first_non_maybe.get_or_insert(ty);
- non_maybe_count += 1;
- }
- }
-
- match non_maybe_count {
- 0 => {
- let ty = ty::EffectKind::Maybe.to_ty(cx);
- ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
- ecx.instantiate_normalizes_to_term(goal, ty.into());
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
- }
- 1 => {
- let ty = first_non_maybe.unwrap();
- ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
- ecx.instantiate_normalizes_to_term(goal, ty.into());
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
- }
- _ => {
- let mut min = ty::EffectKind::Maybe;
-
- for ty in types.iter() {
- // We can't find the intersection if the types used are generic.
- //
- // FIXME(effects): do we want to look at where clauses to get some
- // clue for the case where generic types are being used?
- let Some(kind) = ty::EffectKind::try_from_ty(cx, ty) else {
- return Err(NoSolution);
- };
-
- let Some(result) = ty::EffectKind::intersection(min, kind) else {
- return Err(NoSolution);
- };
-
- min = result;
- }
-
- let ty = min.to_ty(cx);
- ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
- ecx.instantiate_normalizes_to_term(goal, ty.into());
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
- }
- }
- }
}
impl<D, I> EvalCtxt<'_, D>
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index a8d6536..08cc89d 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -39,6 +39,14 @@
self.def_id()
}
+ fn consider_additional_alias_assumptions(
+ _ecx: &mut EvalCtxt<'_, D>,
+ _goal: Goal<I, Self>,
+ _alias_ty: ty::AliasTy<I>,
+ ) -> Vec<Candidate<I>> {
+ vec![]
+ }
+
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, TraitPredicate<I>>,
@@ -719,47 +727,6 @@
}
})
}
-
- fn consider_builtin_effects_intersection_candidate(
- ecx: &mut EvalCtxt<'_, D>,
- goal: Goal<I, Self>,
- ) -> Result<Candidate<I>, NoSolution> {
- if goal.predicate.polarity != ty::PredicatePolarity::Positive {
- return Err(NoSolution);
- }
-
- let ty::Tuple(types) = goal.predicate.self_ty().kind() else {
- return Err(NoSolution);
- };
-
- let cx = ecx.cx();
- let maybe_count = types
- .iter()
- .filter_map(|ty| ty::EffectKind::try_from_ty(cx, ty))
- .filter(|&ty| ty == ty::EffectKind::Maybe)
- .count();
-
- // Don't do concrete type check unless there are more than one type that will influence the result.
- // This would allow `(Maybe, T): Min` pass even if we know nothing about `T`.
- if types.len() - maybe_count > 1 {
- let mut min = ty::EffectKind::Maybe;
-
- for ty in types.iter() {
- let Some(kind) = ty::EffectKind::try_from_ty(ecx.cx(), ty) else {
- return Err(NoSolution);
- };
-
- let Some(result) = ty::EffectKind::intersection(min, kind) else {
- return Err(NoSolution);
- };
-
- min = result;
- }
- }
-
- ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
- .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
- }
}
impl<D, I> EvalCtxt<'_, D>
diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs
index 41108c9..e1f19be 100644
--- a/compiler/rustc_parse/src/lexer/diagnostics.rs
+++ b/compiler/rustc_parse/src/lexer/diagnostics.rs
@@ -85,7 +85,7 @@
}
}
- // Find the inner-most span candidate for final report
+ // Find the innermost span candidate for final report
let candidate_span =
matched_spans.into_iter().rev().find(|&(_, same_ident)| !same_ident).map(|(span, _)| span);
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index a938450..a1fe550 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -14,6 +14,7 @@
};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sync::Lrc;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, PErr, PResult, Subdiagnostic,
Suggestions, pluralize,
@@ -2437,7 +2438,7 @@
let mut labels = vec![];
while let TokenKind::Interpolated(nt) = &tok.kind {
let tokens = nt.tokens();
- labels.push(nt.clone());
+ labels.push(Lrc::clone(nt));
if let Some(tokens) = tokens
&& let tokens = tokens.to_attr_token_stream()
&& let tokens = tokens.0.deref()
diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml
index b45a8da..ed599145 100644
--- a/compiler/rustc_passes/Cargo.toml
+++ b/compiler/rustc_passes/Cargo.toml
@@ -5,6 +5,7 @@
[dependencies]
# tidy-alphabetical-start
+rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 3f98236..e5e70ba 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -99,6 +99,10 @@
passes_confusables = attribute should be applied to an inherent method
.label = not an inherent method
+passes_const_stable_not_stable =
+ attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
+ .label = attribute specified here
+
passes_continue_labeled_block =
`continue` pointing to a labeled block
.label = labeled blocks cannot be `continue`'d
@@ -465,10 +469,10 @@
`#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal
+
passes_missing_const_err =
- attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+ attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
.help = make the function or method const
- .label = attribute specified here
passes_missing_const_stab_attr =
{$descr} has missing const stability attribute
@@ -618,6 +622,10 @@
passes_repr_align_function =
`repr(align)` attributes on functions are unstable
+passes_repr_align_greater_than_target_max =
+ alignment must not be greater than `isize::MAX` bytes
+ .note = `isize::MAX` is {$size} for the current target
+
passes_repr_conflicting =
conflicting representation hints
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 8644284..8c4592c 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -34,6 +34,7 @@
use rustc_session::parse::feature_err;
use rustc_span::symbol::{Symbol, kw, sym};
use rustc_span::{BytePos, DUMMY_SP, Span};
+use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
@@ -262,7 +263,7 @@
| sym::cfg_attr
// need to be fixed
| sym::cfi_encoding // FIXME(cfi_encoding)
- | sym::pointee // FIXME(derive_smart_pointer)
+ | sym::pointee // FIXME(derive_coerce_pointee)
| sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
| sym::used // handled elsewhere to restrict to static items
| sym::repr // handled elsewhere to restrict to type decls items
@@ -918,12 +919,7 @@
};
match item_kind {
Some(ItemKind::Impl(i)) => {
- let is_valid = matches!(&i.self_ty.kind, hir::TyKind::Tup([_]))
- || if let hir::TyKind::BareFn(bare_fn_ty) = &i.self_ty.kind {
- bare_fn_ty.decl.inputs.len() == 1
- } else {
- false
- }
+ let is_valid = doc_fake_variadic_is_allowed_self_ty(i.self_ty)
|| if let Some(&[hir::GenericArg::Type(ty)]) = i
.of_trait
.as_ref()
@@ -1790,7 +1786,7 @@
| Target::Union
| Target::Enum
| Target::Fn
- | Target::Method(_) => continue,
+ | Target::Method(_) => {}
_ => {
self.dcx().emit_err(
errors::AttrApplication::StructEnumFunctionMethodUnion {
@@ -1800,6 +1796,8 @@
);
}
}
+
+ self.check_align_value(hint);
}
sym::packed => {
if target != Target::Struct && target != Target::Union {
@@ -1897,6 +1895,45 @@
}
}
+ fn check_align_value(&self, item: &MetaItemInner) {
+ match item.singleton_lit_list() {
+ Some((
+ _,
+ MetaItemLit {
+ kind: ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed), ..
+ },
+ )) => {
+ let val = literal.get() as u64;
+ if val > 2_u64.pow(29) {
+ // for values greater than 2^29, a different error will be emitted, make sure that happens
+ self.dcx().span_delayed_bug(
+ item.span(),
+ "alignment greater than 2^29 should be errored on elsewhere",
+ );
+ } else {
+ // only do this check when <= 2^29 to prevent duplicate errors:
+ // alignment greater than 2^29 not supported
+ // alignment is too large for the current target
+
+ let max =
+ Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64;
+ if val > max {
+ self.dcx().emit_err(errors::InvalidReprAlignForTarget {
+ span: item.span(),
+ size: max,
+ });
+ }
+ }
+ }
+
+ // if the attribute is malformed, singleton_lit_list may not be of the expected type or may be None
+ // but an error will have already been emitted, so this code should just skip such attributes
+ Some((_, _)) | None => {
+ self.dcx().span_delayed_bug(item.span(), "malformed repr(align(N))");
+ }
+ }
+ }
+
fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) {
let mut used_linker_span = None;
let mut used_compiler_span = None;
@@ -2002,7 +2039,7 @@
) {
match target {
Target::Fn | Target::Method(_)
- if self.tcx.is_const_fn_raw(hir_id.expect_owner().to_def_id()) => {}
+ if self.tcx.is_const_fn(hir_id.expect_owner().to_def_id()) => {}
// FIXME(#80564): We permit struct fields and match arms to have an
// `#[allow_internal_unstable]` attribute with just a lint, because we previously
// erroneously allowed it and some crates used it accidentally, to be compatible
@@ -2300,10 +2337,10 @@
&mut diag,
&cause,
None,
- Some(ValuePairs::PolySigs(ExpectedFound {
+ Some(param_env.and(ValuePairs::PolySigs(ExpectedFound {
expected: ty::Binder::dummy(expected_sig),
found: ty::Binder::dummy(sig),
- })),
+ }))),
terr,
false,
);
@@ -2630,3 +2667,20 @@
},
}
}
+
+fn doc_fake_variadic_is_allowed_self_ty(self_ty: &hir::Ty<'_>) -> bool {
+ matches!(&self_ty.kind, hir::TyKind::Tup([_]))
+ || if let hir::TyKind::BareFn(bare_fn_ty) = &self_ty.kind {
+ bare_fn_ty.decl.inputs.len() == 1
+ } else {
+ false
+ }
+ || (if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &self_ty.kind
+ && let Some(&[hir::GenericArg::Type(ty)]) =
+ path.segments.last().map(|last| last.args().args)
+ {
+ doc_fake_variadic_is_allowed_self_ty(ty)
+ } else {
+ false
+ })
+}
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index af17fbf..b1db66f 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -7,6 +7,7 @@
use hir::ItemKind;
use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
+use rustc_abi::FieldIdx;
use rustc_data_structures::unord::UnordSet;
use rustc_errors::MultiSpan;
use rustc_hir as hir;
@@ -22,7 +23,6 @@
use rustc_session::lint;
use rustc_session::lint::builtin::DEAD_CODE;
use rustc_span::symbol::{Symbol, sym};
-use rustc_target::abi::FieldIdx;
use crate::errors::{
ChangeFields, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo, UselessAssignment,
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 042e50d..8bd767c1 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -567,6 +567,15 @@
pub hint_spans: Vec<Span>,
}
+#[derive(Diagnostic)]
+#[diag(passes_repr_align_greater_than_target_max, code = E0589)]
+#[note]
+pub(crate) struct InvalidReprAlignForTarget {
+ #[primary_span]
+ pub span: Span,
+ pub size: u64,
+}
+
#[derive(LintDiagnostic)]
#[diag(passes_repr_conflicting, code = E0566)]
pub(crate) struct ReprConflictingLint;
@@ -1574,12 +1583,20 @@
pub span: Span,
pub feature: Symbol,
}
+
#[derive(Diagnostic)]
#[diag(passes_missing_const_err)]
pub(crate) struct MissingConstErr {
#[primary_span]
#[help]
pub fn_sig_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_const_stable_not_stable)]
+pub(crate) struct ConstStableNotStable {
+ #[primary_span]
+ pub fn_sig_span: Span,
#[label]
pub const_span: Span,
}
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 93729a7..0b6cf82 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -1,3 +1,4 @@
+use rustc_abi::{HasDataLayout, TargetDataLayout};
use rustc_ast::Attribute;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
@@ -7,7 +8,6 @@
use rustc_span::Span;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
-use rustc_target::abi::{HasDataLayout, TargetDataLayout};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::infer::TyCtxtInferExt;
use rustc_trait_selection::traits;
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index a176b2b..f69cc74 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -10,13 +10,13 @@
};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
-use rustc_feature::ACCEPTED_LANG_FEATURES;
+use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
+use rustc_hir::{Constness, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
use rustc_middle::middle::privacy::EffectiveVisibilities;
@@ -27,7 +27,6 @@
use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
use rustc_span::Span;
use rustc_span::symbol::{Symbol, sym};
-use rustc_target::spec::abi::Abi;
use tracing::{debug, info};
use crate::errors;
@@ -107,6 +106,7 @@
def_id: LocalDefId,
item_sp: Span,
fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
+ is_foreign_item: bool,
kind: AnnotationKind,
inherit_deprecation: InheritDeprecation,
inherit_const_stability: InheritConstStability,
@@ -163,30 +163,62 @@
}
let stab = attr::find_stability(self.tcx.sess, attrs, item_sp);
- let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item_sp);
+ let const_stab = attr::find_const_stability(
+ self.tcx.sess,
+ attrs,
+ item_sp,
+ fn_sig.is_some_and(|s| s.header.is_const()),
+ );
let body_stab = attr::find_body_stability(self.tcx.sess, attrs);
- let mut const_span = None;
- let const_stab = const_stab.map(|(const_stab, const_span_node)| {
- self.index.const_stab_map.insert(def_id, const_stab);
- const_span = Some(const_span_node);
- const_stab
- });
-
- // If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI,
- // check if the function/method is const or the parent impl block is const
- if let (Some(const_span), Some(fn_sig)) = (const_span, fn_sig)
- && fn_sig.header.abi != Abi::RustIntrinsic
+ // If the current node is a function with const stability attributes (directly given or
+ // implied), check if the function/method is const or the parent impl block is const.
+ if let Some(fn_sig) = fn_sig
&& !fn_sig.header.is_const()
- && (!self.in_trait_impl || !self.tcx.is_const_fn_raw(def_id.to_def_id()))
+ // We have to exclude foreign items as they might be intrinsics. Sadly we can't check
+ // their ABI; `fn_sig.abi` is *not* correct for foreign functions.
+ && !is_foreign_item
+ && const_stab.is_some()
+ && (!self.in_trait_impl || !self.tcx.is_const_fn(def_id.to_def_id()))
+ {
+ self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
+ }
+
+ // If this is marked const *stable*, it must also be regular-stable.
+ if let Some((const_stab, const_span)) = const_stab
+ && let Some(fn_sig) = fn_sig
+ && const_stab.is_const_stable()
+ && !stab.is_some_and(|(s, _)| s.is_stable())
{
self.tcx
.dcx()
- .emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span, const_span });
+ .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span });
}
+ // Stable *language* features shouldn't be used as unstable library features.
+ // (Not doing this for stable library features is checked by tidy.)
+ if let Some((
+ ConstStability { level: Unstable { .. }, feature: Some(feature), .. },
+ const_span,
+ )) = const_stab
+ {
+ if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
+ self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
+ span: const_span,
+ item_sp,
+ });
+ }
+ }
+
+ let const_stab = const_stab.map(|(const_stab, _span)| {
+ self.index.const_stab_map.insert(def_id, const_stab);
+ const_stab
+ });
+
// `impl const Trait for Type` items forward their const stability to their
// immediate children.
+ // FIXME(effects): how is this supposed to interact with `#[rustc_const_stable_indirect]`?
+ // Currently, once that is set, we do not inherit anything from the parent any more.
if const_stab.is_none() {
debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
if let Some(parent) = self.parent_const_stab {
@@ -247,6 +279,8 @@
}
}
+ // Stable *language* features shouldn't be used as unstable library features.
+ // (Not doing this for stable library features is checked by tidy.)
if let Stability { level: Unstable { .. }, feature } = stab {
if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
self.tcx
@@ -260,21 +294,13 @@
self.index.implications.insert(implied_by, feature);
}
- if let Some(ConstStability { level: Unstable { .. }, feature, .. }) = const_stab {
- if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
- self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
- span: const_span.unwrap(), // If const_stab contains Some(..), same is true for const_span
- item_sp,
- });
- }
- }
if let Some(ConstStability {
level: Unstable { implied_by: Some(implied_by), .. },
feature,
..
}) = const_stab
{
- self.index.implications.insert(implied_by, feature);
+ self.index.implications.insert(implied_by, feature.unwrap());
}
self.index.stab_map.insert(def_id, stab);
@@ -372,6 +398,7 @@
ctor_def_id,
i.span,
None,
+ /* is_foreign_item */ false,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@@ -390,6 +417,7 @@
i.owner_id.def_id,
i.span,
fn_sig,
+ /* is_foreign_item */ false,
kind,
InheritDeprecation::Yes,
const_stab_inherit,
@@ -409,6 +437,7 @@
ti.owner_id.def_id,
ti.span,
fn_sig,
+ /* is_foreign_item */ false,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@@ -432,6 +461,7 @@
ii.owner_id.def_id,
ii.span,
fn_sig,
+ /* is_foreign_item */ false,
kind,
InheritDeprecation::Yes,
InheritConstStability::No,
@@ -447,6 +477,7 @@
var.def_id,
var.span,
None,
+ /* is_foreign_item */ false,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@@ -457,6 +488,7 @@
ctor_def_id,
var.span,
None,
+ /* is_foreign_item */ false,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@@ -475,6 +507,7 @@
s.def_id,
s.span,
None,
+ /* is_foreign_item */ false,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@@ -486,10 +519,15 @@
}
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
+ let fn_sig = match &i.kind {
+ rustc_hir::ForeignItemKind::Fn(fn_sig, ..) => Some(fn_sig),
+ _ => None,
+ };
self.annotate(
i.owner_id.def_id,
i.span,
- None,
+ fn_sig,
+ /* is_foreign_item */ true,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@@ -512,6 +550,7 @@
p.def_id,
p.span,
None,
+ /* is_foreign_item */ false,
kind,
InheritDeprecation::No,
InheritConstStability::No,
@@ -540,7 +579,9 @@
}
}
- fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
+ fn check_missing_or_wrong_const_stability(&self, def_id: LocalDefId, span: Span) {
+ // The visitor runs for "unstable-if-unmarked" crates, but we don't yet support
+ // that on the const side.
if !self.tcx.features().staged_api() {
return;
}
@@ -554,10 +595,11 @@
}
let is_const = self.tcx.is_const_fn(def_id.to_def_id())
- || self.tcx.is_const_trait_impl_raw(def_id.to_def_id());
+ || self.tcx.is_const_trait_impl(def_id.to_def_id());
let is_stable =
self.tcx.lookup_stability(def_id).is_some_and(|stability| stability.level.is_stable());
- let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none();
+ let missing_const_stability_attribute =
+ self.tcx.lookup_const_stability(def_id).is_none_or(|s| s.feature.is_none());
if is_const && is_stable && missing_const_stability_attribute {
let descr = self.tcx.def_descr(def_id.to_def_id());
@@ -587,7 +629,7 @@
}
// Ensure stable `const fn` have a const stability attribute.
- self.check_missing_const_stability(i.owner_id.def_id, i.span);
+ self.check_missing_or_wrong_const_stability(i.owner_id.def_id, i.span);
intravisit::walk_item(self, i)
}
@@ -601,7 +643,7 @@
let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id());
if self.tcx.impl_trait_ref(impl_def_id).is_none() {
self.check_missing_stability(ii.owner_id.def_id, ii.span);
- self.check_missing_const_stability(ii.owner_id.def_id, ii.span);
+ self.check_missing_or_wrong_const_stability(ii.owner_id.def_id, ii.span);
}
intravisit::walk_impl_item(self, ii);
}
@@ -670,6 +712,7 @@
CRATE_DEF_ID,
tcx.hir().span(CRATE_HIR_ID),
None,
+ /* is_foreign_item */ false,
AnnotationKind::Required,
InheritDeprecation::Yes,
InheritConstStability::No,
@@ -732,12 +775,23 @@
// For implementations of traits, check the stability of each item
// individually as it's possible to have a stable trait with unstable
// items.
- hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
+ hir::ItemKind::Impl(hir::Impl {
+ constness,
+ of_trait: Some(ref t),
+ self_ty,
+ items,
+ ..
+ }) => {
let features = self.tcx.features();
if features.staged_api() {
let attrs = self.tcx.hir().attrs(item.hir_id());
let stab = attr::find_stability(self.tcx.sess, attrs, item.span);
- let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span);
+ let const_stab = attr::find_const_stability(
+ self.tcx.sess,
+ attrs,
+ item.span,
+ matches!(constness, Constness::Const),
+ );
// If this impl block has an #[unstable] attribute, give an
// error if all involved types and traits are stable, because
@@ -763,7 +817,7 @@
// `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
// needs to have an error emitted.
if features.const_trait_impl()
- && self.tcx.is_const_trait_impl_raw(item.owner_id.to_def_id())
+ && self.tcx.is_const_trait_impl(item.owner_id.to_def_id())
&& const_stab.is_some_and(|(stab, _)| stab.is_const_stable())
{
self.tcx.dcx().emit_err(errors::TraitImplConstStable { span: item.span });
@@ -937,25 +991,25 @@
let enabled_lang_features = tcx.features().enabled_lang_features();
let mut lang_features = UnordSet::default();
- for &(feature, span, since) in enabled_lang_features {
- if let Some(since) = since {
+ for EnabledLangFeature { gate_name, attr_sp, stable_since } in enabled_lang_features {
+ if let Some(version) = stable_since {
// Warn if the user has enabled an already-stable lang feature.
- unnecessary_stable_feature_lint(tcx, span, feature, since);
+ unnecessary_stable_feature_lint(tcx, *attr_sp, *gate_name, *version);
}
- if !lang_features.insert(feature) {
+ if !lang_features.insert(gate_name) {
// Warn if the user enables a lang feature multiple times.
- tcx.dcx().emit_err(errors::DuplicateFeatureErr { span, feature });
+ tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
}
}
let enabled_lib_features = tcx.features().enabled_lib_features();
let mut remaining_lib_features = FxIndexMap::default();
- for (feature, span) in enabled_lib_features {
- if remaining_lib_features.contains_key(&feature) {
+ for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features {
+ if remaining_lib_features.contains_key(gate_name) {
// Warn if the user enables a lib feature multiple times.
- tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature });
+ tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
}
- remaining_lib_features.insert(feature, *span);
+ remaining_lib_features.insert(*gate_name, *attr_sp);
}
// `stdbuild` has special handling for `libc`, so we need to
// recognise the feature when building std.
@@ -987,7 +1041,7 @@
/// time, less loading from metadata is performed and thus compiler performance is improved.
fn check_features<'tcx>(
tcx: TyCtxt<'tcx>,
- remaining_lib_features: &mut FxIndexMap<&Symbol, Span>,
+ remaining_lib_features: &mut FxIndexMap<Symbol, Span>,
remaining_implications: &mut UnordMap<Symbol, Symbol>,
defined_features: &LibFeatures,
all_implications: &UnordMap<Symbol, Symbol>,
@@ -1057,7 +1111,7 @@
}
for (feature, span) in remaining_lib_features {
- tcx.dcx().emit_err(errors::UnknownFeature { span, feature: *feature });
+ tcx.dcx().emit_err(errors::UnknownFeature { span, feature });
}
for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() {
diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml
index 34fb1bd..f98e424 100644
--- a/compiler/rustc_pattern_analysis/Cargo.toml
+++ b/compiler/rustc_pattern_analysis/Cargo.toml
@@ -6,6 +6,8 @@
[dependencies]
# tidy-alphabetical-start
rustc-hash = "2.0.0"
+
+rustc_abi = { path = "../rustc_abi", optional = true }
rustc_apfloat = "0.2.0"
rustc_arena = { path = "../rustc_arena", optional = true }
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
@@ -29,6 +31,7 @@
[features]
default = ["rustc"]
rustc = [
+ "dep:rustc_abi",
"dep:rustc_arena",
"dep:rustc_data_structures",
"dep:rustc_errors",
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 0e132b2..9ea5023 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -1,6 +1,7 @@
use std::fmt;
use std::iter::once;
+use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx};
use rustc_arena::DroplessArena;
use rustc_hir::HirId;
use rustc_hir::def_id::DefId;
@@ -15,7 +16,6 @@
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
-use rustc_target::abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx};
use crate::constructor::Constructor::*;
use crate::constructor::{
diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs
index 17e389d..7649f72 100644
--- a/compiler/rustc_pattern_analysis/src/rustc/print.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs
@@ -11,10 +11,10 @@
use std::fmt;
+use rustc_abi::{FieldIdx, VariantIdx};
use rustc_middle::bug;
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
use rustc_span::sym;
-use rustc_target::abi::{FieldIdx, VariantIdx};
#[derive(Clone, Debug)]
pub(crate) struct FieldPat {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 7827975..0595414 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -137,6 +137,10 @@
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
self.visit_trait(trait_ref)
}
+ ty::ClauseKind::HostEffect(pred) => {
+ try_visit!(self.visit_trait(pred.trait_ref));
+ pred.host.visit_with(self)
+ }
ty::ClauseKind::Projection(ty::ProjectionPredicate {
projection_term: projection_ty,
term,
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index cd7725d..5e30f17 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -134,7 +134,7 @@
encoder,
record_graph,
record_stats,
- prev_graph.clone(),
+ Arc::clone(&prev_graph),
);
let colors = DepNodeColorMap::new(prev_graph_node_count);
diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
index 29a28b1..5a72e80 100644
--- a/compiler/rustc_query_system/src/ich/impls_syntax.rs
+++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs
@@ -111,13 +111,25 @@
impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
// Unfortunately we cannot exhaustively list fields here, since the
- // struct is macro generated.
+ // struct has private fields (to ensure its invariant is maintained)
self.enabled_lang_features().hash_stable(hcx, hasher);
self.enabled_lib_features().hash_stable(hcx, hasher);
+ }
+}
- // FIXME: why do we hash something that is a compile-time constant?
- for feature in rustc_feature::UNSTABLE_LANG_FEATURES.iter() {
- feature.name.hash_stable(hcx, hasher);
- }
+impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::EnabledLangFeature {
+ fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
+ let rustc_feature::EnabledLangFeature { gate_name, attr_sp, stable_since } = self;
+ gate_name.hash_stable(hcx, hasher);
+ attr_sp.hash_stable(hcx, hasher);
+ stable_since.hash_stable(hcx, hasher);
+ }
+}
+
+impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::EnabledLibFeature {
+ fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
+ let rustc_feature::EnabledLibFeature { gate_name, attr_sp } = self;
+ gate_name.hash_stable(hcx, hasher);
+ attr_sp.hash_stable(hcx, hasher);
}
}
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index ca3efc1..5af41b9 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -237,7 +237,7 @@
// the `wait` call below, by 1) the `set` method or 2) by deadlock detection.
// Both of these will remove it from the `waiters` list before resuming
// this thread.
- info.waiters.push(waiter.clone());
+ info.waiters.push(Arc::clone(waiter));
// If this detects a deadlock and the deadlock handler wants to resume this thread
// we have to be in the `wait` call. This is ensured by the deadlock handler
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 0ca6bb8..bdf940a 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -177,7 +177,9 @@
let loaded_macro = self.cstore().load_macro_untracked(def_id, self.tcx);
let macro_data = match loaded_macro {
- LoadedMacro::MacroDef(item, edition) => self.compile_macro(&item, edition),
+ LoadedMacro::MacroDef { def, ident, attrs, span, edition } => {
+ self.compile_macro(&def, ident, &attrs, span, ast::DUMMY_NODE_ID, edition)
+ }
LoadedMacro::ProcMacro(ext) => MacroData::new(Lrc::new(ext)),
};
@@ -1321,7 +1323,7 @@
// Visit attributes after items for backward compatibility.
// This way they can use `macro_rules` defined later.
self.visit_vis(&item.vis);
- self.visit_ident(item.ident);
+ self.visit_ident(&item.ident);
item.kind.walk(item, AssocCtxt::Trait, self);
visit::walk_list!(self, visit_attribute, &item.attrs);
}
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 0047f2c..a825458 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -199,8 +199,10 @@
},
ItemKind::Const(..) => DefKind::Const,
ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn,
- ItemKind::MacroDef(..) => {
- let macro_data = self.resolver.compile_macro(i, self.resolver.tcx.sess.edition());
+ ItemKind::MacroDef(def) => {
+ let edition = self.resolver.tcx.sess.edition();
+ let macro_data =
+ self.resolver.compile_macro(def, i.ident, &i.attrs, i.span, i.id, edition);
let macro_kind = macro_data.ext.macro_kind();
opt_macro_data = Some(macro_data);
DefKind::Macro(macro_kind)
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 033cd7d..adb0ba7 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1205,7 +1205,7 @@
}
fn visit_assoc_item_constraint(&mut self, constraint: &'ast AssocItemConstraint) {
- self.visit_ident(constraint.ident);
+ self.visit_ident(&constraint.ident);
if let Some(ref gen_args) = constraint.gen_args {
// Forbid anonymous lifetimes in GAT parameters until proper semantics are decided.
self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
@@ -4582,7 +4582,7 @@
fn resolve_expr_field(&mut self, f: &'ast ExprField, e: &'ast Expr) {
self.resolve_expr(&f.expr, Some(e));
- self.visit_ident(f.ident);
+ self.visit_ident(&f.ident);
walk_list!(self, visit_attribute, f.attrs.iter());
}
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 35d491c..9abb318 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1694,9 +1694,9 @@
fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc<SyntaxExtension> {
match macro_kind {
- MacroKind::Bang => self.dummy_ext_bang.clone(),
- MacroKind::Derive => self.dummy_ext_derive.clone(),
- MacroKind::Attr => self.non_macro_attr.ext.clone(),
+ MacroKind::Bang => Lrc::clone(&self.dummy_ext_bang),
+ MacroKind::Derive => Lrc::clone(&self.dummy_ext_derive),
+ MacroKind::Attr => Lrc::clone(&self.non_macro_attr.ext),
}
}
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index a9ebffea..0b4d0e0 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -826,7 +826,7 @@
}
_ => None,
},
- None => self.get_macro(res).map(|macro_data| macro_data.ext.clone()),
+ None => self.get_macro(res).map(|macro_data| Lrc::clone(¯o_data.ext)),
};
Ok((ext, res))
}
@@ -1122,9 +1122,25 @@
/// Compile the macro into a `SyntaxExtension` and its rule spans.
///
/// Possibly replace its expander to a pre-defined one for built-in macros.
- pub(crate) fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> MacroData {
- let (mut ext, mut rule_spans) =
- compile_declarative_macro(self.tcx.sess, self.tcx.features(), item, edition);
+ pub(crate) fn compile_macro(
+ &mut self,
+ macro_def: &ast::MacroDef,
+ ident: Ident,
+ attrs: &[ast::Attribute],
+ span: Span,
+ node_id: NodeId,
+ edition: Edition,
+ ) -> MacroData {
+ let (mut ext, mut rule_spans) = compile_declarative_macro(
+ self.tcx.sess,
+ self.tcx.features(),
+ macro_def,
+ ident,
+ attrs,
+ span,
+ node_id,
+ edition,
+ );
if let Some(builtin_name) = ext.builtin_name {
// The macro was marked with `#[rustc_builtin_macro]`.
@@ -1132,28 +1148,22 @@
// The macro is a built-in, replace its expander function
// while still taking everything else from the source code.
// If we already loaded this builtin macro, give a better error message than 'no such builtin macro'.
- match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) {
+ match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(span)) {
BuiltinMacroState::NotYetSeen(builtin_ext) => {
ext.kind = builtin_ext;
rule_spans = Vec::new();
}
- BuiltinMacroState::AlreadySeen(span) => {
- self.dcx().emit_err(errors::AttemptToDefineBuiltinMacroTwice {
- span: item.span,
- note_span: span,
- });
+ BuiltinMacroState::AlreadySeen(note_span) => {
+ self.dcx()
+ .emit_err(errors::AttemptToDefineBuiltinMacroTwice { span, note_span });
}
}
} else {
- self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName {
- span: item.span,
- ident: item.ident,
- });
+ self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident });
}
}
- let ItemKind::MacroDef(def) = &item.kind else { unreachable!() };
- MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: def.macro_rules }
+ MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: macro_def.macro_rules }
}
fn path_accessible(
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index 75cc8f1..e998369 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -7,6 +7,7 @@
# tidy-alphabetical-start
bitflags = "2.4.1"
getopts = "0.2"
+rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs
index 7a32c0c..f3c2199 100644
--- a/compiler/rustc_session/src/code_stats.rs
+++ b/compiler/rustc_session/src/code_stats.rs
@@ -1,10 +1,10 @@
use std::cmp;
+use rustc_abi::{Align, Size};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lock;
use rustc_span::Symbol;
use rustc_span::def_id::DefId;
-use rustc_target::abi::{Align, Size};
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct VariantInfo {
diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs
index ccc0172..31ef2bd 100644
--- a/compiler/rustc_session/src/config/cfg.rs
+++ b/compiler/rustc_session/src/config/cfg.rs
@@ -23,12 +23,12 @@
use std::hash::Hash;
use std::iter;
+use rustc_abi::Align;
use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_lint_defs::BuiltinLintDiag;
use rustc_lint_defs::builtin::EXPLICIT_BUILTIN_CFGS_IN_FLAGS;
use rustc_span::symbol::{Symbol, sym};
-use rustc_target::abi::Align;
use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, TARGETS, Target, TargetTriple};
use crate::Session;
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 3d44810..f20ae85 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -241,7 +241,7 @@
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let emitter = Box::new(
HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle)
- .sm(Some(sm.clone())),
+ .sm(Some(Lrc::clone(&sm))),
);
let dcx = DiagCtxt::new(emitter);
ParseSess::with_dcx(dcx, sm)
@@ -278,7 +278,7 @@
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let emitter = Box::new(HumanEmitter::new(
stderr_destination(ColorConfig::Auto),
- fallback_bundle.clone(),
+ Lrc::clone(&fallback_bundle),
));
let fatal_dcx = DiagCtxt::new(emitter);
let dcx = DiagCtxt::new(Box::new(SilentEmitter {
@@ -297,7 +297,7 @@
}
pub fn clone_source_map(&self) -> Lrc<SourceMap> {
- self.source_map.clone()
+ Lrc::clone(&self.source_map)
}
pub fn buffer_lint(
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 1963cf4..4543453 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1036,7 +1036,8 @@
sopts.unstable_opts.translate_directionality_markers,
);
let source_map = rustc_span::source_map::get_source_map().unwrap();
- let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle);
+ let emitter =
+ default_emitter(&sopts, registry, Lrc::clone(&source_map), bundle, fallback_bundle);
let mut dcx =
DiagCtxt::new(emitter).with_flags(sopts.unstable_opts.dcx_flags(can_emit_warnings));
@@ -1079,7 +1080,7 @@
let target_tlib_path = if host_triple == target_triple {
// Use the same `SearchPath` if host and target triple are identical to avoid unnecessary
// rescanning of the target lib path and an unnecessary allocation.
- host_tlib_path.clone()
+ Lrc::clone(&host_tlib_path)
} else {
Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, target_triple))
};
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 55b4781..a326e85 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -170,7 +170,7 @@
stable_mir::mir::mono::StaticDef(self.create_def_id(did))
}
- pub(crate) fn layout_id(&mut self, layout: rustc_target::abi::Layout<'tcx>) -> Layout {
+ pub(crate) fn layout_id(&mut self, layout: rustc_abi::Layout<'tcx>) -> Layout {
self.layouts.create_or_fetch(layout)
}
}
diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs
index 0d8740a..5c09879 100644
--- a/compiler/rustc_smir/src/rustc_smir/alloc.rs
+++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs
@@ -1,3 +1,4 @@
+use rustc_abi::{Align, Size};
use rustc_middle::mir::ConstValue;
use rustc_middle::mir::interpret::{AllocRange, Pointer, alloc_range};
use stable_mir::Error;
@@ -7,7 +8,7 @@
use crate::rustc_smir::{Stable, Tables};
/// Creates new empty `Allocation` from given `Align`.
-fn new_empty_allocation(align: rustc_target::abi::Align) -> Allocation {
+fn new_empty_allocation(align: Align) -> Allocation {
Allocation {
bytes: Vec::new(),
provenance: ProvenanceMap { ptrs: Vec::new() },
@@ -45,7 +46,7 @@
.align;
let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi);
allocation
- .write_scalar(&tables.tcx, alloc_range(rustc_target::abi::Size::ZERO, size), scalar)
+ .write_scalar(&tables.tcx, alloc_range(Size::ZERO, size), scalar)
.map_err(|e| e.stable(tables))?;
allocation.stable(tables)
}
@@ -59,7 +60,7 @@
}
ConstValue::Slice { data, meta } => {
let alloc_id = tables.tcx.reserve_and_set_memory_alloc(data);
- let ptr = Pointer::new(alloc_id.into(), rustc_target::abi::Size::ZERO);
+ let ptr = Pointer::new(alloc_id.into(), Size::ZERO);
let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx);
let scalar_meta =
rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx);
@@ -72,7 +73,7 @@
allocation
.write_scalar(
&tables.tcx,
- alloc_range(rustc_target::abi::Size::ZERO, tables.tcx.data_layout.pointer_size),
+ alloc_range(Size::ZERO, tables.tcx.data_layout.pointer_size),
scalar_ptr,
)
.map_err(|e| e.stable(tables))?;
@@ -112,10 +113,7 @@
.map(Some)
.collect();
for (i, b) in bytes.iter_mut().enumerate() {
- if !alloc
- .init_mask()
- .get(rustc_target::abi::Size::from_bytes(i + alloc_range.start.bytes_usize()))
- {
+ if !alloc.init_mask().get(Size::from_bytes(i + alloc_range.start.bytes_usize())) {
*b = None;
}
}
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 8fa8f2a..9514ec8 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -161,8 +161,7 @@
fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
let mut tables = self.0.borrow_mut();
let def_id = tables[def_id];
- let GenericPredicates { parent, predicates, effects_min_tys: _ } =
- tables.tcx.predicates_of(def_id);
+ let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id);
stable_mir::ty::GenericPredicates {
parent: parent.map(|did| tables.trait_def(did)),
predicates: predicates
@@ -183,8 +182,7 @@
) -> stable_mir::ty::GenericPredicates {
let mut tables = self.0.borrow_mut();
let def_id = tables[def_id];
- let GenericPredicates { parent, predicates, effects_min_tys: _ } =
- tables.tcx.explicit_predicates_of(def_id);
+ let GenericPredicates { parent, predicates } = tables.tcx.explicit_predicates_of(def_id);
stable_mir::ty::GenericPredicates {
parent: parent.map(|did| tables.trait_def(did)),
predicates: predicates
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
index 06f01ae..410bf0f 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
@@ -1,9 +1,9 @@
-//! Conversion of internal Rust compiler `rustc_target::abi` and `rustc_abi` items to stable ones.
+//! Conversion of internal Rust compiler `rustc_target` and `rustc_abi` items to stable ones.
#![allow(rustc::usage_of_qualified_ty)]
use rustc_middle::ty;
-use rustc_target::abi::call::Conv;
+use rustc_target::callconv::{self, Conv};
use stable_mir::abi::{
AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout,
LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape,
@@ -15,7 +15,7 @@
use crate::rustc_smir::{Stable, Tables};
-impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
+impl<'tcx> Stable<'tcx> for rustc_abi::VariantIdx {
type T = VariantIdx;
fn stable(&self, _: &mut Tables<'_>) -> Self::T {
VariantIdx::to_val(self.as_usize())
@@ -33,7 +33,7 @@
}
}
-impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> {
+impl<'tcx> Stable<'tcx> for rustc_abi::TyAndLayout<'tcx, ty::Ty<'tcx>> {
type T = TyAndLayout;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -41,7 +41,7 @@
}
}
-impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> {
+impl<'tcx> Stable<'tcx> for rustc_abi::Layout<'tcx> {
type T = Layout;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -49,9 +49,7 @@
}
}
-impl<'tcx> Stable<'tcx>
- for rustc_abi::LayoutS<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
-{
+impl<'tcx> Stable<'tcx> for rustc_abi::LayoutData<rustc_abi::FieldIdx, rustc_abi::VariantIdx> {
type T = LayoutShape;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -65,7 +63,7 @@
}
}
-impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> {
+impl<'tcx> Stable<'tcx> for callconv::FnAbi<'tcx, ty::Ty<'tcx>> {
type T = FnAbi;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -81,7 +79,7 @@
}
}
-impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> {
+impl<'tcx> Stable<'tcx> for callconv::ArgAbi<'tcx, ty::Ty<'tcx>> {
type T = ArgAbi;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -93,7 +91,7 @@
}
}
-impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv {
+impl<'tcx> Stable<'tcx> for callconv::Conv {
type T = CallConvention;
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
@@ -122,31 +120,29 @@
}
}
-impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode {
+impl<'tcx> Stable<'tcx> for callconv::PassMode {
type T = PassMode;
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
match self {
- rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore,
- rustc_target::abi::call::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)),
- rustc_target::abi::call::PassMode::Pair(first, second) => {
+ callconv::PassMode::Ignore => PassMode::Ignore,
+ callconv::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)),
+ callconv::PassMode::Pair(first, second) => {
PassMode::Pair(opaque(first), opaque(second))
}
- rustc_target::abi::call::PassMode::Cast { pad_i32, cast } => {
+ callconv::PassMode::Cast { pad_i32, cast } => {
PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) }
}
- rustc_target::abi::call::PassMode::Indirect { attrs, meta_attrs, on_stack } => {
- PassMode::Indirect {
- attrs: opaque(attrs),
- meta_attrs: opaque(meta_attrs),
- on_stack: *on_stack,
- }
- }
+ callconv::PassMode::Indirect { attrs, meta_attrs, on_stack } => PassMode::Indirect {
+ attrs: opaque(attrs),
+ meta_attrs: opaque(meta_attrs),
+ on_stack: *on_stack,
+ },
}
}
}
-impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_target::abi::FieldIdx> {
+impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_abi::FieldIdx> {
type T = FieldsShape;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -163,9 +159,7 @@
}
}
-impl<'tcx> Stable<'tcx>
- for rustc_abi::Variants<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
-{
+impl<'tcx> Stable<'tcx> for rustc_abi::Variants<rustc_abi::FieldIdx, rustc_abi::VariantIdx> {
type T = VariantsShape;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -185,7 +179,7 @@
}
}
-impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_target::abi::VariantIdx> {
+impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_abi::VariantIdx> {
type T = TagEncoding;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index dbae4b7..820d8a6 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -691,11 +691,7 @@
type T = stable_mir::ty::Allocation;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
- alloc::allocation_filter(
- self,
- alloc_range(rustc_target::abi::Size::ZERO, self.size()),
- tables,
- )
+ alloc::allocation_filter(self, alloc_range(rustc_abi::Size::ZERO, self.size()), tables)
}
}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index ef2ee9a..8f05f859 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -588,7 +588,6 @@
.has_late_bound_regions
.as_ref()
.map(|late_bound_regions| late_bound_regions.stable(tables)),
- host_effect_index: self.host_effect_index,
}
}
}
@@ -603,7 +602,7 @@
ty::GenericParamDefKind::Type { has_default, synthetic } => {
GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic }
}
- ty::GenericParamDefKind::Const { has_default, is_host_effect: _, synthetic: _ } => {
+ ty::GenericParamDefKind::Const { has_default, synthetic: _ } => {
GenericParamDefKind::Const { has_default: *has_default }
}
}
@@ -690,6 +689,9 @@
ClauseKind::ConstEvaluatable(const_) => {
stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables))
}
+ ClauseKind::HostEffect(..) => {
+ todo!()
+ }
}
}
}
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 9b27b94..9032156 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -36,7 +36,7 @@
pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
pub(crate) ty_consts: IndexMap<ty::Const<'tcx>, TyConstId>,
pub(crate) mir_consts: IndexMap<mir::Const<'tcx>, MirConstId>,
- pub(crate) layouts: IndexMap<rustc_target::abi::Layout<'tcx>, Layout>,
+ pub(crate) layouts: IndexMap<rustc_abi::Layout<'tcx>, Layout>,
}
impl<'tcx> Tables<'tcx> {
diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs
index 26aa782..9f977b9 100644
--- a/compiler/rustc_span/src/caching_source_map_view.rs
+++ b/compiler/rustc_span/src/caching_source_map_view.rs
@@ -63,7 +63,7 @@
impl<'sm> CachingSourceMapView<'sm> {
pub fn new(source_map: &'sm SourceMap) -> CachingSourceMapView<'sm> {
let files = source_map.files();
- let first_file = files[0].clone();
+ let first_file = Lrc::clone(&files[0]);
let entry = CacheEntry {
time_stamp: 0,
line_number: 0,
@@ -92,7 +92,7 @@
cache_entry.touch(self.time_stamp);
let col = RelativeBytePos(pos.to_u32() - cache_entry.line.start.to_u32());
- return Some((cache_entry.file.clone(), cache_entry.line_number, col));
+ return Some((Lrc::clone(&cache_entry.file), cache_entry.line_number, col));
}
// No cache hit ...
@@ -109,7 +109,7 @@
cache_entry.update(new_file_and_idx, pos, self.time_stamp);
let col = RelativeBytePos(pos.to_u32() - cache_entry.line.start.to_u32());
- Some((cache_entry.file.clone(), cache_entry.line_number, col))
+ Some((Lrc::clone(&cache_entry.file), cache_entry.line_number, col))
}
pub fn span_data_to_lines_and_cols(
@@ -133,7 +133,7 @@
}
(
- lo.file.clone(),
+ Lrc::clone(&lo.file),
lo.line_number,
span_data.lo - lo.line.start,
hi.line_number,
@@ -181,7 +181,7 @@
lo.update(new_file_and_idx, span_data.lo, self.time_stamp);
if !lo.line.contains(&span_data.hi) {
- let new_file_and_idx = Some((lo.file.clone(), lo.file_index));
+ let new_file_and_idx = Some((Lrc::clone(&lo.file), lo.file_index));
let next_oldest = self.oldest_cache_entry_index_avoid(oldest);
let hi = &mut self.line_cache[next_oldest];
hi.update(new_file_and_idx, span_data.hi, self.time_stamp);
@@ -227,7 +227,7 @@
assert_eq!(lo.file_index, hi.file_index);
Some((
- lo.file.clone(),
+ Lrc::clone(&lo.file),
lo.line_number,
span_data.lo - lo.line.start,
hi.line_number,
@@ -277,7 +277,7 @@
let file = &self.source_map.files()[file_idx];
if file_contains(file, pos) {
- return Some((file.clone(), file_idx));
+ return Some((Lrc::clone(file), file_idx));
}
}
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 8a02330..f36bb38 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -286,8 +286,8 @@
});
let file = Lrc::new(file);
- files.source_files.push(file.clone());
- files.stable_id_to_source_file.insert(file_id, file.clone());
+ files.source_files.push(Lrc::clone(&file));
+ files.stable_id_to_source_file.insert(file_id, Lrc::clone(&file));
Ok(file)
}
@@ -386,7 +386,7 @@
/// Return the SourceFile that contains the given `BytePos`
pub fn lookup_source_file(&self, pos: BytePos) -> Lrc<SourceFile> {
let idx = self.lookup_source_file_idx(pos);
- (*self.files.borrow().source_files)[idx].clone()
+ Lrc::clone(&(*self.files.borrow().source_files)[idx])
}
/// Looks up source information about a `BytePos`.
@@ -468,7 +468,7 @@
if lo != hi {
return true;
}
- let f = (*self.files.borrow().source_files)[lo].clone();
+ let f = Lrc::clone(&(*self.files.borrow().source_files)[lo]);
let lo = f.relative_position(sp.lo());
let hi = f.relative_position(sp.hi());
f.lookup_line(lo) != f.lookup_line(hi)
@@ -994,7 +994,7 @@
let filename = self.path_mapping().map_filename_prefix(filename).0;
for sf in self.files.borrow().source_files.iter() {
if filename == sf.name {
- return Some(sf.clone());
+ return Some(Lrc::clone(&sf));
}
}
None
@@ -1003,7 +1003,7 @@
/// For a global `BytePos`, computes the local offset within the containing `SourceFile`.
pub fn lookup_byte_offset(&self, bpos: BytePos) -> SourceFileAndBytePos {
let idx = self.lookup_source_file_idx(bpos);
- let sf = (*self.files.borrow().source_files)[idx].clone();
+ let sf = Lrc::clone(&(*self.files.borrow().source_files)[idx]);
let offset = bpos - sf.start_pos;
SourceFileAndBytePos { sf, pos: offset }
}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 3ab4820..890c4fd 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -171,9 +171,11 @@
CallOnceFuture,
CallRefFuture,
Capture,
+ Cell,
Center,
Cleanup,
Clone,
+ CoercePointee,
CoerceUnsized,
Command,
ConstParamTy,
@@ -195,14 +197,6 @@
Display,
DoubleEndedIterator,
Duration,
- EffectsCompat,
- EffectsIntersection,
- EffectsIntersectionOutput,
- EffectsMaybe,
- EffectsNoRuntime,
- EffectsRuntime,
- EffectsTyCompat,
- Effects__,
Encodable,
Encoder,
Enumerate,
@@ -315,7 +309,6 @@
Sized,
SliceIndex,
SliceIter,
- SmartPointer,
Some,
SpanCtxt,
String,
@@ -417,6 +410,7 @@
arm,
arm_target_feature,
array,
+ as_mut_ptr,
as_ptr,
as_ref,
as_str,
@@ -740,6 +734,7 @@
deref_pure,
deref_target,
derive,
+ derive_coerce_pointee,
derive_const,
derive_default_enum,
derive_smart_pointer,
@@ -1133,6 +1128,7 @@
lazy_normalization_consts,
lazy_type_alias,
le,
+ legacy_receiver,
len,
let_chains,
let_else,
@@ -1573,7 +1569,6 @@
readonly,
realloc,
reason,
- receiver,
recursion_limit,
reexport_test_harness_main,
ref_pat_eat_one_layer_2024,
@@ -1668,6 +1663,7 @@
rustc_confusables,
rustc_const_panic_str,
rustc_const_stable,
+ rustc_const_stable_indirect,
rustc_const_unstable,
rustc_conversion_suggestion,
rustc_deallocator,
@@ -1737,7 +1733,6 @@
rustc_reallocator,
rustc_regions,
rustc_reservation_impl,
- rustc_runtime,
rustc_safe_intrinsic,
rustc_serialize,
rustc_skip_during_method_dispatch,
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index 65aa9e4..644e710 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -7,6 +7,8 @@
# tidy-alphabetical-start
punycode = "0.4.0"
rustc-demangle = "0.1.21"
+
+rustc_abi = { path = "../rustc_abi" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 78e6b9e..5c5ab43 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -135,7 +135,7 @@
// This closure determines the instantiating crate for instances that
// need an instantiating-crate-suffix for their symbol name, in order
// to differentiate between local copies.
- if is_generic(instance, tcx) {
+ if is_generic(instance) {
// For generics we might find re-usable upstream instances. If there
// is one, we rely on the symbol being instantiated locally.
instance.upstream_monomorphization(tcx).unwrap_or(LOCAL_CRATE)
@@ -241,7 +241,7 @@
// the ID of the instantiating crate. This avoids symbol conflicts
// in case the same instances is emitted in two crates of the same
// project.
- let avoid_cross_crate_conflicts = is_generic(instance, tcx) || is_globally_shared_function;
+ let avoid_cross_crate_conflicts = is_generic(instance) || is_globally_shared_function;
let instantiating_crate = avoid_cross_crate_conflicts.then(compute_instantiating_crate);
@@ -276,6 +276,6 @@
symbol
}
-fn is_generic<'tcx>(instance: Instance<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
- instance.args.non_erasable_generics(tcx, instance.def_id()).next().is_some()
+fn is_generic<'tcx>(instance: Instance<'tcx>) -> bool {
+ instance.args.non_erasable_generics().next().is_some()
}
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index d092fa8..868345c 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -2,6 +2,7 @@
use std::iter;
use std::ops::Range;
+use rustc_abi::Integer;
use rustc_data_structures::base_n::ToBaseN;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::intern::Interned;
@@ -17,7 +18,6 @@
TyCtxt, TypeVisitable, TypeVisitableExt, UintTy,
};
use rustc_span::symbol::kw;
-use rustc_target::abi::Integer;
use rustc_target::spec::abi::Abi;
pub(super) fn mangle<'tcx>(
diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs
index 4a21935..ffec763 100644
--- a/compiler/rustc_target/src/callconv/loongarch.rs
+++ b/compiler/rustc_target/src/callconv/loongarch.rs
@@ -1,6 +1,7 @@
use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
use crate::spec::HasTargetSpec;
+use crate::spec::abi::Abi as SpecAbi;
#[derive(Copy, Clone)]
enum RegPassKind {
@@ -359,3 +360,30 @@
);
}
}
+
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi)
+where
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout + HasTargetSpec,
+{
+ if abi == SpecAbi::RustIntrinsic {
+ return;
+ }
+
+ let grlen = cx.data_layout().pointer_size.bits();
+
+ for arg in fn_abi.args.iter_mut() {
+ if arg.is_ignore() {
+ continue;
+ }
+
+ // LLVM integers types do not differentiate between signed or unsigned integers.
+ // Some LoongArch instructions do not have a `.w` suffix version, they use all the
+ // GRLEN bits. By explicitly setting the `signext` or `zeroext` attribute
+ // according to signedness to avoid unnecessary integer extending instructions.
+ //
+ // This is similar to the RISC-V case, see
+ // https://github.com/rust-lang/rust/issues/114508 for details.
+ extend_integer_width(arg, grlen);
+ }
+}
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 5d120a6..25b001b 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -1,11 +1,14 @@
-use std::fmt;
use std::str::FromStr;
+use std::{fmt, iter};
pub use rustc_abi::{Reg, RegKind};
use rustc_macros::HashStable_Generic;
use rustc_span::Symbol;
-use crate::abi::{self, Abi, Align, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
+use crate::abi::{
+ self, Abi, AddressSpace, Align, HasDataLayout, Pointer, Size, TyAbiInterface, TyAndLayout,
+};
+use crate::spec::abi::Abi as SpecAbi;
use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi};
mod aarch64;
@@ -720,6 +723,118 @@
Ok(())
}
+
+ pub fn adjust_for_rust_abi<C>(&mut self, cx: &C, abi: SpecAbi)
+ where
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout + HasTargetSpec,
+ {
+ let spec = cx.target_spec();
+ match &spec.arch[..] {
+ "x86" => x86::compute_rust_abi_info(cx, self, abi),
+ "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi),
+ "loongarch64" => loongarch::compute_rust_abi_info(cx, self, abi),
+ _ => {}
+ };
+
+ for (arg_idx, arg) in self
+ .args
+ .iter_mut()
+ .enumerate()
+ .map(|(idx, arg)| (Some(idx), arg))
+ .chain(iter::once((None, &mut self.ret)))
+ {
+ if arg.is_ignore() {
+ continue;
+ }
+
+ if arg_idx.is_none() && arg.layout.size > Pointer(AddressSpace::DATA).size(cx) * 2 {
+ // Return values larger than 2 registers using a return area
+ // pointer. LLVM and Cranelift disagree about how to return
+ // values that don't fit in the registers designated for return
+ // values. LLVM will force the entire return value to be passed
+ // by return area pointer, while Cranelift will look at each IR level
+ // return value independently and decide to pass it in a
+ // register or not, which would result in the return value
+ // being passed partially in registers and partially through a
+ // return area pointer.
+ //
+ // While Cranelift may need to be fixed as the LLVM behavior is
+ // generally more correct with respect to the surface language,
+ // forcing this behavior in rustc itself makes it easier for
+ // other backends to conform to the Rust ABI and for the C ABI
+ // rustc already handles this behavior anyway.
+ //
+ // In addition LLVM's decision to pass the return value in
+ // registers or using a return area pointer depends on how
+ // exactly the return type is lowered to an LLVM IR type. For
+ // example `Option<u128>` can be lowered as `{ i128, i128 }`
+ // in which case the x86_64 backend would use a return area
+ // pointer, or it could be passed as `{ i32, i128 }` in which
+ // case the x86_64 backend would pass it in registers by taking
+ // advantage of an LLVM ABI extension that allows using 3
+ // registers for the x86_64 sysv call conv rather than the
+ // officially specified 2 registers.
+ //
+ // FIXME: Technically we should look at the amount of available
+ // return registers rather than guessing that there are 2
+ // registers for return values. In practice only a couple of
+ // architectures have less than 2 return registers. None of
+ // which supported by Cranelift.
+ //
+ // NOTE: This adjustment is only necessary for the Rust ABI as
+ // for other ABI's the calling convention implementations in
+ // rustc_target already ensure any return value which doesn't
+ // fit in the available amount of return registers is passed in
+ // the right way for the current target.
+ arg.make_indirect();
+ continue;
+ }
+
+ match arg.layout.abi {
+ Abi::Aggregate { .. } => {}
+
+ // This is a fun case! The gist of what this is doing is
+ // that we want callers and callees to always agree on the
+ // ABI of how they pass SIMD arguments. If we were to *not*
+ // make these arguments indirect then they'd be immediates
+ // in LLVM, which means that they'd used whatever the
+ // appropriate ABI is for the callee and the caller. That
+ // means, for example, if the caller doesn't have AVX
+ // enabled but the callee does, then passing an AVX argument
+ // across this boundary would cause corrupt data to show up.
+ //
+ // This problem is fixed by unconditionally passing SIMD
+ // arguments through memory between callers and callees
+ // which should get them all to agree on ABI regardless of
+ // target feature sets. Some more information about this
+ // issue can be found in #44367.
+ //
+ // Note that the intrinsic ABI is exempt here as
+ // that's how we connect up to LLVM and it's unstable
+ // anyway, we control all calls to it in libstd.
+ Abi::Vector { .. } if abi != SpecAbi::RustIntrinsic && spec.simd_types_indirect => {
+ arg.make_indirect();
+ continue;
+ }
+
+ _ => continue,
+ }
+ // Compute `Aggregate` ABI.
+
+ let is_indirect_not_on_stack =
+ matches!(arg.mode, PassMode::Indirect { on_stack: false, .. });
+ assert!(is_indirect_not_on_stack);
+
+ let size = arg.layout.size;
+ if !arg.layout.is_unsized() && size <= Pointer(AddressSpace::DATA).size(cx) {
+ // We want to pass small aggregates as immediates, but using
+ // an LLVM aggregate type for this leads to bad optimizations,
+ // so we pick an appropriately sized integer type instead.
+ arg.cast_to(Reg { kind: RegKind::Integer, size });
+ }
+ }
+ }
}
impl FromStr for Conv {
diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs
index be6bc701..f96169e 100644
--- a/compiler/rustc_target/src/callconv/riscv.rs
+++ b/compiler/rustc_target/src/callconv/riscv.rs
@@ -7,6 +7,7 @@
use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
use crate::spec::HasTargetSpec;
+use crate::spec::abi::Abi as SpecAbi;
#[derive(Copy, Clone)]
enum RegPassKind {
@@ -365,3 +366,29 @@
);
}
}
+
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi)
+where
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout + HasTargetSpec,
+{
+ if abi == SpecAbi::RustIntrinsic {
+ return;
+ }
+
+ let xlen = cx.data_layout().pointer_size.bits();
+
+ for arg in fn_abi.args.iter_mut() {
+ if arg.is_ignore() {
+ continue;
+ }
+
+ // LLVM integers types do not differentiate between signed or unsigned integers.
+ // Some RISC-V instructions do not have a `.w` suffix version, they use all the
+ // XLEN bits. By explicitly setting the `signext` or `zeroext` attribute
+ // according to signedness to avoid unnecessary integer extending instructions.
+ //
+ // See https://github.com/rust-lang/rust/issues/114508 for details.
+ extend_integer_width(arg, xlen);
+ }
+}
diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs
index 40c3e7a..e907bee 100644
--- a/compiler/rustc_target/src/callconv/x86.rs
+++ b/compiler/rustc_target/src/callconv/x86.rs
@@ -1,6 +1,9 @@
use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind};
-use crate::abi::{Abi, Align, HasDataLayout, TyAbiInterface, TyAndLayout};
+use crate::abi::{
+ Abi, AddressSpace, Align, Float, HasDataLayout, Pointer, TyAbiInterface, TyAndLayout,
+};
use crate::spec::HasTargetSpec;
+use crate::spec::abi::Abi as SpecAbi;
#[derive(PartialEq)]
pub(crate) enum Flavor {
@@ -207,3 +210,35 @@
}
}
}
+
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi)
+where
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout + HasTargetSpec,
+{
+ // Avoid returning floats in x87 registers on x86 as loading and storing from x87
+ // registers will quiet signalling NaNs. Also avoid using SSE registers since they
+ // are not always available (depending on target features).
+ if !fn_abi.ret.is_ignore()
+ // Intrinsics themselves are not actual "real" functions, so theres no need to change their ABIs.
+ && abi != SpecAbi::RustIntrinsic
+ {
+ let has_float = match fn_abi.ret.layout.abi {
+ Abi::Scalar(s) => matches!(s.primitive(), Float(_)),
+ Abi::ScalarPair(s1, s2) => {
+ matches!(s1.primitive(), Float(_)) || matches!(s2.primitive(), Float(_))
+ }
+ _ => false, // anyway not passed via registers on x86
+ };
+ if has_float {
+ if fn_abi.ret.layout.size <= Pointer(AddressSpace::DATA).size(cx) {
+ // Same size or smaller than pointer, return in a register.
+ fn_abi.ret.cast_to(Reg { kind: RegKind::Integer, size: fn_abi.ret.layout.size });
+ } else {
+ // Larger than a pointer, return indirectly.
+ fn_abi.ret.make_indirect();
+ }
+ return;
+ }
+ }
+}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 5ca2a33..f4cbe47 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1803,6 +1803,7 @@
("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
("wasm32-unknown-unknown", wasm32_unknown_unknown),
+ ("wasm32v1-none", wasm32v1_none),
("wasm32-wasi", wasm32_wasi),
("wasm32-wasip1", wasm32_wasip1),
("wasm32-wasip2", wasm32_wasip2),
diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs
index 2519b93..7648f81 100644
--- a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs
+++ b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs
@@ -21,6 +21,7 @@
"-Vgcc_ntox86_cxx",
]),
env: "nto70".into(),
+ vendor: "pc".into(),
stack_probes: StackProbeType::Inline,
..base::nto_qnx::opts()
},
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
index 68d5119..603c0f9 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
@@ -15,7 +15,7 @@
options: TargetOptions {
code_model: Some(CodeModel::Medium),
cpu: "generic".into(),
- features: "+f,+d".into(),
+ features: "+f,+d,+lsx".into(),
llvm_abiname: "lp64d".into(),
max_atomic_width: Some(64),
supported_sanitizers: SanitizerSet::ADDRESS
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
index 25d3559..d7044dd 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
@@ -15,7 +15,7 @@
options: TargetOptions {
code_model: Some(CodeModel::Medium),
cpu: "generic".into(),
- features: "+f,+d".into(),
+ features: "+f,+d,+lsx".into(),
llvm_abiname: "lp64d".into(),
max_atomic_width: Some(64),
crt_static_default: false,
diff --git a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs
new file mode 100644
index 0000000..bf35ae0
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs
@@ -0,0 +1,51 @@
+//! A "bare wasm" target representing a WebAssembly output that does not import
+//! anything from its environment and also specifies an _upper_ bound on the set
+//! of WebAssembly proposals that are supported.
+//!
+//! It's equivalent to the `wasm32-unknown-unknown` target with the additional
+//! flags `-Ctarget-cpu=mvp` and `-Ctarget-feature=+mutable-globals`. This
+//! enables just the features specified in <https://www.w3.org/TR/wasm-core-1/>
+//!
+//! This is a _separate target_ because using `wasm32-unknown-unknown` with
+//! those target flags doesn't automatically rebuild libcore / liballoc with
+//! them, and in order to get those libraries rebuilt you need to use the
+//! nightly Rust feature `-Zbuild-std`. This target is for people who want to
+//! use stable Rust, and target a stable set pf WebAssembly features.
+
+use crate::spec::{Cc, LinkerFlavor, Target, base};
+
+pub(crate) fn target() -> Target {
+ let mut options = base::wasm::options();
+ options.os = "none".into();
+
+ // WebAssembly 1.0 shipped in 2019 and included exactly one proposal
+ // after the initial "MVP" feature set: "mutable-globals".
+ options.cpu = "mvp".into();
+ options.features = "+mutable-globals".into();
+
+ options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::No), &[
+ // For now this target just never has an entry symbol no matter the output
+ // type, so unconditionally pass this.
+ "--no-entry",
+ ]);
+ options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::Yes), &[
+ // Make sure clang uses LLD as its linker and is configured appropriately
+ // otherwise
+ "--target=wasm32-unknown-unknown",
+ "-Wl,--no-entry",
+ ]);
+
+ Target {
+ llvm_target: "wasm32-unknown-unknown".into(),
+ metadata: crate::spec::TargetMetadata {
+ description: Some("WebAssembly".into()),
+ tier: Some(2),
+ host_tools: Some(false),
+ std: Some(false),
+ },
+ pointer_width: 32,
+ data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
+ arch: "wasm32".into(),
+ options,
+ }
+}
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs
index 1aa8249..245a5f0 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710.rs
@@ -21,6 +21,7 @@
"-Vgcc_ntox86_64_cxx",
]),
env: "nto71".into(),
+ vendor: "pc".into(),
..base::nto_qnx::opts()
},
}
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index 7ed2195..cc5931b 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -121,7 +121,13 @@
// Check dynamic linking stuff
// BPF: when targeting user space vms (like rbpf), those can load dynamic libraries.
// hexagon: when targeting QuRT, that OS can load dynamic libraries.
- if self.os == "none" && (self.arch != "bpf" && self.arch != "hexagon") {
+ // wasm{32,64}: dynamic linking is inherent in the definition of the VM.
+ if self.os == "none"
+ && (self.arch != "bpf"
+ && self.arch != "hexagon"
+ && self.arch != "wasm32"
+ && self.arch != "wasm64")
+ {
assert!(!self.dynamic_linking);
}
if self.only_cdylib
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index e92366d..3df8f05 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -167,6 +167,8 @@
("pacg", Stable, &[]),
// FEAT_PAN
("pan", Stable, &[]),
+ // FEAT_PAuth_LR
+ ("pauth-lr", Unstable(sym::aarch64_unstable_target_feature), &[]),
// FEAT_PMUv3
("pmuv3", Stable, &[]),
// FEAT_RNG
@@ -316,7 +318,7 @@
("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
("lzcnt", Stable, &[]),
("movbe", Stable, &[]),
- ("pclmulqdq", Stable, &[]),
+ ("pclmulqdq", Stable, &["sse2"]),
("popcnt", Stable, &[]),
("prfchw", Unstable(sym::prfchw_target_feature), &[]),
("rdrand", Stable, &[]),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index df5800a..574cf1e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -75,6 +75,7 @@
use crate::infer;
use crate::infer::relate::{self, RelateResult, TypeRelation};
use crate::infer::{InferCtxt, TypeTrace, ValuePairs};
+use crate::solve::deeply_normalize_for_diagnostics;
use crate::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
};
@@ -145,21 +146,31 @@
pub fn report_mismatched_types(
&self,
cause: &ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
err: TypeError<'tcx>,
) -> Diag<'a> {
- self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err)
+ self.report_and_explain_type_error(
+ TypeTrace::types(cause, true, expected, actual),
+ param_env,
+ err,
+ )
}
pub fn report_mismatched_consts(
&self,
cause: &ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
expected: ty::Const<'tcx>,
actual: ty::Const<'tcx>,
err: TypeError<'tcx>,
) -> Diag<'a> {
- self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err)
+ self.report_and_explain_type_error(
+ TypeTrace::consts(cause, true, expected, actual),
+ param_env,
+ err,
+ )
}
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
@@ -381,7 +392,7 @@
Some(ty) if expected == ty => {
let source_map = self.tcx.sess.source_map();
err.span_suggestion(
- source_map.end_point(cause.span()),
+ source_map.end_point(cause.span),
"try removing this `?`",
"",
Applicability::MachineApplicable,
@@ -401,6 +412,7 @@
source,
ref prior_non_diverging_arms,
scrut_span,
+ expr_span,
..
}) => match source {
hir::MatchSource::TryDesugar(scrut_hir_id) => {
@@ -419,7 +431,7 @@
Some(ty) if expected == ty => {
let source_map = self.tcx.sess.source_map();
err.span_suggestion(
- source_map.end_point(cause.span()),
+ source_map.end_point(cause.span),
"try removing this `?`",
"",
Applicability::MachineApplicable,
@@ -449,12 +461,12 @@
format!("this and all prior arms are found to be of type `{t}`"),
);
}
- let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) {
+ let outer = if any_multiline_arm || !source_map.is_multiline(expr_span) {
// Cover just `match` and the scrutinee expression, not
// the entire match body, to reduce diagram noise.
- cause.span.shrink_to_lo().to(scrut_span)
+ expr_span.shrink_to_lo().to(scrut_span)
} else {
- cause.span
+ expr_span
};
let msg = "`match` arms have incompatible types";
err.span_label(outer, msg);
@@ -1133,11 +1145,11 @@
diag: &mut Diag<'_>,
cause: &ObligationCause<'tcx>,
secondary_span: Option<(Span, Cow<'static, str>, bool)>,
- mut values: Option<ValuePairs<'tcx>>,
+ mut values: Option<ty::ParamEnvAnd<'tcx, ValuePairs<'tcx>>>,
terr: TypeError<'tcx>,
prefer_label: bool,
) {
- let span = cause.span();
+ let span = cause.span;
// For some types of errors, expected-found does not make
// sense, so just ignore the values we were given.
@@ -1241,8 +1253,11 @@
}
let (expected_found, exp_found, is_simple_error, values) = match values {
None => (None, Mismatch::Fixed("type"), false, None),
- Some(values) => {
- let values = self.resolve_vars_if_possible(values);
+ Some(ty::ParamEnvAnd { param_env, value: values }) => {
+ let mut values = self.resolve_vars_if_possible(values);
+ if self.next_trait_solver() {
+ values = deeply_normalize_for_diagnostics(self, param_env, values);
+ }
let (is_simple_error, exp_found) = match values {
ValuePairs::Terms(ExpectedFound { expected, found }) => {
match (expected.unpack(), found.unpack()) {
@@ -1628,7 +1643,7 @@
terr: TypeError<'tcx>,
) -> Vec<TypeErrorAdditionalDiags> {
let mut suggestions = Vec::new();
- let span = trace.cause.span();
+ let span = trace.cause.span;
let values = self.resolve_vars_if_possible(trace.values);
if let Some((expected, found)) = values.ty() {
match (expected.kind(), found.kind()) {
@@ -1773,18 +1788,26 @@
pub fn report_and_explain_type_error(
&self,
trace: TypeTrace<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
terr: TypeError<'tcx>,
) -> Diag<'a> {
debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
- let span = trace.cause.span();
+ let span = trace.cause.span;
let failure_code = trace.cause.as_failure_code_diag(
terr,
span,
self.type_error_additional_suggestions(&trace, terr),
);
let mut diag = self.dcx().create_err(failure_code);
- self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false);
+ self.note_type_err(
+ &mut diag,
+ &trace.cause,
+ None,
+ Some(param_env.and(trace.values)),
+ terr,
+ false,
+ );
diag
}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
index 14c2bf1..4398af7 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
@@ -237,7 +237,7 @@
expected_args: GenericArgsRef<'tcx>,
actual_args: GenericArgsRef<'tcx>,
) -> Diag<'tcx> {
- let span = cause.span();
+ let span = cause.span;
let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
if let ObligationCauseCode::WhereClause(def_id, span)
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index 94610a9..833358b2 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -295,7 +295,11 @@
let mut err = match origin {
infer::Subtype(box trace) => {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
- let mut err = self.report_and_explain_type_error(trace, terr);
+ let mut err = self.report_and_explain_type_error(
+ trace,
+ self.tcx.param_env(generic_param_scope),
+ terr,
+ );
match (*sub, *sup) {
(ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
(ty::RePlaceholder(_), _) => {
@@ -646,7 +650,11 @@
}
infer::Subtype(box trace) => {
let terr = TypeError::RegionsPlaceholderMismatch;
- return self.report_and_explain_type_error(trace, terr);
+ return self.report_and_explain_type_error(
+ trace,
+ self.tcx.param_env(generic_param_scope),
+ terr,
+ );
}
_ => {
return self.report_concrete_failure(
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 9ee4963..6014ed5 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -156,8 +156,6 @@
(leaf_trait_predicate, &obligation)
};
- let (main_trait_predicate, leaf_trait_predicate, predicate_constness) = self.get_effects_trait_pred_override(main_trait_predicate, leaf_trait_predicate, span);
-
let main_trait_ref = main_trait_predicate.to_poly_trait_ref();
let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref();
@@ -228,7 +226,7 @@
let err_msg = self.get_standard_error_message(
main_trait_predicate,
message,
- predicate_constness,
+ None,
append_const_msg,
post_message,
);
@@ -289,13 +287,6 @@
);
}
- if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Drop)
- && matches!(predicate_constness, Some(ty::BoundConstness::ConstIfConst | ty::BoundConstness::Const))
- {
- err.note("`~const Drop` was renamed to `~const Destruct`");
- err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
- }
-
let explanation = get_explanation_based_on_obligation(
self.tcx,
&obligation,
@@ -541,6 +532,29 @@
err
}
+ ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {
+ // FIXME(effects): We should recompute the predicate with `~const`
+ // if it's `const`, and if it holds, explain that this bound only
+ // *conditionally* holds. If that fails, we should also do selection
+ // to drill this down to an impl or built-in source, so we can
+ // point at it and explain that while the trait *is* implemented,
+ // that implementation is not const.
+ let err_msg = self.get_standard_error_message(
+ bound_predicate.rebind(ty::TraitPredicate {
+ trait_ref: predicate.trait_ref,
+ polarity: ty::PredicatePolarity::Positive,
+ }),
+ None,
+ Some(match predicate.host {
+ ty::HostPolarity::Maybe => ty::BoundConstness::ConstIfConst,
+ ty::HostPolarity::Const => ty::BoundConstness::Const,
+ }),
+ None,
+ String::new(),
+ );
+ struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg)
+ }
+
ty::PredicateKind::Subtype(predicate) => {
// Errors for Subtype predicates show up as
// `FulfillmentErrorCode::SubtypeError`,
@@ -1290,7 +1304,6 @@
(
Some((
data.projection_term,
- false,
self.resolve_vars_if_possible(normalized_term),
data.term,
)),
@@ -1335,7 +1348,7 @@
derive_better_type_error(lhs, rhs)
{
(
- Some((lhs, true, self.resolve_vars_if_possible(expected_term), rhs)),
+ Some((lhs, self.resolve_vars_if_possible(expected_term), rhs)),
better_type_err,
)
} else if let Some(rhs) = rhs.to_alias_term()
@@ -1343,7 +1356,7 @@
derive_better_type_error(rhs, lhs)
{
(
- Some((rhs, true, self.resolve_vars_if_possible(expected_term), lhs)),
+ Some((rhs, self.resolve_vars_if_possible(expected_term), lhs)),
better_type_err,
)
} else {
@@ -1354,7 +1367,7 @@
};
let msg = values
- .and_then(|(predicate, _, normalized_term, expected_term)| {
+ .and_then(|(predicate, normalized_term, expected_term)| {
self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term)
})
.unwrap_or_else(|| {
@@ -1431,8 +1444,12 @@
&mut diag,
&obligation.cause,
secondary_span,
- values.map(|(_, _, normalized_ty, expected_ty)| {
- infer::ValuePairs::Terms(ExpectedFound::new(true, expected_ty, normalized_ty))
+ values.map(|(_, normalized_ty, expected_ty)| {
+ obligation.param_env.and(infer::ValuePairs::Terms(ExpectedFound::new(
+ true,
+ expected_ty,
+ normalized_ty,
+ )))
}),
err,
false,
@@ -1818,6 +1835,7 @@
if impl_trait_ref.references_error() {
return false;
}
+ let self_ty = impl_trait_ref.self_ty().to_string();
err.highlighted_help(vec![
StringPart::normal(format!(
"the trait `{}` ",
@@ -1825,16 +1843,24 @@
)),
StringPart::highlighted("is"),
StringPart::normal(" implemented for `"),
- StringPart::highlighted(impl_trait_ref.self_ty().to_string()),
+ if let [TypeError::Sorts(_)] = &terrs[..] {
+ StringPart::normal(self_ty)
+ } else {
+ StringPart::highlighted(self_ty)
+ },
StringPart::normal("`"),
]);
if let [TypeError::Sorts(exp_found)] = &terrs[..] {
let exp_found = self.resolve_vars_if_possible(*exp_found);
- err.help(format!(
- "for that trait implementation, expected `{}`, found `{}`",
- exp_found.expected, exp_found.found
- ));
+ err.highlighted_help(vec![
+ StringPart::normal("for that trait implementation, "),
+ StringPart::normal("expected `"),
+ StringPart::highlighted(exp_found.expected.to_string()),
+ StringPart::normal("`, found `"),
+ StringPart::highlighted(exp_found.found.to_string()),
+ StringPart::normal("`"),
+ ]);
}
true
@@ -2143,6 +2169,7 @@
// First, attempt to add note to this error with an async-await-specific
// message, and fall back to regular note otherwise.
if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
+ let mut long_ty_file = None;
self.note_obligation_cause_code(
obligation.cause.body_id,
err,
@@ -2151,7 +2178,15 @@
obligation.cause.code(),
&mut vec![],
&mut Default::default(),
+ &mut long_ty_file,
);
+ if let Some(file) = long_ty_file {
+ err.note(format!(
+ "the full name for the type has been written to '{}'",
+ file.display(),
+ ));
+ err.note("consider using `--verbose` to print the full type name to the console");
+ }
self.suggest_unsized_bound_if_applicable(err, obligation);
if let Some(span) = err.span.primary_span()
&& let Some(mut diag) =
@@ -2371,52 +2406,6 @@
})
}
- /// For effects predicates such as `<u32 as Add>::Effects: Compat<host>`, pretend that the
- /// predicate that failed was `u32: Add`. Return the constness of such predicate to later
- /// print as `u32: ~const Add`.
- fn get_effects_trait_pred_override(
- &self,
- p: ty::PolyTraitPredicate<'tcx>,
- leaf: ty::PolyTraitPredicate<'tcx>,
- span: Span,
- ) -> (ty::PolyTraitPredicate<'tcx>, ty::PolyTraitPredicate<'tcx>, Option<ty::BoundConstness>)
- {
- let trait_ref = p.to_poly_trait_ref();
- if !self.tcx.is_lang_item(trait_ref.def_id(), LangItem::EffectsCompat) {
- return (p, leaf, None);
- }
-
- let Some(ty::Alias(ty::AliasTyKind::Projection, projection)) =
- trait_ref.self_ty().no_bound_vars().map(Ty::kind)
- else {
- return (p, leaf, None);
- };
-
- let constness = trait_ref.skip_binder().args.const_at(1);
-
- let constness = if constness == self.tcx.consts.true_ || constness.is_ct_infer() {
- None
- } else if constness == self.tcx.consts.false_ {
- Some(ty::BoundConstness::Const)
- } else if matches!(constness.kind(), ty::ConstKind::Param(_)) {
- Some(ty::BoundConstness::ConstIfConst)
- } else {
- self.dcx().span_bug(span, format!("Unknown constness argument: {constness:?}"));
- };
-
- let new_pred = p.map_bound(|mut trait_pred| {
- trait_pred.trait_ref = projection.trait_ref(self.tcx);
- trait_pred
- });
-
- let new_leaf = leaf.map_bound(|mut trait_pred| {
- trait_pred.trait_ref = projection.trait_ref(self.tcx);
- trait_pred
- });
-
- (new_pred, new_leaf, constness)
- }
-
fn add_tuple_trait_message(
&self,
obligation_cause_code: &ObligationCauseCode<'tcx>,
@@ -2654,6 +2643,7 @@
};
self.report_and_explain_type_error(
TypeTrace::trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
+ obligation.param_env,
terr,
)
}
@@ -2744,6 +2734,7 @@
{
return Ok(self.report_and_explain_type_error(
TypeTrace::trait_refs(&obligation.cause, true, expected_trait_ref, found_trait_ref),
+ obligation.param_env,
ty::error::TypeError::Mismatch,
));
}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index ba57909..b108a93 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -287,6 +287,7 @@
FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self
.report_mismatched_types(
&error.obligation.cause,
+ error.obligation.param_env,
expected_found.expected,
expected_found.found,
*err,
@@ -295,6 +296,7 @@
FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => {
let mut diag = self.report_mismatched_consts(
&error.obligation.cause,
+ error.obligation.param_env,
expected_found.expected,
expected_found.found,
*err,
@@ -303,6 +305,7 @@
if let ObligationCauseCode::WhereClause(..)
| ObligationCauseCode::WhereClauseInExpr(..) = code
{
+ let mut long_ty_file = None;
self.note_obligation_cause_code(
error.obligation.cause.body_id,
&mut diag,
@@ -311,7 +314,17 @@
code,
&mut vec![],
&mut Default::default(),
+ &mut long_ty_file,
);
+ if let Some(file) = long_ty_file {
+ diag.note(format!(
+ "the full name for the type has been written to '{}'",
+ file.display(),
+ ));
+ diag.note(
+ "consider using `--verbose` to print the full type name to the console",
+ );
+ }
}
diag.emit()
}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
index f4c5733..c47c216 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
@@ -144,6 +144,7 @@
obligation.cause.span,
suggest_increasing_limit,
|err| {
+ let mut long_ty_file = None;
self.note_obligation_cause_code(
obligation.cause.body_id,
err,
@@ -152,7 +153,17 @@
obligation.cause.code(),
&mut vec![],
&mut Default::default(),
+ &mut long_ty_file,
);
+ if let Some(file) = long_ty_file {
+ err.note(format!(
+ "the full name for the type has been written to '{}'",
+ file.display(),
+ ));
+ err.note(
+ "consider using `--verbose` to print the full type name to the console",
+ );
+ }
},
);
}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 1fe93cb..a7d1f1b 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -3,6 +3,7 @@
use std::assert_matches::debug_assert_matches;
use std::borrow::Cow;
use std::iter;
+use std::path::PathBuf;
use itertools::{EitherOrBoth, Itertools};
use rustc_data_structures::fx::FxHashSet;
@@ -2703,6 +2704,7 @@
// Add a note for the item obligation that remains - normally a note pointing to the
// bound that introduced the obligation (e.g. `T: Send`).
debug!(?next_code);
+ let mut long_ty_file = None;
self.note_obligation_cause_code(
obligation.cause.body_id,
err,
@@ -2711,6 +2713,7 @@
next_code.unwrap(),
&mut Vec::new(),
&mut Default::default(),
+ &mut long_ty_file,
);
}
@@ -2723,11 +2726,10 @@
cause_code: &ObligationCauseCode<'tcx>,
obligated_types: &mut Vec<Ty<'tcx>>,
seen_requirements: &mut FxHashSet<DefId>,
+ long_ty_file: &mut Option<PathBuf>,
) where
T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
{
- let mut long_ty_file = None;
-
let tcx = self.tcx;
let predicate = predicate.upcast(tcx);
let suggest_remove_deref = |err: &mut Diag<'_, G>, expr: &hir::Expr<'_>| {
@@ -2957,9 +2959,9 @@
}
ObligationCauseCode::Coercion { source, target } => {
let source =
- tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut long_ty_file);
+ tcx.short_ty_string(self.resolve_vars_if_possible(source), long_ty_file);
let target =
- tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut long_ty_file);
+ tcx.short_ty_string(self.resolve_vars_if_possible(target), long_ty_file);
err.note(with_forced_trimmed_paths!(format!(
"required for the cast from `{source}` to `{target}`",
)));
@@ -3249,7 +3251,7 @@
};
if !is_upvar_tys_infer_tuple {
- let ty_str = tcx.short_ty_string(ty, &mut long_ty_file);
+ let ty_str = tcx.short_ty_string(ty, long_ty_file);
let msg = format!("required because it appears within the type `{ty_str}`");
match ty.kind() {
ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) {
@@ -3327,6 +3329,7 @@
&data.parent_code,
obligated_types,
seen_requirements,
+ long_ty_file,
)
});
} else {
@@ -3339,6 +3342,7 @@
cause_code.peel_derives(),
obligated_types,
seen_requirements,
+ long_ty_file,
)
});
}
@@ -3347,8 +3351,8 @@
let mut parent_trait_pred =
self.resolve_vars_if_possible(data.derived.parent_trait_pred);
let parent_def_id = parent_trait_pred.def_id();
- let self_ty_str = tcx
- .short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut long_ty_file);
+ let self_ty_str =
+ tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file);
let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string();
let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
let mut is_auto_trait = false;
@@ -3444,10 +3448,8 @@
count,
pluralize!(count)
));
- let self_ty = tcx.short_ty_string(
- parent_trait_pred.skip_binder().self_ty(),
- &mut long_ty_file,
- );
+ let self_ty = tcx
+ .short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file);
err.note(format!(
"required for `{self_ty}` to implement `{}`",
parent_trait_pred.print_modifiers_and_trait_path()
@@ -3463,6 +3465,7 @@
&data.parent_code,
obligated_types,
seen_requirements,
+ long_ty_file,
)
});
}
@@ -3479,6 +3482,7 @@
&data.parent_code,
obligated_types,
seen_requirements,
+ long_ty_file,
)
});
}
@@ -3493,6 +3497,7 @@
nested,
obligated_types,
seen_requirements,
+ long_ty_file,
)
});
let mut multispan = MultiSpan::from(span);
@@ -3523,6 +3528,7 @@
parent_code,
obligated_types,
seen_requirements,
+ long_ty_file,
)
});
}
@@ -3562,7 +3568,7 @@
}
ObligationCauseCode::OpaqueReturnType(expr_info) => {
if let Some((expr_ty, hir_id)) = expr_info {
- let expr_ty = self.tcx.short_ty_string(expr_ty, &mut long_ty_file);
+ let expr_ty = self.tcx.short_ty_string(expr_ty, long_ty_file);
let expr = self.infcx.tcx.hir().expect_expr(hir_id);
err.span_label(
expr.span,
@@ -3574,14 +3580,6 @@
}
}
}
-
- if let Some(file) = long_ty_file {
- err.note(format!(
- "the full name for the type has been written to '{}'",
- file.display(),
- ));
- err.note("consider using `--verbose` to print the full type name to the console");
- }
}
#[instrument(
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 12aeee0..934fe9e 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -806,7 +806,8 @@
| ty::PredicateKind::Subtype(..)
// FIXME(generic_const_exprs): you can absolutely add this as a where clauses
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
- | ty::PredicateKind::Coerce(..) => {}
+ | ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {}
ty::PredicateKind::Ambiguous => return false,
};
}
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index cc0450e..a068f25 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -245,6 +245,7 @@
| ty::ClauseKind::RegionOutlives(..)
// FIXME(generic_const_exprs): this can mention `Self`
| ty::ClauseKind::ConstEvaluatable(..)
+ | ty::ClauseKind::HostEffect(..)
=> None,
}
}
@@ -284,7 +285,8 @@
| ty::ClauseKind::Projection(_)
| ty::ClauseKind::ConstArgHasType(_, _)
| ty::ClauseKind::WellFormed(_)
- | ty::ClauseKind::ConstEvaluatable(_) => false,
+ | ty::ClauseKind::ConstEvaluatable(_)
+ | ty::ClauseKind::HostEffect(..) => false,
})
}
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
new file mode 100644
index 0000000..bd8c04b
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -0,0 +1,152 @@
+use rustc_hir as hir;
+use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt};
+use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation};
+use rustc_middle::ty::fast_reject::DeepRejectCtxt;
+use rustc_middle::{span_bug, ty};
+use rustc_type_ir::solve::NoSolution;
+use thin_vec::ThinVec;
+
+use super::SelectionContext;
+
+pub type HostEffectObligation<'tcx> = Obligation<'tcx, ty::HostEffectPredicate<'tcx>>;
+
+pub enum EvaluationFailure {
+ Ambiguous,
+ NoSolution,
+}
+
+pub fn evaluate_host_effect_obligation<'tcx>(
+ selcx: &mut SelectionContext<'_, 'tcx>,
+ obligation: &HostEffectObligation<'tcx>,
+) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
+ if selcx.infcx.intercrate {
+ span_bug!(
+ obligation.cause.span,
+ "should not select host obligation in old solver in intercrate mode"
+ );
+ }
+
+ match evaluate_host_effect_from_bounds(selcx, obligation) {
+ Ok(result) => return Ok(result),
+ Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
+ Err(EvaluationFailure::NoSolution) => {}
+ }
+
+ match evaluate_host_effect_from_selection_candiate(selcx, obligation) {
+ Ok(result) => return Ok(result),
+ Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
+ Err(EvaluationFailure::NoSolution) => {}
+ }
+
+ Err(EvaluationFailure::NoSolution)
+}
+
+fn match_candidate<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ obligation: &HostEffectObligation<'tcx>,
+ candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
+) -> Result<ThinVec<PredicateObligation<'tcx>>, NoSolution> {
+ if !candidate.skip_binder().host.satisfies(obligation.predicate.host) {
+ return Err(NoSolution);
+ }
+
+ let candidate = infcx.instantiate_binder_with_fresh_vars(
+ obligation.cause.span,
+ BoundRegionConversionTime::HigherRankedType,
+ candidate,
+ );
+
+ let mut nested = infcx
+ .at(&obligation.cause, obligation.param_env)
+ .eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)?
+ .into_obligations();
+
+ for nested in &mut nested {
+ nested.set_depth_from_parent(obligation.recursion_depth);
+ }
+
+ Ok(nested)
+}
+
+fn evaluate_host_effect_from_bounds<'tcx>(
+ selcx: &mut SelectionContext<'_, 'tcx>,
+ obligation: &HostEffectObligation<'tcx>,
+) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
+ let infcx = selcx.infcx;
+ let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
+ let mut candidate = None;
+
+ for predicate in obligation.param_env.caller_bounds() {
+ let bound_predicate = predicate.kind();
+ if let ty::ClauseKind::HostEffect(data) = predicate.kind().skip_binder() {
+ let data = bound_predicate.rebind(data);
+ if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
+ continue;
+ }
+
+ if !drcx.args_may_unify(
+ obligation.predicate.trait_ref.args,
+ data.skip_binder().trait_ref.args,
+ ) {
+ continue;
+ }
+
+ let is_match = infcx.probe(|_| match_candidate(infcx, obligation, data).is_ok());
+
+ if is_match {
+ if candidate.is_some() {
+ return Err(EvaluationFailure::Ambiguous);
+ } else {
+ candidate = Some(data);
+ }
+ }
+ }
+ }
+
+ if let Some(data) = candidate {
+ Ok(match_candidate(infcx, obligation, data)
+ .expect("candidate matched before, so it should match again"))
+ } else {
+ Err(EvaluationFailure::NoSolution)
+ }
+}
+
+fn evaluate_host_effect_from_selection_candiate<'tcx>(
+ selcx: &mut SelectionContext<'_, 'tcx>,
+ obligation: &HostEffectObligation<'tcx>,
+) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
+ let tcx = selcx.tcx();
+ selcx.infcx.commit_if_ok(|_| {
+ match selcx.select(&obligation.with(tcx, obligation.predicate.trait_ref)) {
+ Ok(None) => Err(EvaluationFailure::Ambiguous),
+ Err(_) => Err(EvaluationFailure::NoSolution),
+ Ok(Some(source)) => match source {
+ ImplSource::UserDefined(impl_) => {
+ if tcx.constness(impl_.impl_def_id) != hir::Constness::Const {
+ return Err(EvaluationFailure::NoSolution);
+ }
+
+ let mut nested = impl_.nested;
+ nested.extend(
+ tcx.const_conditions(impl_.impl_def_id)
+ .instantiate(tcx, impl_.args)
+ .into_iter()
+ .map(|(trait_ref, _)| {
+ obligation.with(
+ tcx,
+ trait_ref.to_host_effect_clause(tcx, obligation.predicate.host),
+ )
+ }),
+ );
+
+ for nested in &mut nested {
+ nested.set_depth_from_parent(obligation.recursion_depth);
+ }
+
+ Ok(nested)
+ }
+ _ => Err(EvaluationFailure::NoSolution),
+ },
+ }
+ })
+}
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 2bdeb00..e3ad21e 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -17,6 +17,7 @@
use thin_vec::ThinVec;
use tracing::{debug, debug_span, instrument};
+use super::effects::{self, HostEffectObligation};
use super::project::{self, ProjectAndUnifyResult};
use super::select::SelectionContext;
use super::{
@@ -372,7 +373,11 @@
| ty::PredicateKind::Subtype(_)
| ty::PredicateKind::Coerce(_)
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
- | ty::PredicateKind::ConstEquate(..) => {
+ | ty::PredicateKind::ConstEquate(..)
+ // FIXME(effects): We may need to do this using the higher-ranked
+ // pred instead of just instantiating it with placeholders b/c of
+ // higher-ranked implied bound issues in the old solver.
+ | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
let pred = ty::Binder::dummy(infcx.enter_forall_and_leak_universe(binder));
let mut obligations = PredicateObligations::with_capacity(1);
obligations.push(obligation.with(infcx.tcx, pred));
@@ -398,6 +403,15 @@
)
}
+ ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => {
+ let host_obligation = obligation.with(infcx.tcx, data);
+
+ self.process_host_obligation(
+ host_obligation,
+ &mut pending_obligation.stalled_on,
+ )
+ }
+
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => {
if infcx.considering_regions {
infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
@@ -450,7 +464,6 @@
ty::ConstKind::Infer(var) => {
let var = match var {
ty::InferConst::Var(vid) => TyOrConstInferVar::Const(vid),
- ty::InferConst::EffectVar(vid) => TyOrConstInferVar::Effect(vid),
ty::InferConst::Fresh(_) => {
bug!("encountered fresh const in fulfill")
}
@@ -847,6 +860,27 @@
}
}
}
+
+ fn process_host_obligation(
+ &mut self,
+ host_obligation: HostEffectObligation<'tcx>,
+ stalled_on: &mut Vec<TyOrConstInferVar>,
+ ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
+ match effects::evaluate_host_effect_obligation(&mut self.selcx, &host_obligation) {
+ Ok(nested) => ProcessResult::Changed(mk_pending(nested)),
+ Err(effects::EvaluationFailure::Ambiguous) => {
+ stalled_on.clear();
+ stalled_on.extend(args_infer_vars(
+ &self.selcx,
+ ty::Binder::dummy(host_obligation.predicate.trait_ref.args),
+ ));
+ ProcessResult::Unchanged
+ }
+ Err(effects::EvaluationFailure::NoSolution) => {
+ ProcessResult::Error(FulfillmentErrorCode::Select(SelectionError::Unimplemented))
+ }
+ }
+ }
}
/// Returns the set of inference variables contained in `args`.
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index cdf2488..f5d9b50 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -6,6 +6,7 @@
pub(crate) mod coherence;
pub mod const_evaluatable;
mod dyn_compatibility;
+pub mod effects;
mod engine;
mod fulfill;
pub mod misc;
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 38722c0..0803dd7 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1180,7 +1180,7 @@
selcx.tcx(),
selcx.tcx().require_lang_item(
LangItem::Sized,
- Some(obligation.cause.span()),
+ Some(obligation.cause.span),
),
[self_ty],
),
@@ -1600,7 +1600,7 @@
// exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`.
let sized_predicate = ty::TraitRef::new(
tcx,
- tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span())),
+ tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)),
[self_ty],
);
obligations.push(obligation.with(tcx, sized_predicate));
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 7601729..bb44645 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -90,7 +90,7 @@
assert!(!self.intercrate);
let c_pred =
self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values);
- self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
+ self.tcx.at(obligation.cause.span).evaluate_obligation(c_pred)
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index dfd0cab..c6e41e5 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -96,6 +96,7 @@
// FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
// if we ever support that
ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
+ | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
@@ -200,6 +201,7 @@
// FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
// if we ever support that
ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
+ | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index eea3867..e027586 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -244,7 +244,6 @@
.param_env
.caller_bounds()
.iter()
- .filter(|p| !p.references_error())
.filter_map(|p| p.as_trait_clause())
// Micro-optimization: filter out predicates relating to different traits.
.filter(|p| p.def_id() == stack.obligation.predicate.def_id())
@@ -394,7 +393,7 @@
let self_ty = obligation.self_ty().skip_binder();
match *self_ty.kind() {
ty::Closure(def_id, _) => {
- let is_const = self.tcx().is_const_fn_raw(def_id);
+ let is_const = self.tcx().is_const_fn(def_id);
debug!(?kind, ?obligation, "assemble_unboxed_candidates");
match self.infcx.closure_kind(self_ty) {
Some(closure_kind) => {
@@ -414,7 +413,7 @@
}
ty::CoroutineClosure(def_id, args) => {
let args = args.as_coroutine_closure();
- let is_const = self.tcx().is_const_fn_raw(def_id);
+ let is_const = self.tcx().is_const_fn(def_id);
if let Some(closure_kind) = self.infcx.closure_kind(self_ty)
// Ambiguity if upvars haven't been constrained yet
&& !args.tupled_upvars_ty().is_ty_var()
@@ -547,7 +546,7 @@
}
}
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
- ty::FnDef(def_id, _args) => {
+ ty::FnDef(def_id, _) => {
let tcx = self.tcx();
if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
&& tcx.codegen_fn_attrs(def_id).target_features.is_empty()
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index d5b1c5a..635d3bc 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -49,7 +49,7 @@
use crate::solve::InferCtxtSelectExt as _;
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
-use crate::traits::{ProjectionCacheKey, Unimplemented};
+use crate::traits::{ProjectionCacheKey, Unimplemented, effects};
mod _match;
mod candidate_assembly;
@@ -645,6 +645,21 @@
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
}
+ ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => {
+ self.infcx.enter_forall(bound_predicate.rebind(data), |data| {
+ match effects::evaluate_host_effect_obligation(
+ self,
+ &obligation.with(self.tcx(), data),
+ ) {
+ Ok(nested) => {
+ self.evaluate_predicates_recursively(previous_stack, nested)
+ }
+ Err(effects::EvaluationFailure::Ambiguous) => Ok(EvaluatedToAmbig),
+ Err(effects::EvaluationFailure::NoSolution) => Ok(EvaluatedToErr),
+ }
+ })
+ }
+
ty::PredicateKind::Subtype(p) => {
let p = bound_predicate.rebind(p);
// Does this code ever run?
@@ -1821,8 +1836,7 @@
|cand: ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars();
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
- // `DiscriminantKindCandidate`, `ConstDestructCandidate`
- // to anything else.
+ // or `DiscriminantKindCandidate` to anything else.
//
// This is a fix for #53123 and prevents winnowing from accidentally extending the
// lifetime of a variable.
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 8904a9a..437343b 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -170,6 +170,10 @@
ty::ClauseKind::Trait(t) => {
wf.compute_trait_pred(t, Elaborate::None);
}
+ ty::ClauseKind::HostEffect(..) => {
+ // Technically the well-formedness of this predicate is implied by
+ // the corresponding trait predicate it should've been generated beside.
+ }
ty::ClauseKind::RegionOutlives(..) => {}
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
wf.compute(ty.into());
@@ -1021,6 +1025,7 @@
}
}
ty::ClauseKind::Trait(_)
+ | ty::ClauseKind::HostEffect(..)
| ty::ClauseKind::RegionOutlives(_)
| ty::ClauseKind::Projection(_)
| ty::ClauseKind::ConstArgHasType(_, _)
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index f01a12b..3e2794f 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -55,6 +55,7 @@
| ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => false,
ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
| ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
+ | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
| ty::PredicateKind::NormalizesTo(..)
| ty::PredicateKind::AliasRelate(..)
diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml
index 4732e96..6a98be1 100644
--- a/compiler/rustc_transmute/Cargo.toml
+++ b/compiler/rustc_transmute/Cargo.toml
@@ -5,6 +5,7 @@
[dependencies]
# tidy-alphabetical-start
+rustc_abi = { path = "../rustc_abi", optional = true }
rustc_ast_ir = { path = "../rustc_ast_ir", optional = true }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_hir = { path = "../rustc_hir", optional = true }
@@ -12,19 +13,18 @@
rustc_macros = { path = "../rustc_macros", optional = true }
rustc_middle = { path = "../rustc_middle", optional = true }
rustc_span = { path = "../rustc_span", optional = true }
-rustc_target = { path = "../rustc_target", optional = true }
tracing = "0.1"
# tidy-alphabetical-end
[features]
rustc = [
+ "dep:rustc_abi",
+ "dep:rustc_ast_ir",
"dep:rustc_hir",
"dep:rustc_infer",
"dep:rustc_macros",
"dep:rustc_middle",
"dep:rustc_span",
- "dep:rustc_target",
- "dep:rustc_ast_ir",
]
[dev-dependencies]
diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs
index a5c47c4..c4c01a8 100644
--- a/compiler/rustc_transmute/src/layout/mod.rs
+++ b/compiler/rustc_transmute/src/layout/mod.rs
@@ -62,10 +62,10 @@
pub mod rustc {
use std::fmt::{self, Write};
+ use rustc_abi::Layout;
use rustc_middle::mir::Mutability;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
use rustc_middle::ty::{self, Ty};
- use rustc_target::abi::Layout;
/// A reference in the layout.
#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 17eddbf..f19a567 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -171,12 +171,12 @@
#[cfg(feature = "rustc")]
pub(crate) mod rustc {
+ use rustc_abi::{
+ FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants,
+ };
use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
use rustc_middle::ty::{self, AdtDef, AdtKind, List, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::ErrorGuaranteed;
- use rustc_target::abi::{
- FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants,
- };
use super::Tree;
use crate::layout::rustc::{Def, Ref, layout_of};
@@ -206,7 +206,7 @@
impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx>) -> Result<Self, Err> {
- use rustc_target::abi::HasDataLayout;
+ use rustc_abi::HasDataLayout;
let layout = layout_of(cx, ty)?;
if let Err(e) = ty.error_reported() {
@@ -339,9 +339,7 @@
// 2. enums that delegate their layout to a variant
// 3. enums with multiple variants
match layout.variants() {
- Variants::Single { .. }
- if layout.abi.is_uninhabited() && layout.size == Size::ZERO =>
- {
+ Variants::Single { .. } if layout.is_uninhabited() && layout.size == Size::ZERO => {
// The layout representation of uninhabited, ZST enums is
// defined to be like that of the `!` type, as opposed of a
// typical enum. Consequently, they cannot be descended into
@@ -446,7 +444,7 @@
/// Constructs a `Tree` representing the value of a enum tag.
fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self {
- use rustc_target::abi::Endian;
+ use rustc_abi::Endian;
let size = tag.size();
let bits = tag.to_bits(size);
let bytes: [u8; 16];
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 09b9ecb..48149a0 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -1,7 +1,7 @@
use std::iter;
-use rustc_abi::Primitive::{Float, Pointer};
-use rustc_abi::{Abi, AddressSpace, PointerKind, Scalar, Size};
+use rustc_abi::Primitive::Pointer;
+use rustc_abi::{Abi, PointerKind, Scalar, Size};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_middle::bug;
@@ -13,8 +13,7 @@
use rustc_session::config::OptLevel;
use rustc_span::def_id::DefId;
use rustc_target::abi::call::{
- ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
- RiscvInterruptKind,
+ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, RiscvInterruptKind,
};
use rustc_target::spec::abi::Abi as SpecAbi;
use tracing::debug;
@@ -678,6 +677,8 @@
let tcx = cx.tcx();
if abi == SpecAbi::Rust || abi == SpecAbi::RustCall || abi == SpecAbi::RustIntrinsic {
+ fn_abi.adjust_for_rust_abi(cx, abi);
+
// Look up the deduced parameter attributes for this function, if we have its def ID and
// we're optimizing in non-incremental mode. We'll tag its parameters with those attributes
// as appropriate.
@@ -688,125 +689,9 @@
&[]
};
- let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, arg_idx: Option<usize>| {
+ for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() {
if arg.is_ignore() {
- return;
- }
-
- // Avoid returning floats in x87 registers on x86 as loading and storing from x87
- // registers will quiet signalling NaNs. Also avoid using SSE registers since they
- // are not always available (depending on target features).
- if tcx.sess.target.arch == "x86"
- && arg_idx.is_none()
- // Intrinsics themselves are not actual "real" functions, so theres no need to
- // change their ABIs.
- && abi != SpecAbi::RustIntrinsic
- {
- let has_float = match arg.layout.abi {
- Abi::Scalar(s) => matches!(s.primitive(), Float(_)),
- Abi::ScalarPair(s1, s2) => {
- matches!(s1.primitive(), Float(_)) || matches!(s2.primitive(), Float(_))
- }
- _ => false, // anyway not passed via registers on x86
- };
- if has_float {
- if arg.layout.size <= Pointer(AddressSpace::DATA).size(cx) {
- // Same size or smaller than pointer, return in a register.
- arg.cast_to(Reg { kind: RegKind::Integer, size: arg.layout.size });
- } else {
- // Larger than a pointer, return indirectly.
- arg.make_indirect();
- }
- return;
- }
- }
-
- if arg_idx.is_none() && arg.layout.size > Pointer(AddressSpace::DATA).size(cx) * 2 {
- // Return values larger than 2 registers using a return area
- // pointer. LLVM and Cranelift disagree about how to return
- // values that don't fit in the registers designated for return
- // values. LLVM will force the entire return value to be passed
- // by return area pointer, while Cranelift will look at each IR level
- // return value independently and decide to pass it in a
- // register or not, which would result in the return value
- // being passed partially in registers and partially through a
- // return area pointer.
- //
- // While Cranelift may need to be fixed as the LLVM behavior is
- // generally more correct with respect to the surface language,
- // forcing this behavior in rustc itself makes it easier for
- // other backends to conform to the Rust ABI and for the C ABI
- // rustc already handles this behavior anyway.
- //
- // In addition LLVM's decision to pass the return value in
- // registers or using a return area pointer depends on how
- // exactly the return type is lowered to an LLVM IR type. For
- // example `Option<u128>` can be lowered as `{ i128, i128 }`
- // in which case the x86_64 backend would use a return area
- // pointer, or it could be passed as `{ i32, i128 }` in which
- // case the x86_64 backend would pass it in registers by taking
- // advantage of an LLVM ABI extension that allows using 3
- // registers for the x86_64 sysv call conv rather than the
- // officially specified 2 registers.
- //
- // FIXME: Technically we should look at the amount of available
- // return registers rather than guessing that there are 2
- // registers for return values. In practice only a couple of
- // architectures have less than 2 return registers. None of
- // which supported by Cranelift.
- //
- // NOTE: This adjustment is only necessary for the Rust ABI as
- // for other ABI's the calling convention implementations in
- // rustc_target already ensure any return value which doesn't
- // fit in the available amount of return registers is passed in
- // the right way for the current target.
- arg.make_indirect();
- return;
- }
-
- match arg.layout.abi {
- Abi::Aggregate { .. } => {}
-
- // This is a fun case! The gist of what this is doing is
- // that we want callers and callees to always agree on the
- // ABI of how they pass SIMD arguments. If we were to *not*
- // make these arguments indirect then they'd be immediates
- // in LLVM, which means that they'd used whatever the
- // appropriate ABI is for the callee and the caller. That
- // means, for example, if the caller doesn't have AVX
- // enabled but the callee does, then passing an AVX argument
- // across this boundary would cause corrupt data to show up.
- //
- // This problem is fixed by unconditionally passing SIMD
- // arguments through memory between callers and callees
- // which should get them all to agree on ABI regardless of
- // target feature sets. Some more information about this
- // issue can be found in #44367.
- //
- // Note that the intrinsic ABI is exempt here as
- // that's how we connect up to LLVM and it's unstable
- // anyway, we control all calls to it in libstd.
- Abi::Vector { .. }
- if abi != SpecAbi::RustIntrinsic && tcx.sess.target.simd_types_indirect =>
- {
- arg.make_indirect();
- return;
- }
-
- _ => return,
- }
- // Compute `Aggregate` ABI.
-
- let is_indirect_not_on_stack =
- matches!(arg.mode, PassMode::Indirect { on_stack: false, .. });
- assert!(is_indirect_not_on_stack, "{:?}", arg);
-
- let size = arg.layout.size;
- if !arg.layout.is_unsized() && size <= Pointer(AddressSpace::DATA).size(cx) {
- // We want to pass small aggregates as immediates, but using
- // an LLVM aggregate type for this leads to bad optimizations,
- // so we pick an appropriately sized integer type instead.
- arg.cast_to(Reg { kind: RegKind::Integer, size });
+ continue;
}
// If we deduced that this parameter was read-only, add that to the attribute list now.
@@ -814,9 +699,7 @@
// The `readonly` parameter only applies to pointers, so we can only do this if the
// argument was passed indirectly. (If the argument is passed directly, it's an SSA
// value, so it's implicitly immutable.)
- if let (Some(arg_idx), &mut PassMode::Indirect { ref mut attrs, .. }) =
- (arg_idx, &mut arg.mode)
- {
+ if let &mut PassMode::Indirect { ref mut attrs, .. } = &mut arg.mode {
// The `deduced_param_attrs` list could be empty if this is a type of function
// we can't deduce any parameters for, so make sure the argument index is in
// bounds.
@@ -827,11 +710,6 @@
}
}
}
- };
-
- fixup(&mut fn_abi.ret, None);
- for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() {
- fixup(arg, Some(arg_idx));
}
} else {
fn_abi
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index a3210dd..16fd282 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -4,9 +4,8 @@
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt};
+use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
use rustc_middle::{bug, span_bug};
-use rustc_span::sym;
use rustc_span::symbol::kw;
pub(crate) fn provide(providers: &mut Providers) {
@@ -15,7 +14,6 @@
associated_item_def_ids,
associated_items,
associated_types_for_impl_traits_in_associated_fn,
- associated_type_for_effects,
associated_type_for_impl_trait_in_trait,
impl_item_implementor_ids,
..*providers
@@ -46,8 +44,7 @@
)
})
.copied(),
- )
- .chain(tcx.associated_type_for_effects(def_id)),
+ ),
)
}
hir::ItemKind::Impl(impl_) => {
@@ -73,8 +70,7 @@
)
})
.copied()
- }))
- .chain(tcx.associated_type_for_effects(def_id)),
+ })),
)
}
_ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
@@ -171,134 +167,6 @@
}
}
-/// Given an `def_id` of a trait or a trait impl:
-///
-/// If `def_id` is a trait that has `#[const_trait]`, then it synthesizes
-/// a new def id corresponding to a new associated type for the effects.
-///
-/// If `def_id` is an impl, then synthesize the associated type according
-/// to the constness of the impl.
-fn associated_type_for_effects(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
- // don't synthesize the associated type even if the user has written `const_trait`
- // if the effects feature is disabled.
- if !tcx.features().effects() {
- return None;
- }
- let (feed, parent_did) = match tcx.def_kind(def_id) {
- DefKind::Trait => {
- let trait_def_id = def_id;
- let attr = tcx.get_attr(def_id, sym::const_trait)?;
-
- let span = attr.span;
- let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, kw::Empty, DefKind::AssocTy);
-
- let local_def_id = trait_assoc_ty.def_id();
- let def_id = local_def_id.to_def_id();
-
- // Copy span of the attribute.
- trait_assoc_ty.def_ident_span(Some(span));
-
- trait_assoc_ty.associated_item(ty::AssocItem {
- name: kw::Empty,
- kind: ty::AssocKind::Type,
- def_id,
- trait_item_def_id: None,
- container: ty::TraitContainer,
- fn_has_self_parameter: false,
- opt_rpitit_info: None,
- is_effects_desugaring: true,
- });
-
- // No default type
- trait_assoc_ty.defaultness(hir::Defaultness::Default { has_value: false });
-
- trait_assoc_ty.is_type_alias_impl_trait(false);
-
- (trait_assoc_ty, trait_def_id)
- }
- DefKind::Impl { .. } => {
- let impl_def_id = def_id;
- let trait_id = tcx.trait_id_of_impl(def_id.to_def_id())?;
-
- // first get the DefId of the assoc type on the trait, if there is not,
- // then we don't need to generate it on the impl.
- let trait_assoc_id = tcx.associated_type_for_effects(trait_id)?;
-
- // FIXME(effects): span
- let span = tcx.def_ident_span(def_id).unwrap();
-
- let impl_assoc_ty = tcx.at(span).create_def(def_id, kw::Empty, DefKind::AssocTy);
-
- let local_def_id = impl_assoc_ty.def_id();
- let def_id = local_def_id.to_def_id();
-
- impl_assoc_ty.def_ident_span(Some(span));
-
- impl_assoc_ty.associated_item(ty::AssocItem {
- name: kw::Empty,
- kind: ty::AssocKind::Type,
- def_id,
- trait_item_def_id: Some(trait_assoc_id),
- container: ty::ImplContainer,
- fn_has_self_parameter: false,
- opt_rpitit_info: None,
- is_effects_desugaring: true,
- });
-
- // no default value.
- impl_assoc_ty.defaultness(hir::Defaultness::Final);
-
- // set the type of the associated type! If this is a const impl,
- // we set to Maybe, otherwise we set to `Runtime`.
- let type_def_id = if tcx.is_const_trait_impl_raw(impl_def_id.to_def_id()) {
- tcx.require_lang_item(hir::LangItem::EffectsMaybe, Some(span))
- } else {
- tcx.require_lang_item(hir::LangItem::EffectsRuntime, Some(span))
- };
- // FIXME(effects): make impls use `Min` for their effect types
- impl_assoc_ty.type_of(ty::EarlyBinder::bind(Ty::new_adt(
- tcx,
- tcx.adt_def(type_def_id),
- ty::GenericArgs::empty(),
- )));
-
- (impl_assoc_ty, impl_def_id)
- }
- def_kind => bug!(
- "associated_type_for_effects: {:?} should be Trait or Impl but is {:?}",
- def_id,
- def_kind
- ),
- };
-
- feed.feed_hir();
-
- // visibility is public.
- feed.visibility(ty::Visibility::Public);
-
- // Copy generics_of of the trait/impl, making the trait/impl as parent.
- feed.generics_of({
- let parent_generics = tcx.generics_of(parent_did);
- let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
-
- ty::Generics {
- parent: Some(parent_did.to_def_id()),
- parent_count,
- own_params: vec![],
- param_def_id_to_index: parent_generics.param_def_id_to_index.clone(),
- has_self: false,
- has_late_bound_regions: None,
- host_effect_index: parent_generics.host_effect_index,
- }
- });
- feed.explicit_item_super_predicates(ty::EarlyBinder::bind(&[]));
-
- // There are no inferred outlives for the synthesized associated type.
- feed.inferred_outlives_of(&[]);
-
- Some(feed.def_id().to_def_id())
-}
-
/// Given an `fn_def_id` of a trait or a trait implementation:
///
/// if `fn_def_id` is a function defined inside a trait, then it synthesizes
@@ -494,7 +362,6 @@
param_def_id_to_index,
has_self: false,
has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
- host_effect_index: parent_generics.host_effect_index,
}
});
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index e755e90..94b80e2 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -6,7 +6,7 @@
use rustc_abi::Primitive::{self, Float, Int, Pointer};
use rustc_abi::{
Abi, AbiAndPrefAlign, AddressSpace, Align, FieldsShape, HasDataLayout, LayoutCalculatorError,
- LayoutS, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange,
+ LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange,
};
use rustc_index::bit_set::BitSet;
use rustc_index::{IndexSlice, IndexVec};
@@ -131,7 +131,7 @@
fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>,
repr: &ReprOptions,
kind: StructKind,
-) -> Result<LayoutS<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
+) -> Result<LayoutData<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
let pack = repr.pack;
if pack.is_some() && repr.align.is_some() {
cx.tcx().dcx().bug("struct cannot be packed and aligned");
@@ -159,7 +159,7 @@
assert!(size.bits() <= 128);
Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
};
- let scalar = |value: Primitive| tcx.mk_layout(LayoutS::scalar(cx, scalar_unit(value)));
+ let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value)));
let univariant =
|fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, repr: &ReprOptions, kind| {
@@ -170,7 +170,7 @@
Ok(match *ty.kind() {
ty::Pat(ty, pat) => {
let layout = cx.layout_of(ty)?.layout;
- let mut layout = LayoutS::clone(&layout.0);
+ let mut layout = LayoutData::clone(&layout.0);
match *pat {
ty::PatternKind::Range { start, end, include_end } => {
if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi {
@@ -206,11 +206,11 @@
}
// Basic scalars.
- ty::Bool => tcx.mk_layout(LayoutS::scalar(cx, Scalar::Initialized {
+ ty::Bool => tcx.mk_layout(LayoutData::scalar(cx, Scalar::Initialized {
value: Int(I8, false),
valid_range: WrappingRange { start: 0, end: 1 },
})),
- ty::Char => tcx.mk_layout(LayoutS::scalar(cx, Scalar::Initialized {
+ ty::Char => tcx.mk_layout(LayoutData::scalar(cx, Scalar::Initialized {
value: Int(I32, false),
valid_range: WrappingRange { start: 0, end: 0x10FFFF },
})),
@@ -220,7 +220,7 @@
ty::FnPtr(..) => {
let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
ptr.valid_range_mut().start = 1;
- tcx.mk_layout(LayoutS::scalar(cx, ptr))
+ tcx.mk_layout(LayoutData::scalar(cx, ptr))
}
// The never type.
@@ -235,7 +235,7 @@
let pointee = tcx.normalize_erasing_regions(param_env, pointee);
if pointee.is_sized(tcx, param_env) {
- return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
+ return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
}
let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type()
@@ -272,7 +272,7 @@
let metadata_layout = cx.layout_of(metadata_ty)?;
// If the metadata is a 1-zst, then the pointer is thin.
if metadata_layout.is_1zst() {
- return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
+ return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
}
let Abi::Scalar(metadata) = metadata_layout.abi else {
@@ -285,7 +285,7 @@
match unsized_part.kind() {
ty::Foreign(..) => {
- return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
+ return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
}
ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
ty::Dynamic(..) => {
@@ -337,7 +337,7 @@
let largest_niche = if count != 0 { element.largest_niche } else { None };
- tcx.mk_layout(LayoutS {
+ tcx.mk_layout(LayoutData {
variants: Variants::Single { index: FIRST_VARIANT },
fields: FieldsShape::Array { stride: element.size, count },
abi,
@@ -350,7 +350,7 @@
}
ty::Slice(element) => {
let element = cx.layout_of(element)?;
- tcx.mk_layout(LayoutS {
+ tcx.mk_layout(LayoutData {
variants: Variants::Single { index: FIRST_VARIANT },
fields: FieldsShape::Array { stride: element.size, count: 0 },
abi: Abi::Aggregate { sized: false },
@@ -361,7 +361,7 @@
unadjusted_abi_align: element.align.abi,
})
}
- ty::Str => tcx.mk_layout(LayoutS {
+ ty::Str => tcx.mk_layout(LayoutData {
variants: Variants::Single { index: FIRST_VARIANT },
fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
abi: Abi::Aggregate { sized: false },
@@ -532,7 +532,7 @@
FieldsShape::Array { stride: e_ly.size, count: e_len }
};
- tcx.mk_layout(LayoutS {
+ tcx.mk_layout(LayoutData {
variants: Variants::Single { index: FIRST_VARIANT },
fields,
abi,
@@ -835,7 +835,7 @@
};
let tag_layout = TyAndLayout {
ty: discr_int.to_ty(tcx, /* signed = */ false),
- layout: tcx.mk_layout(LayoutS::scalar(cx, tag)),
+ layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
};
let promoted_layouts = ineligible_locals.iter().map(|local| {
@@ -991,7 +991,7 @@
Abi::Aggregate { sized: true }
};
- let layout = tcx.mk_layout(LayoutS {
+ let layout = tcx.mk_layout(LayoutData {
variants: Variants::Multiple {
tag,
tag_encoding: TagEncoding::Direct,
diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs
index 6cf114b..3db5a4f 100644
--- a/compiler/rustc_ty_utils/src/layout/invariant.rs
+++ b/compiler/rustc_ty_utils/src/layout/invariant.rs
@@ -10,7 +10,7 @@
// Type-level uninhabitedness should always imply ABI uninhabitedness.
if layout.ty.is_privately_uninhabited(tcx, cx.param_env) {
- assert!(layout.abi.is_uninhabited());
+ assert!(layout.is_uninhabited());
}
if layout.size.bytes() % layout.align.abi.bytes() != 0 {
@@ -262,9 +262,7 @@
)
}
// Skip empty variants.
- if variant.size == Size::ZERO
- || variant.fields.count() == 0
- || variant.abi.is_uninhabited()
+ if variant.size == Size::ZERO || variant.fields.count() == 0 || variant.is_uninhabited()
{
// These are never actually accessed anyway, so we can skip the coherence check
// for them. They also fail that check, since they have
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 28a81b1..aa49999 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -150,6 +150,16 @@
});
}
+ // We extend the param-env of our item with the const conditions of the item,
+ // since we're allowed to assume `~const` bounds hold within the item itself.
+ if tcx.is_conditionally_const(def_id) {
+ predicates.extend(
+ tcx.const_conditions(def_id).instantiate_identity(tcx).into_iter().map(
+ |(trait_ref, _)| trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
+ ),
+ );
+ }
+
let local_did = def_id.as_local();
let unnormalized_env =
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index f20beb7..c06a578 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -496,8 +496,8 @@
/// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity),
/// but on an iterator of values that deref to a `TypeFoldable`.
- pub fn iter_identity_copied(self) -> impl Iterator<Item = <Iter::Item as Deref>::Target> {
- self.value.into_iter().map(|v| *v)
+ pub fn iter_identity_copied(self) -> IterIdentityCopied<Iter> {
+ IterIdentityCopied { it: self.value.into_iter() }
}
}
@@ -546,6 +546,44 @@
{
}
+pub struct IterIdentityCopied<Iter: IntoIterator> {
+ it: Iter::IntoIter,
+}
+
+impl<Iter: IntoIterator> Iterator for IterIdentityCopied<Iter>
+where
+ Iter::Item: Deref,
+ <Iter::Item as Deref>::Target: Copy,
+{
+ type Item = <Iter::Item as Deref>::Target;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.it.next().map(|i| *i)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.it.size_hint()
+ }
+}
+
+impl<Iter: IntoIterator> DoubleEndedIterator for IterIdentityCopied<Iter>
+where
+ Iter::IntoIter: DoubleEndedIterator,
+ Iter::Item: Deref,
+ <Iter::Item as Deref>::Target: Copy,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.it.next_back().map(|i| *i)
+ }
+}
+
+impl<Iter: IntoIterator> ExactSizeIterator for IterIdentityCopied<Iter>
+where
+ Iter::IntoIter: ExactSizeIterator,
+ Iter::Item: Deref,
+ <Iter::Item as Deref>::Target: Copy,
+{
+}
pub struct EarlyBinderIter<I, T> {
t: T,
_tcx: PhantomData<I>,
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index 07cb8b0..3fb7d87 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -108,7 +108,6 @@
CanonicalVarKind::PlaceholderRegion(..) => false,
CanonicalVarKind::Const(_) => true,
CanonicalVarKind::PlaceholderConst(_) => false,
- CanonicalVarKind::Effect => true,
}
}
@@ -118,17 +117,15 @@
CanonicalVarKind::Ty(_)
| CanonicalVarKind::PlaceholderTy(_)
| CanonicalVarKind::Const(_)
- | CanonicalVarKind::PlaceholderConst(_)
- | CanonicalVarKind::Effect => false,
+ | CanonicalVarKind::PlaceholderConst(_) => false,
}
}
pub fn expect_placeholder_index(self) -> usize {
match self.kind {
- CanonicalVarKind::Ty(_)
- | CanonicalVarKind::Region(_)
- | CanonicalVarKind::Const(_)
- | CanonicalVarKind::Effect => panic!("expected placeholder: {self:?}"),
+ CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => {
+ panic!("expected placeholder: {self:?}")
+ }
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(),
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(),
@@ -161,9 +158,6 @@
/// Some kind of const inference variable.
Const(UniverseIndex),
- /// Effect variable `'?E`.
- Effect,
-
/// A "placeholder" that represents "any const".
PlaceholderConst(I::PlaceholderConst),
}
@@ -180,7 +174,6 @@
CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => {
UniverseIndex::ROOT
}
- CanonicalVarKind::Effect => UniverseIndex::ROOT,
}
}
@@ -205,8 +198,7 @@
CanonicalVarKind::PlaceholderConst(placeholder) => {
CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui))
}
- CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float)
- | CanonicalVarKind::Effect => {
+ CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
assert_eq!(ui, UniverseIndex::ROOT);
self
}
@@ -311,10 +303,6 @@
Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
.into()
}
- CanonicalVarKind::Effect => {
- Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
- .into()
- }
CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => {
Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
.into()
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index 7a8c612..03dfe54 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -84,32 +84,12 @@
pub struct ConstVid {}
}
-rustc_index::newtype_index! {
- /// An **effect** **v**ariable **ID**.
- ///
- /// Handling effect infer variables happens separately from const infer variables
- /// because we do not want to reuse any of the const infer machinery. If we try to
- /// relate an effect variable with a normal one, we would ICE, which can catch bugs
- /// where we are not correctly using the effect var for an effect param. Fallback
- /// is also implemented on top of having separate effect and normal const variables.
- #[encodable]
- #[orderable]
- #[debug_format = "?{}e"]
- #[gate_rustc_only]
- pub struct EffectVid {}
-}
-
/// An inference variable for a const, for use in const generics.
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))]
pub enum InferConst {
/// Infer the value of the const.
Var(ConstVid),
- /// Infer the value of the effect.
- ///
- /// For why this is separate from the `Var` variant above, see the
- /// documentation on `EffectVid`.
- EffectVar(EffectVid),
/// A fresh const variable. See `infer::freshen` for more details.
Fresh(u32),
}
@@ -118,7 +98,6 @@
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InferConst::Var(var) => write!(f, "{var:?}"),
- InferConst::EffectVar(var) => write!(f, "{var:?}"),
InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
}
}
@@ -128,7 +107,7 @@
impl<CTX> HashStable<CTX> for InferConst {
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
match self {
- InferConst::Var(_) | InferConst::EffectVar(_) => {
+ InferConst::Var(_) => {
panic!("const variables should not be hashed: {self:?}")
}
InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
diff --git a/compiler/rustc_type_ir/src/effects.rs b/compiler/rustc_type_ir/src/effects.rs
deleted file mode 100644
index ab43533..0000000
--- a/compiler/rustc_type_ir/src/effects.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use crate::Interner;
-use crate::inherent::*;
-use crate::lang_items::TraitSolverLangItem::{EffectsMaybe, EffectsNoRuntime, EffectsRuntime};
-
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub enum EffectKind {
- Maybe,
- Runtime,
- NoRuntime,
-}
-
-impl EffectKind {
- pub fn try_from_def_id<I: Interner>(cx: I, def_id: I::DefId) -> Option<EffectKind> {
- if cx.is_lang_item(def_id, EffectsMaybe) {
- Some(EffectKind::Maybe)
- } else if cx.is_lang_item(def_id, EffectsRuntime) {
- Some(EffectKind::Runtime)
- } else if cx.is_lang_item(def_id, EffectsNoRuntime) {
- Some(EffectKind::NoRuntime)
- } else {
- None
- }
- }
-
- pub fn to_def_id<I: Interner>(self, cx: I) -> I::DefId {
- let lang_item = match self {
- EffectKind::Maybe => EffectsMaybe,
- EffectKind::NoRuntime => EffectsNoRuntime,
- EffectKind::Runtime => EffectsRuntime,
- };
-
- cx.require_lang_item(lang_item)
- }
-
- pub fn try_from_ty<I: Interner>(cx: I, ty: I::Ty) -> Option<EffectKind> {
- if let crate::Adt(def, _) = ty.kind() {
- Self::try_from_def_id(cx, def.def_id())
- } else {
- None
- }
- }
-
- pub fn to_ty<I: Interner>(self, cx: I) -> I::Ty {
- I::Ty::new_adt(cx, cx.adt_def(self.to_def_id(cx)), Default::default())
- }
-
- /// Returns an intersection between two effect kinds. If one effect kind
- /// is more permissive than the other (e.g. `Maybe` vs `Runtime`), this
- /// returns the less permissive effect kind (`Runtime`).
- pub fn intersection(a: Self, b: Self) -> Option<Self> {
- use EffectKind::*;
- match (a, b) {
- (Maybe, x) | (x, Maybe) => Some(x),
- (Runtime, Runtime) => Some(Runtime),
- (NoRuntime, NoRuntime) => Some(NoRuntime),
- (Runtime, NoRuntime) | (NoRuntime, Runtime) => None,
- }
- }
-}
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index dac45ff..72d392e 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -4,7 +4,6 @@
use crate::data_structures::HashSet;
use crate::inherent::*;
-use crate::lang_items::TraitSolverLangItem;
use crate::outlives::{Component, push_outlives_components};
use crate::{self as ty, Interner, Upcast as _};
@@ -130,70 +129,6 @@
return;
}
- // HACK(effects): The following code is required to get implied bounds for effects associated
- // types to work with super traits.
- //
- // Suppose `data` is a trait predicate with the form `<T as Tr>::Fx: EffectsCompat<somebool>`
- // and we know that `trait Tr: ~const SuperTr`, we need to elaborate this predicate into
- // `<T as SuperTr>::Fx: EffectsCompat<somebool>`.
- //
- // Since the semantics for elaborating bounds about effects is equivalent to elaborating
- // bounds about super traits (elaborate `T: Tr` into `T: SuperTr`), we place effects elaboration
- // next to super trait elaboration.
- if cx.is_lang_item(data.def_id(), TraitSolverLangItem::EffectsCompat)
- && matches!(self.mode, Filter::All)
- {
- // first, ensure that the predicate we've got looks like a `<T as Tr>::Fx: EffectsCompat<somebool>`.
- if let ty::Alias(ty::AliasTyKind::Projection, alias_ty) = data.self_ty().kind()
- {
- // look for effects-level bounds that look like `<Self as Tr>::Fx: TyCompat<<Self as SuperTr>::Fx>`
- // on the trait, which is proof to us that `Tr: ~const SuperTr`. We're looking for bounds on the
- // associated trait, so we use `explicit_implied_predicates_of` since it gives us more than just
- // `Self: SuperTr` bounds.
- let bounds = cx.explicit_implied_predicates_of(cx.parent(alias_ty.def_id));
-
- // instantiate the implied bounds, so we get `<T as Tr>::Fx` and not `<Self as Tr>::Fx`.
- let elaborated = bounds.iter_instantiated(cx, alias_ty.args).filter_map(
- |(clause, _)| {
- let ty::ClauseKind::Trait(tycompat_bound) =
- clause.kind().skip_binder()
- else {
- return None;
- };
- if !cx.is_lang_item(
- tycompat_bound.def_id(),
- TraitSolverLangItem::EffectsTyCompat,
- ) {
- return None;
- }
-
- // extract `<T as SuperTr>::Fx` from the `TyCompat` bound.
- let supertrait_effects_ty =
- tycompat_bound.trait_ref.args.type_at(1);
- let ty::Alias(ty::AliasTyKind::Projection, supertrait_alias_ty) =
- supertrait_effects_ty.kind()
- else {
- return None;
- };
-
- // The self types (`T`) must be equal for `<T as Tr>::Fx` and `<T as SuperTr>::Fx`.
- if supertrait_alias_ty.self_ty() != alias_ty.self_ty() {
- return None;
- };
-
- // replace the self type in the original bound `<T as Tr>::Fx: EffectsCompat<somebool>`
- // to the effects type of the super trait. (`<T as SuperTr>::Fx`)
- let elaborated_bound = data.with_self_ty(cx, supertrait_effects_ty);
- Some(
- elaboratable
- .child(bound_clause.rebind(elaborated_bound).upcast(cx)),
- )
- },
- );
- self.extend_deduped(elaborated);
- }
- }
-
let map_to_child_clause =
|(index, (clause, span)): (usize, (I::Clause, I::Span))| {
elaboratable.child_with_derived_cause(
@@ -220,6 +155,16 @@
),
};
}
+ // `T: ~const Trait` implies `T: ~const Supertrait`.
+ ty::ClauseKind::HostEffect(data) => self.extend_deduped(
+ cx.implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| {
+ elaboratable.child(
+ trait_ref
+ .to_host_effect_clause(cx, data.host)
+ .instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)),
+ )
+ }),
+ ),
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
// We know that `T: 'a` for some type `T`. We can
// often elaborate this. For example, if we know that
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index b9f5cde..7c6a3c6 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -38,10 +38,6 @@
&self,
vid: ty::ConstVid,
) -> <Self::Interner as Interner>::Const;
- fn opportunistic_resolve_effect_var(
- &self,
- vid: ty::EffectVid,
- ) -> <Self::Interner as Interner>::Const;
fn opportunistic_resolve_lt_var(
&self,
vid: ty::RegionVid,
@@ -71,7 +67,6 @@
fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid);
fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid);
fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid);
- fn equate_effect_vids_raw(&self, a: ty::EffectVid, b: ty::EffectVid);
fn instantiate_ty_var_raw<R: PredicateEmittingRelation<Self>>(
&self,
@@ -83,11 +78,6 @@
) -> RelateResult<Self::Interner, ()>;
fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue);
fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue);
- fn instantiate_effect_var_raw(
- &self,
- vid: ty::EffectVid,
- value: <Self::Interner as Interner>::Const,
- );
fn instantiate_const_var_raw<R: PredicateEmittingRelation<Self>>(
&self,
relation: &mut R,
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 02ec29a..5af1aa2 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -468,6 +468,14 @@
.transpose()
}
+ fn as_host_effect_clause(self) -> Option<ty::Binder<I, ty::HostEffectPredicate<I>>> {
+ self.kind()
+ .map_bound(
+ |clause| if let ty::ClauseKind::HostEffect(t) = clause { Some(t) } else { None },
+ )
+ .transpose()
+ }
+
fn as_projection_clause(self) -> Option<ty::Binder<I, ty::ProjectionPredicate<I>>> {
self.kind()
.map_bound(
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 4184e9e..6a8113b 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -24,6 +24,7 @@
+ IrPrint<ty::AliasTerm<Self>>
+ IrPrint<ty::TraitRef<Self>>
+ IrPrint<ty::TraitPredicate<Self>>
+ + IrPrint<ty::HostEffectPredicate<Self>>
+ IrPrint<ty::ExistentialTraitRef<Self>>
+ IrPrint<ty::ExistentialProjection<Self>>
+ IrPrint<ty::ProjectionPredicate<Self>>
@@ -228,6 +229,16 @@
def_id: Self::DefId,
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>>;
+ fn is_const_impl(self, def_id: Self::DefId) -> bool;
+ fn const_conditions(
+ self,
+ def_id: Self::DefId,
+ ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>;
+ fn implied_const_bounds(
+ self,
+ def_id: Self::DefId,
+ ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>;
+
fn has_target_features(self, def_id: Self::DefId) -> bool;
fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId;
diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs
index d57d081..0c71f3a 100644
--- a/compiler/rustc_type_ir/src/ir_print.rs
+++ b/compiler/rustc_type_ir/src/ir_print.rs
@@ -2,8 +2,8 @@
use crate::{
AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
- Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate, SubtypePredicate,
- TraitPredicate, TraitRef,
+ HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate,
+ SubtypePredicate, TraitPredicate, TraitRef,
};
pub trait IrPrint<T> {
@@ -53,6 +53,7 @@
NormalizesTo,
SubtypePredicate,
CoercePredicate,
+ HostEffectPredicate,
AliasTy,
AliasTerm,
FnSig,
diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs
index c680c84..d6ca22a 100644
--- a/compiler/rustc_type_ir/src/lang_items.rs
+++ b/compiler/rustc_type_ir/src/lang_items.rs
@@ -20,13 +20,6 @@
Destruct,
DiscriminantKind,
DynMetadata,
- EffectsCompat,
- EffectsIntersection,
- EffectsIntersectionOutput,
- EffectsMaybe,
- EffectsNoRuntime,
- EffectsRuntime,
- EffectsTyCompat,
Fn,
FnMut,
FnOnce,
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 9e6d1f4..e7ca241 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -43,7 +43,6 @@
mod binder;
mod canonical;
mod const_kind;
-mod effects;
mod flags;
mod generic_arg;
mod infer_ctxt;
@@ -67,7 +66,6 @@
#[cfg(feature = "nightly")]
pub use codec::*;
pub use const_kind::*;
-pub use effects::*;
pub use flags::*;
pub use generic_arg::*;
pub use infer_ctxt::*;
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index e8ce39b..c316455 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -111,6 +111,13 @@
pub fn def_id(&self) -> I::DefId {
self.skip_binder().def_id
}
+
+ pub fn to_host_effect_clause(self, cx: I, host: HostPolarity) -> I::Clause {
+ self.map_bound(|trait_ref| {
+ ty::ClauseKind::HostEffect(HostEffectPredicate { trait_ref, host })
+ })
+ .upcast(cx)
+ }
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
@@ -745,6 +752,64 @@
}
}
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+pub struct HostEffectPredicate<I: Interner> {
+ pub trait_ref: ty::TraitRef<I>,
+ pub host: HostPolarity,
+}
+
+impl<I: Interner> HostEffectPredicate<I> {
+ pub fn self_ty(self) -> I::Ty {
+ self.trait_ref.self_ty()
+ }
+
+ pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
+ Self { trait_ref: self.trait_ref.with_self_ty(interner, self_ty), ..self }
+ }
+
+ pub fn def_id(self) -> I::DefId {
+ self.trait_ref.def_id
+ }
+}
+
+impl<I: Interner> ty::Binder<I, HostEffectPredicate<I>> {
+ pub fn def_id(self) -> I::DefId {
+ // Ok to skip binder since trait `DefId` does not care about regions.
+ self.skip_binder().def_id()
+ }
+
+ pub fn self_ty(self) -> ty::Binder<I, I::Ty> {
+ self.map_bound(|trait_ref| trait_ref.self_ty())
+ }
+
+ #[inline]
+ pub fn host(self) -> HostPolarity {
+ self.skip_binder().host
+ }
+}
+
+#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+pub enum HostPolarity {
+ /// May be called in const environments if the callee is const.
+ Maybe,
+ /// Always allowed to be called in const environments.
+ Const,
+}
+
+impl HostPolarity {
+ pub fn satisfies(self, goal: HostPolarity) -> bool {
+ match (self, goal) {
+ (HostPolarity::Const, HostPolarity::Const | HostPolarity::Maybe) => true,
+ (HostPolarity::Maybe, HostPolarity::Maybe) => true,
+ (HostPolarity::Maybe, HostPolarity::Const) => false,
+ }
+ }
+}
+
/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates
/// whether the `a` type is the type that we should label as "expected" when
/// presenting user diagnostics.
diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs
index 46202db..21f4456 100644
--- a/compiler/rustc_type_ir/src/predicate_kind.rs
+++ b/compiler/rustc_type_ir/src/predicate_kind.rs
@@ -37,6 +37,12 @@
/// Constant initializer must evaluate successfully.
ConstEvaluatable(I::Const),
+
+ /// Enforces the constness of the predicate we're calling. Like a projection
+ /// goal from a where clause, it's always going to be paired with a
+ /// corresponding trait clause; this just enforces the *constness* of that
+ /// implementation.
+ HostEffect(ty::HostEffectPredicate<I>),
}
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
@@ -110,6 +116,7 @@
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"),
+ ClauseKind::HostEffect(data) => data.fmt(f),
ClauseKind::Trait(a) => a.fmt(f),
ClauseKind::RegionOutlives(pair) => pair.fmt(f),
ClauseKind::TypeOutlives(pair) => pair.fmt(f),
diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs
index 60a9538..17a3912 100644
--- a/compiler/rustc_type_ir/src/relate/combine.rs
+++ b/compiler/rustc_type_ir/src/relate/combine.rs
@@ -179,23 +179,9 @@
Ok(a)
}
- (
- ty::ConstKind::Infer(ty::InferConst::EffectVar(a_vid)),
- ty::ConstKind::Infer(ty::InferConst::EffectVar(b_vid)),
- ) => {
- infcx.equate_effect_vids_raw(a_vid, b_vid);
- Ok(a)
- }
-
// All other cases of inference with other variables are errors.
- (
- ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)),
- ty::ConstKind::Infer(_),
- )
- | (
- ty::ConstKind::Infer(_),
- ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)),
- ) => {
+ (ty::ConstKind::Infer(ty::InferConst::Var(_)), ty::ConstKind::Infer(_))
+ | (ty::ConstKind::Infer(_), ty::ConstKind::Infer(ty::InferConst::Var(_))) => {
panic!(
"tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
)
@@ -211,16 +197,6 @@
Ok(a)
}
- (ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)), _) => {
- infcx.instantiate_effect_var_raw(vid, b);
- Ok(b)
- }
-
- (_, ty::ConstKind::Infer(ty::InferConst::EffectVar(vid))) => {
- infcx.instantiate_effect_var_raw(vid, a);
- Ok(a)
- }
-
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
if infcx.cx().features().generic_const_exprs() || infcx.next_trait_solver() =>
{
diff --git a/compiler/stable_mir/README.md b/compiler/stable_mir/README.md
index 31dee95..ab2546e 100644
--- a/compiler/stable_mir/README.md
+++ b/compiler/stable_mir/README.md
@@ -1,93 +1,33 @@
-This crate is regularly synced with its mirror in the rustc repo at `compiler/rustc_smir`.
+This crate is currently developed in-tree together with the compiler.
-We use `git subtree` for this to preserve commits and allow the rustc repo to
-edit these crates without having to touch this repo. This keeps the crates compiling
-while allowing us to independently work on them here. The effort of keeping them in
-sync is pushed entirely onto us, without affecting rustc workflows negatively.
-This may change in the future, but changes to policy should only be done via a
-compiler team MCP.
+Our goal is to start publishing `stable_mir` into crates.io.
+Until then, users will use this as any other rustc crate, by installing
+the rustup component `rustc-dev`, and declaring `stable-mir` as an external crate.
-## Instructions for working on this crate locally
-
-Since the crate is the same in the rustc repo and here, the dependencies on rustc_* crates
-will only either work here or there, but never in both places at the same time. Thus we use
-optional dependencies on the rustc_* crates, requiring local development to use
-
-```
-cargo build --no-default-features -Zavoid-dev-deps
-```
-
-in order to compile successfully.
-
-## Instructions for syncing
-
-### Updating this repository
-
-In the rustc repo, execute
-
-```
-git subtree push --prefix=compiler/rustc_smir url_to_your_fork_of_project_stable_mir some_feature_branch
-```
-
-and then open a PR of your `some_feature_branch` against https://github.com/rust-lang/project-stable-mir
-
-### Updating the rustc library
-
-First we need to bump our stack limit, as the rustc repo otherwise quickly hits that:
-
-```
-ulimit -s 60000
-```
-
-#### Maximum function recursion depth (1000) reached
-
-Then we need to disable `dash` as the default shell for sh scripts, as otherwise we run into a
-hard limit of a recursion depth of 1000:
-
-```
-sudo dpkg-reconfigure dash
-```
-
-and then select `No` to disable dash.
-
-
-#### Patching your `git worktree`
-
-The regular git worktree does not scale to repos of the size of the rustc repo.
-So download the `git-subtree.sh` from https://github.com/gitgitgadget/git/pull/493/files and run
-
-```
-sudo cp --backup /path/to/patched/git-subtree.sh /usr/lib/git-core/git-subtree
-sudo chmod --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree
-sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree
-```
-
-#### Actually doing a sync
-
-In the rustc repo, execute
-
-```
-git subtree pull --prefix=compiler/rustc_smir https://github.com/rust-lang/project-stable-mir smir
-```
-
-Note: only ever sync to rustc from the project-stable-mir's `smir` branch. Do not sync with your own forks.
-
-Then open a PR against rustc just like a regular PR.
+See the StableMIR ["Getting Started"](https://rust-lang.github.io/project-stable-mir/getting-started.html)
+guide for more information.
## Stable MIR Design
-The stable-mir will follow a similar approach to proc-macro2. It’s
-implementation will eventually be broken down into two main crates:
+The stable-mir will follow a similar approach to proc-macro2. Its
+implementation is split between two main crates:
- `stable_mir`: Public crate, to be published on crates.io, which will contain
-the stable data structure as well as proxy APIs to make calls to the
-compiler.
-- `rustc_smir`: The compiler crate that will translate from internal MIR to
-SMIR. This crate will also implement APIs that will be invoked by
-stable-mir to query the compiler for more information.
+the stable data structure as well as calls to `rustc_smir` APIs. The
+translation between stable and internal constructs will also be done in this crate,
+however, this is currently implemented in the `rustc_smir` crate.[^translation].
+- `rustc_smir`: This crate implements the public APIs to the compiler.
+It is responsible for gathering all the information requested, and providing
+the data in its unstable form.
-This will help tools to communicate with the rust compiler via stable APIs. Tools will depend on
-`stable_mir` crate, which will invoke the compiler using APIs defined in `rustc_smir`. I.e.:
+[^translation]: This is currently implemented in the `rustc_smir` crate,
+but we are working to change that.
+
+I.e.,
+tools will depend on `stable_mir` crate,
+which will invoke the compiler using APIs defined in `rustc_smir`.
+
+I.e.:
```
┌──────────────────────────────────┐ ┌──────────────────────────────────┐
@@ -104,9 +44,3 @@
More details can be found here:
https://hackmd.io/XhnYHKKuR6-LChhobvlT-g?view
-
-For now, the code for these two crates are in separate modules of this crate.
-The modules have the same name for simplicity. We also have a third module,
-`rustc_internal` which will expose APIs and definitions that allow users to
-gather information from internal MIR constructs that haven't been exposed in
-the `stable_mir` module.
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 9e6fbc8..8db1258 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -1393,7 +1393,6 @@
pub param_def_id_to_index: Vec<(GenericDef, u32)>,
pub has_self: bool,
pub has_late_bound_regions: Option<Span>,
- pub host_effect_index: Option<usize>,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
diff --git a/config.example.toml b/config.example.toml
index 168ac35..d5b904e 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -84,6 +84,9 @@
# Wheter to build Enzyme as AutoDiff backend.
#enzyme = false
+# Whether to build LLVM with support for it's gpu offload runtime.
+#offload = false
+
# Indicates whether ccache is used when building LLVM. Set to `true` to use the first `ccache` in
# PATH, or set an absolute path to use a specific version.
#ccache = false
@@ -419,6 +422,9 @@
# passed to cargo invocations.
#jobs = 0
+# What custom diff tool to use for displaying compiletest tests.
+#compiletest-diff-tool = <none>
+
# =============================================================================
# General install configuration options
# =============================================================================
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 3e79141..e4956c7 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -183,45 +183,41 @@
#![stable(feature = "rust1", since = "1.0.0")]
-use core::any::Any;
-use core::async_iter::AsyncIterator;
+use core::borrow::{Borrow, BorrowMut};
#[cfg(not(no_global_oom_handling))]
use core::clone::CloneToUninit;
use core::cmp::Ordering;
-use core::error::Error;
+use core::error::{self, Error};
+use core::fmt;
use core::future::Future;
use core::hash::{Hash, Hasher};
-use core::iter::FusedIterator;
use core::marker::{Tuple, Unsize};
use core::mem::{self, SizedTypeProperties};
use core::ops::{
AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut,
- DerefPure, DispatchFromDyn, Receiver,
+ DerefPure, DispatchFromDyn, LegacyReceiver,
};
use core::pin::{Pin, PinCoerceUnsized};
use core::ptr::{self, NonNull, Unique};
use core::task::{Context, Poll};
-use core::{borrow, fmt, slice};
-
-#[unstable(feature = "thin_box", issue = "92791")]
-pub use thin::ThinBox;
#[cfg(not(no_global_oom_handling))]
use crate::alloc::handle_alloc_error;
use crate::alloc::{AllocError, Allocator, Global, Layout};
-#[cfg(not(no_global_oom_handling))]
-use crate::borrow::Cow;
use crate::raw_vec::RawVec;
#[cfg(not(no_global_oom_handling))]
use crate::str::from_boxed_utf8_unchecked;
-#[cfg(not(no_global_oom_handling))]
-use crate::string::String;
-use crate::vec;
-#[cfg(not(no_global_oom_handling))]
-use crate::vec::Vec;
+/// Conversion related impls for `Box<_>` (`From`, `downcast`, etc)
+mod convert;
+/// Iterator related impls for `Box<_>`.
+mod iter;
+/// [`ThinBox`] implementation.
mod thin;
+#[unstable(feature = "thin_box", issue = "92791")]
+pub use thin::ThinBox;
+
/// A pointer type that uniquely owns a heap allocation of type `T`.
///
/// See the [module-level documentation](../../std/boxed/index.html) for more.
@@ -1768,6 +1764,41 @@
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "box_slice_clone", since = "1.3.0")]
+impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> {
+ fn clone(&self) -> Self {
+ let alloc = Box::allocator(self).clone();
+ self.to_vec_in(alloc).into_boxed_slice()
+ }
+
+ /// Copies `source`'s contents into `self` without creating a new allocation,
+ /// so long as the two are of the same length.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = Box::new([5, 6, 7]);
+ /// let mut y = Box::new([8, 9, 10]);
+ /// let yp: *const [i32] = &*y;
+ ///
+ /// y.clone_from(&x);
+ ///
+ /// // The value is the same
+ /// assert_eq!(x, y);
+ ///
+ /// // And no allocation occurred
+ /// assert_eq!(yp, &*y);
+ /// ```
+ fn clone_from(&mut self, source: &Self) {
+ if self.len() == source.len() {
+ self.clone_from_slice(&source);
+ } else {
+ *self = source.clone();
+ }
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "box_slice_clone", since = "1.3.0")]
impl Clone for Box<str> {
fn clone(&self) -> Self {
// this makes a copy of the data
@@ -1787,6 +1818,7 @@
PartialEq::ne(&**self, &**other)
}
}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + PartialOrd, A: Allocator> PartialOrd for Box<T, A> {
#[inline]
@@ -1810,6 +1842,7 @@
PartialOrd::gt(&**self, &**other)
}
}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + Ord, A: Allocator> Ord for Box<T, A> {
#[inline]
@@ -1817,6 +1850,7 @@
Ord::cmp(&**self, &**other)
}
}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + Eq, A: Allocator> Eq for Box<T, A> {}
@@ -1879,462 +1913,6 @@
}
}
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "from_for_ptrs", since = "1.6.0")]
-impl<T> From<T> for Box<T> {
- /// Converts a `T` into a `Box<T>`
- ///
- /// The conversion allocates on the heap and moves `t`
- /// from the stack into it.
- ///
- /// # Examples
- ///
- /// ```rust
- /// let x = 5;
- /// let boxed = Box::new(5);
- ///
- /// assert_eq!(Box::from(x), boxed);
- /// ```
- fn from(t: T) -> Self {
- Box::new(t)
- }
-}
-
-#[stable(feature = "pin", since = "1.33.0")]
-impl<T: ?Sized, A: Allocator> From<Box<T, A>> for Pin<Box<T, A>>
-where
- A: 'static,
-{
- /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
- /// `*boxed` will be pinned in memory and unable to be moved.
- ///
- /// This conversion does not allocate on the heap and happens in place.
- ///
- /// This is also available via [`Box::into_pin`].
- ///
- /// Constructing and pinning a `Box` with <code><Pin<Box\<T>>>::from([Box::new]\(x))</code>
- /// can also be written more concisely using <code>[Box::pin]\(x)</code>.
- /// This `From` implementation is useful if you already have a `Box<T>`, or you are
- /// constructing a (pinned) `Box` in a different way than with [`Box::new`].
- fn from(boxed: Box<T, A>) -> Self {
- Box::into_pin(boxed)
- }
-}
-
-/// Specialization trait used for `From<&[T]>`.
-#[cfg(not(no_global_oom_handling))]
-trait BoxFromSlice<T> {
- fn from_slice(slice: &[T]) -> Self;
-}
-
-#[cfg(not(no_global_oom_handling))]
-impl<T: Clone> BoxFromSlice<T> for Box<[T]> {
- #[inline]
- default fn from_slice(slice: &[T]) -> Self {
- slice.to_vec().into_boxed_slice()
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-impl<T: Copy> BoxFromSlice<T> for Box<[T]> {
- #[inline]
- fn from_slice(slice: &[T]) -> Self {
- let len = slice.len();
- let buf = RawVec::with_capacity(len);
- unsafe {
- ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
- buf.into_box(slice.len()).assume_init()
- }
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "box_from_slice", since = "1.17.0")]
-impl<T: Clone> From<&[T]> for Box<[T]> {
- /// Converts a `&[T]` into a `Box<[T]>`
- ///
- /// This conversion allocates on the heap
- /// and performs a copy of `slice` and its contents.
- ///
- /// # Examples
- /// ```rust
- /// // create a &[u8] which will be used to create a Box<[u8]>
- /// let slice: &[u8] = &[104, 101, 108, 108, 111];
- /// let boxed_slice: Box<[u8]> = Box::from(slice);
- ///
- /// println!("{boxed_slice:?}");
- /// ```
- #[inline]
- fn from(slice: &[T]) -> Box<[T]> {
- <Self as BoxFromSlice<T>>::from_slice(slice)
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "box_from_cow", since = "1.45.0")]
-impl<T: Clone> From<Cow<'_, [T]>> for Box<[T]> {
- /// Converts a `Cow<'_, [T]>` into a `Box<[T]>`
- ///
- /// When `cow` is the `Cow::Borrowed` variant, this
- /// conversion allocates on the heap and copies the
- /// underlying slice. Otherwise, it will try to reuse the owned
- /// `Vec`'s allocation.
- #[inline]
- fn from(cow: Cow<'_, [T]>) -> Box<[T]> {
- match cow {
- Cow::Borrowed(slice) => Box::from(slice),
- Cow::Owned(slice) => Box::from(slice),
- }
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "box_from_slice", since = "1.17.0")]
-impl From<&str> for Box<str> {
- /// Converts a `&str` into a `Box<str>`
- ///
- /// This conversion allocates on the heap
- /// and performs a copy of `s`.
- ///
- /// # Examples
- ///
- /// ```rust
- /// let boxed: Box<str> = Box::from("hello");
- /// println!("{boxed}");
- /// ```
- #[inline]
- fn from(s: &str) -> Box<str> {
- unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) }
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "box_from_cow", since = "1.45.0")]
-impl From<Cow<'_, str>> for Box<str> {
- /// Converts a `Cow<'_, str>` into a `Box<str>`
- ///
- /// When `cow` is the `Cow::Borrowed` variant, this
- /// conversion allocates on the heap and copies the
- /// underlying `str`. Otherwise, it will try to reuse the owned
- /// `String`'s allocation.
- ///
- /// # Examples
- ///
- /// ```rust
- /// use std::borrow::Cow;
- ///
- /// let unboxed = Cow::Borrowed("hello");
- /// let boxed: Box<str> = Box::from(unboxed);
- /// println!("{boxed}");
- /// ```
- ///
- /// ```rust
- /// # use std::borrow::Cow;
- /// let unboxed = Cow::Owned("hello".to_string());
- /// let boxed: Box<str> = Box::from(unboxed);
- /// println!("{boxed}");
- /// ```
- #[inline]
- fn from(cow: Cow<'_, str>) -> Box<str> {
- match cow {
- Cow::Borrowed(s) => Box::from(s),
- Cow::Owned(s) => Box::from(s),
- }
- }
-}
-
-#[stable(feature = "boxed_str_conv", since = "1.19.0")]
-impl<A: Allocator> From<Box<str, A>> for Box<[u8], A> {
- /// Converts a `Box<str>` into a `Box<[u8]>`
- ///
- /// This conversion does not allocate on the heap and happens in place.
- ///
- /// # Examples
- /// ```rust
- /// // create a Box<str> which will be used to create a Box<[u8]>
- /// let boxed: Box<str> = Box::from("hello");
- /// let boxed_str: Box<[u8]> = Box::from(boxed);
- ///
- /// // create a &[u8] which will be used to create a Box<[u8]>
- /// let slice: &[u8] = &[104, 101, 108, 108, 111];
- /// let boxed_slice = Box::from(slice);
- ///
- /// assert_eq!(boxed_slice, boxed_str);
- /// ```
- #[inline]
- fn from(s: Box<str, A>) -> Self {
- let (raw, alloc) = Box::into_raw_with_allocator(s);
- unsafe { Box::from_raw_in(raw as *mut [u8], alloc) }
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "box_from_array", since = "1.45.0")]
-impl<T, const N: usize> From<[T; N]> for Box<[T]> {
- /// Converts a `[T; N]` into a `Box<[T]>`
- ///
- /// This conversion moves the array to newly heap-allocated memory.
- ///
- /// # Examples
- ///
- /// ```rust
- /// let boxed: Box<[u8]> = Box::from([4, 2]);
- /// println!("{boxed:?}");
- /// ```
- fn from(array: [T; N]) -> Box<[T]> {
- Box::new(array)
- }
-}
-
-/// Casts a boxed slice to a boxed array.
-///
-/// # Safety
-///
-/// `boxed_slice.len()` must be exactly `N`.
-unsafe fn boxed_slice_as_array_unchecked<T, A: Allocator, const N: usize>(
- boxed_slice: Box<[T], A>,
-) -> Box<[T; N], A> {
- debug_assert_eq!(boxed_slice.len(), N);
-
- let (ptr, alloc) = Box::into_raw_with_allocator(boxed_slice);
- // SAFETY: Pointer and allocator came from an existing box,
- // and our safety condition requires that the length is exactly `N`
- unsafe { Box::from_raw_in(ptr as *mut [T; N], alloc) }
-}
-
-#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
-impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
- type Error = Box<[T]>;
-
- /// Attempts to convert a `Box<[T]>` into a `Box<[T; N]>`.
- ///
- /// The conversion occurs in-place and does not require a
- /// new memory allocation.
- ///
- /// # Errors
- ///
- /// Returns the old `Box<[T]>` in the `Err` variant if
- /// `boxed_slice.len()` does not equal `N`.
- fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
- if boxed_slice.len() == N {
- Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
- } else {
- Err(boxed_slice)
- }
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_array_try_from_vec", since = "1.66.0")]
-impl<T, const N: usize> TryFrom<Vec<T>> for Box<[T; N]> {
- type Error = Vec<T>;
-
- /// Attempts to convert a `Vec<T>` into a `Box<[T; N]>`.
- ///
- /// Like [`Vec::into_boxed_slice`], this is in-place if `vec.capacity() == N`,
- /// but will require a reallocation otherwise.
- ///
- /// # Errors
- ///
- /// Returns the original `Vec<T>` in the `Err` variant if
- /// `boxed_slice.len()` does not equal `N`.
- ///
- /// # Examples
- ///
- /// This can be used with [`vec!`] to create an array on the heap:
- ///
- /// ```
- /// let state: Box<[f32; 100]> = vec![1.0; 100].try_into().unwrap();
- /// assert_eq!(state.len(), 100);
- /// ```
- fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> {
- if vec.len() == N {
- let boxed_slice = vec.into_boxed_slice();
- Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
- } else {
- Err(vec)
- }
- }
-}
-
-impl<A: Allocator> Box<dyn Any, A> {
- /// Attempts to downcast the box to a concrete type.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::any::Any;
- ///
- /// fn print_if_string(value: Box<dyn Any>) {
- /// if let Ok(string) = value.downcast::<String>() {
- /// println!("String ({}): {}", string.len(), string);
- /// }
- /// }
- ///
- /// let my_string = "Hello World".to_string();
- /// print_if_string(Box::new(my_string));
- /// print_if_string(Box::new(0i8));
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
- if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
- }
-
- /// Downcasts the box to a concrete type.
- ///
- /// For a safe alternative see [`downcast`].
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(downcast_unchecked)]
- ///
- /// use std::any::Any;
- ///
- /// let x: Box<dyn Any> = Box::new(1_usize);
- ///
- /// unsafe {
- /// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
- /// }
- /// ```
- ///
- /// # Safety
- ///
- /// The contained value must be of type `T`. Calling this method
- /// with the incorrect type is *undefined behavior*.
- ///
- /// [`downcast`]: Self::downcast
- #[inline]
- #[unstable(feature = "downcast_unchecked", issue = "90850")]
- pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
- debug_assert!(self.is::<T>());
- unsafe {
- let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self);
- Box::from_raw_in(raw as *mut T, alloc)
- }
- }
-}
-
-impl<A: Allocator> Box<dyn Any + Send, A> {
- /// Attempts to downcast the box to a concrete type.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::any::Any;
- ///
- /// fn print_if_string(value: Box<dyn Any + Send>) {
- /// if let Ok(string) = value.downcast::<String>() {
- /// println!("String ({}): {}", string.len(), string);
- /// }
- /// }
- ///
- /// let my_string = "Hello World".to_string();
- /// print_if_string(Box::new(my_string));
- /// print_if_string(Box::new(0i8));
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
- if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
- }
-
- /// Downcasts the box to a concrete type.
- ///
- /// For a safe alternative see [`downcast`].
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(downcast_unchecked)]
- ///
- /// use std::any::Any;
- ///
- /// let x: Box<dyn Any + Send> = Box::new(1_usize);
- ///
- /// unsafe {
- /// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
- /// }
- /// ```
- ///
- /// # Safety
- ///
- /// The contained value must be of type `T`. Calling this method
- /// with the incorrect type is *undefined behavior*.
- ///
- /// [`downcast`]: Self::downcast
- #[inline]
- #[unstable(feature = "downcast_unchecked", issue = "90850")]
- pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
- debug_assert!(self.is::<T>());
- unsafe {
- let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self);
- Box::from_raw_in(raw as *mut T, alloc)
- }
- }
-}
-
-impl<A: Allocator> Box<dyn Any + Send + Sync, A> {
- /// Attempts to downcast the box to a concrete type.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::any::Any;
- ///
- /// fn print_if_string(value: Box<dyn Any + Send + Sync>) {
- /// if let Ok(string) = value.downcast::<String>() {
- /// println!("String ({}): {}", string.len(), string);
- /// }
- /// }
- ///
- /// let my_string = "Hello World".to_string();
- /// print_if_string(Box::new(my_string));
- /// print_if_string(Box::new(0i8));
- /// ```
- #[inline]
- #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
- pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
- if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
- }
-
- /// Downcasts the box to a concrete type.
- ///
- /// For a safe alternative see [`downcast`].
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(downcast_unchecked)]
- ///
- /// use std::any::Any;
- ///
- /// let x: Box<dyn Any + Send + Sync> = Box::new(1_usize);
- ///
- /// unsafe {
- /// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
- /// }
- /// ```
- ///
- /// # Safety
- ///
- /// The contained value must be of type `T`. Calling this method
- /// with the incorrect type is *undefined behavior*.
- ///
- /// [`downcast`]: Self::downcast
- #[inline]
- #[unstable(feature = "downcast_unchecked", issue = "90850")]
- pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
- debug_assert!(self.is::<T>());
- unsafe {
- let (raw, alloc): (*mut (dyn Any + Send + Sync), _) =
- Box::into_raw_with_allocator(self);
- Box::from_raw_in(raw as *mut T, alloc)
- }
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Display + ?Sized, A: Allocator> fmt::Display for Box<T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -2378,73 +1956,8 @@
#[unstable(feature = "deref_pure_trait", issue = "87121")]
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Box<T, A> {}
-#[unstable(feature = "receiver_trait", issue = "none")]
-impl<T: ?Sized, A: Allocator> Receiver for Box<T, A> {}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator + ?Sized, A: Allocator> Iterator for Box<I, A> {
- type Item = I::Item;
- fn next(&mut self) -> Option<I::Item> {
- (**self).next()
- }
- fn size_hint(&self) -> (usize, Option<usize>) {
- (**self).size_hint()
- }
- fn nth(&mut self, n: usize) -> Option<I::Item> {
- (**self).nth(n)
- }
- fn last(self) -> Option<I::Item> {
- BoxIter::last(self)
- }
-}
-
-trait BoxIter {
- type Item;
- fn last(self) -> Option<Self::Item>;
-}
-
-impl<I: Iterator + ?Sized, A: Allocator> BoxIter for Box<I, A> {
- type Item = I::Item;
- default fn last(self) -> Option<I::Item> {
- #[inline]
- fn some<T>(_: Option<T>, x: T) -> Option<T> {
- Some(x)
- }
-
- self.fold(None, some)
- }
-}
-
-/// Specialization for sized `I`s that uses `I`s implementation of `last()`
-/// instead of the default.
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator, A: Allocator> BoxIter for Box<I, A> {
- fn last(self) -> Option<I::Item> {
- (*self).last()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: DoubleEndedIterator + ?Sized, A: Allocator> DoubleEndedIterator for Box<I, A> {
- fn next_back(&mut self) -> Option<I::Item> {
- (**self).next_back()
- }
- fn nth_back(&mut self, n: usize) -> Option<I::Item> {
- (**self).nth_back(n)
- }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: ExactSizeIterator + ?Sized, A: Allocator> ExactSizeIterator for Box<I, A> {
- fn len(&self) -> usize {
- (**self).len()
- }
- fn is_empty(&self) -> bool {
- (**self).is_empty()
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {}
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
impl<Args: Tuple, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
@@ -2501,157 +2014,24 @@
#[unstable(feature = "coerce_unsized", issue = "18598")]
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Box<T, A> {}
+
// It is quite crucial that we only allow the `Global` allocator here.
// Handling arbitrary custom allocators (which can affect the `Box` layout heavily!)
// would need a lot of codegen and interpreter adjustments.
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T, Global> {}
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_slice_from_iter", since = "1.32.0")]
-impl<I> FromIterator<I> for Box<[I]> {
- fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
- iter.into_iter().collect::<Vec<_>>().into_boxed_slice()
- }
-}
-
-/// This implementation is required to make sure that the `Box<[I]>: IntoIterator`
-/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
-#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
-impl<I, A: Allocator> !Iterator for Box<[I], A> {}
-
-/// This implementation is required to make sure that the `&Box<[I]>: IntoIterator`
-/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
-#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
-impl<'a, I, A: Allocator> !Iterator for &'a Box<[I], A> {}
-
-/// This implementation is required to make sure that the `&mut Box<[I]>: IntoIterator`
-/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
-#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
-impl<'a, I, A: Allocator> !Iterator for &'a mut Box<[I], A> {}
-
-// Note: the `#[rustc_skip_during_method_dispatch(boxed_slice)]` on `trait IntoIterator`
-// hides this implementation from explicit `.into_iter()` calls on editions < 2024,
-// so those calls will still resolve to the slice implementation, by reference.
-#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
-impl<I, A: Allocator> IntoIterator for Box<[I], A> {
- type IntoIter = vec::IntoIter<I, A>;
- type Item = I;
- fn into_iter(self) -> vec::IntoIter<I, A> {
- self.into_vec().into_iter()
- }
-}
-
-#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
-impl<'a, I, A: Allocator> IntoIterator for &'a Box<[I], A> {
- type IntoIter = slice::Iter<'a, I>;
- type Item = &'a I;
- fn into_iter(self) -> slice::Iter<'a, I> {
- self.iter()
- }
-}
-
-#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
-impl<'a, I, A: Allocator> IntoIterator for &'a mut Box<[I], A> {
- type IntoIter = slice::IterMut<'a, I>;
- type Item = &'a mut I;
- fn into_iter(self) -> slice::IterMut<'a, I> {
- self.iter_mut()
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
-impl FromIterator<char> for Box<str> {
- fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
- String::from_iter(iter).into_boxed_str()
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
-impl<'a> FromIterator<&'a char> for Box<str> {
- fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
- String::from_iter(iter).into_boxed_str()
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
-impl<'a> FromIterator<&'a str> for Box<str> {
- fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
- String::from_iter(iter).into_boxed_str()
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
-impl FromIterator<String> for Box<str> {
- fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
- String::from_iter(iter).into_boxed_str()
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
-impl<A: Allocator> FromIterator<Box<str, A>> for Box<str> {
- fn from_iter<T: IntoIterator<Item = Box<str, A>>>(iter: T) -> Self {
- String::from_iter(iter).into_boxed_str()
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
-impl<'a> FromIterator<Cow<'a, str>> for Box<str> {
- fn from_iter<T: IntoIterator<Item = Cow<'a, str>>>(iter: T) -> Self {
- String::from_iter(iter).into_boxed_str()
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "box_slice_clone", since = "1.3.0")]
-impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> {
- fn clone(&self) -> Self {
- let alloc = Box::allocator(self).clone();
- self.to_vec_in(alloc).into_boxed_slice()
- }
-
- /// Copies `source`'s contents into `self` without creating a new allocation,
- /// so long as the two are of the same length.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = Box::new([5, 6, 7]);
- /// let mut y = Box::new([8, 9, 10]);
- /// let yp: *const [i32] = &*y;
- ///
- /// y.clone_from(&x);
- ///
- /// // The value is the same
- /// assert_eq!(x, y);
- ///
- /// // And no allocation occurred
- /// assert_eq!(yp, &*y);
- /// ```
- fn clone_from(&mut self, source: &Self) {
- if self.len() == source.len() {
- self.clone_from_slice(&source);
- } else {
- *self = source.clone();
- }
- }
-}
-
#[stable(feature = "box_borrow", since = "1.1.0")]
-impl<T: ?Sized, A: Allocator> borrow::Borrow<T> for Box<T, A> {
+impl<T: ?Sized, A: Allocator> Borrow<T> for Box<T, A> {
fn borrow(&self) -> &T {
&**self
}
}
#[stable(feature = "box_borrow", since = "1.1.0")]
-impl<T: ?Sized, A: Allocator> borrow::BorrowMut<T> for Box<T, A> {
+impl<T: ?Sized, A: Allocator> BorrowMut<T> for Box<T, A> {
fn borrow_mut(&mut self) -> &mut T {
&mut **self
}
@@ -2728,311 +2108,23 @@
}
}
-#[unstable(feature = "async_iterator", issue = "79024")]
-impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for Box<S> {
- type Item = S::Item;
-
- fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
- Pin::new(&mut **self).poll_next(cx)
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- (**self).size_hint()
- }
-}
-
-impl dyn Error {
- #[inline]
- #[stable(feature = "error_downcast", since = "1.3.0")]
- #[rustc_allow_incoherent_impl]
- /// Attempts to downcast the box to a concrete type.
- pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
- if self.is::<T>() {
- unsafe {
- let raw: *mut dyn Error = Box::into_raw(self);
- Ok(Box::from_raw(raw as *mut T))
- }
- } else {
- Err(self)
- }
- }
-}
-
-impl dyn Error + Send {
- #[inline]
- #[stable(feature = "error_downcast", since = "1.3.0")]
- #[rustc_allow_incoherent_impl]
- /// Attempts to downcast the box to a concrete type.
- pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
- let err: Box<dyn Error> = self;
- <dyn Error>::downcast(err).map_err(|s| unsafe {
- // Reapply the `Send` marker.
- mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
- })
- }
-}
-
-impl dyn Error + Send + Sync {
- #[inline]
- #[stable(feature = "error_downcast", since = "1.3.0")]
- #[rustc_allow_incoherent_impl]
- /// Attempts to downcast the box to a concrete type.
- pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
- let err: Box<dyn Error> = self;
- <dyn Error>::downcast(err).map_err(|s| unsafe {
- // Reapply the `Send + Sync` markers.
- mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
- })
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
- /// Converts a type of [`Error`] into a box of dyn [`Error`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::fmt;
- /// use std::mem;
- ///
- /// #[derive(Debug)]
- /// struct AnError;
- ///
- /// impl fmt::Display for AnError {
- /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- /// write!(f, "An error")
- /// }
- /// }
- ///
- /// impl Error for AnError {}
- ///
- /// let an_error = AnError;
- /// assert!(0 == mem::size_of_val(&an_error));
- /// let a_boxed_error = Box::<dyn Error>::from(an_error);
- /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- fn from(err: E) -> Box<dyn Error + 'a> {
- Box::new(err)
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
- /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of
- /// dyn [`Error`] + [`Send`] + [`Sync`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::fmt;
- /// use std::mem;
- ///
- /// #[derive(Debug)]
- /// struct AnError;
- ///
- /// impl fmt::Display for AnError {
- /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- /// write!(f, "An error")
- /// }
- /// }
- ///
- /// impl Error for AnError {}
- ///
- /// unsafe impl Send for AnError {}
- ///
- /// unsafe impl Sync for AnError {}
- ///
- /// let an_error = AnError;
- /// assert!(0 == mem::size_of_val(&an_error));
- /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(an_error);
- /// assert!(
- /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
- Box::new(err)
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> From<String> for Box<dyn Error + Send + Sync + 'a> {
- /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::mem;
- ///
- /// let a_string_error = "a string error".to_string();
- /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_string_error);
- /// assert!(
- /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- #[inline]
- fn from(err: String) -> Box<dyn Error + Send + Sync + 'a> {
- struct StringError(String);
-
- impl Error for StringError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- &self.0
- }
- }
-
- impl fmt::Display for StringError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(&self.0, f)
- }
- }
-
- // Purposefully skip printing "StringError(..)"
- impl fmt::Debug for StringError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(&self.0, f)
- }
- }
-
- Box::new(StringError(err))
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "string_box_error", since = "1.6.0")]
-impl<'a> From<String> for Box<dyn Error + 'a> {
- /// Converts a [`String`] into a box of dyn [`Error`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::mem;
- ///
- /// let a_string_error = "a string error".to_string();
- /// let a_boxed_error = Box::<dyn Error>::from(a_string_error);
- /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- fn from(str_err: String) -> Box<dyn Error + 'a> {
- let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
- let err2: Box<dyn Error> = err1;
- err2
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
- /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
- ///
- /// [`str`]: prim@str
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::mem;
- ///
- /// let a_str_error = "a str error";
- /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_str_error);
- /// assert!(
- /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- #[inline]
- fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
- From::from(String::from(err))
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "string_box_error", since = "1.6.0")]
-impl<'a> From<&str> for Box<dyn Error + 'a> {
- /// Converts a [`str`] into a box of dyn [`Error`].
- ///
- /// [`str`]: prim@str
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::mem;
- ///
- /// let a_str_error = "a str error";
- /// let a_boxed_error = Box::<dyn Error>::from(a_str_error);
- /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- fn from(err: &str) -> Box<dyn Error + 'a> {
- From::from(String::from(err))
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "cow_box_error", since = "1.22.0")]
-impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
- /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::mem;
- /// use std::borrow::Cow;
- ///
- /// let a_cow_str_error = Cow::from("a str error");
- /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_cow_str_error);
- /// assert!(
- /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
- From::from(String::from(err))
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "cow_box_error", since = "1.22.0")]
-impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + 'a> {
- /// Converts a [`Cow`] into a box of dyn [`Error`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::mem;
- /// use std::borrow::Cow;
- ///
- /// let a_cow_str_error = Cow::from("a str error");
- /// let a_boxed_error = Box::<dyn Error>::from(a_cow_str_error);
- /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- fn from(err: Cow<'b, str>) -> Box<dyn Error + 'a> {
- From::from(String::from(err))
- }
-}
-
#[stable(feature = "box_error", since = "1.8.0")]
-impl<T: core::error::Error> core::error::Error for Box<T> {
+impl<E: Error> Error for Box<E> {
#[allow(deprecated, deprecated_in_future)]
fn description(&self) -> &str {
- core::error::Error::description(&**self)
+ Error::description(&**self)
}
#[allow(deprecated)]
- fn cause(&self) -> Option<&dyn core::error::Error> {
- core::error::Error::cause(&**self)
+ fn cause(&self) -> Option<&dyn Error> {
+ Error::cause(&**self)
}
- fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
- core::error::Error::source(&**self)
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ Error::source(&**self)
}
- fn provide<'b>(&'b self, request: &mut core::error::Request<'b>) {
- core::error::Error::provide(&**self, request);
+ fn provide<'b>(&'b self, request: &mut error::Request<'b>) {
+ Error::provide(&**self, request);
}
}
-
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
-unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Box<T, A> {}
diff --git a/library/alloc/src/boxed/convert.rs b/library/alloc/src/boxed/convert.rs
new file mode 100644
index 0000000..19a583c
--- /dev/null
+++ b/library/alloc/src/boxed/convert.rs
@@ -0,0 +1,747 @@
+use core::any::Any;
+use core::error::Error;
+use core::mem;
+use core::pin::Pin;
+#[cfg(not(no_global_oom_handling))]
+use core::{fmt, ptr};
+
+use crate::alloc::Allocator;
+#[cfg(not(no_global_oom_handling))]
+use crate::borrow::Cow;
+use crate::boxed::Box;
+#[cfg(not(no_global_oom_handling))]
+use crate::raw_vec::RawVec;
+#[cfg(not(no_global_oom_handling))]
+use crate::str::from_boxed_utf8_unchecked;
+#[cfg(not(no_global_oom_handling))]
+use crate::string::String;
+#[cfg(not(no_global_oom_handling))]
+use crate::vec::Vec;
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "from_for_ptrs", since = "1.6.0")]
+impl<T> From<T> for Box<T> {
+ /// Converts a `T` into a `Box<T>`
+ ///
+ /// The conversion allocates on the heap and moves `t`
+ /// from the stack into it.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// let x = 5;
+ /// let boxed = Box::new(5);
+ ///
+ /// assert_eq!(Box::from(x), boxed);
+ /// ```
+ fn from(t: T) -> Self {
+ Box::new(t)
+ }
+}
+
+#[stable(feature = "pin", since = "1.33.0")]
+impl<T: ?Sized, A: Allocator> From<Box<T, A>> for Pin<Box<T, A>>
+where
+ A: 'static,
+{
+ /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
+ /// `*boxed` will be pinned in memory and unable to be moved.
+ ///
+ /// This conversion does not allocate on the heap and happens in place.
+ ///
+ /// This is also available via [`Box::into_pin`].
+ ///
+ /// Constructing and pinning a `Box` with <code><Pin<Box\<T>>>::from([Box::new]\(x))</code>
+ /// can also be written more concisely using <code>[Box::pin]\(x)</code>.
+ /// This `From` implementation is useful if you already have a `Box<T>`, or you are
+ /// constructing a (pinned) `Box` in a different way than with [`Box::new`].
+ fn from(boxed: Box<T, A>) -> Self {
+ Box::into_pin(boxed)
+ }
+}
+
+/// Specialization trait used for `From<&[T]>`.
+#[cfg(not(no_global_oom_handling))]
+trait BoxFromSlice<T> {
+ fn from_slice(slice: &[T]) -> Self;
+}
+
+#[cfg(not(no_global_oom_handling))]
+impl<T: Clone> BoxFromSlice<T> for Box<[T]> {
+ #[inline]
+ default fn from_slice(slice: &[T]) -> Self {
+ slice.to_vec().into_boxed_slice()
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+impl<T: Copy> BoxFromSlice<T> for Box<[T]> {
+ #[inline]
+ fn from_slice(slice: &[T]) -> Self {
+ let len = slice.len();
+ let buf = RawVec::with_capacity(len);
+ unsafe {
+ ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
+ buf.into_box(slice.len()).assume_init()
+ }
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "box_from_slice", since = "1.17.0")]
+impl<T: Clone> From<&[T]> for Box<[T]> {
+ /// Converts a `&[T]` into a `Box<[T]>`
+ ///
+ /// This conversion allocates on the heap
+ /// and performs a copy of `slice` and its contents.
+ ///
+ /// # Examples
+ /// ```rust
+ /// // create a &[u8] which will be used to create a Box<[u8]>
+ /// let slice: &[u8] = &[104, 101, 108, 108, 111];
+ /// let boxed_slice: Box<[u8]> = Box::from(slice);
+ ///
+ /// println!("{boxed_slice:?}");
+ /// ```
+ #[inline]
+ fn from(slice: &[T]) -> Box<[T]> {
+ <Self as BoxFromSlice<T>>::from_slice(slice)
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "box_from_cow", since = "1.45.0")]
+impl<T: Clone> From<Cow<'_, [T]>> for Box<[T]> {
+ /// Converts a `Cow<'_, [T]>` into a `Box<[T]>`
+ ///
+ /// When `cow` is the `Cow::Borrowed` variant, this
+ /// conversion allocates on the heap and copies the
+ /// underlying slice. Otherwise, it will try to reuse the owned
+ /// `Vec`'s allocation.
+ #[inline]
+ fn from(cow: Cow<'_, [T]>) -> Box<[T]> {
+ match cow {
+ Cow::Borrowed(slice) => Box::from(slice),
+ Cow::Owned(slice) => Box::from(slice),
+ }
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "box_from_slice", since = "1.17.0")]
+impl From<&str> for Box<str> {
+ /// Converts a `&str` into a `Box<str>`
+ ///
+ /// This conversion allocates on the heap
+ /// and performs a copy of `s`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// let boxed: Box<str> = Box::from("hello");
+ /// println!("{boxed}");
+ /// ```
+ #[inline]
+ fn from(s: &str) -> Box<str> {
+ unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) }
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "box_from_cow", since = "1.45.0")]
+impl From<Cow<'_, str>> for Box<str> {
+ /// Converts a `Cow<'_, str>` into a `Box<str>`
+ ///
+ /// When `cow` is the `Cow::Borrowed` variant, this
+ /// conversion allocates on the heap and copies the
+ /// underlying `str`. Otherwise, it will try to reuse the owned
+ /// `String`'s allocation.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use std::borrow::Cow;
+ ///
+ /// let unboxed = Cow::Borrowed("hello");
+ /// let boxed: Box<str> = Box::from(unboxed);
+ /// println!("{boxed}");
+ /// ```
+ ///
+ /// ```rust
+ /// # use std::borrow::Cow;
+ /// let unboxed = Cow::Owned("hello".to_string());
+ /// let boxed: Box<str> = Box::from(unboxed);
+ /// println!("{boxed}");
+ /// ```
+ #[inline]
+ fn from(cow: Cow<'_, str>) -> Box<str> {
+ match cow {
+ Cow::Borrowed(s) => Box::from(s),
+ Cow::Owned(s) => Box::from(s),
+ }
+ }
+}
+
+#[stable(feature = "boxed_str_conv", since = "1.19.0")]
+impl<A: Allocator> From<Box<str, A>> for Box<[u8], A> {
+ /// Converts a `Box<str>` into a `Box<[u8]>`
+ ///
+ /// This conversion does not allocate on the heap and happens in place.
+ ///
+ /// # Examples
+ /// ```rust
+ /// // create a Box<str> which will be used to create a Box<[u8]>
+ /// let boxed: Box<str> = Box::from("hello");
+ /// let boxed_str: Box<[u8]> = Box::from(boxed);
+ ///
+ /// // create a &[u8] which will be used to create a Box<[u8]>
+ /// let slice: &[u8] = &[104, 101, 108, 108, 111];
+ /// let boxed_slice = Box::from(slice);
+ ///
+ /// assert_eq!(boxed_slice, boxed_str);
+ /// ```
+ #[inline]
+ fn from(s: Box<str, A>) -> Self {
+ let (raw, alloc) = Box::into_raw_with_allocator(s);
+ unsafe { Box::from_raw_in(raw as *mut [u8], alloc) }
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "box_from_array", since = "1.45.0")]
+impl<T, const N: usize> From<[T; N]> for Box<[T]> {
+ /// Converts a `[T; N]` into a `Box<[T]>`
+ ///
+ /// This conversion moves the array to newly heap-allocated memory.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// let boxed: Box<[u8]> = Box::from([4, 2]);
+ /// println!("{boxed:?}");
+ /// ```
+ fn from(array: [T; N]) -> Box<[T]> {
+ Box::new(array)
+ }
+}
+
+/// Casts a boxed slice to a boxed array.
+///
+/// # Safety
+///
+/// `boxed_slice.len()` must be exactly `N`.
+unsafe fn boxed_slice_as_array_unchecked<T, A: Allocator, const N: usize>(
+ boxed_slice: Box<[T], A>,
+) -> Box<[T; N], A> {
+ debug_assert_eq!(boxed_slice.len(), N);
+
+ let (ptr, alloc) = Box::into_raw_with_allocator(boxed_slice);
+ // SAFETY: Pointer and allocator came from an existing box,
+ // and our safety condition requires that the length is exactly `N`
+ unsafe { Box::from_raw_in(ptr as *mut [T; N], alloc) }
+}
+
+#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
+impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
+ type Error = Box<[T]>;
+
+ /// Attempts to convert a `Box<[T]>` into a `Box<[T; N]>`.
+ ///
+ /// The conversion occurs in-place and does not require a
+ /// new memory allocation.
+ ///
+ /// # Errors
+ ///
+ /// Returns the old `Box<[T]>` in the `Err` variant if
+ /// `boxed_slice.len()` does not equal `N`.
+ fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
+ if boxed_slice.len() == N {
+ Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
+ } else {
+ Err(boxed_slice)
+ }
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_array_try_from_vec", since = "1.66.0")]
+impl<T, const N: usize> TryFrom<Vec<T>> for Box<[T; N]> {
+ type Error = Vec<T>;
+
+ /// Attempts to convert a `Vec<T>` into a `Box<[T; N]>`.
+ ///
+ /// Like [`Vec::into_boxed_slice`], this is in-place if `vec.capacity() == N`,
+ /// but will require a reallocation otherwise.
+ ///
+ /// # Errors
+ ///
+ /// Returns the original `Vec<T>` in the `Err` variant if
+ /// `boxed_slice.len()` does not equal `N`.
+ ///
+ /// # Examples
+ ///
+ /// This can be used with [`vec!`] to create an array on the heap:
+ ///
+ /// ```
+ /// let state: Box<[f32; 100]> = vec![1.0; 100].try_into().unwrap();
+ /// assert_eq!(state.len(), 100);
+ /// ```
+ fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> {
+ if vec.len() == N {
+ let boxed_slice = vec.into_boxed_slice();
+ Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
+ } else {
+ Err(vec)
+ }
+ }
+}
+
+impl<A: Allocator> Box<dyn Any, A> {
+ /// Attempts to downcast the box to a concrete type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::any::Any;
+ ///
+ /// fn print_if_string(value: Box<dyn Any>) {
+ /// if let Ok(string) = value.downcast::<String>() {
+ /// println!("String ({}): {}", string.len(), string);
+ /// }
+ /// }
+ ///
+ /// let my_string = "Hello World".to_string();
+ /// print_if_string(Box::new(my_string));
+ /// print_if_string(Box::new(0i8));
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
+ if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+ }
+
+ /// Downcasts the box to a concrete type.
+ ///
+ /// For a safe alternative see [`downcast`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ ///
+ /// [`downcast`]: Self::downcast
+ #[inline]
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+ debug_assert!(self.is::<T>());
+ unsafe {
+ let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self);
+ Box::from_raw_in(raw as *mut T, alloc)
+ }
+ }
+}
+
+impl<A: Allocator> Box<dyn Any + Send, A> {
+ /// Attempts to downcast the box to a concrete type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::any::Any;
+ ///
+ /// fn print_if_string(value: Box<dyn Any + Send>) {
+ /// if let Ok(string) = value.downcast::<String>() {
+ /// println!("String ({}): {}", string.len(), string);
+ /// }
+ /// }
+ ///
+ /// let my_string = "Hello World".to_string();
+ /// print_if_string(Box::new(my_string));
+ /// print_if_string(Box::new(0i8));
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
+ if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+ }
+
+ /// Downcasts the box to a concrete type.
+ ///
+ /// For a safe alternative see [`downcast`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any + Send> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ ///
+ /// [`downcast`]: Self::downcast
+ #[inline]
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+ debug_assert!(self.is::<T>());
+ unsafe {
+ let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self);
+ Box::from_raw_in(raw as *mut T, alloc)
+ }
+ }
+}
+
+impl<A: Allocator> Box<dyn Any + Send + Sync, A> {
+ /// Attempts to downcast the box to a concrete type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::any::Any;
+ ///
+ /// fn print_if_string(value: Box<dyn Any + Send + Sync>) {
+ /// if let Ok(string) = value.downcast::<String>() {
+ /// println!("String ({}): {}", string.len(), string);
+ /// }
+ /// }
+ ///
+ /// let my_string = "Hello World".to_string();
+ /// print_if_string(Box::new(my_string));
+ /// print_if_string(Box::new(0i8));
+ /// ```
+ #[inline]
+ #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
+ pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
+ if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+ }
+
+ /// Downcasts the box to a concrete type.
+ ///
+ /// For a safe alternative see [`downcast`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any + Send + Sync> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ ///
+ /// [`downcast`]: Self::downcast
+ #[inline]
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+ debug_assert!(self.is::<T>());
+ unsafe {
+ let (raw, alloc): (*mut (dyn Any + Send + Sync), _) =
+ Box::into_raw_with_allocator(self);
+ Box::from_raw_in(raw as *mut T, alloc)
+ }
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
+ /// Converts a type of [`Error`] into a box of dyn [`Error`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::fmt;
+ /// use std::mem;
+ ///
+ /// #[derive(Debug)]
+ /// struct AnError;
+ ///
+ /// impl fmt::Display for AnError {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "An error")
+ /// }
+ /// }
+ ///
+ /// impl Error for AnError {}
+ ///
+ /// let an_error = AnError;
+ /// assert!(0 == mem::size_of_val(&an_error));
+ /// let a_boxed_error = Box::<dyn Error>::from(an_error);
+ /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(err: E) -> Box<dyn Error + 'a> {
+ Box::new(err)
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
+ /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of
+ /// dyn [`Error`] + [`Send`] + [`Sync`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::fmt;
+ /// use std::mem;
+ ///
+ /// #[derive(Debug)]
+ /// struct AnError;
+ ///
+ /// impl fmt::Display for AnError {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "An error")
+ /// }
+ /// }
+ ///
+ /// impl Error for AnError {}
+ ///
+ /// unsafe impl Send for AnError {}
+ ///
+ /// unsafe impl Sync for AnError {}
+ ///
+ /// let an_error = AnError;
+ /// assert!(0 == mem::size_of_val(&an_error));
+ /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(an_error);
+ /// assert!(
+ /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
+ Box::new(err)
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<String> for Box<dyn Error + Send + Sync + 'a> {
+ /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ ///
+ /// let a_string_error = "a string error".to_string();
+ /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_string_error);
+ /// assert!(
+ /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ #[inline]
+ fn from(err: String) -> Box<dyn Error + Send + Sync + 'a> {
+ struct StringError(String);
+
+ impl Error for StringError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ &self.0
+ }
+ }
+
+ impl fmt::Display for StringError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&self.0, f)
+ }
+ }
+
+ // Purposefully skip printing "StringError(..)"
+ impl fmt::Debug for StringError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&self.0, f)
+ }
+ }
+
+ Box::new(StringError(err))
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "string_box_error", since = "1.6.0")]
+impl<'a> From<String> for Box<dyn Error + 'a> {
+ /// Converts a [`String`] into a box of dyn [`Error`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ ///
+ /// let a_string_error = "a string error".to_string();
+ /// let a_boxed_error = Box::<dyn Error>::from(a_string_error);
+ /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(str_err: String) -> Box<dyn Error + 'a> {
+ let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
+ let err2: Box<dyn Error> = err1;
+ err2
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
+ /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
+ ///
+ /// [`str`]: prim@str
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ ///
+ /// let a_str_error = "a str error";
+ /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_str_error);
+ /// assert!(
+ /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ #[inline]
+ fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
+ From::from(String::from(err))
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "string_box_error", since = "1.6.0")]
+impl<'a> From<&str> for Box<dyn Error + 'a> {
+ /// Converts a [`str`] into a box of dyn [`Error`].
+ ///
+ /// [`str`]: prim@str
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ ///
+ /// let a_str_error = "a str error";
+ /// let a_boxed_error = Box::<dyn Error>::from(a_str_error);
+ /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(err: &str) -> Box<dyn Error + 'a> {
+ From::from(String::from(err))
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "cow_box_error", since = "1.22.0")]
+impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
+ /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ /// use std::borrow::Cow;
+ ///
+ /// let a_cow_str_error = Cow::from("a str error");
+ /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_cow_str_error);
+ /// assert!(
+ /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
+ From::from(String::from(err))
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "cow_box_error", since = "1.22.0")]
+impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + 'a> {
+ /// Converts a [`Cow`] into a box of dyn [`Error`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::mem;
+ /// use std::borrow::Cow;
+ ///
+ /// let a_cow_str_error = Cow::from("a str error");
+ /// let a_boxed_error = Box::<dyn Error>::from(a_cow_str_error);
+ /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+ /// ```
+ fn from(err: Cow<'b, str>) -> Box<dyn Error + 'a> {
+ From::from(String::from(err))
+ }
+}
+
+impl dyn Error {
+ /// Attempts to downcast the box to a concrete type.
+ #[inline]
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[rustc_allow_incoherent_impl]
+ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
+ if self.is::<T>() {
+ unsafe {
+ let raw: *mut dyn Error = Box::into_raw(self);
+ Ok(Box::from_raw(raw as *mut T))
+ }
+ } else {
+ Err(self)
+ }
+ }
+}
+
+impl dyn Error + Send {
+ /// Attempts to downcast the box to a concrete type.
+ #[inline]
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[rustc_allow_incoherent_impl]
+ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
+ let err: Box<dyn Error> = self;
+ <dyn Error>::downcast(err).map_err(|s| unsafe {
+ // Reapply the `Send` marker.
+ mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
+ })
+ }
+}
+
+impl dyn Error + Send + Sync {
+ /// Attempts to downcast the box to a concrete type.
+ #[inline]
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[rustc_allow_incoherent_impl]
+ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
+ let err: Box<dyn Error> = self;
+ <dyn Error>::downcast(err).map_err(|s| unsafe {
+ // Reapply the `Send + Sync` markers.
+ mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
+ })
+ }
+}
diff --git a/library/alloc/src/boxed/iter.rs b/library/alloc/src/boxed/iter.rs
new file mode 100644
index 0000000..90582aa
--- /dev/null
+++ b/library/alloc/src/boxed/iter.rs
@@ -0,0 +1,194 @@
+use core::async_iter::AsyncIterator;
+use core::iter::FusedIterator;
+use core::pin::Pin;
+use core::slice;
+use core::task::{Context, Poll};
+
+use crate::alloc::Allocator;
+#[cfg(not(no_global_oom_handling))]
+use crate::borrow::Cow;
+use crate::boxed::Box;
+#[cfg(not(no_global_oom_handling))]
+use crate::string::String;
+use crate::vec;
+#[cfg(not(no_global_oom_handling))]
+use crate::vec::Vec;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Iterator + ?Sized, A: Allocator> Iterator for Box<I, A> {
+ type Item = I::Item;
+ fn next(&mut self) -> Option<I::Item> {
+ (**self).next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (**self).size_hint()
+ }
+ fn nth(&mut self, n: usize) -> Option<I::Item> {
+ (**self).nth(n)
+ }
+ fn last(self) -> Option<I::Item> {
+ BoxIter::last(self)
+ }
+}
+
+trait BoxIter {
+ type Item;
+ fn last(self) -> Option<Self::Item>;
+}
+
+impl<I: Iterator + ?Sized, A: Allocator> BoxIter for Box<I, A> {
+ type Item = I::Item;
+ default fn last(self) -> Option<I::Item> {
+ #[inline]
+ fn some<T>(_: Option<T>, x: T) -> Option<T> {
+ Some(x)
+ }
+
+ self.fold(None, some)
+ }
+}
+
+/// Specialization for sized `I`s that uses `I`s implementation of `last()`
+/// instead of the default.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Iterator, A: Allocator> BoxIter for Box<I, A> {
+ fn last(self) -> Option<I::Item> {
+ (*self).last()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: DoubleEndedIterator + ?Sized, A: Allocator> DoubleEndedIterator for Box<I, A> {
+ fn next_back(&mut self) -> Option<I::Item> {
+ (**self).next_back()
+ }
+ fn nth_back(&mut self, n: usize) -> Option<I::Item> {
+ (**self).nth_back(n)
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: ExactSizeIterator + ?Sized, A: Allocator> ExactSizeIterator for Box<I, A> {
+ fn len(&self) -> usize {
+ (**self).len()
+ }
+ fn is_empty(&self) -> bool {
+ (**self).is_empty()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {}
+
+#[unstable(feature = "async_iterator", issue = "79024")]
+impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for Box<S> {
+ type Item = S::Item;
+
+ fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+ Pin::new(&mut **self).poll_next(cx)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (**self).size_hint()
+ }
+}
+
+/// This implementation is required to make sure that the `Box<[I]>: IntoIterator`
+/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
+#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
+impl<I, A: Allocator> !Iterator for Box<[I], A> {}
+
+/// This implementation is required to make sure that the `&Box<[I]>: IntoIterator`
+/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
+#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
+impl<'a, I, A: Allocator> !Iterator for &'a Box<[I], A> {}
+
+/// This implementation is required to make sure that the `&mut Box<[I]>: IntoIterator`
+/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
+#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
+impl<'a, I, A: Allocator> !Iterator for &'a mut Box<[I], A> {}
+
+// Note: the `#[rustc_skip_during_method_dispatch(boxed_slice)]` on `trait IntoIterator`
+// hides this implementation from explicit `.into_iter()` calls on editions < 2024,
+// so those calls will still resolve to the slice implementation, by reference.
+#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
+impl<I, A: Allocator> IntoIterator for Box<[I], A> {
+ type IntoIter = vec::IntoIter<I, A>;
+ type Item = I;
+ fn into_iter(self) -> vec::IntoIter<I, A> {
+ self.into_vec().into_iter()
+ }
+}
+
+#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
+impl<'a, I, A: Allocator> IntoIterator for &'a Box<[I], A> {
+ type IntoIter = slice::Iter<'a, I>;
+ type Item = &'a I;
+ fn into_iter(self) -> slice::Iter<'a, I> {
+ self.iter()
+ }
+}
+
+#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
+impl<'a, I, A: Allocator> IntoIterator for &'a mut Box<[I], A> {
+ type IntoIter = slice::IterMut<'a, I>;
+ type Item = &'a mut I;
+ fn into_iter(self) -> slice::IterMut<'a, I> {
+ self.iter_mut()
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_slice_from_iter", since = "1.32.0")]
+impl<I> FromIterator<I> for Box<[I]> {
+ fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
+ iter.into_iter().collect::<Vec<_>>().into_boxed_slice()
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
+impl FromIterator<char> for Box<str> {
+ fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
+ String::from_iter(iter).into_boxed_str()
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
+impl<'a> FromIterator<&'a char> for Box<str> {
+ fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
+ String::from_iter(iter).into_boxed_str()
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
+impl<'a> FromIterator<&'a str> for Box<str> {
+ fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
+ String::from_iter(iter).into_boxed_str()
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
+impl FromIterator<String> for Box<str> {
+ fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
+ String::from_iter(iter).into_boxed_str()
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
+impl<A: Allocator> FromIterator<Box<str, A>> for Box<str> {
+ fn from_iter<T: IntoIterator<Item = Box<str, A>>>(iter: T) -> Self {
+ String::from_iter(iter).into_boxed_str()
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
+impl<'a> FromIterator<Cow<'a, str>> for Box<str> {
+ fn from_iter<T: IntoIterator<Item = Cow<'a, str>>>(iter: T) -> Self {
+ String::from_iter(iter).into_boxed_str()
+ }
+}
diff --git a/library/alloc/src/collections/binary_heap/tests.rs b/library/alloc/src/collections/binary_heap/tests.rs
index c183187..ad0a020 100644
--- a/library/alloc/src/collections/binary_heap/tests.rs
+++ b/library/alloc/src/collections/binary_heap/tests.rs
@@ -350,7 +350,7 @@
mem::forget(it);
}))
.unwrap();
- // Behaviour after leaking is explicitly unspecified and order is arbitrary,
+ // Behavior after leaking is explicitly unspecified and order is arbitrary,
// so it's fine if these start failing, but probably worth knowing.
assert!(q.is_empty());
assert_eq!(a.dropped() + b.dropped() + c.dropped(), 1);
@@ -377,7 +377,7 @@
mem::forget(it);
}))
.unwrap();
- // Behaviour after leaking is explicitly unspecified,
+ // Behavior after leaking is explicitly unspecified,
// so it's fine if these start failing, but probably worth knowing.
assert_eq!(q.len(), 2);
assert_eq!(a.dropped(), 0);
diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs
index 4737293..d137d27 100644
--- a/library/alloc/src/collections/btree/append.rs
+++ b/library/alloc/src/collections/btree/append.rs
@@ -79,7 +79,7 @@
}
open_node.push(key, value, right_tree);
- // Go down to the right-most leaf again.
+ // Go down to the rightmost leaf again.
cur_node = open_node.forget_type().last_leaf_edge().into_node();
}
diff --git a/library/alloc/src/collections/btree/fix.rs b/library/alloc/src/collections/btree/fix.rs
index 95fb52b..09edea3 100644
--- a/library/alloc/src/collections/btree/fix.rs
+++ b/library/alloc/src/collections/btree/fix.rs
@@ -102,7 +102,7 @@
pub fn fix_right_border_of_plentiful(&mut self) {
let mut cur_node = self.borrow_mut();
while let Internal(internal) = cur_node.force() {
- // Check if right-most child is underfull.
+ // Check if rightmost child is underfull.
let mut last_kv = internal.last_kv().consider_for_balancing();
debug_assert!(last_kv.left_child_len() >= MIN_LEN * 2);
let right_child_len = last_kv.right_child_len();
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index d0e4137..db16d82 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -1216,7 +1216,7 @@
{
let mut it = map.extract_if(|dummy, _| dummy.query(true));
catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
- // Iterator behaviour after a panic is explicitly unspecified,
+ // Iterator behavior after a panic is explicitly unspecified,
// so this is just the current implementation:
let result = catch_unwind(AssertUnwindSafe(|| it.next()));
assert!(matches!(result, Ok(None)));
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index 5c513d3..2a853ef 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -1521,7 +1521,7 @@
right_node.val_area_mut(..count - 1),
);
- // Move the left-most stolen pair to the parent.
+ // Move the leftmost stolen pair to the parent.
let k = left_node.key_area_mut(new_left_len).assume_init_read();
let v = left_node.val_area_mut(new_left_len).assume_init_read();
let (k, v) = self.parent.replace_kv(k, v);
@@ -1570,7 +1570,7 @@
// Move leaf data.
{
- // Move the right-most stolen pair to the parent.
+ // Move the rightmost stolen pair to the parent.
let k = right_node.key_area_mut(count - 1).assume_init_read();
let v = right_node.val_area_mut(count - 1).assume_init_read();
let (k, v) = self.parent.replace_kv(k, v);
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 50a5f3c..dd9dfa3 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -129,6 +129,7 @@
#![feature(iter_advance_by)]
#![feature(iter_next_chunk)]
#![feature(layout_for_ptr)]
+#![feature(legacy_receiver_trait)]
#![feature(local_waker)]
#![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_uninit_array_transpose)]
@@ -138,7 +139,6 @@
#![feature(ptr_internals)]
#![feature(ptr_metadata)]
#![feature(ptr_sub_ptr)]
-#![feature(receiver_trait)]
#![feature(set_ptr_value)]
#![feature(sized_type_properties)]
#![feature(slice_from_ptr_range)]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 45de061..85a9120 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -103,7 +103,7 @@
/// `RawVec` with capacity `usize::MAX`. Useful for implementing
/// delayed allocation.
#[must_use]
- #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))]
pub const fn new() -> Self {
Self::new_in(Global)
}
@@ -179,7 +179,7 @@
/// Like `new`, but parameterized over the choice of allocator for
/// the returned `RawVec`.
#[inline]
- #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))]
pub const fn new_in(alloc: A) -> Self {
Self { inner: RawVecInner::new_in(alloc, align_of::<T>()), _marker: PhantomData }
}
@@ -409,7 +409,7 @@
impl<A: Allocator> RawVecInner<A> {
#[inline]
- #[rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "raw_vec_internals_const", since = "1.81"))]
const fn new_in(alloc: A, align: usize) -> Self {
let ptr = unsafe { core::mem::transmute(align) };
// `cap: 0` means "unallocated". zero-sized types are ignored.
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 582d850..9fdd51c 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -252,7 +252,7 @@
use core::iter;
use core::marker::{PhantomData, Unsize};
use core::mem::{self, ManuallyDrop, align_of_val_raw};
-use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver};
+use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver};
use core::panic::{RefUnwindSafe, UnwindSafe};
#[cfg(not(no_global_oom_handling))]
use core::pin::Pin;
@@ -2222,8 +2222,8 @@
#[unstable(feature = "deref_pure_trait", issue = "87121")]
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Rc<T, A> {}
-#[unstable(feature = "receiver_trait", issue = "none")]
-impl<T: ?Sized> Receiver for Rc<T> {}
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+impl<T: ?Sized> LegacyReceiver for Rc<T> {}
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc<T, A> {
@@ -3075,7 +3075,7 @@
///
/// drop(strong);
/// // But not any more. We can do weak.as_ptr(), but accessing the pointer would lead to
- /// // undefined behaviour.
+ /// // undefined behavior.
/// // assert_eq!("hello", unsafe { &*weak.as_ptr() });
/// ```
///
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 1367724..15a1b0f 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -18,7 +18,7 @@
use core::iter;
use core::marker::{PhantomData, Unsize};
use core::mem::{self, ManuallyDrop, align_of_val_raw};
-use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver};
+use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, LegacyReceiver};
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::pin::{Pin, PinCoerceUnsized};
use core::ptr::{self, NonNull};
@@ -804,7 +804,7 @@
// observe a non-zero strong count. Therefore we need at least "Release" ordering
// in order to synchronize with the `compare_exchange_weak` in `Weak::upgrade`.
//
- // "Acquire" ordering is not required. When considering the possible behaviours
+ // "Acquire" ordering is not required. When considering the possible behaviors
// of `data_fn` we only need to look at what it could do with a reference to a
// non-upgradeable `Weak`:
// - It can *clone* the `Weak`, increasing the weak reference count.
@@ -2189,8 +2189,8 @@
#[unstable(feature = "deref_pure_trait", issue = "87121")]
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Arc<T, A> {}
-#[unstable(feature = "receiver_trait", issue = "none")]
-impl<T: ?Sized> Receiver for Arc<T> {}
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+impl<T: ?Sized> LegacyReceiver for Arc<T> {}
#[cfg(not(no_global_oom_handling))]
impl<T: ?Sized + CloneToUninit, A: Allocator + Clone> Arc<T, A> {
@@ -2788,7 +2788,7 @@
///
/// drop(strong);
/// // But not any more. We can do weak.as_ptr(), but accessing the pointer would lead to
- /// // undefined behaviour.
+ /// // undefined behavior.
/// // assert_eq!("hello", unsafe { &*weak.as_ptr() });
/// ```
///
diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs
index bcc5bf4..ba57d94 100644
--- a/library/alloc/src/vec/is_zero.rs
+++ b/library/alloc/src/vec/is_zero.rs
@@ -172,7 +172,7 @@
fn is_zero(&self) -> bool {
// SAFETY: This is *not* a stable layout guarantee, but
// inside `core` we're allowed to rely on the current rustc
- // behaviour that options of bools will be one byte with
+ // behavior that options of bools will be one byte with
// no padding, so long as they're nested less than 254 deep.
let raw: u8 = unsafe { core::mem::transmute(*self) };
raw == 0
diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs
index bfc31a6..544f60d 100644
--- a/library/alloc/tests/boxed.rs
+++ b/library/alloc/tests/boxed.rs
@@ -4,6 +4,7 @@
use core::ptr::NonNull;
#[test]
+#[cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))]
fn uninitialized_zero_size_box() {
assert_eq!(
&*Box::<()>::new_uninit() as *const _,
diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs
index 3f1c58b..32d15c3 100644
--- a/library/core/benches/lib.rs
+++ b/library/core/benches/lib.rs
@@ -8,7 +8,6 @@
#![feature(iter_array_chunks)]
#![feature(iter_next_chunk)]
#![feature(iter_advance_by)]
-#![feature(isqrt)]
extern crate test;
diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs
index 68f00d0..8f48af2 100644
--- a/library/core/src/alloc/global.rs
+++ b/library/core/src/alloc/global.rs
@@ -173,7 +173,7 @@
/// # Safety
///
/// The caller has to ensure that `layout` has non-zero size. Like `alloc`
- /// zero sized `layout` can result in undefined behaviour.
+ /// zero sized `layout` can result in undefined behavior.
/// However the allocated block of memory is guaranteed to be initialized.
///
/// # Errors
@@ -234,7 +234,7 @@
/// does not overflow `isize` (i.e., the rounded value must be less than or
/// equal to `isize::MAX`).
///
- /// If these are not followed, undefined behaviour can result.
+ /// If these are not followed, undefined behavior can result.
///
/// (Extension subtraits might provide more specific bounds on
/// behavior, e.g., guarantee a sentinel address or a null pointer
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index fca32b9..95cf942 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -66,7 +66,6 @@
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
#[inline]
- #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> {
if Layout::is_size_align_valid(size, align) {
// SAFETY: Layout::is_size_align_valid checks the preconditions for this call.
@@ -127,7 +126,6 @@
#[rustc_const_stable(feature = "const_alloc_layout_unchecked", since = "1.36.0")]
#[must_use]
#[inline]
- #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
assert_unsafe_precondition!(
check_library_ub,
@@ -159,7 +157,7 @@
#[must_use = "this returns the minimum alignment, \
without modifying the layout"]
#[inline]
- #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
+ #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(ptr_alignment_type))]
pub const fn align(&self) -> usize {
self.align.as_usize()
}
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index e1fa432..7e6c042 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -304,6 +304,7 @@
/// ```
///
/// See the [module-level documentation](self) for more.
+#[cfg_attr(not(test), rustc_diagnostic_item = "Cell")]
#[stable(feature = "rust1", since = "1.0.0")]
#[repr(transparent)]
#[rustc_pub_transparent]
@@ -1221,7 +1222,7 @@
/// Unlike `RefCell::borrow`, this method is unsafe because it does not
/// return a `Ref`, thus leaving the borrow flag untouched. Mutably
/// borrowing the `RefCell` while the reference returned by this method
- /// is alive is undefined behaviour.
+ /// is alive is undefined behavior.
///
/// # Examples
///
@@ -2287,6 +2288,7 @@
/// Unwraps the value, consuming the cell.
#[inline]
+ #[rustc_const_unstable(feature = "sync_unsafe_cell", issue = "95439")]
pub const fn into_inner(self) -> T {
self.value.into_inner()
}
diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs
index d323fbe..5ac3351 100644
--- a/library/core/src/cell/lazy.rs
+++ b/library/core/src/cell/lazy.rs
@@ -79,6 +79,7 @@
/// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string()));
/// ```
#[unstable(feature = "lazy_cell_into_inner", issue = "125623")]
+ #[rustc_const_unstable(feature = "lazy_cell_into_inner", issue = "125623")]
pub const fn into_inner(this: Self) -> Result<T, F> {
match this.state.into_inner() {
State::Init(data) => Ok(data),
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 30c0fff..206bbf5 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -320,8 +320,9 @@
/// '1'.is_digit(37);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_char_is_digit", issue = "132241")]
#[inline]
- pub fn is_digit(self, radix: u32) -> bool {
+ pub const fn is_digit(self, radix: u32) -> bool {
self.to_digit(radix).is_some()
}
@@ -1770,7 +1771,7 @@
/// Panics if the buffer is not large enough.
/// A buffer of length four is large enough to encode any `char`.
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
-#[rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_char_encode_utf8", since = "1.83.0"))]
#[doc(hidden)]
#[inline]
#[rustc_allow_const_fn_unstable(const_eval_select)]
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 4377b49..5a3b936 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -380,7 +380,7 @@
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
// This is a lang item only so that `BinOp::Cmp` in MIR can return it.
-// It has no special behaviour, but does require that the three variants
+// It has no special behavior, but does require that the three variants
// `Less`/`Equal`/`Greater` remain `-1_i8`/`0_i8`/`+1_i8` respectively.
#[lang = "Ordering"]
#[repr(i8)]
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 15b00b9..93dd351 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -137,11 +137,11 @@
// FIXME: const stability attributes should not be required here, I think
impl FromBytesWithNulError {
- #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0"))]
const fn interior_nul(pos: usize) -> FromBytesWithNulError {
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
}
- #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0"))]
const fn not_nul_terminated() -> FromBytesWithNulError {
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
}
@@ -464,7 +464,9 @@
/// behavior when `ptr` is used inside the `unsafe` block:
///
/// ```no_run
- /// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)]
+ /// # #![allow(unused_must_use)]
+ /// # #![cfg_attr(bootstrap, expect(temporary_cstring_as_ptr))]
+ /// # #![cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))]
/// use std::ffi::CString;
///
/// // Do not do this:
@@ -730,7 +732,7 @@
/// located within `isize::MAX` from `ptr`.
#[inline]
#[unstable(feature = "cstr_internals", issue = "none")]
-#[rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cstr_from_ptr", since = "1.81.0"))]
#[rustc_allow_const_fn_unstable(const_eval_select)]
const unsafe fn strlen(ptr: *const c_char) -> usize {
const fn strlen_ct(s: *const c_char) -> usize {
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 4cbcfb0..f3b5423 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -333,7 +333,10 @@
#[unstable(feature = "fmt_internals", issue = "none")]
impl<'a> Arguments<'a> {
#[inline]
- #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
+ #[cfg_attr(
+ bootstrap,
+ rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")
+ )]
pub const fn new_const<const N: usize>(pieces: &'a [&'static str; N]) -> Self {
const { assert!(N <= 1) };
Arguments { pieces, fmt: None, args: &[] }
@@ -438,6 +441,7 @@
#[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")]
#[must_use]
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
pub const fn as_str(&self) -> Option<&'static str> {
match (self.pieces, self.args) {
([], []) => Some(""),
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index a69f0af..78df51f 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -506,7 +506,7 @@
/// # }
/// ```
#[unstable(feature = "hint_must_use", issue = "94745")]
-#[rustc_const_unstable(feature = "hint_must_use", issue = "94745")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "hint_must_use", issue = "94745"))]
#[must_use] // <-- :)
#[inline(always)]
pub const fn must_use<T>(value: T) -> T {
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 97e7276..fc09da7 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -14,9 +14,10 @@
//! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration.
//!
//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
-//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
-//! without T-lang consultation, because it bakes a feature into the language that cannot be
-//! replicated in user code without compiler support.
+//! `#[rustc_const_stable_indirect]` needs to be added to the intrinsic (`#[rustc_const_unstable]`
+//! can be removed then). Such a change should not be done without T-lang consultation, because it
+//! may bake a feature into the language that cannot be replicated in user code without compiler
+//! support.
//!
//! # Volatiles
//!
@@ -930,7 +931,7 @@
/// on most platforms.
/// On Unix, the
/// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or
- /// `SIGBUS`. The precise behaviour is not guaranteed and not stable.
+ /// `SIGBUS`. The precise behavior is not guaranteed and not stable.
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn abort() -> !;
@@ -943,7 +944,11 @@
/// reach code marked with this function.
///
/// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`].
- #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")]
+ #[cfg_attr(
+ bootstrap,
+ rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")
+ )]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unreachable() -> !;
}
@@ -958,7 +963,8 @@
/// own, or if it does not enable any significant optimizations.
///
/// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`].
-#[rustc_const_stable(feature = "const_assume", since = "1.77.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assume", since = "1.77.0"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
@@ -980,7 +986,11 @@
/// any safety invariants.
///
/// This intrinsic does not have a stable counterpart.
-#[rustc_const_unstable(feature = "const_likely", issue = "none")]
+#[cfg_attr(
+ bootstrap,
+ rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION")
+)]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_nounwind]
@@ -1000,7 +1010,11 @@
/// any safety invariants.
///
/// This intrinsic does not have a stable counterpart.
-#[rustc_const_unstable(feature = "const_likely", issue = "none")]
+#[cfg_attr(
+ bootstrap,
+ rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION")
+)]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_nounwind]
@@ -1041,7 +1055,8 @@
/// This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
- #[rustc_const_stable(feature = "const_assert_type", since = "1.59.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn assert_inhabited<T>();
@@ -1050,7 +1065,8 @@
/// zero-initialization: This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
- #[rustc_const_stable(feature = "const_assert_type2", since = "1.75.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn assert_zero_valid<T>();
@@ -1058,7 +1074,8 @@
/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
- #[rustc_const_stable(feature = "const_assert_type2", since = "1.75.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn assert_mem_uninitialized_valid<T>();
@@ -1071,7 +1088,8 @@
/// any safety invariants.
///
/// Consider using [`core::panic::Location::caller`] instead.
- #[rustc_const_stable(feature = "const_caller_location", since = "1.79.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn caller_location() -> &'static crate::panic::Location<'static>;
@@ -1085,7 +1103,8 @@
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
- #[rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn forget<T: ?Sized>(_: T);
@@ -1384,14 +1403,15 @@
/// Like [`transmute`], but even less checked at compile-time: rather than
/// giving an error for `size_of::<Src>() != size_of::<Dst>()`, it's
- /// **Undefined Behaviour** at runtime.
+ /// **Undefined Behavior** at runtime.
///
/// Prefer normal `transmute` where possible, for the extra checking, since
/// both do exactly the same thing at runtime, if they both compile.
///
/// This is not expected to ever be exposed directly to users, rather it
/// may eventually be exposed through some more-constrained API.
- #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn transmute_unchecked<Src, Dst>(src: Src) -> Dst;
@@ -1408,7 +1428,8 @@
/// any safety invariants.
///
/// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop).
- #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn needs_drop<T: ?Sized>() -> bool;
@@ -1430,7 +1451,8 @@
///
/// The stabilized version of this intrinsic is [`pointer::offset`].
#[must_use = "returns a new pointer rather than modifying its argument"]
- #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
@@ -1448,7 +1470,8 @@
///
/// The stabilized version of this intrinsic is [`pointer::wrapping_offset`].
#[must_use = "returns a new pointer rather than modifying its argument"]
- #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
@@ -2131,7 +2154,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `count_ones` method. For example,
/// [`u32::count_ones`]
- #[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn ctpop<T: Copy>(x: T) -> u32;
@@ -2172,7 +2196,8 @@
/// let num_leading = ctlz(x);
/// assert_eq!(num_leading, 16);
/// ```
- #[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn ctlz<T: Copy>(x: T) -> u32;
@@ -2194,7 +2219,8 @@
/// let num_leading = unsafe { ctlz_nonzero(x) };
/// assert_eq!(num_leading, 3);
/// ```
- #[rustc_const_stable(feature = "constctlz", since = "1.50.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn ctlz_nonzero<T: Copy>(x: T) -> u32;
@@ -2234,7 +2260,8 @@
/// let num_trailing = cttz(x);
/// assert_eq!(num_trailing, 16);
/// ```
- #[rustc_const_stable(feature = "const_cttz", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn cttz<T: Copy>(x: T) -> u32;
@@ -2256,7 +2283,8 @@
/// let num_trailing = unsafe { cttz_nonzero(x) };
/// assert_eq!(num_trailing, 3);
/// ```
- #[rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn cttz_nonzero<T: Copy>(x: T) -> u32;
@@ -2270,7 +2298,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `swap_bytes` method. For example,
/// [`u32::swap_bytes`]
- #[rustc_const_stable(feature = "const_bswap", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn bswap<T: Copy>(x: T) -> T;
@@ -2285,7 +2314,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `reverse_bits` method. For example,
/// [`u32::reverse_bits`]
- #[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn bitreverse<T: Copy>(x: T) -> T;
@@ -2311,7 +2341,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `overflowing_add` method. For example,
/// [`u32::overflowing_add`]
- #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
@@ -2326,7 +2357,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `overflowing_sub` method. For example,
/// [`u32::overflowing_sub`]
- #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn sub_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
@@ -2341,7 +2373,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `overflowing_mul` method. For example,
/// [`u32::overflowing_mul`]
- #[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn mul_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
@@ -2360,7 +2393,11 @@
/// Safe wrappers for this intrinsic are available on the integer
/// primitives via the `checked_div` method. For example,
/// [`u32::checked_div`]
- #[rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0")]
+ #[cfg_attr(
+ bootstrap,
+ rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0")
+ )]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_div<T: Copy>(x: T, y: T) -> T;
/// Returns the remainder of an unchecked division, resulting in
@@ -2369,7 +2406,11 @@
/// Safe wrappers for this intrinsic are available on the integer
/// primitives via the `checked_rem` method. For example,
/// [`u32::checked_rem`]
- #[rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0")]
+ #[cfg_attr(
+ bootstrap,
+ rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0")
+ )]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_rem<T: Copy>(x: T, y: T) -> T;
@@ -2379,7 +2420,8 @@
/// Safe wrappers for this intrinsic are available on the integer
/// primitives via the `checked_shl` method. For example,
/// [`u32::checked_shl`]
- #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_shl<T: Copy, U: Copy>(x: T, y: U) -> T;
/// Performs an unchecked right shift, resulting in undefined behavior when
@@ -2388,7 +2430,8 @@
/// Safe wrappers for this intrinsic are available on the integer
/// primitives via the `checked_shr` method. For example,
/// [`u32::checked_shr`]
- #[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_shr<T: Copy, U: Copy>(x: T, y: U) -> T;
@@ -2397,7 +2440,8 @@
///
/// The stable counterpart of this intrinsic is `unchecked_add` on the various
/// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`].
- #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_add<T: Copy>(x: T, y: T) -> T;
@@ -2406,7 +2450,8 @@
///
/// The stable counterpart of this intrinsic is `unchecked_sub` on the various
/// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`].
- #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_sub<T: Copy>(x: T, y: T) -> T;
@@ -2415,7 +2460,8 @@
///
/// The stable counterpart of this intrinsic is `unchecked_mul` on the various
/// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`].
- #[rustc_const_stable(feature = "unchecked_math", since = "1.79.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn unchecked_mul<T: Copy>(x: T, y: T) -> T;
@@ -2429,7 +2475,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `rotate_left` method. For example,
/// [`u32::rotate_left`]
- #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn rotate_left<T: Copy>(x: T, shift: u32) -> T;
@@ -2444,7 +2491,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `rotate_right` method. For example,
/// [`u32::rotate_right`]
- #[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn rotate_right<T: Copy>(x: T, shift: u32) -> T;
@@ -2459,7 +2507,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `wrapping_add` method. For example,
/// [`u32::wrapping_add`]
- #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn wrapping_add<T: Copy>(a: T, b: T) -> T;
@@ -2473,7 +2522,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `wrapping_sub` method. For example,
/// [`u32::wrapping_sub`]
- #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn wrapping_sub<T: Copy>(a: T, b: T) -> T;
@@ -2487,7 +2537,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `wrapping_mul` method. For example,
/// [`u32::wrapping_mul`]
- #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn wrapping_mul<T: Copy>(a: T, b: T) -> T;
@@ -2502,7 +2553,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `saturating_add` method. For example,
/// [`u32::saturating_add`]
- #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn saturating_add<T: Copy>(a: T, b: T) -> T;
@@ -2516,7 +2568,8 @@
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `saturating_sub` method. For example,
/// [`u32::saturating_sub`]
- #[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn saturating_sub<T: Copy>(a: T, b: T) -> T;
@@ -2527,7 +2580,8 @@
/// This intrinsic can *only* be called where the pointer is a local without
/// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it
/// trivially obeys runtime-MIR rules about derefs in operands.
- #[rustc_const_stable(feature = "const_ptr_read", since = "1.71.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn read_via_copy<T>(ptr: *const T) -> T;
@@ -2537,7 +2591,8 @@
/// This intrinsic can *only* be called where the pointer is a local without
/// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so
/// that it trivially obeys runtime-MIR rules about derefs in operands.
- #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn write_via_move<T>(ptr: *mut T, value: T);
@@ -2550,7 +2605,8 @@
/// any safety invariants.
///
/// The stabilized version of this intrinsic is [`core::mem::discriminant`].
- #[rustc_const_stable(feature = "const_discriminant", since = "1.75.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
@@ -2584,7 +2640,8 @@
pub fn nontemporal_store<T>(ptr: *mut T, val: T);
/// See documentation of `<*const T>::offset_from` for details.
- #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
@@ -2850,7 +2907,8 @@
/// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the
/// user has UB checks disabled, the checks will still get optimized out. This intrinsic is
/// primarily used by [`ub_checks::assert_unsafe_precondition`].
-#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // just for UB checks
#[unstable(feature = "core_intrinsics", issue = "none")]
#[inline(always)]
#[rustc_intrinsic]
@@ -2935,7 +2993,8 @@
/// The stabilized version of this intrinsic is [`core::mem::size_of`].
#[rustc_nounwind]
#[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_size_of", since = "1.40.0"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const fn size_of<T>() -> usize {
@@ -2952,7 +3011,8 @@
/// The stabilized version of this intrinsic is [`core::mem::align_of`].
#[rustc_nounwind]
#[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_min_align_of", since = "1.40.0"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const fn min_align_of<T>() -> usize {
@@ -3065,7 +3125,8 @@
/// change the possible layouts of pointers.
#[rustc_nounwind]
#[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const fn aggregate_raw_ptr<P: AggregateRawPtr<D, Metadata = M>, D, M>(_data: D, _meta: M) -> P {
@@ -3090,7 +3151,11 @@
/// This is used to implement functions like `ptr::metadata`.
#[rustc_nounwind]
#[unstable(feature = "core_intrinsics", issue = "none")]
-#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+#[cfg_attr(
+ bootstrap,
+ cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))
+)]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M {
@@ -3197,7 +3262,15 @@
#[rustc_diagnostic_item = "ptr_copy_nonoverlapping"]
pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
- #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
+ #[cfg_attr(
+ bootstrap,
+ rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")
+ )]
+ #[cfg_attr(
+ not(bootstrap),
+ rustc_const_unstable(feature = "core_intrinsics", issue = "none")
+ )]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
}
@@ -3301,7 +3374,15 @@
#[rustc_diagnostic_item = "ptr_copy"]
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
extern "rust-intrinsic" {
- #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
+ #[cfg_attr(
+ bootstrap,
+ rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")
+ )]
+ #[cfg_attr(
+ not(bootstrap),
+ rustc_const_unstable(feature = "core_intrinsics", issue = "none")
+ )]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}
@@ -3382,7 +3463,8 @@
#[rustc_diagnostic_item = "ptr_write_bytes"]
pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
extern "rust-intrinsic" {
- #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
#[rustc_nounwind]
fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
}
@@ -3643,6 +3725,7 @@
/// Inform Miri that a given pointer definitely has a certain alignment.
#[cfg(miri)]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize) {
extern "Rust" {
/// Miri-provided extern function to promise that a given pointer is properly aligned for
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index a2ab39c..6539964 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -298,7 +298,7 @@
);
define!(
"mir_unwind_unreachable",
- /// An unwind action that triggers undefined behaviour.
+ /// An unwind action that triggers undefined behavior.
fn UnwindUnreachable() -> UnwindActionArg
);
define!(
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 6d30f35..2a0ef01 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -71,7 +71,7 @@
/// this can be useful for specializing [`FromIterator`] implementations or recovering the
/// remaining elements after an iterator has been partially exhausted.
///
-/// Note that implementations do not necessarily have to provide access to the inner-most
+/// Note that implementations do not necessarily have to provide access to the innermost
/// source of a pipeline. A stateful intermediate adapter might eagerly evaluate a part
/// of the pipeline and expose its internal storage as source.
///
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 86660f2..2cf2ea5 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -346,7 +346,6 @@
fn into_iter(self) -> Self::IntoIter;
}
-#[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> IntoIterator for I {
type Item = I::Item;
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 1687756..115fdd7 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -107,6 +107,7 @@
//
// Library features:
// tidy-alphabetical-start
+#![cfg_attr(bootstrap, feature(const_fmt_arguments_new))]
#![feature(array_ptr_get)]
#![feature(asm_experimental_arch)]
#![feature(const_align_of_val)]
@@ -121,11 +122,8 @@
#![feature(const_eval_select)]
#![feature(const_exact_div)]
#![feature(const_float_methods)]
-#![feature(const_fmt_arguments_new)]
#![feature(const_hash)]
#![feature(const_heap)]
-#![feature(const_index_range_slice_index)]
-#![feature(const_likely)]
#![feature(const_nonnull_new)]
#![feature(const_num_midpoint)]
#![feature(const_option_ext)]
@@ -136,6 +134,7 @@
#![feature(const_raw_ptr_comparison)]
#![feature(const_size_of_val)]
#![feature(const_size_of_val_raw)]
+#![feature(const_sockaddr_setters)]
#![feature(const_strict_overflow_ops)]
#![feature(const_swap)]
#![feature(const_try)]
@@ -144,13 +143,13 @@
#![feature(const_typed_swap)]
#![feature(const_ub_checks)]
#![feature(const_unicode_case_lookup)]
+#![feature(core_intrinsics)]
#![feature(coverage_attribute)]
#![feature(do_not_recommend)]
#![feature(internal_impls_macro)]
#![feature(ip)]
#![feature(is_ascii_octdigit)]
#![feature(is_val_statically_known)]
-#![feature(isqrt)]
#![feature(lazy_get)]
#![feature(link_cfg)]
#![feature(non_null_from_ref)]
@@ -159,6 +158,7 @@
#![feature(ptr_alignment_type)]
#![feature(ptr_metadata)]
#![feature(set_ptr_value)]
+#![feature(slice_as_chunks)]
#![feature(slice_ptr_get)]
#![feature(str_internals)]
#![feature(str_split_inclusive_remainder)]
@@ -185,7 +185,9 @@
#![feature(cfg_target_has_atomic_equal_alignment)]
#![feature(cfg_ub_checks)]
#![feature(const_for)]
+#![feature(const_is_char_boundary)]
#![feature(const_precise_live_drops)]
+#![feature(const_str_split_at)]
#![feature(decl_macro)]
#![feature(deprecated_suggestion)]
#![feature(doc_cfg)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index aed6be4..1c5c58d 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -1063,53 +1063,10 @@
}
/// Derive macro generating impls of traits related to smart pointers.
-#[rustc_builtin_macro(SmartPointer, attributes(pointee))]
+#[rustc_builtin_macro(CoercePointee, attributes(pointee))]
#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)]
-#[unstable(feature = "derive_smart_pointer", issue = "123430")]
-pub macro SmartPointer($item:item) {
+#[unstable(feature = "derive_coerce_pointee", issue = "123430")]
+#[cfg(not(bootstrap))]
+pub macro CoercePointee($item:item) {
/* compiler built-in */
}
-
-// Support traits and types for the desugaring of const traits and
-// `~const` bounds. Not supposed to be used by anything other than
-// the compiler.
-#[doc(hidden)]
-#[unstable(
- feature = "effect_types",
- issue = "none",
- reason = "internal module for implementing effects"
-)]
-#[allow(missing_debug_implementations)] // these unit structs don't need `Debug` impls.
-pub mod effects {
- #[lang = "EffectsNoRuntime"]
- pub struct NoRuntime;
- #[lang = "EffectsMaybe"]
- pub struct Maybe;
- #[lang = "EffectsRuntime"]
- pub struct Runtime;
-
- #[lang = "EffectsCompat"]
- pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {}
-
- impl Compat<false> for NoRuntime {}
- impl Compat<true> for Runtime {}
- impl<#[rustc_runtime] const RUNTIME: bool> Compat<RUNTIME> for Maybe {}
-
- #[lang = "EffectsTyCompat"]
- #[marker]
- pub trait TyCompat<T: ?Sized> {}
-
- impl<T: ?Sized> TyCompat<T> for T {}
- impl<T: ?Sized> TyCompat<Maybe> for T {}
-
- #[lang = "EffectsIntersection"]
- pub trait Intersection {
- #[lang = "EffectsIntersectionOutput"]
- type Output: ?Sized;
- }
-
- // FIXME(effects): remove this after next trait solver lands
- impl Intersection for () {
- type Output = Maybe;
- }
-}
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index ea73cfc..b4252ef 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -723,7 +723,7 @@
/// this does not constitute a stable guarantee), because the only
/// requirement the compiler knows about it is that the data pointer must be
/// non-null. Dropping such a `Vec<T>` however will cause undefined
- /// behaviour.
+ /// behavior.
///
/// [`assume_init`]: MaybeUninit::assume_init
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index d3360c1..0d1f4a9 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -373,6 +373,7 @@
/// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true);
/// ```
#[unstable(feature = "ip", issue = "27709")]
+ #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
#[must_use]
#[inline]
pub const fn is_benchmarking(&self) -> bool {
diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs
index 4e33917..9204797 100644
--- a/library/core/src/net/socket_addr.rs
+++ b/library/core/src/net/socket_addr.rs
@@ -49,6 +49,15 @@
/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
/// [`IPv4` address]: Ipv4Addr
///
+/// # Textual representation
+///
+/// `SocketAddrV4` provides a [`FromStr`](crate::str::FromStr) implementation.
+/// It accepts an IPv4 address in its [textual representation], followed by a
+/// single `:`, followed by the port encoded as a decimal integer. Other
+/// formats are not accepted.
+///
+/// [textual representation]: Ipv4Addr#textual-representation
+///
/// # Examples
///
/// ```
@@ -82,6 +91,32 @@
/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
/// [`IPv6` address]: Ipv6Addr
///
+/// # Textual representation
+///
+/// `SocketAddrV6` provides a [`FromStr`](crate::str::FromStr) implementation,
+/// based on the bracketed format recommended by [IETF RFC 5952],
+/// with scope identifiers based on those specified in [IETF RFC 4007].
+///
+/// It accepts addresses consisting of the following elements, in order:
+/// - A left square bracket (`[`)
+/// - The [textual representation] of an IPv6 address
+/// - _Optionally_, a percent sign (`%`) followed by the scope identifier
+/// encoded as a decimal integer
+/// - A right square bracket (`]`)
+/// - A colon (`:`)
+/// - The port, encoded as a decimal integer.
+///
+/// For example, the string `[2001:db8::413]:443` represents a `SocketAddrV6`
+/// with the address `2001:db8::413` and port `443`. The string
+/// `[2001:db8::413%612]:443` represents the same address and port, with a
+/// scope identifier of `612`.
+///
+/// Other formats are not accepted.
+///
+/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952#section-6
+/// [IETF RFC 4007]: https://tools.ietf.org/html/rfc4007#section-11
+/// [textual representation]: Ipv6Addr#textual-representation
+///
/// # Examples
///
/// ```
@@ -92,6 +127,10 @@
/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket));
/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
/// assert_eq!(socket.port(), 8080);
+///
+/// let mut with_scope = socket.clone();
+/// with_scope.set_scope_id(3);
+/// assert_eq!("[2001:db8::1%3]:8080".parse(), Ok(with_scope));
/// ```
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -159,9 +198,10 @@
/// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
/// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
/// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
#[inline]
- pub fn set_ip(&mut self, new_ip: IpAddr) {
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+ pub const fn set_ip(&mut self, new_ip: IpAddr) {
// `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
match (self, new_ip) {
(&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip),
@@ -202,9 +242,10 @@
/// socket.set_port(1025);
/// assert_eq!(socket.port(), 1025);
/// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
#[inline]
- pub fn set_port(&mut self, new_port: u16) {
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+ pub const fn set_port(&mut self, new_port: u16) {
match *self {
SocketAddr::V4(ref mut a) => a.set_port(new_port),
SocketAddr::V6(ref mut a) => a.set_port(new_port),
@@ -307,9 +348,10 @@
/// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1));
/// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
/// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
#[inline]
- pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+ pub const fn set_ip(&mut self, new_ip: Ipv4Addr) {
self.ip = new_ip;
}
@@ -342,9 +384,10 @@
/// socket.set_port(4242);
/// assert_eq!(socket.port(), 4242);
/// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
#[inline]
- pub fn set_port(&mut self, new_port: u16) {
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+ pub const fn set_port(&mut self, new_port: u16) {
self.port = new_port;
}
}
@@ -403,9 +446,10 @@
/// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
/// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
/// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
#[inline]
- pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+ pub const fn set_ip(&mut self, new_ip: Ipv6Addr) {
self.ip = new_ip;
}
@@ -438,9 +482,10 @@
/// socket.set_port(4242);
/// assert_eq!(socket.port(), 4242);
/// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
#[inline]
- pub fn set_port(&mut self, new_port: u16) {
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+ pub const fn set_port(&mut self, new_port: u16) {
self.port = new_port;
}
@@ -485,9 +530,10 @@
/// socket.set_flowinfo(56);
/// assert_eq!(socket.flowinfo(), 56);
/// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
#[inline]
- pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+ pub const fn set_flowinfo(&mut self, new_flowinfo: u32) {
self.flowinfo = new_flowinfo;
}
@@ -527,9 +573,10 @@
/// socket.set_scope_id(42);
/// assert_eq!(socket.scope_id(), 42);
/// ```
- #[stable(feature = "sockaddr_setters", since = "1.9.0")]
#[inline]
- pub fn set_scope_id(&mut self, new_scope_id: u32) {
+ #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+ #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+ pub const fn set_scope_id(&mut self, new_scope_id: u32) {
self.scope_id = new_scope_id;
}
}
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 5ab2ab5..e8161cc 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -288,7 +288,6 @@
// concerns about portability, so this implementation is for
// private use internally.
#[inline]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
pub(crate) const fn abs_private(self) -> f128 {
// SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
unsafe {
@@ -319,7 +318,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn is_infinite(self) -> bool {
(self == f128::INFINITY) | (self == f128::NEG_INFINITY)
}
@@ -346,7 +344,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn is_finite(self) -> bool {
// There's no need to handle NaN separately: if self is NaN,
// the comparison is not true, exactly as desired.
@@ -380,7 +377,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn is_subnormal(self) -> bool {
matches!(self.classify(), FpCategory::Subnormal)
}
@@ -412,7 +408,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn is_normal(self) -> bool {
matches!(self.classify(), FpCategory::Normal)
}
@@ -437,7 +432,6 @@
/// ```
#[inline]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn classify(self) -> FpCategory {
let bits = self.to_bits();
match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) {
@@ -915,7 +909,6 @@
/// ```
#[inline]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_bits(self) -> u128 {
// SAFETY: `u128` is a plain old datatype so we can always transmute to it.
@@ -964,7 +957,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn from_bits(v: u128) -> Self {
// It turns out the safety issues with sNaN were overblown! Hooray!
// SAFETY: `u128` is a plain old datatype so we can always transmute from it.
@@ -991,7 +983,6 @@
/// ```
#[inline]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_be_bytes(self) -> [u8; 16] {
self.to_bits().to_be_bytes()
@@ -1017,7 +1008,6 @@
/// ```
#[inline]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_le_bytes(self) -> [u8; 16] {
self.to_bits().to_le_bytes()
@@ -1054,7 +1044,6 @@
/// ```
#[inline]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_ne_bytes(self) -> [u8; 16] {
self.to_bits().to_ne_bytes()
@@ -1082,7 +1071,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn from_be_bytes(bytes: [u8; 16]) -> Self {
Self::from_bits(u128::from_be_bytes(bytes))
}
@@ -1109,7 +1097,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn from_le_bytes(bytes: [u8; 16]) -> Self {
Self::from_bits(u128::from_le_bytes(bytes))
}
@@ -1146,7 +1133,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f128", issue = "116909")]
- #[rustc_const_unstable(feature = "f128", issue = "116909")]
pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self {
Self::from_bits(u128::from_ne_bytes(bytes))
}
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index 60a8849..8b3f3b7 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -282,7 +282,6 @@
// concerns about portability, so this implementation is for
// private use internally.
#[inline]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
pub(crate) const fn abs_private(self) -> f16 {
// SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
unsafe { mem::transmute::<u16, f16>(mem::transmute::<f16, u16>(self) & !Self::SIGN_MASK) }
@@ -310,7 +309,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn is_infinite(self) -> bool {
(self == f16::INFINITY) | (self == f16::NEG_INFINITY)
}
@@ -336,7 +334,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn is_finite(self) -> bool {
// There's no need to handle NaN separately: if self is NaN,
// the comparison is not true, exactly as desired.
@@ -368,7 +365,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn is_subnormal(self) -> bool {
matches!(self.classify(), FpCategory::Subnormal)
}
@@ -398,7 +394,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn is_normal(self) -> bool {
matches!(self.classify(), FpCategory::Normal)
}
@@ -422,7 +417,6 @@
/// ```
#[inline]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn classify(self) -> FpCategory {
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
@@ -901,7 +895,6 @@
/// ```
#[inline]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_bits(self) -> u16 {
// SAFETY: `u16` is a plain old datatype so we can always transmute to it.
@@ -949,7 +942,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn from_bits(v: u16) -> Self {
// It turns out the safety issues with sNaN were overblown! Hooray!
// SAFETY: `u16` is a plain old datatype so we can always transmute from it.
@@ -975,7 +967,6 @@
/// ```
#[inline]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_be_bytes(self) -> [u8; 2] {
self.to_bits().to_be_bytes()
@@ -1000,7 +991,6 @@
/// ```
#[inline]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_le_bytes(self) -> [u8; 2] {
self.to_bits().to_le_bytes()
@@ -1038,7 +1028,6 @@
/// ```
#[inline]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_ne_bytes(self) -> [u8; 2] {
self.to_bits().to_ne_bytes()
@@ -1062,7 +1051,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn from_be_bytes(bytes: [u8; 2]) -> Self {
Self::from_bits(u16::from_be_bytes(bytes))
}
@@ -1085,7 +1073,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn from_le_bytes(bytes: [u8; 2]) -> Self {
Self::from_bits(u16::from_le_bytes(bytes))
}
@@ -1119,7 +1106,6 @@
#[inline]
#[must_use]
#[unstable(feature = "f16", issue = "116909")]
- #[rustc_const_unstable(feature = "f16", issue = "116909")]
pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self {
Self::from_bits(u16::from_ne_bytes(bytes))
}
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 7241b3f..3a9060df 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -449,7 +449,7 @@
#[inline]
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
let (a, b) = self.overflowing_add(rhs);
- if unlikely!(b) { None } else { Some(a) }
+ if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict integer addition. Computes `self + rhs`, panicking
@@ -545,7 +545,7 @@
#[inline]
pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option<Self> {
let (a, b) = self.overflowing_add_unsigned(rhs);
- if unlikely!(b) { None } else { Some(a) }
+ if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict addition with an unsigned integer. Computes `self + rhs`,
@@ -601,7 +601,7 @@
#[inline]
pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
let (a, b) = self.overflowing_sub(rhs);
- if unlikely!(b) { None } else { Some(a) }
+ if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict integer subtraction. Computes `self - rhs`, panicking if
@@ -697,7 +697,7 @@
#[inline]
pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option<Self> {
let (a, b) = self.overflowing_sub_unsigned(rhs);
- if unlikely!(b) { None } else { Some(a) }
+ if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict subtraction with an unsigned integer. Computes `self - rhs`,
@@ -753,7 +753,7 @@
#[inline]
pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
let (a, b) = self.overflowing_mul(rhs);
- if unlikely!(b) { None } else { Some(a) }
+ if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict integer multiplication. Computes `self * rhs`, panicking if
@@ -849,7 +849,7 @@
without modifying the original"]
#[inline]
pub const fn checked_div(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
+ if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
None
} else {
// SAFETY: div by zero and by INT_MIN have been checked above
@@ -924,7 +924,7 @@
#[inline]
pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
// Using `&` helps LLVM see that it is the same check made in division.
- if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
+ if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
None
} else {
Some(self.div_euclid(rhs))
@@ -997,7 +997,7 @@
without modifying the original"]
#[inline]
pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
+ if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
None
} else {
// SAFETY: div by zero and by INT_MIN have been checked above
@@ -1071,7 +1071,7 @@
#[inline]
pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
// Using `&` helps LLVM see that it is the same check made in division.
- if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
+ if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
None
} else {
Some(self.rem_euclid(rhs))
@@ -1142,7 +1142,7 @@
#[inline]
pub const fn checked_neg(self) -> Option<Self> {
let (a, b) = self.overflowing_neg();
- if unlikely!(b) { None } else { Some(a) }
+ if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Unchecked negation. Computes `-self`, assuming overflow cannot occur.
@@ -1629,11 +1629,10 @@
///
/// Basic usage:
/// ```
- /// #![feature(isqrt)]
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_isqrt(), Some(3));")]
/// ```
- #[unstable(feature = "isqrt", issue = "116226")]
- #[rustc_const_unstable(feature = "isqrt", issue = "116226")]
+ #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -2564,7 +2563,7 @@
without modifying the original"]
pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
// Using `&` helps LLVM see that it is the same check made in division.
- if unlikely!((self == Self::MIN) & (rhs == -1)) {
+ if intrinsics::unlikely((self == Self::MIN) & (rhs == -1)) {
(self, true)
} else {
(self / rhs, false)
@@ -2595,7 +2594,7 @@
without modifying the original"]
pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
// Using `&` helps LLVM see that it is the same check made in division.
- if unlikely!((self == Self::MIN) & (rhs == -1)) {
+ if intrinsics::unlikely((self == Self::MIN) & (rhs == -1)) {
(self, true)
} else {
(self.div_euclid(rhs), false)
@@ -2625,7 +2624,7 @@
#[must_use = "this returns the result of the operation, \
without modifying the original"]
pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
- if unlikely!(rhs == -1) {
+ if intrinsics::unlikely(rhs == -1) {
(0, self == Self::MIN)
} else {
(self % rhs, false)
@@ -2657,7 +2656,7 @@
#[inline]
#[track_caller]
pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
- if unlikely!(rhs == -1) {
+ if intrinsics::unlikely(rhs == -1) {
(0, self == Self::MIN)
} else {
(self.rem_euclid(rhs), false)
@@ -2686,7 +2685,7 @@
without modifying the original"]
#[allow(unused_attributes)]
pub const fn overflowing_neg(self) -> (Self, bool) {
- if unlikely!(self == Self::MIN) {
+ if intrinsics::unlikely(self == Self::MIN) {
(Self::MIN, true)
} else {
(-self, false)
@@ -2880,11 +2879,10 @@
///
/// Basic usage:
/// ```
- /// #![feature(isqrt)]
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")]
/// ```
- #[unstable(feature = "isqrt", issue = "116226")]
- #[rustc_const_unstable(feature = "isqrt", issue = "116226")]
+ #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -3181,44 +3179,6 @@
}
}
- /// Calculates the middle point of `self` and `rhs`.
- ///
- /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a
- /// sufficiently-large signed integral type. This implies that the result is
- /// always rounded towards negative infinity and that no overflow will ever occur.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(num_midpoint)]
- #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")]
- #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-1), -1);")]
- #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(0), -1);")]
- /// ```
- #[unstable(feature = "num_midpoint", issue = "110840")]
- #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
- #[rustc_allow_const_fn_unstable(const_num_midpoint)]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- #[inline]
- pub const fn midpoint(self, rhs: Self) -> Self {
- const U: $UnsignedT = <$SelfT>::MIN.unsigned_abs();
-
- // Map an $SelfT to an $UnsignedT
- // ex: i8 [-128; 127] to [0; 255]
- const fn map(a: $SelfT) -> $UnsignedT {
- (a as $UnsignedT) ^ U
- }
-
- // Map an $UnsignedT to an $SelfT
- // ex: u8 [0; 255] to [-128; 127]
- const fn demap(a: $UnsignedT) -> $SelfT {
- (a ^ U) as $SelfT
- }
-
- demap(<$UnsignedT>::midpoint(map(self), map(rhs)))
- }
-
/// Returns the logarithm of the number with respect to an arbitrary base,
/// rounded down.
///
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 5e2f458..9a5e211 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -16,13 +16,6 @@
};
}
-#[allow_internal_unstable(const_likely)]
-macro_rules! unlikely {
- ($e: expr) => {
- intrinsics::unlikely($e)
- };
-}
-
// Use this when the generated code should differ between signed and unsigned types.
macro_rules! sign_dependent_expr {
(signed ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => {
@@ -131,6 +124,37 @@
((self ^ rhs) >> 1) + (self & rhs)
}
};
+ ($SelfT:ty, signed) => {
+ /// Calculates the middle point of `self` and `rhs`.
+ ///
+ /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a
+ /// sufficiently-large signed integral type. This implies that the result is
+ /// always rounded towards zero and that no overflow will ever occur.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(num_midpoint)]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")]
+ #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")]
+ #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")]
+ /// ```
+ #[unstable(feature = "num_midpoint", issue = "110840")]
+ #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn midpoint(self, rhs: Self) -> Self {
+ // Use the well known branchless algorithm from Hacker's Delight to compute
+ // `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`.
+ let t = ((self ^ rhs) >> 1) + (self & rhs);
+ // Except that it fails for integers whose sum is an odd negative number as
+ // their floor is one less than their average. So we adjust the result.
+ t + (if t < 0 { 1 } else { 0 } & (self ^ rhs))
+ }
+ };
($SelfT:ty, $WideT:ty, unsigned) => {
/// Calculates the middle point of `self` and `rhs`.
///
@@ -154,6 +178,32 @@
((self as $WideT + rhs as $WideT) / 2) as $SelfT
}
};
+ ($SelfT:ty, $WideT:ty, signed) => {
+ /// Calculates the middle point of `self` and `rhs`.
+ ///
+ /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a
+ /// sufficiently-large signed integral type. This implies that the result is
+ /// always rounded towards zero and that no overflow will ever occur.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(num_midpoint)]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")]
+ #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")]
+ #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")]
+ /// ```
+ #[unstable(feature = "num_midpoint", issue = "110840")]
+ #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
+ ((self as $WideT + rhs as $WideT) / 2) as $SelfT
+ }
+ };
}
macro_rules! widening_impl {
@@ -307,6 +357,7 @@
from_xe_bytes_doc = "",
bound_condition = "",
}
+ midpoint_impl! { i8, i16, signed }
}
impl i16 {
@@ -330,6 +381,7 @@
from_xe_bytes_doc = "",
bound_condition = "",
}
+ midpoint_impl! { i16, i32, signed }
}
impl i32 {
@@ -353,6 +405,7 @@
from_xe_bytes_doc = "",
bound_condition = "",
}
+ midpoint_impl! { i32, i64, signed }
}
impl i64 {
@@ -376,6 +429,7 @@
from_xe_bytes_doc = "",
bound_condition = "",
}
+ midpoint_impl! { i64, i128, signed }
}
impl i128 {
@@ -401,6 +455,7 @@
from_xe_bytes_doc = "",
bound_condition = "",
}
+ midpoint_impl! { i128, signed }
}
#[cfg(target_pointer_width = "16")]
@@ -425,6 +480,7 @@
from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
bound_condition = " on 16-bit targets",
}
+ midpoint_impl! { isize, i32, signed }
}
#[cfg(target_pointer_width = "32")]
@@ -449,6 +505,7 @@
from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
bound_condition = " on 32-bit targets",
}
+ midpoint_impl! { isize, i64, signed }
}
#[cfg(target_pointer_width = "64")]
@@ -473,6 +530,7 @@
from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
bound_condition = " on 64-bit targets",
}
+ midpoint_impl! { isize, i128, signed }
}
/// If the 6th bit is set ascii is lower case.
@@ -1397,7 +1455,7 @@
#[doc(hidden)]
#[inline(always)]
#[unstable(issue = "none", feature = "std_internals")]
-#[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_from_str", since = "1.82.0"))]
pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
}
@@ -1416,6 +1474,7 @@
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn from_str_radix_panic(radix: u32) {
// The only difference between these two functions is their panic message.
intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt);
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index e5c9a7e..f6e2719 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -355,7 +355,7 @@
}
/// Creates a non-zero without checking whether the value is non-zero.
- /// This results in undefined behaviour if the value is zero.
+ /// This results in undefined behavior if the value is zero.
///
/// # Safety
///
@@ -952,9 +952,9 @@
/// Multiplies two non-zero integers together,
/// assuming overflow cannot occur.
- /// Overflow is unchecked, and it is undefined behaviour to overflow
+ /// Overflow is unchecked, and it is undefined behavior to overflow
/// *even if the result would wrap to a non-zero value*.
- /// The behaviour is undefined as soon as
+ /// The behavior is undefined as soon as
#[doc = sign_dependent_expr!{
$signedness ?
if signed {
@@ -1323,9 +1323,9 @@
/// Adds an unsigned integer to a non-zero value,
/// assuming overflow cannot occur.
- /// Overflow is unchecked, and it is undefined behaviour to overflow
+ /// Overflow is unchecked, and it is undefined behavior to overflow
/// *even if the result would wrap to a non-zero value*.
- /// The behaviour is undefined as soon as
+ /// The behavior is undefined as soon as
#[doc = concat!("`self + rhs > ", stringify!($Int), "::MAX`.")]
///
/// # Examples
@@ -1527,7 +1527,6 @@
///
/// Basic usage:
/// ```
- /// #![feature(isqrt)]
/// # use std::num::NonZero;
/// #
/// # fn main() { test().unwrap(); }
@@ -1539,8 +1538,8 @@
/// # Some(())
/// # }
/// ```
- #[unstable(feature = "isqrt", issue = "116226")]
- #[rustc_const_unstable(feature = "isqrt", issue = "116226")]
+ #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -1599,7 +1598,7 @@
/// Computes the absolute value of self.
#[doc = concat!("See [`", stringify!($Int), "::abs`]")]
- /// for documentation on overflow behaviour.
+ /// for documentation on overflow behavior.
///
/// # Example
///
@@ -1878,7 +1877,7 @@
/// Negates self, overflowing if this is equal to the minimum value.
///
#[doc = concat!("See [`", stringify!($Int), "::overflowing_neg`]")]
- /// for documentation on overflow behaviour.
+ /// for documentation on overflow behavior.
///
/// # Example
///
@@ -1943,7 +1942,7 @@
/// of the type.
///
#[doc = concat!("See [`", stringify!($Int), "::wrapping_neg`]")]
- /// for documentation on overflow behaviour.
+ /// for documentation on overflow behavior.
///
/// # Example
///
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index d9036ab..eb4ea4b 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -491,7 +491,7 @@
// Per <https://github.com/rust-lang/rust/pull/124114#issuecomment-2066173305>,
// LLVM is happy to re-form the intrinsic later if useful.
- if unlikely!(intrinsics::add_with_overflow(self, rhs).1) {
+ if intrinsics::unlikely(intrinsics::add_with_overflow(self, rhs).1) {
None
} else {
// SAFETY: Just checked it doesn't overflow
@@ -593,7 +593,7 @@
#[inline]
pub const fn checked_add_signed(self, rhs: $SignedT) -> Option<Self> {
let (a, b) = self.overflowing_add_signed(rhs);
- if unlikely!(b) { None } else { Some(a) }
+ if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict addition with a signed integer. Computes `self + rhs`,
@@ -845,7 +845,7 @@
#[inline]
pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
let (a, b) = self.overflowing_mul(rhs);
- if unlikely!(b) { None } else { Some(a) }
+ if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict integer multiplication. Computes `self * rhs`, panicking if
@@ -940,7 +940,7 @@
without modifying the original"]
#[inline]
pub const fn checked_div(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0) {
+ if intrinsics::unlikely(rhs == 0) {
None
} else {
// SAFETY: div by zero has been checked above and unsigned types have no other
@@ -1001,7 +1001,7 @@
without modifying the original"]
#[inline]
pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0) {
+ if intrinsics::unlikely(rhs == 0) {
None
} else {
Some(self.div_euclid(rhs))
@@ -1061,7 +1061,7 @@
without modifying the original"]
#[inline]
pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0) {
+ if intrinsics::unlikely(rhs == 0) {
None
} else {
// SAFETY: div by zero has been checked above and unsigned types have no other
@@ -1123,7 +1123,7 @@
without modifying the original"]
#[inline]
pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
- if unlikely!(rhs == 0) {
+ if intrinsics::unlikely(rhs == 0) {
None
} else {
Some(self.rem_euclid(rhs))
@@ -1362,7 +1362,7 @@
#[inline]
pub const fn checked_neg(self) -> Option<Self> {
let (a, b) = self.overflowing_neg();
- if unlikely!(b) { None } else { Some(a) }
+ if intrinsics::unlikely(b) { None } else { Some(a) }
}
/// Strict negation. Computes `-self`, panicking unless `self ==
@@ -2753,11 +2753,10 @@
///
/// Basic usage:
/// ```
- /// #![feature(isqrt)]
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")]
/// ```
- #[unstable(feature = "isqrt", issue = "116226")]
- #[rustc_const_unstable(feature = "isqrt", issue = "116226")]
+ #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -3009,7 +3008,7 @@
// overflow cases it instead ends up returning the maximum value
// of the type, and can return 0 for 0.
#[inline]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_pow", since = "1.50.0"))]
const fn one_less_than_next_power_of_two(self) -> Self {
if self <= 1 { return 0; }
@@ -3086,7 +3085,7 @@
/// ```
#[inline]
#[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
- reason = "needs decision on wrapping behaviour")]
+ reason = "needs decision on wrapping behavior")]
#[rustc_const_unstable(feature = "wrapping_next_power_of_two", issue = "32463")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs
index 1ac6d316..1156b38 100644
--- a/library/core/src/num/wrapping.rs
+++ b/library/core/src/num/wrapping.rs
@@ -1043,7 +1043,7 @@
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
- reason = "needs decision on wrapping behaviour")]
+ reason = "needs decision on wrapping behavior")]
pub fn next_power_of_two(self) -> Self {
Wrapping(self.0.wrapping_next_power_of_two())
}
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index f0d2c76..1ef9990 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -15,7 +15,7 @@
///
/// Types that implement `Deref` or `DerefMut` are often called "smart
/// pointers" and the mechanism of deref coercion has been specifically designed
-/// to facilitate the pointer-like behaviour that name suggests. Often, the
+/// to facilitate the pointer-like behavior that name suggests. Often, the
/// purpose of a "smart pointer" type is to change the ownership semantics
/// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the
/// storage semantics of a contained value (for example, [`Box`][box]).
@@ -42,7 +42,7 @@
/// 1. a value of the type transparently behaves like a value of the target
/// type;
/// 1. the implementation of the deref function is cheap; and
-/// 1. users of the type will not be surprised by any deref coercion behaviour.
+/// 1. users of the type will not be surprised by any deref coercion behavior.
///
/// In general, deref traits **should not** be implemented if:
///
@@ -185,7 +185,7 @@
///
/// Types that implement `DerefMut` or `Deref` are often called "smart
/// pointers" and the mechanism of deref coercion has been specifically designed
-/// to facilitate the pointer-like behaviour that name suggests. Often, the
+/// to facilitate the pointer-like behavior that name suggests. Often, the
/// purpose of a "smart pointer" type is to change the ownership semantics
/// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the
/// storage semantics of a contained value (for example, [`Box`][box]).
@@ -297,15 +297,21 @@
/// Indicates that a struct can be used as a method receiver, without the
/// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box<T>`,
/// `Rc<T>`, `&T`, and `Pin<P>`.
-#[lang = "receiver"]
-#[unstable(feature = "receiver_trait", issue = "none")]
+///
+/// This trait will shortly be removed and replaced with a more generic
+/// facility based around the current "arbitrary self types" unstable feature.
+/// That new facility will use a replacement trait called `Receiver` which is
+/// why this is now named `LegacyReceiver`.
+#[cfg_attr(bootstrap, lang = "receiver")]
+#[cfg_attr(not(bootstrap), lang = "legacy_receiver")]
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
#[doc(hidden)]
-pub trait Receiver {
+pub trait LegacyReceiver {
// Empty.
}
-#[unstable(feature = "receiver_trait", issue = "none")]
-impl<T: ?Sized> Receiver for &T {}
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+impl<T: ?Sized> LegacyReceiver for &T {}
-#[unstable(feature = "receiver_trait", issue = "none")]
-impl<T: ?Sized> Receiver for &mut T {}
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+impl<T: ?Sized> LegacyReceiver for &mut T {}
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index 5464bf6..c9f47e5 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -168,8 +168,8 @@
pub use self::coroutine::{Coroutine, CoroutineState};
#[unstable(feature = "deref_pure_trait", issue = "87121")]
pub use self::deref::DerefPure;
-#[unstable(feature = "receiver_trait", issue = "none")]
-pub use self::deref::Receiver;
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+pub use self::deref::LegacyReceiver;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::deref::{Deref, DerefMut};
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 0b996c4..2aa4f17 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -150,7 +150,7 @@
//! It is further guaranteed that, for the cases above, one can
//! [`mem::transmute`] from all valid values of `T` to `Option<T>` and
//! from `Some::<T>(_)` to `T` (but transmuting `None::<T>` to `T`
-//! is undefined behaviour).
+//! is undefined behavior).
//!
//! # Method overview
//!
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index af2c83b..1d950eb 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -168,6 +168,7 @@
#[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")]
#[must_use]
#[inline]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
pub const fn as_str(&self) -> Option<&'static str> {
self.message.as_str()
}
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 7420579..9071d67 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -50,7 +50,8 @@
#[track_caller]
#[lang = "panic_fmt"] // needed for const-evaluated panics
#[rustc_do_not_const_check] // hooked by const-eval
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
if cfg!(feature = "panic_immediate_abort") {
super::intrinsics::abort()
@@ -84,7 +85,9 @@
// and unwinds anyway, we will hit the "unwinding out of nounwind function" guard,
// which causes a "panic in a function that cannot unwind".
#[rustc_nounwind]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
+#[rustc_allow_const_fn_unstable(const_eval_select)]
pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! {
#[inline] // this should always be inlined into `panic_nounwind_fmt`
#[track_caller]
@@ -131,7 +134,8 @@
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
#[lang = "panic"] // used by lints and miri for panics
pub const fn panic(expr: &'static str) -> ! {
// Use Arguments::new_const instead of format_args!("{expr}") to potentially
@@ -169,7 +173,8 @@
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
- #[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+ #[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+ #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
#[lang = stringify!($lang)]
pub const fn $lang() -> ! {
// Use Arguments::new_const instead of format_args!("{expr}") to potentially
@@ -216,7 +221,8 @@
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics
#[rustc_nounwind]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
pub const fn panic_nounwind(expr: &'static str) -> ! {
panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ false);
}
@@ -232,7 +238,8 @@
#[track_caller]
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
pub const fn panic_explicit() -> ! {
panic_display(&"explicit panic");
}
@@ -249,7 +256,8 @@
#[inline]
#[track_caller]
#[rustc_diagnostic_item = "panic_str_2015"]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
pub const fn panic_str_2015(expr: &str) -> ! {
panic_display(&expr);
}
@@ -259,7 +267,8 @@
#[rustc_do_not_const_check] // hooked by const-eval
// enforce a &&str argument in const-check and hook this by const-eval
#[rustc_const_panic_str]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
panic_fmt(format_args!("{}", *x));
}
@@ -327,8 +336,9 @@
}
/// This function is used instead of panic_fmt in const eval.
-#[lang = "const_panic_fmt"]
-#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+#[lang = "const_panic_fmt"] // needed by const-eval machine to replace calls to `panic_fmt` lang item
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "panic_internals", issue = "none"))]
+#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // must follow stable const rules since it is exposed to stable
pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
if let Some(msg) = fmt.as_str() {
// The panic_display function is hooked by const eval.
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 5d5733d..254b306 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -921,7 +921,7 @@
#![stable(feature = "pin", since = "1.33.0")]
use crate::hash::{Hash, Hasher};
-use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver};
+use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver};
#[allow(unused_imports)]
use crate::{
cell::{RefCell, UnsafeCell},
@@ -1692,8 +1692,8 @@
#[unstable(feature = "deref_pure_trait", issue = "87121")]
unsafe impl<Ptr: DerefPure> DerefPure for Pin<Ptr> {}
-#[unstable(feature = "receiver_trait", issue = "none")]
-impl<Ptr: Receiver> Receiver for Pin<Ptr> {}
+#[unstable(feature = "legacy_receiver_trait", issue = "none")]
+impl<Ptr: LegacyReceiver> LegacyReceiver for Pin<Ptr> {}
#[stable(feature = "pin", since = "1.33.0")]
impl<Ptr: fmt::Debug> fmt::Debug for Pin<Ptr> {
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 95fa6c9..4a6fca5 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -100,7 +100,7 @@
///
/// Both match arms must produce values of type [`u32`], but since `break` never produces a value
/// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another
-/// behaviour of the `!` type - expressions with type `!` will coerce into any other type.
+/// behavior of the `!` type - expressions with type `!` will coerce into any other type.
///
/// [`u32`]: prim@u32
/// [`exit`]: ../std/process/fn.exit.html
@@ -134,7 +134,7 @@
///
/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns`
/// feature is present this means we can exhaustively match on [`Result<T, !>`] by just taking the
-/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain
+/// [`Ok`] variant. This illustrates another behavior of `!` - it can be used to "delete" certain
/// enum variants from generic types like `Result`.
///
/// ## Infinite loops
@@ -351,7 +351,7 @@
/// ```
///
/// ```no_run
-/// // Undefined behaviour
+/// // Undefined behavior
/// let _ = unsafe { char::from_u32_unchecked(0x110000) };
/// ```
///
@@ -568,7 +568,7 @@
/// Instead of coercing a reference to a raw pointer, you can use the macros
/// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`).
/// These macros allow you to create raw pointers to fields to which you cannot
-/// create a reference (without causing undefined behaviour), such as an
+/// create a reference (without causing undefined behavior), such as an
/// unaligned field. This might be necessary if packed structs or uninitialized
/// memory is involved.
///
@@ -1453,7 +1453,7 @@
/// <code>&[bool]</code> can only point to an allocation containing the integer values `1`
/// ([`true`](../std/keyword.true.html)) or `0` ([`false`](../std/keyword.false.html)), but
/// creating a <code>&[bool]</code> that points to an allocation containing
-/// the value `3` causes undefined behaviour.
+/// the value `3` causes undefined behavior.
/// In fact, <code>[Option]\<&T></code> has the same memory representation as a
/// nullable but aligned pointer, and can be passed across FFI boundaries as such.
///
@@ -1612,6 +1612,9 @@
/// pointers, make your type [`Option<fn()>`](core::option#options-and-pointers-nullable-pointers)
/// with your required signature.
///
+/// Note that FFI requires additional care to ensure that the ABI for both sides of the call match.
+/// The exact requirements are not currently documented.
+///
/// ### Safety
///
/// Plain function pointers are obtained by casting either plain functions, or closures that don't
@@ -1750,8 +1753,13 @@
/// is also used rarely. So, most likely you do not have to worry about ABI compatibility.
///
/// But assuming such circumstances, what are the rules? For this section, we are only considering
-/// the ABI of direct Rust-to-Rust calls, not linking in general -- once functions are imported via
-/// `extern` blocks, there are more things to consider that we do not go into here.
+/// the ABI of direct Rust-to-Rust calls (with both definition and callsite visible to the
+/// Rust compiler), not linking in general -- once functions are imported via `extern` blocks, there
+/// are more things to consider that we do not go into here. Note that this also applies to
+/// passing/calling functions across language boundaries via function pointers.
+///
+/// **Nothing in this section should be taken as a guarantee for non-Rust-to-Rust calls, even with
+/// types from `core::ffi` or `libc`**.
///
/// For two signatures to be considered *ABI-compatible*, they must use a compatible ABI string,
/// must take the same number of arguments, the individual argument types and the return types must
diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs
index 50706fc..2538d60 100644
--- a/library/core/src/ptr/alignment.rs
+++ b/library/core/src/ptr/alignment.rs
@@ -41,7 +41,7 @@
/// This provides the same numerical value as [`mem::align_of`],
/// but in an `Alignment` instead of a `usize`.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
- #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+ #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const fn of<T>() -> Self {
// SAFETY: rustc ensures that type alignment is always a power of two.
@@ -53,7 +53,7 @@
///
/// Note that `0` is not a power of two, nor a valid alignment.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
- #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+ #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const fn new(align: usize) -> Option<Self> {
if align.is_power_of_two() {
@@ -73,7 +73,7 @@
/// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`.
/// It must *not* be zero.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
- #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+ #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const unsafe fn new_unchecked(align: usize) -> Self {
assert_unsafe_precondition!(
@@ -89,7 +89,7 @@
/// Returns the alignment as a [`usize`].
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
- #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+ #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const fn as_usize(self) -> usize {
self.0 as usize
@@ -97,7 +97,7 @@
/// Returns the alignment as a <code>[NonZero]<[usize]></code>.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
- #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+ #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const fn as_nonzero(self) -> NonZero<usize> {
// SAFETY: All the discriminants are non-zero.
@@ -118,7 +118,7 @@
/// assert_eq!(Alignment::new(1024).unwrap().log2(), 10);
/// ```
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
- #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+ #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const fn log2(self) -> u32 {
self.as_nonzero().trailing_zeros()
@@ -148,7 +148,7 @@
/// assert_ne!(one.mask(Alignment::of::<Align4>().mask()), one);
/// ```
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
- #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+ #[cfg_attr(bootstrap, rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070"))]
#[inline]
pub const fn mask(self) -> usize {
// SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow.
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 9ee0fb5..75d681d 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -39,6 +39,7 @@
}
#[inline]
+ #[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
const fn const_impl(ptr: *const u8) -> bool {
match (ptr).guaranteed_eq(null_mut()) {
Some(res) => res,
@@ -113,7 +114,7 @@
/// println!("{:?}", unsafe { &*bad });
/// ```
#[unstable(feature = "set_ptr_value", issue = "75091")]
- #[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[inline]
pub const fn with_metadata_of<U>(self, meta: *const U) -> *const U
@@ -409,6 +410,7 @@
T: Sized,
{
#[inline]
+ #[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool {
#[inline]
fn runtime(this: *const (), count: isize, size: usize) -> bool {
@@ -704,7 +706,7 @@
/// but it provides slightly more information to the optimizer, which can
/// sometimes allow it to optimize slightly better with some backends.
///
- /// This method can be though of as recovering the `count` that was passed
+ /// This method can be thought of as recovering the `count` that was passed
/// to [`add`](#method.add) (or, with the parameters in the other order,
/// to [`sub`](#method.sub)). The following are all equivalent, assuming
/// that their safety preconditions are met:
@@ -761,6 +763,7 @@
where
T: Sized,
{
+ #[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_ptr_ge(this: *const (), origin: *const ()) -> bool {
fn runtime(this: *const (), origin: *const ()) -> bool {
this >= origin
@@ -902,6 +905,7 @@
{
#[cfg(debug_assertions)]
#[inline]
+ #[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool {
#[inline]
fn runtime(this: *const (), count: usize, size: usize) -> bool {
@@ -1010,6 +1014,7 @@
{
#[cfg(debug_assertions)]
#[inline]
+ #[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool {
#[inline]
fn runtime(this: *const (), count: usize, size: usize) -> bool {
@@ -1622,6 +1627,7 @@
}
#[inline]
+ #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
const fn const_impl(ptr: *const (), align: usize) -> bool {
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
ptr.align_offset(align) == 0
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index 09c4002..5f20cb2 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -92,7 +92,7 @@
///
/// assert_eq!(std::ptr::metadata("foo"), 3_usize);
/// ```
-#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
#[inline]
pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
ptr_metadata(ptr)
@@ -106,7 +106,7 @@
///
/// [`slice::from_raw_parts`]: crate::slice::from_raw_parts
#[unstable(feature = "ptr_metadata", issue = "81513")]
-#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
#[inline]
pub const fn from_raw_parts<T: ?Sized>(
data_pointer: *const impl Thin,
@@ -120,7 +120,7 @@
///
/// See the documentation of [`from_raw_parts`] for more details.
#[unstable(feature = "ptr_metadata", issue = "81513")]
-#[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
#[inline]
pub const fn from_raw_parts_mut<T: ?Sized>(
data_pointer: *mut impl Thin,
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index f769b51..e9f5bf4 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -134,7 +134,7 @@
//! # Provenance
//!
//! Pointers are not *simply* an "integer" or "address". For instance, it's uncontroversial
-//! to say that a Use After Free is clearly Undefined Behaviour, even if you "get lucky"
+//! to say that a Use After Free is clearly Undefined Behavior, even if you "get lucky"
//! and the freed memory gets reallocated before your read/write (in fact this is the
//! worst-case scenario, UAFs would be much less concerning if this didn't happen!).
//! As another example, consider that [`wrapping_offset`] is documented to "remember"
@@ -591,8 +591,8 @@
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[inline(always)]
#[must_use]
-#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub const fn without_provenance<T>(addr: usize) -> *const T {
// An int-to-pointer transmute currently has exactly the intended semantics: it creates a
// pointer without provenance. Note that this is *not* a stable guarantee about transmute
@@ -602,7 +602,7 @@
unsafe { mem::transmute(addr) }
}
-/// Creates a new pointer that is dangling, but well-aligned.
+/// Creates a new pointer that is dangling, but non-null and well-aligned.
///
/// This is useful for initializing types which lazily allocate, like
/// `Vec::new` does.
@@ -613,8 +613,8 @@
/// some other means.
#[inline(always)]
#[must_use]
-#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub const fn dangling<T>() -> *const T {
without_provenance(mem::align_of::<T>())
}
@@ -634,8 +634,8 @@
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
#[inline(always)]
#[must_use]
-#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub const fn without_provenance_mut<T>(addr: usize) -> *mut T {
// An int-to-pointer transmute currently has exactly the intended semantics: it creates a
// pointer without provenance. Note that this is *not* a stable guarantee about transmute
@@ -645,7 +645,7 @@
unsafe { mem::transmute(addr) }
}
-/// Creates a new pointer that is dangling, but well-aligned.
+/// Creates a new pointer that is dangling, but non-null and well-aligned.
///
/// This is useful for initializing types which lazily allocate, like
/// `Vec::new` does.
@@ -656,8 +656,8 @@
/// some other means.
#[inline(always)]
#[must_use]
-#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")]
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
+#[rustc_const_stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
pub const fn dangling_mut<T>() -> *mut T {
without_provenance_mut(mem::align_of::<T>())
}
@@ -1125,7 +1125,7 @@
unsafe { swap_nonoverlapping_simple_untyped(x, y, count) }
}
-/// Same behaviour and safety conditions as [`swap_nonoverlapping`]
+/// Same behavior and safety conditions as [`swap_nonoverlapping`]
///
/// LLVM can vectorize this (at least it can for the power-of-two-sized types
/// `swap_nonoverlapping` tries to use) so no need to manually SIMD it.
@@ -1854,6 +1854,7 @@
/// Any questions go to @nagisa.
#[allow(ptr_to_integer_transmute_in_consts)]
#[lang = "align_offset"]
+#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
// FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
// 1, where the method versions of these operations are not inlined.
@@ -2107,13 +2108,39 @@
/// Compares the *addresses* of the two function pointers for equality.
///
-/// Function pointers comparisons can have surprising results since
-/// they are never guaranteed to be unique and could vary between different
-/// code generation units. Furthermore, different functions could have the
-/// same address after being merged together.
+/// This is the same as `f == g`, but using this function makes clear that the potentially
+/// surprising semantics of function pointer comparison are involved.
///
-/// This is the same as `f == g` but using this function makes clear
-/// that you are aware of these potentially surprising semantics.
+/// There are **very few guarantees** about how functions are compiled and they have no intrinsic
+/// “identity”; in particular, this comparison:
+///
+/// * May return `true` unexpectedly, in cases where functions are equivalent.
+///
+/// For example, the following program is likely (but not guaranteed) to print `(true, true)`
+/// when compiled with optimization:
+///
+/// ```
+/// # #![feature(ptr_fn_addr_eq)]
+/// let f: fn(i32) -> i32 = |x| x;
+/// let g: fn(i32) -> i32 = |x| x + 0; // different closure, different body
+/// let h: fn(u32) -> u32 = |x| x + 0; // different signature too
+/// dbg!(std::ptr::fn_addr_eq(f, g), std::ptr::fn_addr_eq(f, h)); // not guaranteed to be equal
+/// ```
+///
+/// * May return `false` in any case.
+///
+/// This is particularly likely with generic functions but may happen with any function.
+/// (From an implementation perspective, this is possible because functions may sometimes be
+/// processed more than once by the compiler, resulting in duplicate machine code.)
+///
+/// Despite these false positives and false negatives, this comparison can still be useful.
+/// Specifically, if
+///
+/// * `T` is the same type as `U`, `T` is a [subtype] of `U`, or `U` is a [subtype] of `T`, and
+/// * `ptr::fn_addr_eq(f, g)` returns true,
+///
+/// then calling `f` and calling `g` will be equivalent.
+///
///
/// # Examples
///
@@ -2125,6 +2152,8 @@
/// fn b() { println!("b"); }
/// assert!(!ptr::fn_addr_eq(a as fn(), b as fn()));
/// ```
+///
+/// [subtype]: https://doc.rust-lang.org/reference/subtyping.html
#[unstable(feature = "ptr_fn_addr_eq", issue = "129322")]
#[inline(always)]
#[must_use = "function pointer comparison produces a value"]
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 782934f..408e722 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -94,7 +94,7 @@
/// // This dereference is UB. The pointer only has provenance for `x` but points to `y`.
/// println!("{:?}", unsafe { &*bad });
#[unstable(feature = "set_ptr_value", issue = "75091")]
- #[rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[inline]
pub const fn with_metadata_of<U>(self, meta: *const U) -> *mut U
@@ -405,6 +405,7 @@
T: Sized,
{
#[inline]
+ #[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool {
#[inline]
fn runtime(this: *const (), count: isize, size: usize) -> bool {
@@ -867,7 +868,7 @@
/// but it provides slightly more information to the optimizer, which can
/// sometimes allow it to optimize slightly better with some backends.
///
- /// This method can be though of as recovering the `count` that was passed
+ /// This method can be thought of as recovering the `count` that was passed
/// to [`add`](#method.add) (or, with the parameters in the other order,
/// to [`sub`](#method.sub)). The following are all equivalent, assuming
/// that their safety preconditions are met:
@@ -984,6 +985,7 @@
{
#[cfg(debug_assertions)]
#[inline]
+ #[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool {
#[inline]
fn runtime(this: *const (), count: usize, size: usize) -> bool {
@@ -1092,6 +1094,7 @@
{
#[cfg(debug_assertions)]
#[inline]
+ #[rustc_allow_const_fn_unstable(const_eval_select)]
const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool {
#[inline]
fn runtime(this: *const (), count: usize, size: usize) -> bool {
@@ -1871,6 +1874,7 @@
}
#[inline]
+ #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
const fn const_impl(ptr: *mut (), align: usize) -> bool {
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
ptr.align_offset(align) == 0
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index d91bbe1..86ef1f3 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -107,9 +107,7 @@
#[must_use]
#[inline]
pub const fn dangling() -> Self {
- // SAFETY: mem::align_of() returns a non-zero usize which is then casted
- // to a *mut T. Therefore, `ptr` is not null and the conditions for
- // calling new_unchecked() are respected.
+ // SAFETY: ptr::dangling_mut() returns a non-null well-aligned pointer.
unsafe {
let ptr = crate::ptr::dangling_mut::<T>();
NonNull::new_unchecked(ptr)
@@ -1510,7 +1508,6 @@
#[inline]
#[must_use]
#[unstable(feature = "slice_ptr_get", issue = "74265")]
- #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
pub const fn as_non_null_ptr(self) -> NonNull<T> {
self.cast()
}
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index 4810ebe..a796820 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -92,6 +92,7 @@
/// Creates a new `Unique` if `ptr` is non-null.
#[inline]
+ #[rustc_const_unstable(feature = "ptr_internals", issue = "none")]
pub const fn new(ptr: *mut T) -> Option<Self> {
if let Some(pointer) = NonNull::new(ptr) {
Some(Unique { pointer, _marker: PhantomData })
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index a03e9fb..21e0460 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -346,6 +346,8 @@
/// If any of these loads produces something for which `contains_nonascii`
/// (above) returns true, then we know the answer is false.
#[inline]
+#[rustc_allow_const_fn_unstable(const_raw_ptr_comparison, const_pointer_is_aligned)] // only in a debug assertion
+#[rustc_allow_const_fn_unstable(const_align_offset)] // behavior does not change when `align_offset` fails
const fn is_ascii(s: &[u8]) -> bool {
const USIZE_SIZE: usize = mem::size_of::<usize>();
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 1769612..9cb0064 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -257,3 +257,29 @@
memchr::memchr(byte, bytes).is_some()
}
}
+
+macro_rules! impl_slice_contains {
+ ($($t:ty),*) => {
+ $(
+ impl SliceContains for $t {
+ #[inline]
+ fn slice_contains(&self, arr: &[$t]) -> bool {
+ // Make our LANE_COUNT 4x the normal lane count (aiming for 128 bit vectors).
+ // The compiler will nicely unroll it.
+ const LANE_COUNT: usize = 4 * (128 / (mem::size_of::<$t>() * 8));
+ // SIMD
+ let mut chunks = arr.chunks_exact(LANE_COUNT);
+ for chunk in &mut chunks {
+ if chunk.iter().fold(false, |acc, x| acc | (*x == *self)) {
+ return true;
+ }
+ }
+ // Scalar remainder
+ return chunks.remainder().iter().any(|x| *x == *self);
+ }
+ }
+ )*
+ };
+}
+
+impl_slice_contains!(u16, u32, u64, i16, i32, i64, f32, f64, usize, isize);
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index bc8571c..231ab73 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -31,6 +31,7 @@
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
// FIXME(const-hack): once integer formatting in panics is possible, we
// should use the same implementation at compiletime and runtime.
@@ -52,6 +53,7 @@
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
// FIXME(const-hack): once integer formatting in panics is possible, we
// should use the same implementation at compiletime and runtime.
@@ -73,6 +75,7 @@
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
const fn slice_index_order_fail(index: usize, end: usize) -> ! {
// FIXME(const-hack): once integer formatting in panics is possible, we
// should use the same implementation at compiletime and runtime.
@@ -310,7 +313,6 @@
/// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here
/// than there are for a general `Range<usize>` (which might be `100..3`).
-#[rustc_const_unstable(feature = "const_index_range_slice_index", issue = "none")]
unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
type Output = [T];
diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs
index be19c3d..5760462 100644
--- a/library/core/src/slice/memchr.rs
+++ b/library/core/src/slice/memchr.rs
@@ -15,7 +15,7 @@
/// bytes where the borrow propagated all the way to the most significant
/// bit."
#[inline]
-#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
const fn contains_zero_byte(x: usize) -> bool {
x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
}
@@ -23,7 +23,7 @@
/// Returns the first index matching the byte `x` in `text`.
#[inline]
#[must_use]
-#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> {
// Fast path for small slices.
if text.len() < 2 * USIZE_BYTES {
@@ -34,7 +34,7 @@
}
#[inline]
-#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
let mut i = 0;
@@ -52,7 +52,7 @@
#[rustc_allow_const_fn_unstable(const_cmp)]
#[rustc_allow_const_fn_unstable(const_align_offset)]
-#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_memchr", since = "1.65.0"))]
const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
// Scan for a single byte value by reading two `usize` words at a time.
//
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index dbcfe94..27e51af 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1265,6 +1265,7 @@
/// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
+ #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[must_use]
pub const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] {
@@ -1310,6 +1311,7 @@
/// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
+ #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[track_caller]
#[must_use]
@@ -1344,6 +1346,7 @@
/// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
+ #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[track_caller]
#[must_use]
@@ -1422,6 +1425,7 @@
/// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
+ #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[must_use]
pub const unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] {
@@ -1462,6 +1466,7 @@
/// assert_eq!(v, &[1, 1, 2, 2, 9]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
+ #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[track_caller]
#[must_use]
@@ -1502,6 +1507,7 @@
/// assert_eq!(v, &[9, 1, 1, 2, 2]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
+ #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[track_caller]
#[must_use]
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 89addc4..9ef99e9 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -185,8 +185,9 @@
/// ```
#[must_use]
#[stable(feature = "is_char_boundary", since = "1.9.0")]
+ #[rustc_const_unstable(feature = "const_is_char_boundary", issue = "131516")]
#[inline]
- pub fn is_char_boundary(&self, index: usize) -> bool {
+ pub const fn is_char_boundary(&self, index: usize) -> bool {
// 0 is always ok.
// Test for 0 explicitly so that it can optimize out the check
// easily and skip reading string data for that case.
@@ -195,8 +196,8 @@
return true;
}
- match self.as_bytes().get(index) {
- // For `None` we have two options:
+ if index >= self.len() {
+ // For `true` we have two options:
//
// - index == self.len()
// Empty strings are valid, so return true
@@ -205,9 +206,9 @@
//
// The check is placed exactly here, because it improves generated
// code on higher opt-levels. See PR #84751 for more details.
- None => index == self.len(),
-
- Some(&b) => b.is_utf8_char_boundary(),
+ index == self.len()
+ } else {
+ self.as_bytes()[index].is_utf8_char_boundary()
}
}
@@ -637,7 +638,8 @@
#[inline]
#[must_use]
#[stable(feature = "str_split_at", since = "1.4.0")]
- pub fn split_at(&self, mid: usize) -> (&str, &str) {
+ #[rustc_const_unstable(feature = "const_str_split_at", issue = "131518")]
+ pub const fn split_at(&self, mid: usize) -> (&str, &str) {
match self.split_at_checked(mid) {
None => slice_error_fail(self, 0, mid),
Some(pair) => pair,
@@ -677,7 +679,8 @@
#[inline]
#[must_use]
#[stable(feature = "str_split_at", since = "1.4.0")]
- pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
+ #[rustc_const_unstable(feature = "const_str_split_at", issue = "131518")]
+ pub const fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
// is_char_boundary checks that the index is in [0, .len()]
if self.is_char_boundary(mid) {
// SAFETY: just checked that `mid` is on a char boundary.
@@ -716,11 +719,12 @@
#[inline]
#[must_use]
#[stable(feature = "split_at_checked", since = "1.80.0")]
- pub fn split_at_checked(&self, mid: usize) -> Option<(&str, &str)> {
+ #[rustc_const_unstable(feature = "const_str_split_at", issue = "131518")]
+ pub const fn split_at_checked(&self, mid: usize) -> Option<(&str, &str)> {
// is_char_boundary checks that the index is in [0, .len()]
if self.is_char_boundary(mid) {
// SAFETY: just checked that `mid` is on a char boundary.
- Some(unsafe { (self.get_unchecked(0..mid), self.get_unchecked(mid..self.len())) })
+ Some(unsafe { self.split_at_unchecked(mid) })
} else {
None
}
@@ -756,7 +760,9 @@
#[inline]
#[must_use]
#[stable(feature = "split_at_checked", since = "1.80.0")]
- pub fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut str, &mut str)> {
+ #[rustc_const_unstable(feature = "const_str_split_at", issue = "131518")]
+ #[rustc_allow_const_fn_unstable(const_is_char_boundary)]
+ pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut str, &mut str)> {
// is_char_boundary checks that the index is in [0, .len()]
if self.is_char_boundary(mid) {
// SAFETY: just checked that `mid` is on a char boundary.
@@ -772,7 +778,25 @@
///
/// The caller must ensure that `mid` is a valid byte offset from the start
/// of the string and falls on the boundary of a UTF-8 code point.
- unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut str, &mut str) {
+ const unsafe fn split_at_unchecked(&self, mid: usize) -> (&str, &str) {
+ let len = self.len();
+ let ptr = self.as_ptr();
+ // SAFETY: caller guarantees `mid` is on a char boundary.
+ unsafe {
+ (
+ from_utf8_unchecked(slice::from_raw_parts(ptr, mid)),
+ from_utf8_unchecked(slice::from_raw_parts(ptr.add(mid), len - mid)),
+ )
+ }
+ }
+
+ /// Divides one string slice into two at an index.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that `mid` is a valid byte offset from the start
+ /// of the string and falls on the boundary of a UTF-8 code point.
+ const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut str, &mut str) {
let len = self.len();
let ptr = self.as_mut_ptr();
// SAFETY: caller guarantees `mid` is on a char boundary.
diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs
index eb60eff..665c9fc 100644
--- a/library/core/src/str/pattern.rs
+++ b/library/core/src/str/pattern.rs
@@ -57,9 +57,9 @@
/// [`Searcher`] type, which does the actual work of finding
/// occurrences of the pattern in a string.
///
-/// Depending on the type of the pattern, the behaviour of methods like
+/// Depending on the type of the pattern, the behavior of methods like
/// [`str::find`] and [`str::contains`] can change. The table below describes
-/// some of those behaviours.
+/// some of those behaviors.
///
/// | Pattern type | Match condition |
/// |--------------------------|-------------------------------------------|
@@ -162,7 +162,9 @@
}
/// Returns the pattern as utf-8 bytes if possible.
- fn as_utf8_pattern(&self) -> Option<Utf8Pattern<'_>>;
+ fn as_utf8_pattern(&self) -> Option<Utf8Pattern<'_>> {
+ None
+ }
}
/// Result of calling [`Pattern::as_utf8_pattern()`].
/// Can be used for inspecting the contents of a [`Pattern`] in cases
@@ -675,11 +677,6 @@
fn into_searcher(self, haystack: &str) -> MultiCharEqSearcher<'_, C> {
MultiCharEqSearcher { haystack, char_eq: self.0, char_indices: haystack.char_indices() }
}
-
- #[inline]
- fn as_utf8_pattern(&self) -> Option<Utf8Pattern<'_>> {
- None
- }
}
unsafe impl<'a, C: MultiCharEq> Searcher<'a> for MultiCharEqSearcher<'a, C> {
@@ -770,11 +767,6 @@
{
($pmap)(self).strip_suffix_of(haystack)
}
-
- #[inline]
- fn as_utf8_pattern(&self) -> Option<Utf8Pattern<'_>> {
- None
- }
};
}
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 17ba18c..93b4ad5 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -2122,7 +2122,8 @@
$stable_access:meta,
$stable_from:meta,
$stable_nand:meta,
- $const_stable:meta,
+ $const_stable_new:meta,
+ $const_stable_into_inner:meta,
$diagnostic_item:meta,
$s_int_type:literal,
$extra_feature:expr,
@@ -2204,7 +2205,7 @@
/// ```
#[inline]
#[$stable]
- #[$const_stable]
+ #[$const_stable_new]
#[must_use]
pub const fn new(v: $int_type) -> Self {
Self {v: UnsafeCell::new(v)}
@@ -2406,7 +2407,7 @@
/// ```
#[inline]
#[$stable_access]
- #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")]
+ #[$const_stable_into_inner]
pub const fn into_inner(self) -> $int_type {
self.v.into_inner()
}
@@ -3054,6 +3055,7 @@
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
+ rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI8"),
"i8",
"",
@@ -3072,6 +3074,7 @@
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
+ rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU8"),
"u8",
"",
@@ -3090,6 +3093,7 @@
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
+ rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI16"),
"i16",
"",
@@ -3108,6 +3112,7 @@
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
+ rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU16"),
"u16",
"",
@@ -3126,6 +3131,7 @@
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
+ rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI32"),
"i32",
"",
@@ -3144,6 +3150,7 @@
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
+ rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU32"),
"u32",
"",
@@ -3162,6 +3169,7 @@
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
+ rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI64"),
"i64",
"",
@@ -3180,6 +3188,7 @@
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
+ rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU64"),
"u64",
"",
@@ -3197,7 +3206,8 @@
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",
@@ -3215,7 +3225,8 @@
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",
@@ -3238,6 +3249,7 @@
stable(feature = "atomic_from", since = "1.23.0"),
stable(feature = "atomic_nand", since = "1.27.0"),
rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"),
+ rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicIsize"),
"isize",
"",
@@ -3256,6 +3268,7 @@
stable(feature = "atomic_from", since = "1.23.0"),
stable(feature = "atomic_nand", since = "1.27.0"),
rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"),
+ rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicUsize"),
"usize",
"",
diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs
index fbf8daf..af25f13 100644
--- a/library/core/src/sync/exclusive.rs
+++ b/library/core/src/sync/exclusive.rs
@@ -106,6 +106,7 @@
/// Unwrap the value contained in the `Exclusive`
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+ #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
#[inline]
pub const fn into_inner(self) -> T {
@@ -129,6 +130,7 @@
/// access to the underlying value, but _pinned_ `Exclusive`s only
/// produce _pinned_ access to the underlying value.
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+ #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
#[inline]
pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
@@ -152,6 +154,7 @@
/// a _pinned mutable_ reference to a `T`. This allows you to skip
/// building an `Exclusive` with [`Exclusive::new`].
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
+ #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
#[inline]
pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive<T>> {
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 3e795e7..fb7af82 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -321,7 +321,7 @@
/// Creates a ContextBuilder from a Waker.
#[inline]
#[unstable(feature = "local_waker", issue = "118959")]
- #[rustc_const_stable(feature = "const_waker", since = "1.82.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_waker", since = "1.82.0"))]
pub const fn from_waker(waker: &'a Waker) -> Self {
// SAFETY: LocalWaker is just Waker without thread safety
let local_waker = unsafe { transmute(waker) };
@@ -379,7 +379,7 @@
/// Builds the `Context`.
#[inline]
#[unstable(feature = "local_waker", issue = "118959")]
- #[rustc_const_stable(feature = "const_waker", since = "1.82.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_waker", since = "1.82.0"))]
pub const fn build(self) -> Context<'a> {
let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self;
Context { waker, local_waker, ext: AssertUnwindSafe(ext), _marker, _marker2 }
diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs
index daaaf5a..9156643 100644
--- a/library/core/src/ub_checks.rs
+++ b/library/core/src/ub_checks.rs
@@ -47,7 +47,7 @@
/// order to call it. Since the precompiled standard library is built with full debuginfo and these
/// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
/// debuginfo to have a measurable compile-time impact on debug builds.
-#[allow_internal_unstable(const_ub_checks)] // permit this to be called in stably-const fn
+#[cfg_attr(bootstrap, allow_internal_unstable(const_ub_checks))] // permit this to be called in stably-const fn
#[macro_export]
#[unstable(feature = "ub_checks", issue = "none")]
macro_rules! assert_unsafe_precondition {
@@ -64,7 +64,8 @@
#[rustc_no_mir_inline]
#[inline]
#[rustc_nounwind]
- #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
+ #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
+ #[rustc_allow_const_fn_unstable(const_ptr_is_null, const_ub_checks)] // only for UB checks
const fn precondition_check($($name:$ty),*) {
if !$e {
::core::panicking::panic_nounwind(
@@ -90,8 +91,9 @@
///
/// The intention is to not do that when running in the interpreter, as that one has its own
/// language UB checks which generally produce better errors.
-#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))]
#[inline]
+#[rustc_allow_const_fn_unstable(const_eval_select)]
pub(crate) const fn check_language_ub() -> bool {
#[inline]
fn runtime() -> bool {
@@ -116,6 +118,7 @@
/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
/// check is anyway not executed in `const`.
#[inline]
+#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize, is_zst: bool) -> bool {
ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
}
@@ -132,6 +135,7 @@
/// Note that in const-eval this function just returns `true` and therefore must
/// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
#[inline]
+#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
pub(crate) const fn is_nonoverlapping(
src: *const (),
dst: *const (),
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 14603aa..2a9f166 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -22,7 +22,6 @@
#![feature(const_eval_select)]
#![feature(const_hash)]
#![feature(const_heap)]
-#![feature(const_likely)]
#![feature(const_nonnull_new)]
#![feature(const_num_midpoint)]
#![feature(const_option_ext)]
@@ -54,7 +53,6 @@
#![feature(ip)]
#![feature(ip_from)]
#![feature(is_ascii_octdigit)]
-#![feature(isqrt)]
#![feature(iter_advance_by)]
#![feature(iter_array_chunks)]
#![feature(iter_chain)]
diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
index 7d3381e..474d570 100644
--- a/library/core/tests/num/int_macros.rs
+++ b/library/core/tests/num/int_macros.rs
@@ -113,7 +113,7 @@
// Rotating these should make no difference
//
// We test using 124 bits because to ensure that overlong bit shifts do
- // not cause undefined behaviour. See #10183.
+ // not cause undefined behavior. See #10183.
assert_eq_const_safe!(_0.rotate_left(124), _0);
assert_eq_const_safe!(_1.rotate_left(124), _1);
assert_eq_const_safe!(_0.rotate_right(124), _0);
@@ -369,8 +369,8 @@
assert_eq_const_safe!(<$T>::midpoint(3, 4), 3);
assert_eq_const_safe!(<$T>::midpoint(4, 3), 3);
- assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), -1);
- assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), -1);
+ assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), 0);
+ assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), 0);
assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN);
assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX);
diff --git a/library/core/tests/num/midpoint.rs b/library/core/tests/num/midpoint.rs
new file mode 100644
index 0000000..71e9800
--- /dev/null
+++ b/library/core/tests/num/midpoint.rs
@@ -0,0 +1,54 @@
+//! Test the following expectations:
+//! - midpoint(a, b) == (a + b) / 2
+//! - midpoint(a, b) == midpoint(b, a)
+//! - midpoint(-a, -b) == -midpoint(a, b)
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_obvious_impl_i8() {
+ for a in i8::MIN..=i8::MAX {
+ for b in i8::MIN..=i8::MAX {
+ assert_eq!(i8::midpoint(a, b), ((a as i16 + b as i16) / 2) as i8);
+ }
+ }
+}
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_obvious_impl_u8() {
+ for a in u8::MIN..=u8::MAX {
+ for b in u8::MIN..=u8::MAX {
+ assert_eq!(u8::midpoint(a, b), ((a as u16 + b as u16) / 2) as u8);
+ }
+ }
+}
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_order_expectation_i8() {
+ for a in i8::MIN..=i8::MAX {
+ for b in i8::MIN..=i8::MAX {
+ assert_eq!(i8::midpoint(a, b), i8::midpoint(b, a));
+ }
+ }
+}
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_order_expectation_u8() {
+ for a in u8::MIN..=u8::MAX {
+ for b in u8::MIN..=u8::MAX {
+ assert_eq!(u8::midpoint(a, b), u8::midpoint(b, a));
+ }
+ }
+}
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_negative_expectation() {
+ for a in 0..=i8::MAX {
+ for b in 0..=i8::MAX {
+ assert_eq!(i8::midpoint(-a, -b), -i8::midpoint(a, b));
+ }
+ }
+}
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 6da9b9a..0add9a0 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -28,6 +28,7 @@
mod flt2dec;
mod int_log;
mod int_sqrt;
+mod midpoint;
mod ops;
mod wrapping;
diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs
index 105aad4..ad8e484 100644
--- a/library/core/tests/num/uint_macros.rs
+++ b/library/core/tests/num/uint_macros.rs
@@ -79,7 +79,7 @@
// Rotating these should make no difference
//
// We test using 124 bits because to ensure that overlong bit shifts do
- // not cause undefined behaviour. See #10183.
+ // not cause undefined behavior. See #10183.
assert_eq_const_safe!(_0.rotate_left(124), _0);
assert_eq_const_safe!(_1.rotate_left(124), _1);
assert_eq_const_safe!(_0.rotate_right(124), _0);
diff --git a/library/proc_macro/src/bridge/symbol.rs b/library/proc_macro/src/bridge/symbol.rs
index 37aaee6..edad6e7 100644
--- a/library/proc_macro/src/bridge/symbol.rs
+++ b/library/proc_macro/src/bridge/symbol.rs
@@ -76,7 +76,7 @@
.all(|b| matches!(b, b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9'))
}
- // Mimics the behaviour of `Symbol::can_be_raw` from `rustc_span`
+ // Mimics the behavior of `Symbol::can_be_raw` from `rustc_span`
fn can_be_raw(string: &str) -> bool {
match string {
"_" | "super" | "self" | "Self" | "crate" => false,
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index ae47bb7..1577024 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -32,6 +32,7 @@
#![feature(restricted_std)]
#![feature(rustc_attrs)]
#![feature(min_specialization)]
+#![feature(extend_one)]
#![recursion_limit = "256"]
#![allow(internal_features)]
#![deny(ffi_unwind_calls)]
@@ -43,6 +44,7 @@
mod diagnostic;
mod escape;
+mod to_tokens;
use std::ffi::CStr;
use std::ops::{Range, RangeBounds};
@@ -52,6 +54,8 @@
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
pub use diagnostic::{Diagnostic, Level, MultiSpan};
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+pub use to_tokens::ToTokens;
use crate::escape::{EscapeOptions, escape_bytes};
diff --git a/library/proc_macro/src/to_tokens.rs b/library/proc_macro/src/to_tokens.rs
new file mode 100644
index 0000000..8f697b4
--- /dev/null
+++ b/library/proc_macro/src/to_tokens.rs
@@ -0,0 +1,310 @@
+use std::borrow::Cow;
+use std::ffi::{CStr, CString};
+use std::rc::Rc;
+
+use crate::{ConcatTreesHelper, Group, Ident, Literal, Punct, Span, TokenStream, TokenTree};
+
+/// Types that can be interpolated inside a [`quote!`] invocation.
+///
+/// [`quote!`]: crate::quote!
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+pub trait ToTokens {
+ /// Write `self` to the given `TokenStream`.
+ ///
+ /// # Example
+ ///
+ /// Example implementation for a struct representing Rust paths like
+ /// `std::cmp::PartialEq`:
+ ///
+ /// ```
+ /// #![feature(proc_macro_totokens)]
+ ///
+ /// use std::iter;
+ /// use proc_macro::{Spacing, Punct, TokenStream, TokenTree, ToTokens};
+ ///
+ /// pub struct Path {
+ /// pub global: bool,
+ /// pub segments: Vec<PathSegment>,
+ /// }
+ ///
+ /// impl ToTokens for Path {
+ /// fn to_tokens(&self, tokens: &mut TokenStream) {
+ /// for (i, segment) in self.segments.iter().enumerate() {
+ /// if i > 0 || self.global {
+ /// // Double colon `::`
+ /// tokens.extend(iter::once(TokenTree::from(Punct::new(':', Spacing::Joint))));
+ /// tokens.extend(iter::once(TokenTree::from(Punct::new(':', Spacing::Alone))));
+ /// }
+ /// segment.to_tokens(tokens);
+ /// }
+ /// }
+ /// }
+ /// #
+ /// # pub struct PathSegment;
+ /// #
+ /// # impl ToTokens for PathSegment {
+ /// # fn to_tokens(&self, tokens: &mut TokenStream) {
+ /// # unimplemented!()
+ /// # }
+ /// # }
+ /// ```
+ fn to_tokens(&self, tokens: &mut TokenStream);
+
+ /// Convert `self` directly into a `TokenStream` object.
+ ///
+ /// This method is implicitly implemented using `to_tokens`, and acts as a
+ /// convenience method for consumers of the `ToTokens` trait.
+ fn to_token_stream(&self) -> TokenStream {
+ let mut tokens = TokenStream::new();
+ self.to_tokens(&mut tokens);
+ tokens
+ }
+
+ /// Convert `self` directly into a `TokenStream` object.
+ ///
+ /// This method is implicitly implemented using `to_tokens`, and acts as a
+ /// convenience method for consumers of the `ToTokens` trait.
+ fn into_token_stream(self) -> TokenStream
+ where
+ Self: Sized,
+ {
+ self.to_token_stream()
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for TokenTree {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.extend_one(self.clone());
+ }
+
+ fn into_token_stream(self) -> TokenStream {
+ let mut builder = ConcatTreesHelper::new(1);
+ builder.push(self);
+ builder.build()
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for TokenStream {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.extend(self.clone());
+ }
+
+ fn into_token_stream(self) -> TokenStream {
+ self
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for Literal {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.extend_one(TokenTree::from(self.clone()));
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for Ident {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.extend_one(TokenTree::from(self.clone()));
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for Punct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.extend_one(TokenTree::from(self.clone()));
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for Group {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.extend_one(TokenTree::from(self.clone()));
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl<T: ToTokens + ?Sized> ToTokens for &T {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ (**self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl<T: ToTokens + ?Sized> ToTokens for &mut T {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ (**self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl<T: ToTokens + ?Sized> ToTokens for Box<T> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ (**self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl<T: ToTokens + ?Sized> ToTokens for Rc<T> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ (**self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl<T: ToTokens + ToOwned + ?Sized> ToTokens for Cow<'_, T> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ (**self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl<T: ToTokens> ToTokens for Option<T> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if let Some(t) = self {
+ t.to_tokens(tokens);
+ }
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for u8 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::u8_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for u16 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::u16_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for u32 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::u32_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for u64 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::u64_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for u128 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::u128_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for i8 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::i8_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for i16 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::i16_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for i32 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::i32_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for i64 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::i64_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for i128 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::i128_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for f32 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::f32_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for f64 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::f64_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for usize {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::usize_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for isize {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::isize_suffixed(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for bool {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let word = if *self { "true" } else { "false" };
+ Ident::new(word, Span::call_site()).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for char {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::character(*self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for str {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::string(self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for String {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::string(self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for CStr {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::c_string(self).to_tokens(tokens)
+ }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for CString {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ Literal::c_string(self).to_tokens(tokens)
+ }
+}
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index fa8ea95..b79ad1c 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -1098,7 +1098,7 @@
_ => panic!(),
});
catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
- // Iterator behaviour after a panic is explicitly unspecified,
+ // Iterator behavior after a panic is explicitly unspecified,
// so this is just the current implementation:
let result = catch_unwind(AssertUnwindSafe(|| it.next()));
assert!(result.is_err());
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 97a1b84..d732a15 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -618,7 +618,7 @@
///
/// # Deprecation
///
-/// This function is deprecated because the behaviour on Windows is not correct.
+/// This function is deprecated because the behavior on Windows is not correct.
/// The 'HOME' environment variable is not standard on Windows, and may not produce
/// desired results; for instance, under Cygwin or Mingw it will return `/home/you`
/// when it should return `C:\Users\you`.
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 8a0d2a7..3079c8b 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1197,7 +1197,7 @@
/// Sets the option for truncating a previous file.
///
- /// If a file is successfully opened with this option set it will truncate
+ /// If a file is successfully opened with this option set to true, it will truncate
/// the file to 0 length if it already exists.
///
/// The file must be opened with write access for truncate to work.
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index 8502354..b952c85 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -453,6 +453,29 @@
Ok(n)
}
+ fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+ let (front, back) = self.as_slices();
+
+ // Use only the front buffer if it is big enough to fill `buf`, else use
+ // the back buffer too.
+ match buf.split_at_mut_checked(front.len()) {
+ None => buf.copy_from_slice(&front[..buf.len()]),
+ Some((buf_front, buf_back)) => match back.split_at_checked(buf_back.len()) {
+ Some((back, _)) => {
+ buf_front.copy_from_slice(front);
+ buf_back.copy_from_slice(back);
+ }
+ None => {
+ self.clear();
+ return Err(io::Error::READ_EXACT_EOF);
+ }
+ },
+ }
+
+ self.drain(..buf.len());
+ Ok(())
+ }
+
#[inline]
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
let (ref mut front, _) = self.as_slices();
@@ -462,6 +485,29 @@
Ok(())
}
+ fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ let len = cursor.capacity();
+ let (front, back) = self.as_slices();
+
+ match front.split_at_checked(cursor.capacity()) {
+ Some((front, _)) => cursor.append(front),
+ None => {
+ cursor.append(front);
+ match back.split_at_checked(cursor.capacity()) {
+ Some((back, _)) => cursor.append(back),
+ None => {
+ cursor.append(back);
+ self.clear();
+ return Err(io::Error::READ_EXACT_EOF);
+ }
+ }
+ }
+ }
+
+ self.drain(..len);
+ Ok(())
+ }
+
#[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
// The total len is known upfront so we can reserve it in a single call.
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 8c1a3c7..1de52eb 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -364,6 +364,7 @@
#![feature(std_internals)]
#![feature(str_internals)]
#![feature(strict_provenance_atomic_ptr)]
+#![feature(sync_unsafe_cell)]
#![feature(ub_checks)]
// tidy-alphabetical-end
//
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index a964db2..ba6481f 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -153,7 +153,7 @@
///
/// It is possible to inadvertently set this flag, like in the example below.
/// Therefore, it is important to be vigilant while changing options to mitigate
- /// unexpected behaviour.
+ /// unexpected behavior.
///
/// ```no_run
/// use std::fs::File;
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 63edfdb..62125f8 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1167,7 +1167,7 @@
/// path.push(r"..\otherdir");
/// path.push("system32");
///
-/// The behaviour of `PathBuf` may be changed to a panic on such inputs
+/// The behavior of `PathBuf` may be changed to a panic on such inputs
/// in the future. [`Extend::extend`] should be used to add multi-part paths.
#[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1409,7 +1409,7 @@
/// (That is, it will have the same parent.)
///
/// The argument is not sanitized, so can include separators. This
- /// behaviour may be changed to a panic in the future.
+ /// behavior may be changed to a panic in the future.
///
/// [`self.file_name`]: Path::file_name
/// [`pop`]: PathBuf::pop
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index f24fe35..6933528 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -119,7 +119,7 @@
//! when given a `.bat` file as the application to run, it will automatically
//! convert that into running `cmd.exe /c` with the batch file as the next argument.
//!
-//! For historical reasons Rust currently preserves this behaviour when using
+//! For historical reasons Rust currently preserves this behavior when using
//! [`Command::new`], and escapes the arguments according to `cmd.exe` rules.
//! Due to the complexity of `cmd.exe` argument handling, it might not be
//! possible to safely escape some special characters, and using them will result
@@ -2318,7 +2318,7 @@
/// Rust IO buffers (eg, from `BufWriter`) will not be flushed.
/// Likewise, C stdio buffers will (on most platforms) not be flushed.
///
-/// This is in contrast to the default behaviour of [`panic!`] which unwinds
+/// This is in contrast to the default behavior of [`panic!`] which unwinds
/// the current thread's stack and calls all destructors.
/// When `panic="abort"` is set, either as an argument to `rustc` or in a
/// crate's Cargo.toml, [`panic!`] and `abort` are similar. However,
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index 88cc95c..fb0b495 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -96,9 +96,23 @@
#[test]
#[cfg_attr(any(windows, target_os = "vxworks"), ignore)]
fn set_current_dir_works() {
+ // On many Unix platforms this will use the posix_spawn path.
let mut cmd = shell_cmd();
cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
assert_eq!(run_output(cmd), "/\n");
+
+ // Also test the fork/exec path by setting a pre_exec function.
+ #[cfg(unix)]
+ {
+ use crate::os::unix::process::CommandExt;
+
+ let mut cmd = shell_cmd();
+ cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
+ unsafe {
+ cmd.pre_exec(|| Ok(()));
+ }
+ assert_eq!(run_output(cmd), "/\n");
+ }
}
#[test]
diff --git a/library/std/src/random.rs b/library/std/src/random.rs
index cdb88c7..45f51dd 100644
--- a/library/std/src/random.rs
+++ b/library/std/src/random.rs
@@ -38,7 +38,7 @@
/// Vita | `arc4random_buf`
/// Hermit | `read_entropy`
/// Horizon | `getrandom` shim
-/// Hurd, L4Re, QNX | `/dev/urandom`
+/// AIX, Hurd, L4Re, QNX | `/dev/urandom`
/// Redox | `/scheme/rand`
/// RTEMS | [`arc4random_buf`](https://docs.rtems.org/branches/master/bsp-howto/getentropy.html)
/// SGX | [`rdrand`](https://en.wikipedia.org/wiki/RDRAND)
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 80e7c3c..b249223 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -110,7 +110,7 @@
// handle does not match the current ID, we should attempt to use the
// current thread ID here instead of unconditionally creating a new
// one. Also see #130210.
- let thread = Thread::new_main(thread::current_id());
+ let thread = unsafe { Thread::new_main(thread::current_id()) };
if let Err(_thread) = thread::set_current(thread) {
// `thread::current` will create a new handle if none has been set yet.
// Thus, if someone uses it before main, this call will fail. That's a
diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs
index 34acd9c..2c8ba41 100644
--- a/library/std/src/sync/mpmc/array.rs
+++ b/library/std/src/sync/mpmc/array.rs
@@ -484,7 +484,7 @@
///
/// # Panicking
/// If a destructor panics, the remaining messages are leaked, matching the
- /// behaviour of the unbounded channel.
+ /// behavior of the unbounded channel.
///
/// # Safety
/// This method must only be called when dropping the last receiver. The
diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs
index 993df93..27db4b6 100644
--- a/library/std/src/sync/once.rs
+++ b/library/std/src/sync/once.rs
@@ -288,7 +288,7 @@
///
/// If this [`Once`] has been poisoned because an initialization closure has
/// panicked, this method will also panic. Use [`wait_force`](Self::wait_force)
- /// if this behaviour is not desired.
+ /// if this behavior is not desired.
#[unstable(feature = "once_wait", issue = "127527")]
pub fn wait(&self) {
if !self.inner.is_completed() {
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index be615a5..0ae3cf4 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -634,6 +634,26 @@
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T: PartialEq> PartialEq for OnceLock<T> {
+ /// Equality for two `OnceLock`s.
+ ///
+ /// Two `OnceLock`s are equal if they either both contain values and their
+ /// values are equal, or if neither contains a value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::OnceLock;
+ ///
+ /// let five = OnceLock::new();
+ /// five.set(5).unwrap();
+ ///
+ /// let also_five = OnceLock::new();
+ /// also_five.set(5).unwrap();
+ ///
+ /// assert!(five == also_five);
+ ///
+ /// assert!(OnceLock::<u32>::new() == OnceLock::<u32>::new());
+ /// ```
#[inline]
fn eq(&self, other: &OnceLock<T>) -> bool {
self.get() == other.get()
diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
index 5d0110c..8f7d786 100644
--- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
@@ -273,7 +273,7 @@
// We don't know what someone who calls into_raw() will do with this value, but it should
// have the conventional Unix representation. Despite the fact that this is not
// standardised in SuS or POSIX, all Unix systems encode the signal and exit status the
- // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
+ // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behavior on every
// Unix.)
//
// The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
index 4551d49..8faf1fd 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -448,7 +448,6 @@
use core::sync::atomic::{AtomicU8, Ordering};
use crate::mem::MaybeUninit;
- use crate::sys::weak::weak;
use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used};
if self.get_gid().is_some()
@@ -462,6 +461,8 @@
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
+ use crate::sys::weak::weak;
+
weak! {
fn pidfd_spawnp(
*mut libc::c_int,
@@ -575,16 +576,44 @@
}
}
- // Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory,
- // and maybe others will gain this non-POSIX function too. We'll check
- // for this weak symbol as soon as it's needed, so we can return early
- // otherwise to do a manual chdir before exec.
- weak! {
- fn posix_spawn_file_actions_addchdir_np(
- *mut libc::posix_spawn_file_actions_t,
- *const libc::c_char
- ) -> libc::c_int
+ type PosixSpawnAddChdirFn = unsafe extern "C" fn(
+ *mut libc::posix_spawn_file_actions_t,
+ *const libc::c_char,
+ ) -> libc::c_int;
+
+ /// Get the function pointer for adding a chdir action to a
+ /// `posix_spawn_file_actions_t`, if available, assuming a dynamic libc.
+ ///
+ /// Some platforms can set a new working directory for a spawned process in the
+ /// `posix_spawn` path. This function looks up the function pointer for adding
+ /// such an action to a `posix_spawn_file_actions_t` struct.
+ #[cfg(not(all(target_os = "linux", target_env = "musl")))]
+ fn get_posix_spawn_addchdir() -> Option<PosixSpawnAddChdirFn> {
+ use crate::sys::weak::weak;
+
+ weak! {
+ fn posix_spawn_file_actions_addchdir_np(
+ *mut libc::posix_spawn_file_actions_t,
+ *const libc::c_char
+ ) -> libc::c_int
+ }
+
+ posix_spawn_file_actions_addchdir_np.get()
}
+
+ /// Get the function pointer for adding a chdir action to a
+ /// `posix_spawn_file_actions_t`, if available, on platforms where the function
+ /// is known to exist.
+ ///
+ /// Weak symbol lookup doesn't work with statically linked libcs, so in cases
+ /// where static linking is possible we need to either check for the presence
+ /// of the symbol at compile time or know about it upfront.
+ #[cfg(all(target_os = "linux", target_env = "musl"))]
+ fn get_posix_spawn_addchdir() -> Option<PosixSpawnAddChdirFn> {
+ // Our minimum required musl supports this function, so we can just use it.
+ Some(libc::posix_spawn_file_actions_addchdir_np)
+ }
+
let addchdir = match self.get_cwd() {
Some(cwd) => {
if cfg!(target_vendor = "apple") {
@@ -597,7 +626,10 @@
return Ok(None);
}
}
- match posix_spawn_file_actions_addchdir_np.get() {
+ // Check for the availability of the posix_spawn addchdir
+ // function now. If it isn't available, bail and use the
+ // fork/exec path.
+ match get_posix_spawn_addchdir() {
Some(f) => Some((f, cwd)),
None => return Ok(None),
}
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index b237fa4..5a9bfcc 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -1159,7 +1159,7 @@
// Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10
// Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the
// computer is in Developer Mode, but SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE must be
- // added to dwFlags to opt into this behaviour.
+ // added to dwFlags to opt into this behavior.
let result = cvt(unsafe {
c::CreateSymbolicLinkW(
link.as_ptr(),
diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs
index 95b51e7..17bb03f 100644
--- a/library/std/src/sys/pal/windows/process.rs
+++ b/library/std/src/sys/pal/windows/process.rs
@@ -47,7 +47,7 @@
}
}
-// Comparing Windows environment variable keys[1] are behaviourally the
+// Comparing Windows environment variable keys[1] are behaviorally the
// composition of two operations[2]:
//
// 1. Case-fold both strings. This is done using a language-independent
@@ -338,8 +338,8 @@
// If at least one of stdin, stdout or stderr are set (i.e. are non null)
// then set the `hStd` fields in `STARTUPINFO`.
- // Otherwise skip this and allow the OS to apply its default behaviour.
- // This provides more consistent behaviour between Win7 and Win8+.
+ // Otherwise skip this and allow the OS to apply its default behavior.
+ // This provides more consistent behavior between Win7 and Win8+.
let is_set = |stdio: &Handle| !stdio.as_raw_handle().is_null();
if is_set(&stderr) || is_set(&stdout) || is_set(&stdin) {
si.dwFlags |= c::STARTF_USESTDHANDLES;
@@ -507,7 +507,7 @@
Exists: FnMut(PathBuf) -> Option<Vec<u16>>,
{
// 1. Child paths
- // This is for consistency with Rust's historic behaviour.
+ // This is for consistency with Rust's historic behavior.
if let Some(paths) = child_paths {
for path in env::split_paths(paths).filter(|p| !p.as_os_str().is_empty()) {
if let Some(path) = exists(path) {
diff --git a/library/std/src/sys/pal/windows/process/tests.rs b/library/std/src/sys/pal/windows/process/tests.rs
index b567151..1bcc5fa 100644
--- a/library/std/src/sys/pal/windows/process/tests.rs
+++ b/library/std/src/sys/pal/windows/process/tests.rs
@@ -191,7 +191,7 @@
/*
Some of the following tests may need to be changed if you are deliberately
- changing the behaviour of `resolve_exe`.
+ changing the behavior of `resolve_exe`.
*/
let empty_paths = || None;
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index 28bce52..2c8ce42 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -99,7 +99,7 @@
}
// Attempt to use high-precision sleep (Windows 10, version 1803+).
// On error fallback to the standard `Sleep` function.
- // Also preserves the zero duration behaviour of `Sleep`.
+ // Also preserves the zero duration behavior of `Sleep`.
if dur.is_zero() || high_precision_sleep(dur).is_err() {
unsafe { c::Sleep(super::dur2timeout(dur)) }
}
diff --git a/library/std/src/sys/path/windows/tests.rs b/library/std/src/sys/path/windows/tests.rs
index 623c623..f2a60e3 100644
--- a/library/std/src/sys/path/windows/tests.rs
+++ b/library/std/src/sys/path/windows/tests.rs
@@ -119,7 +119,7 @@
/// See #101358.
///
-/// Note that the exact behaviour here may change in the future.
+/// Note that the exact behavior here may change in the future.
/// In which case this test will need to adjusted.
#[test]
fn broken_unc_path() {
diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs
index 073fdc4..e3cb792 100644
--- a/library/std/src/sys/random/linux.rs
+++ b/library/std/src/sys/random/linux.rs
@@ -30,7 +30,7 @@
//! data the system has available at the time.
//!
//! So in conclusion, we always want the output of the non-blocking pool, but
-//! may need to wait until it is initalized. The default behaviour of `getrandom`
+//! may need to wait until it is initalized. The default behavior of `getrandom`
//! is to wait until the non-blocking pool is initialized and then draw from there,
//! so if `getrandom` is available, we use its default to generate the bytes. For
//! `HashMap`, however, we need to specify the `GRND_INSECURE` flags, but that
@@ -39,7 +39,7 @@
//! succeed if the pool is initialized. If it isn't, we fall back to the file
//! access method.
//!
-//! The behaviour of `/dev/urandom` is inverse to that of `getrandom`: it always
+//! The behavior of `/dev/urandom` is inverse to that of `getrandom`: it always
//! yields data, even when the pool is not initialized. For generating `HashMap`
//! keys, this is not important, so we can use it directly. For secure data
//! however, we need to wait until initialization, which we can do by `poll`ing
diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs
index edc2cac..f42351d 100644
--- a/library/std/src/sys/random/mod.rs
+++ b/library/std/src/sys/random/mod.rs
@@ -40,6 +40,7 @@
mod horizon;
pub use horizon::fill_bytes;
} else if #[cfg(any(
+ target_os = "aix",
target_os = "hurd",
target_os = "l4re",
target_os = "nto",
diff --git a/library/std/src/sys/sync/condvar/no_threads.rs b/library/std/src/sys/sync/condvar/no_threads.rs
index 36b89c5..2a67ed7 100644
--- a/library/std/src/sys/sync/condvar/no_threads.rs
+++ b/library/std/src/sys/sync/condvar/no_threads.rs
@@ -5,7 +5,7 @@
impl Condvar {
#[inline]
- #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))]
pub const fn new() -> Condvar {
Condvar {}
}
diff --git a/library/std/src/sys/sync/condvar/pthread.rs b/library/std/src/sys/sync/condvar/pthread.rs
index 986cd0c..cee728e 100644
--- a/library/std/src/sys/sync/condvar/pthread.rs
+++ b/library/std/src/sys/sync/condvar/pthread.rs
@@ -66,7 +66,7 @@
// On DragonFly pthread_cond_destroy() returns EINVAL if called on
// a condvar that was just initialized with
// libc::PTHREAD_COND_INITIALIZER. Once it is used or
- // pthread_cond_init() is called, this behaviour no longer occurs.
+ // pthread_cond_init() is called, this behavior no longer occurs.
debug_assert!(r == 0 || r == libc::EINVAL);
} else {
debug_assert_eq!(r, 0);
diff --git a/library/std/src/sys/sync/mutex/no_threads.rs b/library/std/src/sys/sync/mutex/no_threads.rs
index 4a13c55..7b24357 100644
--- a/library/std/src/sys/sync/mutex/no_threads.rs
+++ b/library/std/src/sys/sync/mutex/no_threads.rs
@@ -10,7 +10,7 @@
impl Mutex {
#[inline]
- #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))]
pub const fn new() -> Mutex {
Mutex { locked: Cell::new(false) }
}
diff --git a/library/std/src/sys/sync/mutex/pthread.rs b/library/std/src/sys/sync/mutex/pthread.rs
index 87c95f4..abd5812 100644
--- a/library/std/src/sys/sync/mutex/pthread.rs
+++ b/library/std/src/sys/sync/mutex/pthread.rs
@@ -65,7 +65,7 @@
// On DragonFly pthread_mutex_destroy() returns EINVAL if called on a
// mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER.
// Once it is used (locked/unlocked) or pthread_mutex_init() is called,
- // this behaviour no longer occurs.
+ // this behavior no longer occurs.
debug_assert!(r == 0 || r == libc::EINVAL);
} else {
debug_assert_eq!(r, 0);
@@ -88,7 +88,7 @@
/// since the `lock` and the lock must have occurred on the current thread.
///
/// # Safety
- /// Causes undefined behaviour if the mutex is not locked.
+ /// Causes undefined behavior if the mutex is not locked.
#[inline]
pub(crate) unsafe fn get_assert_locked(&self) -> *mut libc::pthread_mutex_t {
unsafe { self.inner.get_unchecked().0.get() }
diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs
index cdcffe7..fb1b496 100644
--- a/library/std/src/sys/sync/once/no_threads.rs
+++ b/library/std/src/sys/sync/once/no_threads.rs
@@ -35,7 +35,7 @@
impl Once {
#[inline]
- #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_once_new", since = "1.32.0"))]
pub const fn new() -> Once {
Once { state: Cell::new(State::Incomplete) }
}
diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs
index 3e83a4a..177d0d7 100644
--- a/library/std/src/sys/sync/once/queue.rs
+++ b/library/std/src/sys/sync/once/queue.rs
@@ -116,7 +116,7 @@
impl Once {
#[inline]
- #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_once_new", since = "1.32.0"))]
pub const fn new() -> Once {
Once { state_and_queue: AtomicPtr::new(ptr::without_provenance_mut(INCOMPLETE)) }
}
diff --git a/library/std/src/sys/sync/once_box.rs b/library/std/src/sys/sync/once_box.rs
index 9d24db2..4105af5 100644
--- a/library/std/src/sys/sync/once_box.rs
+++ b/library/std/src/sys/sync/once_box.rs
@@ -36,7 +36,7 @@
/// ```
///
/// # Safety
- /// This causes undefined behaviour if the assumption above is violated.
+ /// This causes undefined behavior if the assumption above is violated.
#[inline]
pub unsafe fn get_unchecked(&self) -> &T {
unsafe { &*self.ptr.load(Relaxed) }
diff --git a/library/std/src/sys/sync/rwlock/futex.rs b/library/std/src/sys/sync/rwlock/futex.rs
index df22c36..447048e 100644
--- a/library/std/src/sys/sync/rwlock/futex.rs
+++ b/library/std/src/sys/sync/rwlock/futex.rs
@@ -283,7 +283,7 @@
futex_wake(&self.writer_notify)
// Note that FreeBSD and DragonFlyBSD don't tell us whether they woke
// up any threads or not, and always return `false` here. That still
- // results in correct behaviour: it just means readers get woken up as
+ // results in correct behavior: it just means readers get woken up as
// well in case both readers and writers were waiting.
}
diff --git a/library/std/src/sys/sync/rwlock/no_threads.rs b/library/std/src/sys/sync/rwlock/no_threads.rs
index 789ef9b..6965e2e 100644
--- a/library/std/src/sys/sync/rwlock/no_threads.rs
+++ b/library/std/src/sys/sync/rwlock/no_threads.rs
@@ -10,7 +10,7 @@
impl RwLock {
#[inline]
- #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+ #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))]
pub const fn new() -> RwLock {
RwLock { mode: Cell::new(0) }
}
diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs
index 733f51c..8899619 100644
--- a/library/std/src/sys/sync/rwlock/queue.rs
+++ b/library/std/src/sys/sync/rwlock/queue.rs
@@ -8,7 +8,7 @@
//! * `pthread` is an external library, meaning the fast path of acquiring an
//! uncontended lock cannot be inlined.
//! * Some platforms (at least glibc before version 2.25) have buggy implementations
-//! that can easily lead to undefined behaviour in safe Rust code when not properly
+//! that can easily lead to undefined behavior in safe Rust code when not properly
//! guarded against.
//! * On some platforms (e.g. macOS), the lock is very slow.
//!
diff --git a/library/std/src/sys/sync/thread_parking/darwin.rs b/library/std/src/sys/sync/thread_parking/darwin.rs
index 96e3d23..0553c5e 100644
--- a/library/std/src/sys/sync/thread_parking/darwin.rs
+++ b/library/std/src/sys/sync/thread_parking/darwin.rs
@@ -5,7 +5,7 @@
//! rejection from the App Store).
//!
//! Therefore, we need to look for other synchronization primitives. Luckily, Darwin
-//! supports semaphores, which allow us to implement the behaviour we need with
+//! supports semaphores, which allow us to implement the behavior we need with
//! only one primitive (as opposed to a mutex-condvar pair). We use the semaphore
//! provided by libdispatch, as the underlying Mach semaphore is only dubiously
//! public.
diff --git a/library/std/src/sys/sync/thread_parking/pthread.rs b/library/std/src/sys/sync/thread_parking/pthread.rs
index 5f195d0..76df73b 100644
--- a/library/std/src/sys/sync/thread_parking/pthread.rs
+++ b/library/std/src/sys/sync/thread_parking/pthread.rs
@@ -97,7 +97,7 @@
/// The constructed parker must never be moved.
pub unsafe fn new_in_place(parker: *mut Parker) {
// Use the default mutex implementation to allow for simpler initialization.
- // This could lead to undefined behaviour when deadlocking. This is avoided
+ // This could lead to undefined behavior when deadlocking. This is avoided
// by not deadlocking. Note in particular the unlocking operation before any
// panic, as code after the panic could try to park again.
(&raw mut (*parker).state).write(AtomicUsize::new(EMPTY));
diff --git a/library/std/src/sys/sync/thread_parking/windows7.rs b/library/std/src/sys/sync/thread_parking/windows7.rs
index 8f7e66c..f7585e8 100644
--- a/library/std/src/sys/sync/thread_parking/windows7.rs
+++ b/library/std/src/sys/sync/thread_parking/windows7.rs
@@ -35,7 +35,7 @@
// different implementations.
//
// Unfortunately, NT Keyed Events are an undocumented Windows API. However:
-// - This API is relatively simple with obvious behaviour, and there are
+// - This API is relatively simple with obvious behavior, and there are
// several (unofficial) articles documenting the details. [1]
// - `parking_lot` has been using this API for years (on Windows versions
// before Windows 8). [2] Many big projects extensively use parking_lot,
@@ -43,7 +43,7 @@
// - It is the underlying API used by Windows SRW locks and Windows critical
// sections. [3] [4]
// - The source code of the implementations of Wine, ReactOs, and Windows XP
-// are available and match the expected behaviour.
+// are available and match the expected behavior.
// - The main risk with an undocumented API is that it might change in the
// future. But since we only use it for older versions of Windows, that's not
// a problem.
diff --git a/library/std/src/sys/thread_local/key/racy.rs b/library/std/src/sys/thread_local/key/racy.rs
index 69f1145..97df899 100644
--- a/library/std/src/sys/thread_local/key/racy.rs
+++ b/library/std/src/sys/thread_local/key/racy.rs
@@ -30,7 +30,7 @@
const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1;
impl LazyKey {
- #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
+ #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))]
pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> LazyKey {
LazyKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor }
}
diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs
index f5a2aaa..58f291f 100644
--- a/library/std/src/sys/thread_local/os.rs
+++ b/library/std/src/sys/thread_local/os.rs
@@ -60,7 +60,7 @@
}
impl<T: 'static> Storage<T> {
- #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
+ #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))]
pub const fn new() -> Storage<T> {
Storage { key: LazyKey::new(Some(destroy_value::<T>)), marker: PhantomData }
}
diff --git a/library/std/src/sys/thread_local/statik.rs b/library/std/src/sys/thread_local/statik.rs
index ba94caa..4da01a8 100644
--- a/library/std/src/sys/thread_local/statik.rs
+++ b/library/std/src/sys/thread_local/statik.rs
@@ -14,12 +14,11 @@
(@key $t:ty, const $init:expr) => {{
const __INIT: $t = $init;
+ // NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed.
unsafe {
- use $crate::thread::LocalKey;
- use $crate::thread::local_impl::EagerStorage;
-
- LocalKey::new(|_| {
- static VAL: EagerStorage<$t> = EagerStorage { value: __INIT };
+ $crate::thread::LocalKey::new(|_| {
+ static VAL: $crate::thread::local_impl::EagerStorage<$t> =
+ $crate::thread::local_impl::EagerStorage { value: __INIT };
&VAL.value
})
}
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 88bf186..9edb3fa 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -237,7 +237,7 @@
reason = "recently added to create a key",
issue = "none"
)]
- #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
+ #[cfg_attr(bootstrap, rustc_const_unstable(feature = "thread_local_internals", issue = "none"))]
pub const unsafe fn new(inner: fn(Option<&mut Option<T>>) -> *const T) -> LocalKey<T> {
LocalKey { inner }
}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 3975388..227ee9d 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -158,9 +158,12 @@
#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))]
mod tests;
+use core::cell::SyncUnsafeCell;
+use core::ffi::CStr;
+use core::mem::MaybeUninit;
+
use crate::any::Any;
use crate::cell::UnsafeCell;
-use crate::ffi::CStr;
use crate::marker::PhantomData;
use crate::mem::{self, ManuallyDrop, forget};
use crate::num::NonZero;
@@ -875,7 +878,7 @@
///
/// # Platform-specific behavior
///
-/// This function uses [`sleep`] internally, see its platform-specific behaviour.
+/// This function uses [`sleep`] internally, see its platform-specific behavior.
///
///
/// # Examples
@@ -946,7 +949,7 @@
}
/// Used to ensure that `park` and `park_timeout` do not unwind, as that can
-/// cause undefined behaviour if not handled correctly (see #102398 for context).
+/// cause undefined behavior if not handled correctly (see #102398 for context).
struct PanicGuard;
impl Drop for PanicGuard {
@@ -1125,7 +1128,7 @@
let guard = PanicGuard;
// SAFETY: park_timeout is called on the parker owned by this thread.
unsafe {
- current().inner.as_ref().parker().park_timeout(dur);
+ current().0.parker().park_timeout(dur);
}
// No panic occurred, do not abort.
forget(guard);
@@ -1232,30 +1235,31 @@
// Thread
////////////////////////////////////////////////////////////////////////////////
-/// The internal representation of a `Thread`'s name.
-enum ThreadName {
- Main,
- Other(ThreadNameString),
- Unnamed,
-}
-
// This module ensures private fields are kept private, which is necessary to enforce the safety requirements.
mod thread_name_string {
use core::str;
- use super::ThreadName;
use crate::ffi::{CStr, CString};
/// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated.
pub(crate) struct ThreadNameString {
inner: CString,
}
+
+ impl ThreadNameString {
+ pub fn as_str(&self) -> &str {
+ // SAFETY: `self.inner` is only initialised via `String`, which upholds the validity invariant of `str`.
+ unsafe { str::from_utf8_unchecked(self.inner.to_bytes()) }
+ }
+ }
+
impl core::ops::Deref for ThreadNameString {
type Target = CStr;
fn deref(&self) -> &CStr {
&self.inner
}
}
+
impl From<String> for ThreadNameString {
fn from(s: String) -> Self {
Self {
@@ -1263,34 +1267,82 @@
}
}
}
- impl ThreadName {
- pub fn as_cstr(&self) -> Option<&CStr> {
- match self {
- ThreadName::Main => Some(c"main"),
- ThreadName::Other(other) => Some(other),
- ThreadName::Unnamed => None,
- }
- }
-
- pub fn as_str(&self) -> Option<&str> {
- // SAFETY: `as_cstr` can only return `Some` for a fixed CStr or a `ThreadNameString`,
- // which is guaranteed to be UTF-8.
- self.as_cstr().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
- }
- }
}
pub(crate) use thread_name_string::ThreadNameString;
-/// The internal representation of a `Thread` handle
-struct Inner {
- name: ThreadName, // Guaranteed to be UTF-8
+static MAIN_THREAD_INFO: SyncUnsafeCell<(MaybeUninit<ThreadId>, MaybeUninit<Parker>)> =
+ SyncUnsafeCell::new((MaybeUninit::uninit(), MaybeUninit::uninit()));
+
+/// The internal representation of a `Thread` that is not the main thread.
+struct OtherInner {
+ name: Option<ThreadNameString>,
id: ThreadId,
parker: Parker,
}
+/// The internal representation of a `Thread` handle.
+#[derive(Clone)]
+enum Inner {
+ /// Represents the main thread. May only be constructed by Thread::new_main.
+ Main(&'static (ThreadId, Parker)),
+ /// Represents any other thread.
+ Other(Pin<Arc<OtherInner>>),
+}
+
impl Inner {
- fn parker(self: Pin<&Self>) -> Pin<&Parker> {
- unsafe { Pin::map_unchecked(self, |inner| &inner.parker) }
+ fn id(&self) -> ThreadId {
+ match self {
+ Self::Main((thread_id, _)) => *thread_id,
+ Self::Other(other) => other.id,
+ }
+ }
+
+ fn cname(&self) -> Option<&CStr> {
+ match self {
+ Self::Main(_) => Some(c"main"),
+ Self::Other(other) => other.name.as_deref(),
+ }
+ }
+
+ fn name(&self) -> Option<&str> {
+ match self {
+ Self::Main(_) => Some("main"),
+ Self::Other(other) => other.name.as_ref().map(ThreadNameString::as_str),
+ }
+ }
+
+ fn into_raw(self) -> *const () {
+ match self {
+ // Just return the pointer to `MAIN_THREAD_INFO`.
+ Self::Main(ptr) => crate::ptr::from_ref(ptr).cast(),
+ Self::Other(arc) => {
+ // Safety: We only expose an opaque pointer, which maintains the `Pin` invariant.
+ let inner = unsafe { Pin::into_inner_unchecked(arc) };
+ Arc::into_raw(inner) as *const ()
+ }
+ }
+ }
+
+ /// # Safety
+ ///
+ /// See [`Thread::from_raw`].
+ unsafe fn from_raw(ptr: *const ()) -> Self {
+ // If the pointer is to `MAIN_THREAD_INFO`, we know it is the `Main` variant.
+ if crate::ptr::eq(ptr.cast(), &MAIN_THREAD_INFO) {
+ Self::Main(unsafe { &*ptr.cast() })
+ } else {
+ // Safety: Upheld by caller
+ Self::Other(unsafe { Pin::new_unchecked(Arc::from_raw(ptr as *const OtherInner)) })
+ }
+ }
+
+ fn parker(&self) -> Pin<&Parker> {
+ match self {
+ Self::Main((_, parker_ref)) => Pin::static_ref(parker_ref),
+ Self::Other(inner) => unsafe {
+ Pin::map_unchecked(inner.as_ref(), |inner| &inner.parker)
+ },
+ }
}
}
@@ -1314,33 +1366,47 @@
/// docs of [`Builder`] and [`spawn`] for more details.
///
/// [`thread::current`]: current::current
-pub struct Thread {
- inner: Pin<Arc<Inner>>,
-}
+pub struct Thread(Inner);
impl Thread {
/// Used only internally to construct a thread object without spawning.
pub(crate) fn new(id: ThreadId, name: String) -> Thread {
- Self::new_inner(id, ThreadName::Other(name.into()))
+ Self::new_inner(id, Some(ThreadNameString::from(name)))
}
pub(crate) fn new_unnamed(id: ThreadId) -> Thread {
- Self::new_inner(id, ThreadName::Unnamed)
+ Self::new_inner(id, None)
}
- /// Constructs the thread handle for the main thread.
- pub(crate) fn new_main(id: ThreadId) -> Thread {
- Self::new_inner(id, ThreadName::Main)
+ /// Used in runtime to construct main thread
+ ///
+ /// # Safety
+ ///
+ /// This must only ever be called once, and must be called on the main thread.
+ pub(crate) unsafe fn new_main(thread_id: ThreadId) -> Thread {
+ // Safety: As this is only called once and on the main thread, nothing else is accessing MAIN_THREAD_INFO
+ // as the only other read occurs in `main_thread_info` *after* the main thread has been constructed,
+ // and this function is the only one that constructs the main thread.
+ //
+ // Pre-main thread spawning cannot hit this either, as the caller promises that this is only called on the main thread.
+ let main_thread_info = unsafe { &mut *MAIN_THREAD_INFO.get() };
+
+ unsafe { Parker::new_in_place((&raw mut main_thread_info.1).cast()) };
+ main_thread_info.0.write(thread_id);
+
+ // Store a `'static` ref to the initialised ThreadId and Parker,
+ // to avoid having to repeatedly prove initialisation.
+ Self(Inner::Main(unsafe { &*MAIN_THREAD_INFO.get().cast() }))
}
- fn new_inner(id: ThreadId, name: ThreadName) -> Thread {
+ fn new_inner(id: ThreadId, name: Option<ThreadNameString>) -> Thread {
// We have to use `unsafe` here to construct the `Parker` in-place,
// which is required for the UNIX implementation.
//
// SAFETY: We pin the Arc immediately after creation, so its address never
// changes.
let inner = unsafe {
- let mut arc = Arc::<Inner>::new_uninit();
+ let mut arc = Arc::<OtherInner>::new_uninit();
let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr();
(&raw mut (*ptr).name).write(name);
(&raw mut (*ptr).id).write(id);
@@ -1348,7 +1414,7 @@
Pin::new_unchecked(arc.assume_init())
};
- Thread { inner }
+ Self(Inner::Other(inner))
}
/// Like the public [`park`], but callable on any handle. This is used to
@@ -1357,7 +1423,7 @@
/// # Safety
/// May only be called from the thread to which this handle belongs.
pub(crate) unsafe fn park(&self) {
- unsafe { self.inner.as_ref().parker().park() }
+ unsafe { self.0.parker().park() }
}
/// Atomically makes the handle's token available if it is not already.
@@ -1393,7 +1459,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn unpark(&self) {
- self.inner.as_ref().parker().unpark();
+ self.0.parker().unpark();
}
/// Gets the thread's unique identifier.
@@ -1413,7 +1479,7 @@
#[stable(feature = "thread_id", since = "1.19.0")]
#[must_use]
pub fn id(&self) -> ThreadId {
- self.inner.id
+ self.0.id()
}
/// Gets the thread's name.
@@ -1456,7 +1522,11 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
pub fn name(&self) -> Option<&str> {
- self.inner.name.as_str()
+ self.0.name()
+ }
+
+ fn cname(&self) -> Option<&CStr> {
+ self.0.cname()
}
/// Consumes the `Thread`, returning a raw pointer.
@@ -1480,9 +1550,7 @@
/// ```
#[unstable(feature = "thread_raw", issue = "97523")]
pub fn into_raw(self) -> *const () {
- // Safety: We only expose an opaque pointer, which maintains the `Pin` invariant.
- let inner = unsafe { Pin::into_inner_unchecked(self.inner) };
- Arc::into_raw(inner) as *const ()
+ self.0.into_raw()
}
/// Constructs a `Thread` from a raw pointer.
@@ -1504,11 +1572,7 @@
#[unstable(feature = "thread_raw", issue = "97523")]
pub unsafe fn from_raw(ptr: *const ()) -> Thread {
// Safety: Upheld by caller.
- unsafe { Thread { inner: Pin::new_unchecked(Arc::from_raw(ptr as *const Inner)) } }
- }
-
- fn cname(&self) -> Option<&CStr> {
- self.inner.name.as_cstr()
+ unsafe { Thread(Inner::from_raw(ptr)) }
}
}
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index f28a056..9f4f8a0 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -178,9 +178,9 @@
/// system.
///
/// A `SystemTime` does not count leap seconds.
-/// `SystemTime::now()`'s behaviour around a leap second
+/// `SystemTime::now()`'s behavior around a leap second
/// is the same as the operating system's wall clock.
-/// The precise behaviour near a leap second
+/// The precise behavior near a leap second
/// (e.g. whether the clock appears to run slow or fast, or stop, or jump)
/// depends on platform and configuration,
/// so should not be relied on.
diff --git a/library/stdarch b/library/stdarch
index c881fe3..ff9a444 160000
--- a/library/stdarch
+++ b/library/stdarch
@@ -1 +1 @@
-Subproject commit c881fe3231b3947a4766aa15a26a93022fbb8723
+Subproject commit ff9a4445038eae46fd095188740946808581bc0e
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 04909cd..d7ae029 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -1092,9 +1092,6 @@
if not os.path.exists(cargo_dir):
eprint('ERROR: vendoring required, but .cargo/config does not exist.')
raise Exception("{} not found".format(cargo_dir))
- else:
- if os.path.exists(cargo_dir):
- shutil.rmtree(cargo_dir)
def parse_args(args):
"""Parse the command line arguments that the python script needs."""
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 15137fb..2e173c9 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -72,6 +72,7 @@
o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
o("llvm-enzyme", "llvm.enzyme", "build LLVM with enzyme")
+o("llvm-offload", "llvm.offload", "build LLVM with gpu offload support")
o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface")
o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")
o("debug-assertions-std", "rust.debug-assertions-std", "build the standard library with debugging assertions")
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 27bbc8b..e13d4cc 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -15,7 +15,6 @@
use std::process::Stdio;
use std::{env, fs, str};
-use build_helper::git::get_closest_merge_commit;
use serde_derive::Deserialize;
use crate::core::build_steps::tool::SourceType;
@@ -27,7 +26,7 @@
use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
use crate::utils::exec::command;
use crate::utils::helpers::{
- self, exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
+ exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
};
use crate::{CLang, Compiler, DependencyType, GitRepo, LLVM_TOOLS, Mode};
@@ -125,23 +124,9 @@
// Force compilation of the standard library from source if the `library` is modified. This allows
// library team to compile the standard library without needing to compile the compiler with
// the `rust.download-rustc=true` option.
- let force_recompile =
- if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() {
- let closest_merge_commit =
- get_closest_merge_commit(Some(&builder.src), &builder.config.git_config(), &[])
- .unwrap();
-
- // Check if `library` has changes (returns false otherwise)
- !t!(helpers::git(Some(&builder.src))
- .args(["diff-index", "--quiet", &closest_merge_commit])
- .arg("--")
- .arg(builder.src.join("library"))
- .as_command_mut()
- .status())
- .success()
- } else {
- false
- };
+ let force_recompile = builder.rust_info().is_managed_git_subrepository()
+ && builder.download_rustc()
+ && builder.config.last_modified_commit(&["library"], "download-rustc", true).is_none();
run.builder.ensure(Std {
compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index ca2b874..69ec832 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -170,7 +170,14 @@
builder.add_rustc_lib_path(compiler, &mut rustbook_cmd);
}
- rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).run(builder);
+ rustbook_cmd
+ .arg("build")
+ .arg(&src)
+ .arg("-d")
+ .arg(&out)
+ .arg("--rust-root")
+ .arg(&builder.src)
+ .run(builder);
for lang in &self.languages {
let out = out.join(lang);
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index a2d40f6..ffb7d9a 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -472,6 +472,21 @@
cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";"));
}
+ let mut enabled_llvm_runtimes = Vec::new();
+
+ if builder.config.llvm_offload {
+ enabled_llvm_runtimes.push("offload");
+ //FIXME(ZuseZ4): LLVM intends to drop the offload dependency on openmp.
+ //Remove this line once they achieved it.
+ enabled_llvm_runtimes.push("openmp");
+ }
+
+ if !enabled_llvm_runtimes.is_empty() {
+ enabled_llvm_runtimes.sort();
+ enabled_llvm_runtimes.dedup();
+ cfg.define("LLVM_ENABLE_RUNTIMES", enabled_llvm_runtimes.join(";"));
+ }
+
if let Some(num_linkers) = builder.config.llvm_link_jobs {
if num_linkers > 0 {
cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 27acaff..2ad1b39 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1836,6 +1836,9 @@
if builder.config.cmd.only_modified() {
cmd.arg("--only-modified");
}
+ if let Some(compiletest_diff_tool) = &builder.config.compiletest_diff_tool {
+ cmd.arg("--compiletest-diff-tool").arg(compiletest_diff_tool);
+ }
let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 50f71e1..bb837eb 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1,8 +1,6 @@
use std::path::PathBuf;
use std::{env, fs};
-use build_helper::git::get_closest_merge_commit;
-
use crate::core::build_steps::compile;
use crate::core::build_steps::toolstate::ToolState;
use crate::core::builder;
@@ -10,7 +8,7 @@
use crate::core::config::TargetSelection;
use crate::utils::channel::GitInfo;
use crate::utils::exec::{BootstrapCommand, command};
-use crate::utils::helpers::{add_dylib_path, exe, git, t};
+use crate::utils::helpers::{add_dylib_path, exe, t};
use crate::{Compiler, Kind, Mode, gha};
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
@@ -596,28 +594,11 @@
&& target_compiler.stage > 0
&& builder.rust_info().is_managed_git_subrepository()
{
- let commit = get_closest_merge_commit(
- Some(&builder.config.src),
- &builder.config.git_config(),
- &[],
- )
- .unwrap();
+ let files_to_track = &["src/librustdoc", "src/tools/rustdoc"];
- let librustdoc_src = builder.config.src.join("src/librustdoc");
- let rustdoc_src = builder.config.src.join("src/tools/rustdoc");
-
- // FIXME: The change detection logic here is quite similar to `Config::download_ci_rustc_commit`.
- // It would be better to unify them.
- let has_changes = !git(Some(&builder.config.src))
- .allow_failure()
- .run_always()
- .args(["diff-index", "--quiet", &commit])
- .arg("--")
- .arg(librustdoc_src)
- .arg(rustdoc_src)
- .run(builder);
-
- if !has_changes {
+ // Check if unchanged
+ if builder.config.last_modified_commit(files_to_track, "download-rustc", true).is_some()
+ {
let precompiled_rustdoc = builder
.config
.ci_rustc_dir()
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index aeb81b1..139ca7e 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -224,6 +224,7 @@
pub llvm_assertions: bool,
pub llvm_tests: bool,
pub llvm_enzyme: bool,
+ pub llvm_offload: bool,
pub llvm_plugins: bool,
pub llvm_optimize: bool,
pub llvm_thin_lto: bool,
@@ -368,6 +369,9 @@
/// The paths to work with. For example: with `./x check foo bar` we get
/// `paths=["foo", "bar"]`.
pub paths: Vec<PathBuf>,
+
+ /// Command for visual diff display, e.g. `diff-tool --color=always`.
+ pub compiletest_diff_tool: Option<String>,
}
#[derive(Clone, Debug, Default)]
@@ -892,6 +896,7 @@
android_ndk: Option<PathBuf> = "android-ndk",
optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
jobs: Option<u32> = "jobs",
+ compiletest_diff_tool: Option<String> = "compiletest-diff-tool",
}
}
@@ -934,6 +939,7 @@
use_libcxx: Option<bool> = "use-libcxx",
use_linker: Option<String> = "use-linker",
allow_old_toolchain: Option<bool> = "allow-old-toolchain",
+ offload: Option<bool> = "offload",
polly: Option<bool> = "polly",
clang: Option<bool> = "clang",
enable_warnings: Option<bool> = "enable-warnings",
@@ -1512,6 +1518,7 @@
android_ndk,
optimized_compiler_builtins,
jobs,
+ compiletest_diff_tool,
} = toml.build.unwrap_or_default();
config.jobs = Some(threads_from_config(flags.jobs.unwrap_or(jobs.unwrap_or(0))));
@@ -1642,6 +1649,7 @@
// we'll infer default values for them later
let mut llvm_tests = None;
let mut llvm_enzyme = None;
+ let mut llvm_offload = None;
let mut llvm_plugins = None;
let mut debug = None;
let mut debug_assertions = None;
@@ -1879,6 +1887,7 @@
use_libcxx,
use_linker,
allow_old_toolchain,
+ offload,
polly,
clang,
enable_warnings,
@@ -1895,6 +1904,7 @@
set(&mut config.ninja_in_file, ninja);
llvm_tests = tests;
llvm_enzyme = enzyme;
+ llvm_offload = offload;
llvm_plugins = plugins;
set(&mut config.llvm_optimize, optimize_toml);
set(&mut config.llvm_thin_lto, thin_lto);
@@ -1916,6 +1926,7 @@
set(&mut config.llvm_use_libcxx, use_libcxx);
config.llvm_use_linker.clone_from(&use_linker);
config.llvm_allow_old_toolchain = allow_old_toolchain.unwrap_or(false);
+ config.llvm_offload = offload.unwrap_or(false);
config.llvm_polly = polly.unwrap_or(false);
config.llvm_clang = clang.unwrap_or(false);
config.llvm_enable_warnings = enable_warnings.unwrap_or(false);
@@ -2092,6 +2103,7 @@
config.llvm_tests = llvm_tests.unwrap_or(false);
config.llvm_enzyme = llvm_enzyme.unwrap_or(false);
+ config.llvm_offload = llvm_offload.unwrap_or(false);
config.llvm_plugins = llvm_plugins.unwrap_or(false);
config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true));
@@ -2158,6 +2170,7 @@
config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None);
config.optimized_compiler_builtins =
optimized_compiler_builtins.unwrap_or(config.channel != "dev");
+ config.compiletest_diff_tool = compiletest_diff_tool;
let download_rustc = config.download_rustc_commit.is_some();
// See https://github.com/rust-lang/compiler-team/issues/326
@@ -2754,25 +2767,25 @@
}
};
- let files_to_track = &[
- self.src.join("compiler"),
- self.src.join("library"),
- self.src.join("src/version"),
- self.src.join("src/stage0"),
- self.src.join("src/ci/channel"),
- ];
+ let files_to_track =
+ &["compiler", "library", "src/version", "src/stage0", "src/ci/channel"];
// Look for a version to compare to based on the current commit.
// Only commits merged by bors will have CI artifacts.
- let commit =
- get_closest_merge_commit(Some(&self.src), &self.git_config(), files_to_track).unwrap();
- if commit.is_empty() {
- println!("ERROR: could not find commit hash for downloading rustc");
- println!("HELP: maybe your repository history is too shallow?");
- println!("HELP: consider disabling `download-rustc`");
- println!("HELP: or fetch enough history to include one upstream commit");
- crate::exit!(1);
- }
+ let commit = match self.last_modified_commit(files_to_track, "download-rustc", if_unchanged)
+ {
+ Some(commit) => commit,
+ None => {
+ if if_unchanged {
+ return None;
+ }
+ println!("ERROR: could not find commit hash for downloading rustc");
+ println!("HELP: maybe your repository history is too shallow?");
+ println!("HELP: consider disabling `download-rustc`");
+ println!("HELP: or fetch enough history to include one upstream commit");
+ crate::exit!(1);
+ }
+ };
if CiEnv::is_ci() && {
let head_sha =
@@ -2787,31 +2800,7 @@
return None;
}
- // Warn if there were changes to the compiler or standard library since the ancestor commit.
- let has_changes = !t!(helpers::git(Some(&self.src))
- .args(["diff-index", "--quiet", &commit])
- .arg("--")
- .args(files_to_track)
- .as_command_mut()
- .status())
- .success();
- if has_changes {
- if if_unchanged {
- if self.is_verbose() {
- println!(
- "WARNING: saw changes to compiler/ or library/ since {commit}; \
- ignoring `download-rustc`"
- );
- }
- return None;
- }
- println!(
- "WARNING: `download-rustc` is enabled, but there are changes to \
- compiler/ or library/"
- );
- }
-
- Some(commit.to_string())
+ Some(commit)
}
fn parse_download_ci_llvm(
@@ -2882,14 +2871,7 @@
// Warn if there were changes to the compiler or standard library since the ancestor commit.
let mut git = helpers::git(Some(&self.src));
- git.args(["diff-index", "--quiet", &commit, "--"]);
-
- // Handle running from a directory other than the top level
- let top_level = &self.src;
-
- for path in modified_paths {
- git.arg(top_level.join(path));
- }
+ git.args(["diff-index", "--quiet", &commit, "--"]).args(modified_paths);
let has_changes = !t!(git.as_command_mut().status()).success();
if has_changes {
@@ -2981,6 +2963,7 @@
use_libcxx,
use_linker,
allow_old_toolchain,
+ offload,
polly,
clang,
enable_warnings,
@@ -3003,6 +2986,7 @@
err!(current_llvm_config.use_libcxx, use_libcxx);
err!(current_llvm_config.use_linker, use_linker);
err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain);
+ err!(current_llvm_config.offload, offload);
err!(current_llvm_config.polly, polly);
err!(current_llvm_config.clang, clang);
err!(current_llvm_config.build_config, build_config);
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index a9db0377..ba74cab 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -541,7 +541,7 @@
}
let output = helpers::git(Some(&self.src))
.args(["config", "--file"])
- .arg(self.config.src.join(".gitmodules"))
+ .arg(".gitmodules")
.args(["--get-regexp", "path"])
.run_capture(self)
.stdout();
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 9169bc9..b9cf8f0 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -280,4 +280,14 @@
severity: ChangeSeverity::Info,
summary: "Allow setting `--jobs` in config.toml with `build.jobs`.",
},
+ ChangeInfo {
+ change_id: 131181,
+ severity: ChangeSeverity::Info,
+ summary: "New option `build.compiletest-diff-tool` that adds support for a custom differ for compiletest",
+ },
+ ChangeInfo {
+ change_id: 131513,
+ severity: ChangeSeverity::Info,
+ summary: "New option `llvm.offload` to control whether the llvm offload runtime for GPU support is built. Implicitly enables the openmp runtime as dependency.",
+ },
];
diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
new file mode 100644
index 0000000..dcfea77
--- /dev/null
+++ b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile
@@ -0,0 +1,58 @@
+FROM ubuntu:22.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ g++ \
+ make \
+ ninja-build \
+ file \
+ curl \
+ ca-certificates \
+ python3 \
+ python3-dev \
+ libxml2-dev \
+ libncurses-dev \
+ libedit-dev \
+ swig \
+ doxygen \
+ git \
+ cmake \
+ sudo \
+ gdb \
+ libssl-dev \
+ pkg-config \
+ xz-utils \
+ lld \
+ clang \
+ && rm -rf /var/lib/apt/lists/*
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1
+ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
+
+# llvm.use-linker conflicts with downloading CI LLVM
+ENV NO_DOWNLOAD_CI_LLVM 1
+
+ENV RUST_CONFIGURE_ARGS \
+ --build=aarch64-unknown-linux-gnu \
+ --enable-debug \
+ --enable-lld \
+ --set llvm.use-linker=lld \
+ --set target.aarch64-unknown-linux-gnu.linker=clang \
+ --set target.aarch64-unknown-linux-gnu.cc=clang \
+ --set target.aarch64-unknown-linux-gnu.cxx=clang++
+
+# This job appears to be checking two separate things:
+# - That we can build the compiler with `--enable-debug`
+# (without necessarily testing the result).
+# - That the tests with `//@ needs-force-clang-based-tests` pass, since they
+# don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set.
+# - FIXME(https://github.com/rust-lang/rust/pull/126155#issuecomment-2156314273):
+# Currently we only run the subset of tests with "clang" in their name.
+# - See also FIXME(#132034)
+
+ENV SCRIPT \
+ python3 ../x.py --stage 2 build && \
+ python3 ../x.py --stage 2 test tests/run-make --test-args clang
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index 410f0f9..ece5f17 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -56,9 +56,9 @@
CFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
CXX_x86_64_fortanix_unknown_sgx=clang++-11 \
CXXFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
- AR_i686_unknown_freebsd=i686-unknown-freebsd13-ar \
- CC_i686_unknown_freebsd=i686-unknown-freebsd13-clang \
- CXX_i686_unknown_freebsd=i686-unknown-freebsd13-clang++ \
+ AR_i686_unknown_freebsd=i686-unknown-freebsd12-ar \
+ CC_i686_unknown_freebsd=i686-unknown-freebsd12-clang \
+ CXX_i686_unknown_freebsd=i686-unknown-freebsd12-clang++ \
CC_aarch64_unknown_uefi=clang-11 \
CXX_aarch64_unknown_uefi=clang++-11 \
CC_i686_unknown_uefi=clang-11 \
@@ -118,6 +118,7 @@
ENV TARGETS=$TARGETS,wasm32-wasip1
ENV TARGETS=$TARGETS,wasm32-wasip1-threads
ENV TARGETS=$TARGETS,wasm32-wasip2
+ENV TARGETS=$TARGETS,wasm32v1-none
ENV TARGETS=$TARGETS,sparcv9-sun-solaris
ENV TARGETS=$TARGETS,x86_64-pc-solaris
ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
index fd0f5da..f42e6f7 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
@@ -29,9 +29,9 @@
RUN /scripts/cmake.sh
ENV \
- AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-ar \
- CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang \
- CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang++
+ AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar \
+ CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang \
+ CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang++
ENV HOSTS=x86_64-unknown-freebsd
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index 0f8ebb9..fdc8a73 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -51,7 +51,8 @@
/scripts/check-default-config-profiles.sh && \
python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
python3 ../x.py clippy bootstrap -Dwarnings && \
- python3 ../x.py clippy compiler library -Aclippy::all -Dclippy::correctness && \
+ python3 ../x.py clippy library -Aclippy::all -Dclippy::correctness && \
+ python3 ../x.py clippy compiler -Aclippy::all -Dclippy::correctness -Dclippy::clone_on_ref_ptr && \
python3 ../x.py build --stage 0 src/tools/build-manifest && \
python3 ../x.py test --stage 0 src/tools/compiletest && \
python3 ../x.py test --stage 0 core alloc std test proc_macro && \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
index fa31801..292dbfd 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
@@ -49,9 +49,7 @@
# (without necessarily testing the result).
# - That the tests with `//@ needs-force-clang-based-tests` pass, since they
# don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set.
-# - FIXME(https://github.com/rust-lang/rust/pull/126155#issuecomment-2156314273):
-# Currently we only run the subset of tests with "clang" in their name.
ENV SCRIPT \
python3 ../x.py --stage 2 build && \
- python3 ../x.py --stage 2 test tests/run-make --test-args clang
+ python3 ../x.py --stage 2 test tests/run-make
diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh
index 4826b81..0d02636 100755
--- a/src/ci/docker/scripts/freebsd-toolchain.sh
+++ b/src/ci/docker/scripts/freebsd-toolchain.sh
@@ -5,8 +5,8 @@
arch=$1
binutils_version=2.40
-freebsd_version=13.2
-triple=$arch-unknown-freebsd13
+freebsd_version=12.3
+triple=$arch-unknown-freebsd12
sysroot=/usr/local/$triple
hide_output() {
@@ -59,7 +59,7 @@
# Originally downloaded from:
# URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz
-URL=https://ci-mirrors.rust-lang.org/rustc/2024-02-18-freebsd-${freebsd_version}-${freebsd_arch}-base.txz
+URL=https://ci-mirrors.rust-lang.org/rustc/2022-05-06-freebsd-${freebsd_version}-${freebsd_arch}-base.txz
curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}"
# Clang can do cross-builds out of the box, if we give it the right
@@ -68,7 +68,7 @@
# there might be other problems.)
#
# The --target option is last because the cross-build of LLVM uses
-# --target without an OS version ("-freebsd" vs. "-freebsd13"). This
+# --target without an OS version ("-freebsd" vs. "-freebsd12"). This
# makes Clang default to libstdc++ (which no longer exists), and also
# controls other features, like GNU-style symbol table hashing and
# anything predicated on the version number in the __FreeBSD__
diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py
index 1aa9a4a..77e2741 100755
--- a/src/ci/docker/scripts/fuchsia-test-runner.py
+++ b/src/ci/docker/scripts/fuchsia-test-runner.py
@@ -287,7 +287,7 @@
@property
def package_server_log_path(self) -> Path:
- return self.tmp_dir().joinpath("package_server_log")
+ return self.tmp_dir().joinpath(f"repo_{self.TEST_REPO_NAME}.log")
@property
def emulator_log_path(self) -> Path:
@@ -401,6 +401,7 @@
# Set configs
configs = {
"log.enabled": "true",
+ "log.dir": self.tmp_dir(),
"test.is_isolated": "true",
"test.experimental_structured_output": "true",
}
@@ -575,43 +576,19 @@
stderr_handler=self.subprocess_logger.debug,
)
- # Add repository
- check_call_with_logging(
- [
- ffx_path,
- "repository",
- "add-from-pm",
- "--repository",
- self.TEST_REPO_NAME,
- self.repo_dir(),
- ],
- env=ffx_env,
- stdout_handler=self.subprocess_logger.debug,
- stderr_handler=self.subprocess_logger.debug,
- )
-
- # Start repository server
- # Note that we must first enable the repository server daemon.
- check_call_with_logging(
- [
- ffx_path,
- "config",
- "set",
- "repository.server.enabled",
- "true",
- ],
- env=ffx_env,
- stdout_handler=self.subprocess_logger.debug,
- stderr_handler=self.subprocess_logger.debug,
- )
check_call_with_logging(
[
ffx_path,
"repository",
"server",
"start",
+ "--background",
"--address",
"[::]:0",
+ "--repo-path",
+ self.repo_dir(),
+ "--repository",
+ self.TEST_REPO_NAME
],
env=ffx_env,
stdout_handler=self.subprocess_logger.debug,
@@ -1009,6 +986,21 @@
stderr_handler=self.subprocess_logger.debug,
)
+ # Stop the package server
+ self.env_logger.info("Stopping package server...")
+ check_call_with_logging(
+ [
+ self.tool_path("ffx"),
+ "repository",
+ "server",
+ "stop",
+ self.TEST_REPO_NAME
+ ],
+ env=self.ffx_cmd_env(),
+ stdout_handler=self.subprocess_logger.debug,
+ stderr_handler=self.subprocess_logger.debug,
+ )
+
# Stop ffx isolation
self.env_logger.info("Stopping ffx isolation...")
self.stop_ffx_isolation()
diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh
index 27dbfc6..f07515f 100755
--- a/src/ci/docker/scripts/rfl-build.sh
+++ b/src/ci/docker/scripts/rfl-build.sh
@@ -2,7 +2,7 @@
set -euo pipefail
-LINUX_VERSION=v6.12-rc2
+LINUX_VERSION=28e848386b92645f93b9f2fdba5882c3ca7fb3e2
# Build rustc, rustdoc, cargo, clippy-driver and rustfmt
../x.py build --stage 2 library rustdoc clippy rustfmt
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 2b63660..a401092 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -123,6 +123,9 @@
- image: aarch64-gnu
<<: *job-aarch64-linux
+ - image: aarch64-gnu-debug
+ <<: *job-aarch64-linux
+
- image: arm-android
<<: *job-linux-4c
@@ -253,7 +256,9 @@
<<: *job-linux-4c
- image: x86_64-gnu-debug
- <<: *job-linux-4c
+ # This seems to be needed because a full stage 2 build + run-make tests
+ # overwhelms the storage capacity of the standard 4c runner.
+ <<: *job-linux-4c-largedisk
- image: x86_64-gnu-distcheck
<<: *job-linux-8c
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 3962c35..8e2f525 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -47,11 +47,6 @@
export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
-# suppress change-tracker warnings on CI
-if [ "$CI" != "" ]; then
- RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set change-id=99999999"
-fi
-
# If runner uses an incompatible option and `FORCE_CI_RUSTC` is not defined,
# switch to in-tree rustc.
if [ "$FORCE_CI_RUSTC" == "" ]; then
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
index c7ebae2..1f07c24 160000
--- a/src/doc/edition-guide
+++ b/src/doc/edition-guide
@@ -1 +1 @@
-Subproject commit c7ebae25cb4801a31b6f05353f6d85bfa6feedd1
+Subproject commit 1f07c242f8162a711a5ac5a4ea8fa7ec884ee7a9
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
index f40a8b4..ddbf1b4 160000
--- a/src/doc/embedded-book
+++ b/src/doc/embedded-book
@@ -1 +1 @@
-Subproject commit f40a8b420ec4b4505d9489965e261f1d5c28ba23
+Subproject commit ddbf1b4e2858fedb71b7c42eb15c4576517dc125
diff --git a/src/doc/reference b/src/doc/reference
index c64e52a..23ce619 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit c64e52a3d306eac0129f3ad6c6d8806ab99ae2e9
+Subproject commit 23ce619966541bf2c80d45fdfeecf3393e360a13
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
index 07bc9ca..59d94ea 160000
--- a/src/doc/rustc-dev-guide
+++ b/src/doc/rustc-dev-guide
@@ -1 +1 @@
-Subproject commit 07bc9ca9eb1cd6d9fbbf758c2753b748804a134f
+Subproject commit 59d94ea75a0b157e148af14c73c2dd60efb7b60a
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 795908b..18f76ac 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -66,9 +66,10 @@
- [powerpc-unknown-openbsd](platform-support/powerpc-unknown-openbsd.md)
- [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md)
- [powerpc64-ibm-aix](platform-support/aix.md)
+ - [riscv32e*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md)
+ - [riscv32i*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md)
- [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md)
- [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
- - [riscv32*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md)
- [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md)
- [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md)
- [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
@@ -86,6 +87,7 @@
- [wasm32-wasip2](platform-support/wasm32-wasip2.md)
- [wasm32-unknown-emscripten](platform-support/wasm32-unknown-emscripten.md)
- [wasm32-unknown-unknown](platform-support/wasm32-unknown-unknown.md)
+ - [wasm32v1-none](platform-support/wasm32v1-none.md)
- [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
- [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md)
- [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index e9c73ef..04bb40d 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -100,7 +100,7 @@
[`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29)
[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3)
`s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17)
-`x86_64-unknown-freebsd` | 64-bit FreeBSD (version 13.2)
+`x86_64-unknown-freebsd` | 64-bit FreeBSD
`x86_64-unknown-illumos` | illumos
`x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3
[`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64
@@ -166,7 +166,7 @@
`i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, musl 1.2.3 [^x86_32-floats-x87]
[`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android [^x86_32-floats-return-ABI]
[`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+), LLVM ABI [^x86_32-floats-return-ABI]
-`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD (version 13.2) [^x86_32-floats-return-ABI]
+`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD [^x86_32-floats-return-ABI]
`i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 [^x86_32-floats-return-ABI]
[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI
[`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI)
@@ -195,6 +195,7 @@
`wasm32-wasi` | ✓ | WebAssembly with WASI (undergoing a [rename to `wasm32-wasip1`][wasi-rename])
[`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASI
[`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads
+[`wasm32v1-none`](platform-support/wasm32v1-none.md) | * | WebAssembly limited to 1.0 features and no imports
[`x86_64-apple-ios`](platform-support/apple-ios.md) | ✓ | 64-bit x86 iOS
[`x86_64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | Mac Catalyst on x86_64
[`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
@@ -257,7 +258,7 @@
[`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? | | ARM64 TEEOS |
[`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS |
[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS |
-`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD (version 13.2)
+`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
[`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit
`aarch64-unknown-illumos` | ✓ | ✓ | ARM64 illumos
`aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI)
@@ -276,14 +277,14 @@
`armv4t-unknown-linux-gnueabi` | ? | | Armv4T Linux
[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare Armv5TE
`armv5te-unknown-linux-uclibceabi` | ? | | Armv5TE Linux with uClibc
-`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD (version 13.2)
+`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD
[`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv6 NetBSD w/hard-float
[`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? | | Armv6k Nintendo 3DS, Horizon (Requires devkitARM toolchain)
[`armv7-rtems-eabihf`](platform-support/armv7-rtems-eabihf.md) | ? | | RTEMS OS for ARM BSPs
[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ | | Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
[`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | Armv7-A Linux with uClibc, softfloat
[`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat
-`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD (version 13.2)
+`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD
[`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv7-A NetBSD w/hard-float
[`armv7-unknown-trusty`](platform-support/trusty.md) | ? | |
[`armv7-wrs-vxworks-eabihf`](platform-support/vxworks.md) | ✓ | | Armv7-A for VxWorks
@@ -342,9 +343,9 @@
[`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * | |
[`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | |
[`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ | |
-`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2, version 13.2)
-`powerpc64le-unknown-freebsd` | | | PPC64LE FreeBSD (version 13.2)
-`powerpc-unknown-freebsd` | | | PowerPC FreeBSD (version 13.2)
+`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
+`powerpc64le-unknown-freebsd` | | | PPC64LE FreeBSD
+`powerpc-unknown-freebsd` | | | PowerPC FreeBSD
`powerpc64-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3
[`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | |
`powerpc64le-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3, Little Endian
@@ -360,7 +361,7 @@
[`riscv32imafc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF
[`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ✓ | |
[`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit
-`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD (version 13.2)
+`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD
`riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia
[`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD
[`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
@@ -413,8 +414,8 @@
[`riscv32imafc-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 32bit with NuttX
[`riscv64imac-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 64bit with NuttX
[`riscv64gc-unknown-nuttx-elf`](platform-support/nuttx.md) | * | | RISC-V 64bit with NuttX
-[`riscv32e-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32E ISA)
-[`riscv32em-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32EM ISA)
-[`riscv32emc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32EMC ISA)
+[`riscv32e-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * | | Bare RISC-V (RV32E ISA)
+[`riscv32em-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * | | Bare RISC-V (RV32EM ISA)
+[`riscv32emc-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * | | Bare RISC-V (RV32EMC ISA)
[runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets
diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md
index 5643c6a..0622f4d 100644
--- a/src/doc/rustc/src/platform-support/fuchsia.md
+++ b/src/doc/rustc/src/platform-support/fuchsia.md
@@ -525,14 +525,6 @@
pkg/repo
```
-Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using:
-
-```sh
-${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \
- --repository hello-fuchsia \
- pkg/repo
-```
-
## Running a Fuchsia component on an emulator
At this point, we are ready to run our Fuchsia
@@ -590,7 +582,8 @@
package to the emulator:
```sh
-${SDK_PATH}/tools/${ARCH}/ffx repository server start
+${SDK_PATH}/tools/${ARCH}/ffx repository server start \
+ --background --repository hello-fuchsia --repo-path pkg-repo
```
Once the repository server is up and running, register it with the target Fuchsia system running in the emulator:
diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
index 48a8df0..73264ab 100644
--- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
+++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
@@ -132,10 +132,20 @@
If you're compiling WebAssembly code for an engine that does not support a
feature in LLVM's default feature set then the feature must be disabled at
-compile time. Note, though, that enabled features may be used in the standard
-library or precompiled libraries shipped via rustup. This means that not only
-does your own code need to be compiled with the correct set of flags but the
-Rust standard library additionally must be recompiled.
+compile time. There are two approaches to choose from:
+
+ - If you are targeting a feature set no smaller than the W3C WebAssembly Core
+ 1.0 recommendation -- which is equivalent to the WebAssembly MVP plus the
+ `mutable-globals` feature -- and you are building `no_std`, then you can
+ simply use the [`wasm32v1-none` target](./wasm32v1-none.md) instead of
+ `wasm32-unknown-unknown`, which uses only those minimal features and
+ includes a core and alloc library built with only those minimal features.
+
+ - Otherwise -- if you need std, or if you need to target the ultra-minimal
+ "MVP" feature set, excluding `mutable-globals` -- you will need to manually
+ specify `-Ctarget-cpu=mvp` and also rebuild the stdlib using that target to
+ ensure no features are used in the stdlib. This in turn requires use of a
+ nightly compiler.
Compiling all code for the initial release of WebAssembly looks like:
@@ -150,9 +160,9 @@
will produce a binary that uses only the original WebAssembly features by
default and no proposals since its inception.
-To enable individual features it can be done with `-Ctarget-feature=+foo`.
-Available features for Rust code itself are documented in the [reference] and
-can also be found through:
+To enable individual features on either this target or `wasm32v1-none`, pass
+arguments of the form `-Ctarget-feature=+foo`. Available features for Rust code
+itself are documented in the [reference] and can also be found through:
```sh
$ rustc -Ctarget-feature=help --target wasm32-unknown-unknown
diff --git a/src/doc/rustc/src/platform-support/wasm32v1-none.md b/src/doc/rustc/src/platform-support/wasm32v1-none.md
new file mode 100644
index 0000000..46f89c2
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/wasm32v1-none.md
@@ -0,0 +1,109 @@
+# `wasm32v1-none`
+
+**Tier: 2**
+
+The `wasm32v1-none` target is a WebAssembly compilation target that:
+
+- Imports nothing from its host environment
+- Enables no proposals / features past the [W3C WebAssembly Core 1.0 spec]
+
+[W3C WebAssembly Core 1.0 spec]: https://www.w3.org/TR/wasm-core-1/
+
+The target is very similar to [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md) and similarly uses LLVM's `wasm32-unknown-unknown` backend target. It contains only three minor differences:
+
+* Setting the `target-cpu` to `mvp` rather than the default `generic`. Requesting `mvp` disables _all_ WebAssembly proposals / LLVM target feature flags.
+* Enabling the [Import/Export of Mutable Globals] proposal (i.e. the `+mutable-globals` LLVM target feature flag)
+* Not compiling the `std` library at all, rather than compiling it with stubs.
+
+[Import/Export of Mutable Globals]: https://github.com/WebAssembly/mutable-global
+
+## Target maintainers
+
+- Alex Crichton, https://github.com/alexcrichton
+- Graydon Hoare, https://github.com/graydon
+
+## Requirements
+
+This target is cross-compiled. It does not support `std`, only `core` and `alloc`. Since it imports nothing from its environment, any `std` parts that use OS facilities would be stubbed out with functions-that-fail anyways, and the experience of working with the stub `std` in the `wasm32-unknown-unknown` target was deemed not something worth repeating here.
+
+Everything else about this target's requirements, building, usage and testing is the same as what's described in the [`wasm32-unknown-unknown` document](./wasm32-unknown-unknown.md), just using the target string `wasm32v1-none` in place of `wasm32-unknown-unknown`.
+
+## Conditionally compiling code
+
+It's recommended to conditionally compile code for this target with:
+
+```text
+#[cfg(all(target_family = "wasm", target_os = "none"))]
+```
+
+Note that there is no way to tell via `#[cfg]` whether code will be running on
+the web or not.
+
+## Enabled WebAssembly features
+
+As noted above, _no WebAssembly proposals past 1.0_ are enabled on this target by default. Indeed, the entire point of this target is to have a way to compile for a stable "no post-1.0 proposals" subset of WebAssembly _on stable Rust_.
+
+The [W3C WebAssembly Core 1.0 spec] was adopted as a W3C recommendation in December 2019, and includes exactly one "post-MVP" proposal: the [Import/Export of Mutable Globals] proposal.
+
+All subsequent proposals are _disabled_ on this target by default, though they can be individually enabled by passing LLVM target-feature flags.
+
+For reference sake, the set of proposals that LLVM supports at the time of writing, that this target _does not enable by default_, are listed here along with their LLVM target-feature flags:
+
+* Post-1.0 proposals (integrated into the WebAssembly core 2.0 spec):
+ * [Bulk memory] - `+bulk-memory`
+ * [Sign-extending operations] - `+sign-ext`
+ * [Non-trapping fp-to-int operations] - `+nontrapping-fptoint`
+ * [Multi-value] - `+multivalue`
+ * [Reference Types] - `+reference-types`
+ * [Fixed-width SIMD] - `+simd128`
+* Post-2.0 proposals:
+ * [Threads] (supported by atomics) - `+atomics`
+ * [Exception handling] - `+exception-handling`
+ * [Extended Constant Expressions] - `+extended-const`
+ * [Half Precision] - `+half-precision`
+ * [Multiple memories]- `+multimemory`
+ * [Relaxed SIMD] - `+relaxed-simd`
+ * [Tail call] - `+tail-call`
+
+[Bulk memory]: https://github.com/WebAssembly/spec/blob/main/proposals/bulk-memory-operations/Overview.md
+[Sign-extending operations]: https://github.com/WebAssembly/spec/blob/main/proposals/sign-extension-ops/Overview.md
+[Non-trapping fp-to-int operations]: https://github.com/WebAssembly/spec/blob/main/proposals/nontrapping-float-to-int-conversion/Overview.md
+[Multi-value]: https://github.com/WebAssembly/spec/blob/main/proposals/multi-value/Overview.md
+[Reference Types]: https://github.com/WebAssembly/spec/blob/main/proposals/reference-types/Overview.md
+[Fixed-width SIMD]: https://github.com/WebAssembly/spec/blob/main/proposals/simd/SIMD.md
+[Threads]: https://github.com/webassembly/threads
+[Exception handling]: https://github.com/WebAssembly/exception-handling
+[Extended Constant Expressions]: https://github.com/WebAssembly/extended-const
+[Half Precision]: https://github.com/WebAssembly/half-precision
+[Multiple memories]: https://github.com/WebAssembly/multi-memory
+[Relaxed SIMD]: https://github.com/WebAssembly/relaxed-simd
+[Tail call]: https://github.com/WebAssembly/tail-call
+
+Additional proposals in the future are, of course, also not enabled by default.
+
+## Rationale relative to wasm32-unknown-unknown
+
+As noted in the [`wasm32-unknown-unknown` document](./wasm32-unknown-unknown.md), it is possible to compile with `--target wasm32-unknown-unknown` and disable all WebAssembly proposals "by hand", by passing `-Ctarget-cpu=mvp`. Furthermore one can enable proposals one by one by passing LLVM target feature flags, such as `-Ctarget-feature=+mutable-globals`.
+
+Is it therefore reasonable to wonder what the difference is between building with this:
+
+```sh
+$ rustc --target wasm32-unknown-unknown -Ctarget-cpu=mvp -Ctarget-feature=+mutable-globals
+```
+
+and building with this:
+
+```sh
+$ rustc --target wasm32v1-none
+```
+
+The difference is in how the `core` and `alloc` crates are compiled for distribution with the toolchain, and whether it works on _stable_ Rust toolchains or requires _nightly_ ones. Again referring back to the [`wasm32-unknown-unknown` document](./wasm32-unknown-unknown.md), note that to disable all post-MVP proposals on that target one _actually_ has to compile with this:
+
+```sh
+$ export RUSTFLAGS="-Ctarget-cpu=mvp -Ctarget-feature=+mutable-globals"
+$ cargo +nightly build -Zbuild-std=panic_abort,std --target wasm32-unknown-unknown
+```
+
+Which not only rebuilds `std`, `core` and `alloc` (which is somewhat costly and annoying) but more importantly requires the use of nightly Rust toolchains (for the `-Zbuild-std` flag). This is very undesirable for the target audience, which consists of people targeting WebAssembly implementations that prioritize stability, simplicity and/or security over feature support.
+
+This `wasm32v1-none` target exists as an alternative option that works on stable Rust toolchains, without rebuilding the stdlib.
diff --git a/src/doc/rustc/src/symbol-mangling/v0.md b/src/doc/rustc/src/symbol-mangling/v0.md
index 6329e87..1099425 100644
--- a/src/doc/rustc/src/symbol-mangling/v0.md
+++ b/src/doc/rustc/src/symbol-mangling/v0.md
@@ -1208,7 +1208,7 @@
* Named functions, methods, and statics shall be represented by a *[path]* production.
-* Paths should be rooted at the inner-most entity that can act as a path root.
+* Paths should be rooted at the innermost entity that can act as a path root.
Roots can be crate-ids, inherent impls, trait impls, and (for items within default methods) trait definitions.
* The compiler is free to choose disambiguation indices and namespace tags from
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index 24940f0..4679acf 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -690,7 +690,6 @@
LeakSanitizer is supported on the following targets:
-* `aarch64-apple-darwin`
* `aarch64-unknown-linux-gnu`
* `x86_64-apple-darwin`
* `x86_64-unknown-linux-gnu`
diff --git a/src/etc/cat-and-grep.sh b/src/etc/cat-and-grep.sh
index 238f7f5..68c6993 100755
--- a/src/etc/cat-and-grep.sh
+++ b/src/etc/cat-and-grep.sh
@@ -33,7 +33,6 @@
case "$OPTION" in
v)
INVERT=1
- ERROR_MSG='should not be found'
;;
i)
GREPFLAGS="i$GREPFLAGS"
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index 599e1e8..851b01a 100755
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -250,7 +250,7 @@
os.path.join(
# We go back to `src`.
os.path.dirname(os.path.dirname(__file__)),
- "tools/compiletest/src/command-list.rs",
+ "tools/compiletest/src/directive-list.rs",
),
"r",
encoding="utf8"
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 42df0b2..57b6de6 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -2,6 +2,7 @@
name = "rustdoc"
version = "0.0.0"
edition = "2021"
+build = "build.rs"
[lib]
path = "lib.rs"
@@ -24,13 +25,15 @@
tracing-tree = "0.3.0"
threadpool = "1.8.1"
unicode-segmentation = "1.9"
-sha2 = "0.10.8"
[dependencies.tracing-subscriber]
version = "0.3.3"
default-features = false
features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"]
+[build-dependencies]
+sha2 = "0.10.8"
+
[dev-dependencies]
expect-test = "1.4.0"
diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs
new file mode 100644
index 0000000..69337fb
--- /dev/null
+++ b/src/librustdoc/build.rs
@@ -0,0 +1,48 @@
+fn main() {
+ // generate sha256 files
+ // this avoids having to perform hashing at runtime
+ let files = &[
+ "static/css/rustdoc.css",
+ "static/css/noscript.css",
+ "static/css/normalize.css",
+ "static/js/main.js",
+ "static/js/search.js",
+ "static/js/settings.js",
+ "static/js/src-script.js",
+ "static/js/storage.js",
+ "static/js/scrape-examples.js",
+ "static/COPYRIGHT.txt",
+ "static/LICENSE-APACHE.txt",
+ "static/LICENSE-MIT.txt",
+ "static/images/rust-logo.svg",
+ "static/images/favicon.svg",
+ "static/images/favicon-32x32.png",
+ "static/fonts/FiraSans-Regular.woff2",
+ "static/fonts/FiraSans-Medium.woff2",
+ "static/fonts/FiraSans-LICENSE.txt",
+ "static/fonts/SourceSerif4-Regular.ttf.woff2",
+ "static/fonts/SourceSerif4-Bold.ttf.woff2",
+ "static/fonts/SourceSerif4-It.ttf.woff2",
+ "static/fonts/SourceSerif4-LICENSE.md",
+ "static/fonts/SourceCodePro-Regular.ttf.woff2",
+ "static/fonts/SourceCodePro-Semibold.ttf.woff2",
+ "static/fonts/SourceCodePro-It.ttf.woff2",
+ "static/fonts/SourceCodePro-LICENSE.txt",
+ "static/fonts/NanumBarunGothic.ttf.woff2",
+ "static/fonts/NanumBarunGothic-LICENSE.txt",
+ ];
+ let out_dir = std::env::var("OUT_DIR").expect("standard Cargo environment variable");
+ for path in files {
+ let inpath = format!("html/{path}");
+ println!("cargo::rerun-if-changed={inpath}");
+ let bytes = std::fs::read(inpath).expect("static path exists");
+ use sha2::Digest;
+ let bytes = sha2::Sha256::digest(bytes);
+ let mut digest = format!("-{bytes:x}");
+ digest.truncate(9);
+ let outpath = std::path::PathBuf::from(format!("{out_dir}/{path}.sha256"));
+ std::fs::create_dir_all(outpath.parent().expect("all file paths are in a directory"))
+ .expect("should be able to write to out_dir");
+ std::fs::write(&outpath, digest.as_bytes()).expect("write to out_dir");
+ }
+}
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index d966f99..31e4e79 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -156,7 +156,7 @@
.iter()
.inspect(|param| {
if cfg!(debug_assertions) {
- debug_assert!(!param.is_anonymous_lifetime() && !param.is_host_effect());
+ debug_assert!(!param.is_anonymous_lifetime());
if let ty::GenericParamDefKind::Type { synthetic, .. } = param.kind {
debug_assert!(!synthetic && param.name != kw::SelfUpper);
}
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index e7f921e..97529e4 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -248,9 +248,7 @@
// Check to see if it is a macro 2.0 or built-in macro
if matches!(
CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.tcx),
- LoadedMacro::MacroDef(def, _)
- if matches!(&def.kind, ast::ItemKind::MacroDef(ast_def)
- if !ast_def.macro_rules)
+ LoadedMacro::MacroDef { def, .. } if !def.macro_rules
) {
once(crate_name).chain(relative).collect()
} else {
@@ -747,24 +745,12 @@
is_doc_hidden: bool,
) -> clean::ItemKind {
match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) {
- LoadedMacro::MacroDef(item_def, _) => match macro_kind {
+ LoadedMacro::MacroDef { def, .. } => match macro_kind {
MacroKind::Bang => {
- if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
- let vis =
- cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id));
- clean::MacroItem(clean::Macro {
- source: utils::display_macro_source(
- cx,
- name,
- def,
- def_id,
- vis,
- is_doc_hidden,
- ),
- })
- } else {
- unreachable!()
- }
+ let vis = cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id));
+ clean::MacroItem(clean::Macro {
+ source: utils::display_macro_source(cx, name, &def, def_id, vis, is_doc_hidden),
+ })
}
MacroKind::Derive | MacroKind::Attr => {
clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() })
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index bf16880..ea349f8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -368,7 +368,9 @@
// FIXME(generic_const_exprs): should this do something?
ty::ClauseKind::ConstEvaluatable(..)
| ty::ClauseKind::WellFormed(..)
- | ty::ClauseKind::ConstArgHasType(..) => None,
+ | ty::ClauseKind::ConstArgHasType(..)
+ // FIXME(effects): We can probably use this `HostEffect` pred to render `~const`.
+ | ty::ClauseKind::HostEffect(_) => None,
}
}
@@ -542,7 +544,7 @@
synthetic,
})
}
- ty::GenericParamDefKind::Const { has_default, synthetic, is_host_effect: _ } => {
+ ty::GenericParamDefKind::Const { has_default, synthetic } => {
(def.name, GenericParamDefKind::Const {
ty: Box::new(clean_middle_ty(
ty::Binder::dummy(
@@ -617,7 +619,7 @@
synthetic,
})
}
- hir::GenericParamKind::Const { ty, default, synthetic, is_host_effect: _ } => {
+ hir::GenericParamKind::Const { ty, default, synthetic } => {
(param.name.ident().name, GenericParamDefKind::Const {
ty: Box::new(clean_ty(ty, cx)),
default: default.map(|ct| {
@@ -797,7 +799,7 @@
}
true
}
- ty::GenericParamDefKind::Const { is_host_effect, .. } => !is_host_effect,
+ ty::GenericParamDefKind::Const { .. } => true,
})
.map(|param| clean_generic_param_def(param, ParamDefaults::Yes, cx))
.collect();
@@ -1398,7 +1400,6 @@
clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), ty::GenericPredicates {
parent: None,
predicates,
- effects_min_tys: ty::List::empty(),
});
simplify::move_bounds_to_generic_parameters(&mut generics);
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 6090de1..c62144b 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -8,7 +8,6 @@
use rustc_ast::MetaItemInner;
use rustc_ast_pretty::pprust;
use rustc_attr::{ConstStability, Deprecation, Stability, StableSince};
-use rustc_const_eval::const_eval::is_unstable_const_fn;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
@@ -641,12 +640,11 @@
asyncness: ty::Asyncness,
) -> hir::FnHeader {
let sig = tcx.fn_sig(def_id).skip_binder();
- let constness =
- if tcx.is_const_fn(def_id) || is_unstable_const_fn(tcx, def_id).is_some() {
- hir::Constness::Const
- } else {
- hir::Constness::NotConst
- };
+ let constness = if tcx.is_const_fn(def_id) {
+ hir::Constness::Const
+ } else {
+ hir::Constness::NotConst
+ };
let asyncness = match asyncness {
ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
ty::Asyncness::No => hir::IsAsync::NotAsync,
@@ -664,9 +662,7 @@
safety
},
abi,
- constness: if tcx.is_const_fn(def_id)
- || is_unstable_const_fn(tcx, def_id).is_some()
- {
+ constness: if tcx.is_const_fn(def_id) {
hir::Constness::Const
} else {
hir::Constness::NotConst
@@ -1366,8 +1362,7 @@
pub(crate) fn is_synthetic_param(&self) -> bool {
match self.kind {
- GenericParamDefKind::Lifetime { .. } => false,
- GenericParamDefKind::Const { synthetic: is_host_effect, .. } => is_host_effect,
+ GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
GenericParamDefKind::Type { synthetic, .. } => synthetic,
}
}
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index fdf628b..d3a545f 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -114,10 +114,6 @@
// Elide internal host effect args.
let param = generics.param_at(index, cx.tcx);
- if param.is_host_effect() {
- return None;
- }
-
let arg = ty::Binder::bind_with_vars(arg, bound_vars);
// Elide arguments that coincide with their default.
diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs
index efbb332..3ae6093 100644
--- a/src/librustdoc/doctest/make.rs
+++ b/src/librustdoc/doctest/make.rs
@@ -289,7 +289,12 @@
// Recurse through functions body. It is necessary because the doctest source code is
// wrapped in a function to limit the number of AST errors. If we don't recurse into
// functions, we would thing all top-level items (so basically nothing).
- fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<&str>) {
+ fn check_item(
+ item: &ast::Item,
+ info: &mut ParseSourceInfo,
+ crate_name: &Option<&str>,
+ is_top_level: bool,
+ ) {
if !info.has_global_allocator
&& item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator)
{
@@ -297,13 +302,15 @@
}
match item.kind {
ast::ItemKind::Fn(ref fn_item) if !info.has_main_fn => {
- if item.ident.name == sym::main {
+ if item.ident.name == sym::main && is_top_level {
info.has_main_fn = true;
}
if let Some(ref body) = fn_item.body {
for stmt in &body.stmts {
match stmt.kind {
- ast::StmtKind::Item(ref item) => check_item(item, info, crate_name),
+ ast::StmtKind::Item(ref item) => {
+ check_item(item, info, crate_name, false)
+ }
ast::StmtKind::MacCall(..) => info.found_macro = true,
_ => {}
}
@@ -329,7 +336,7 @@
loop {
match parser.parse_item(ForceCollect::No) {
Ok(Some(item)) => {
- check_item(&item, info, crate_name);
+ check_item(&item, info, crate_name, true);
if info.has_main_fn && info.found_extern_crate {
break;
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 5c599f2..8e8e5c6 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -16,6 +16,7 @@
use rustc_attr::{ConstStability, StabilityLevel, StableSince};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_metadata::creader::{CStore, LoadedMacro};
@@ -25,7 +26,6 @@
use rustc_span::{Symbol, sym};
use rustc_target::spec::abi::Abi;
use tracing::{debug, trace};
-use {rustc_ast as ast, rustc_hir as hir};
use super::url_parts_builder::{UrlPartsBuilder, estimate_item_path_byte_length};
use crate::clean::types::ExternalLocation;
@@ -554,10 +554,8 @@
// Check to see if it is a macro 2.0 or built-in macro.
// More information in <https://rust-lang.github.io/rfcs/1584-macros.html>.
let is_macro_2 = match cstore.load_macro_untracked(def_id, tcx) {
- LoadedMacro::MacroDef(def, _) => {
- // If `ast_def.macro_rules` is `true`, then it's not a macro 2.0.
- matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) if !ast_def.macro_rules)
- }
+ // If `def.macro_rules` is `true`, then it's not a macro 2.0.
+ LoadedMacro::MacroDef { def, .. } => !def.macro_rules,
_ => false,
};
@@ -1368,6 +1366,24 @@
write!(f, " -> ")?;
fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?;
}
+ } else if let clean::Type::Path { path } = type_
+ && let Some(generics) = path.generics()
+ && generics.len() == 1
+ && self.kind.is_fake_variadic()
+ {
+ let ty = generics[0];
+ let wrapper = anchor(path.def_id(), path.last(), cx);
+ if f.alternate() {
+ write!(f, "{wrapper:#}<")?;
+ } else {
+ write!(f, "{wrapper}<")?;
+ }
+ self.print_type(ty, f, use_absolute, cx)?;
+ if f.alternate() {
+ write!(f, ">")?;
+ } else {
+ write!(f, ">")?;
+ }
} else {
fmt_type(&type_, f, use_absolute, cx)?;
}
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 399730a..8446235 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1010,7 +1010,9 @@
// don't display const unstable if entirely unstable
None
} else {
- let unstable = if let Some(n) = issue {
+ let unstable = if let Some(n) = issue
+ && let Some(feature) = feature
+ {
format!(
"<a \
href=\"https://github.com/rust-lang/rust/issues/{n}\" \
@@ -2010,9 +2012,9 @@
);
if let Some(link) = src_href {
if has_stability {
- write!(rightside, " · <a class=\"src\" href=\"{link}\">source</a>")
+ write!(rightside, " · <a class=\"src\" href=\"{link}\">Source</a>")
} else {
- write!(rightside, "<a class=\"src rightside\" href=\"{link}\">source</a>")
+ write!(rightside, "<a class=\"src rightside\" href=\"{link}\">Source</a>")
}
}
if has_stability && has_src_ref {
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index c958458b..d1939ad 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -759,7 +759,10 @@
}
});
let (mut inputs, mut output, where_clause) = match item.kind {
- clean::FunctionItem(ref f) | clean::MethodItem(ref f, _) | clean::TyMethodItem(ref f) => {
+ clean::ForeignFunctionItem(ref f, _)
+ | clean::FunctionItem(ref f)
+ | clean::MethodItem(ref f, _)
+ | clean::TyMethodItem(ref f) => {
get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
}
_ => return None,
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
index cd4e597..79209ce 100644
--- a/src/librustdoc/html/render/type_layout.rs
+++ b/src/librustdoc/html/render/type_layout.rs
@@ -60,8 +60,8 @@
span_bug!(tcx.def_span(ty_def_id), "not an adt")
};
let name = adt.variant(variant_idx).name;
- let is_unsized = variant_layout.abi.is_unsized();
- let is_uninhabited = variant_layout.abi.is_uninhabited();
+ let is_unsized = variant_layout.is_unsized();
+ let is_uninhabited = variant_layout.is_uninhabited();
let size = variant_layout.size.bytes() - tag_size;
let type_layout_size = TypeLayoutSize { is_unsized, is_uninhabited, size };
(name, type_layout_size)
@@ -72,8 +72,8 @@
};
let type_layout_size = tcx.layout_of(param_env.and(ty)).map(|layout| {
- let is_unsized = layout.abi.is_unsized();
- let is_uninhabited = layout.abi.is_uninhabited();
+ let is_unsized = layout.is_unsized();
+ let is_uninhabited = layout.is_uninhabited();
let size = layout.size.bytes();
TypeLayoutSize { is_unsized, is_uninhabited, size }
});
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 12b63460..c82f7e9 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -112,7 +112,7 @@
md_opts.output = cx.dst.clone();
md_opts.external_html = cx.shared.layout.external_html.clone();
try_err!(
- crate::markdown::render(&index_page, md_opts, cx.shared.edition()),
+ crate::markdown::render_and_write(&index_page, md_opts, cx.shared.edition()),
&index_page
);
}
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 2c17fd5..1042d25 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -185,7 +185,7 @@
grid-template-columns: minmax(105px, 1fr) minmax(0, max-content);
grid-template-rows: minmax(25px, min-content) min-content min-content;
padding-bottom: 6px;
- margin-bottom: 11px;
+ margin-bottom: 15px;
}
.rustdoc-breadcrumbs {
grid-area: main-heading-breadcrumbs;
@@ -230,7 +230,7 @@
padding: 0;
white-space: pre-wrap;
}
-.structfield {
+.structfield, .sub-variant-field {
margin: 0.6em 0;
}
@@ -959,7 +959,7 @@
background: var(--table-alt-row-background-color);
}
-.docblock .stab, .docblock-short .stab {
+.docblock .stab, .docblock-short .stab, .docblock p code {
display: inline-block;
}
@@ -1004,6 +1004,7 @@
display: flex;
height: 34px;
flex-grow: 1;
+ margin-bottom: 4px;
}
.src nav.sub {
margin: 0 0 -10px 0;
@@ -2253,7 +2254,12 @@
/* We don't display this button on mobile devices. */
#copy-path {
- display: none;
+ /* display: none; avoided as a layout hack.
+ When there's one line, we get an effective line-height of 34px,
+ because that's how big the image is, but if the header wraps,
+ they're packed more tightly than that. */
+ width: 0;
+ visibility: hidden;
}
/* Text label takes up too much space at this size. */
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 9e0803f..a4dc8cd 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -12,8 +12,8 @@
}
impl StaticFile {
- fn new(filename: &str, bytes: &'static [u8]) -> StaticFile {
- Self { filename: static_filename(filename, bytes), bytes }
+ fn new(filename: &str, bytes: &'static [u8], sha256: &'static str) -> StaticFile {
+ Self { filename: static_filename(filename, sha256), bytes }
}
pub(crate) fn minified(&self) -> Vec<u8> {
@@ -55,17 +55,9 @@
filename.into()
}
-pub(crate) fn static_filename(filename: &str, contents: &[u8]) -> PathBuf {
+pub(crate) fn static_filename(filename: &str, sha256: &str) -> PathBuf {
let filename = filename.rsplit('/').next().unwrap();
- suffix_path(filename, &static_suffix(contents))
-}
-
-fn static_suffix(bytes: &[u8]) -> String {
- use sha2::Digest;
- let bytes = sha2::Sha256::digest(bytes);
- let mut digest = format!("-{bytes:x}");
- digest.truncate(9);
- digest
+ suffix_path(filename, &sha256)
}
macro_rules! static_files {
@@ -74,8 +66,9 @@
$(pub $field: StaticFile,)+
}
+ // sha256 files are generated in build.rs
pub(crate) static STATIC_FILES: std::sync::LazyLock<StaticFiles> = std::sync::LazyLock::new(|| StaticFiles {
- $($field: StaticFile::new($file_path, include_bytes!($file_path)),)+
+ $($field: StaticFile::new($file_path, include_bytes!($file_path), include_str!(concat!(env!("OUT_DIR"), "/", $file_path, ".sha256"))),)+
});
pub(crate) fn for_each<E>(f: impl Fn(&StaticFile) -> Result<(), E>) -> Result<(), E> {
diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html
index f60720b..9fd575b 100644
--- a/src/librustdoc/html/templates/print_item.html
+++ b/src/librustdoc/html/templates/print_item.html
@@ -26,7 +26,7 @@
{% match src_href %}
{% when Some with (href) %}
{% if !stability_since_raw.is_empty() +%} · {%+ endif %}
- <a class="src" href="{{href|safe}}">source</a> {#+ #}
+ <a class="src" href="{{href|safe}}">Source</a> {#+ #}
{% else %}
{% endmatch %}
</span> {# #}
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 10fc0ea..7c9dcd4 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -37,7 +37,6 @@
extern crate rustc_ast;
extern crate rustc_ast_pretty;
extern crate rustc_attr;
-extern crate rustc_const_eval;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_errors;
@@ -817,7 +816,7 @@
return wrap_return(
dcx,
interface::run_compiler(config, |_compiler| {
- markdown::render(&md_input, render_options, edition)
+ markdown::render_and_write(&md_input, render_options, edition)
}),
);
}
diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs
index bdfdeea..2afb9e5 100644
--- a/src/librustdoc/lint.rs
+++ b/src/librustdoc/lint.rs
@@ -31,9 +31,9 @@
allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
let lints = || {
- lint::builtin::HardwiredLints::get_lints()
+ lint::builtin::HardwiredLints::lint_vec()
.into_iter()
- .chain(rustc_lint::SoftLints::get_lints())
+ .chain(rustc_lint::SoftLints::lint_vec())
};
let lint_opts = lints()
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 978f96f..76eac08 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -1,3 +1,13 @@
+//! Standalone markdown rendering.
+//!
+//! For the (much more common) case of rendering markdown in doc-comments, see
+//! [crate::html::markdown].
+//!
+//! This is used when [rendering a markdown file to an html file][docs], without processing
+//! rust source code.
+//!
+//! [docs]: https://doc.rust-lang.org/stable/rustdoc/#using-standalone-markdown-files
+
use std::fmt::Write as _;
use std::fs::{File, create_dir_all, read_to_string};
use std::io::prelude::*;
@@ -33,7 +43,7 @@
/// (e.g., output = "bar" => "bar/foo.html").
///
/// Requires session globals to be available, for symbol interning.
-pub(crate) fn render<P: AsRef<Path>>(
+pub(crate) fn render_and_write<P: AsRef<Path>>(
input: P,
options: RenderOptions,
edition: Edition,
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 62e1695..925cbfe 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -161,6 +161,7 @@
"wasm32-wasip1",
"wasm32-wasip1-threads",
"wasm32-wasip2",
+ "wasm32v1-none",
"x86_64-apple-darwin",
"x86_64-apple-ios",
"x86_64-apple-ios-macabi",
diff --git a/src/tools/cargo b/src/tools/cargo
index cf53cc5..e75214e 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit cf53cc54bb593b5ec3dc2be4b1702f50c36d24d5
+Subproject commit e75214ea4936d2f2c909a71a1237042cc0e14b07
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 495d8ce..4774352 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -31,6 +31,7 @@
pub COGNITIVE_COMPLEXITY,
nursery,
"functions that should be split up into multiple functions"
+ @eval_always = true
}
pub struct CognitiveComplexity {
diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs
new file mode 100644
index 0000000..2fe37a6
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/ctfe.rs
@@ -0,0 +1,40 @@
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, FnDecl};
+use rustc_lint::Level::Deny;
+use rustc_lint::{LateContext, LateLintPass, Lint};
+use rustc_session::declare_lint_pass;
+use rustc_span::Span;
+
+/// Ensures that Constant-time Function Evaluation is being done (specifically, MIR lint passes).
+/// As Clippy deactivates codegen, this lint ensures that CTFE (used in hard errors) is still ran.
+pub static CLIPPY_CTFE: &Lint = &Lint {
+ name: &"clippy::CLIPPY_CTFE",
+ default_level: Deny,
+ desc: "Ensure CTFE is being made",
+ edition_lint_opts: None,
+ report_in_external_macro: true,
+ future_incompatible: None,
+ is_externally_loaded: true,
+ crate_level_only: false,
+ eval_always: true,
+ ..Lint::default_fields_for_macro()
+};
+
+// No static CLIPPY_CTFE_INFO because we want this lint to be invisible
+
+declare_lint_pass! { ClippyCtfe => [CLIPPY_CTFE] }
+
+impl<'tcx> LateLintPass<'tcx> for ClippyCtfe {
+ fn check_fn(
+ &mut self,
+ cx: &LateContext<'_>,
+ _: FnKind<'tcx>,
+ _: &'tcx FnDecl<'tcx>,
+ _: &'tcx Body<'tcx>,
+ _: Span,
+ defid: LocalDefId,
+ ) {
+ cx.tcx.ensure().mir_drops_elaborated_and_const_checked(defid); // Lint
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs b/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
index b1e39c7..a785a9d 100644
--- a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
+++ b/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
@@ -9,6 +9,7 @@
$desc:literal,
$version_expr:expr,
$version_lit:literal
+ $(, $eval_always: literal)?
) => {
rustc_session::declare_tool_lint! {
$(#[doc = $lit])*
@@ -17,6 +18,7 @@
$category,
$desc,
report_in_external_macro:true
+ $(, @eval_always = $eval_always)?
}
pub(crate) static ${concat($lint_name, _INFO)}: &'static crate::LintInfo = &crate::LintInfo {
@@ -33,11 +35,12 @@
pub $lint_name:ident,
restriction,
$desc:literal
+ $(@eval_always = $eval_always: literal)?
) => {
declare_clippy_lint! {@
$(#[doc = $lit])*
pub $lint_name, Allow, crate::LintCategory::Restriction, $desc,
- Some($version), $version
+ Some($version), $version $(, $eval_always)?
}
};
(
@@ -46,12 +49,12 @@
pub $lint_name:ident,
style,
$desc:literal
+ $(@eval_always = $eval_always: literal)?
) => {
declare_clippy_lint! {@
$(#[doc = $lit])*
pub $lint_name, Warn, crate::LintCategory::Style, $desc,
- Some($version), $version
-
+ Some($version), $version $(, $eval_always)?
}
};
(
@@ -60,11 +63,12 @@
pub $lint_name:ident,
correctness,
$desc:literal
+ $(@eval_always = $eval_always: literal)?
) => {
declare_clippy_lint! {@
$(#[doc = $lit])*
pub $lint_name, Deny, crate::LintCategory::Correctness, $desc,
- Some($version), $version
+ Some($version), $version $(, $eval_always)?
}
};
@@ -74,11 +78,12 @@
pub $lint_name:ident,
perf,
$desc:literal
+ $(@eval_always = $eval_always: literal)?
) => {
declare_clippy_lint! {@
$(#[doc = $lit])*
pub $lint_name, Warn, crate::LintCategory::Perf, $desc,
- Some($version), $version
+ Some($version), $version $(, $eval_always)?
}
};
(
@@ -87,11 +92,12 @@
pub $lint_name:ident,
complexity,
$desc:literal
+ $(@eval_always = $eval_always: literal)?
) => {
declare_clippy_lint! {@
$(#[doc = $lit])*
pub $lint_name, Warn, crate::LintCategory::Complexity, $desc,
- Some($version), $version
+ Some($version), $version $(, $eval_always)?
}
};
(
@@ -100,11 +106,12 @@
pub $lint_name:ident,
suspicious,
$desc:literal
+ $(@eval_always = $eval_always: literal)?
) => {
declare_clippy_lint! {@
$(#[doc = $lit])*
pub $lint_name, Warn, crate::LintCategory::Suspicious, $desc,
- Some($version), $version
+ Some($version), $version $(, $eval_always)?
}
};
(
@@ -113,11 +120,12 @@
pub $lint_name:ident,
nursery,
$desc:literal
+ $(@eval_always = $eval_always: literal)?
) => {
declare_clippy_lint! {@
$(#[doc = $lit])*
pub $lint_name, Allow, crate::LintCategory::Nursery, $desc,
- Some($version), $version
+ Some($version), $version $(, $eval_always)?
}
};
(
@@ -126,11 +134,12 @@
pub $lint_name:ident,
pedantic,
$desc:literal
+ $(@eval_always = $eval_always: literal)?
) => {
declare_clippy_lint! {@
$(#[doc = $lit])*
pub $lint_name, Allow, crate::LintCategory::Pedantic, $desc,
- Some($version), $version
+ Some($version), $version $(, $eval_always)?
}
};
(
@@ -139,11 +148,12 @@
pub $lint_name:ident,
cargo,
$desc:literal
+ $(@eval_always = $eval_always: literal)?
) => {
declare_clippy_lint! {@
$(#[doc = $lit])*
pub $lint_name, Allow, crate::LintCategory::Cargo, $desc,
- Some($version), $version
+ Some($version), $version $(, $eval_always)?
}
};
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 0066ed6..77dbe9b 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -166,7 +166,7 @@
#[clippy::version = ""]
("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
#[clippy::version = ""]
- ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
+ ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"),
#[clippy::version = ""]
("clippy::undropped_manually_drops", "undropped_manually_drops"),
#[clippy::version = ""]
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 82a66cc..e8e21edd 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -324,7 +324,7 @@
// If the current self type doesn't implement Copy (due to generic constraints), search to see if
// there's a Copy impl for any instance of the adt.
if !is_copy(cx, ty) {
- if ty_subs.non_erasable_generics(cx.tcx, ty_adt.did()).next().is_some() {
+ if ty_subs.non_erasable_generics().next().is_some() {
let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| {
impls.iter().any(|&id| {
matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _)
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 6e29dde..1411053 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -65,6 +65,7 @@
#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
mod utils;
+pub mod ctfe; // Very important lint, do not remove (rust#125116)
pub mod declared_lints;
pub mod deprecated_lints;
@@ -605,6 +606,8 @@
});
}
+ store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe));
+
store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf)));
store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
store.register_late_pass(|_| Box::new(utils::author::Author));
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs b/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs
index 032cd3e..22b2c89 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/ident_iter.rs
@@ -39,7 +39,7 @@
struct IdentCollector(Vec<Ident>);
impl Visitor<'_> for IdentCollector {
- fn visit_ident(&mut self, ident: Ident) {
- self.0.push(ident);
+ fn visit_ident(&mut self, ident: &Ident) {
+ self.0.push(*ident);
}
}
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 5f12b6b..4673986 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -334,7 +334,7 @@
| TerminatorKind::TailCall { func, args, fn_span: _ } => {
let fn_ty = func.ty(body, tcx);
if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
- if !is_const_fn(tcx, fn_def_id, msrv) {
+ if !is_stable_const_fn(tcx, fn_def_id, msrv) {
return Err((
span,
format!(
@@ -377,12 +377,12 @@
}
}
-fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
+fn is_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
tcx.is_const_fn(def_id)
- && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
+ && tcx.lookup_const_stability(def_id).is_none_or(|const_stab| {
if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level {
// Checking MSRV is manually necessary because `rustc` has no such concept. This entire
- // function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
+ // function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`.
// as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
let const_stab_rust_version = match since {
@@ -393,8 +393,12 @@
msrv.meets(const_stab_rust_version)
} else {
- // Unstable const fn with the feature enabled.
- msrv.current().is_none()
+ // Unstable const fn, check if the feature is enabled. We need both the regular stability
+ // feature and (if set) the const stability feature to const-call this function.
+ let stab = tcx.lookup_stability(def_id);
+ let is_enabled = stab.is_some_and(|s| s.is_stable() || tcx.features().enabled(s.feature))
+ && const_stab.feature.is_none_or(|f| tcx.features().enabled(f));
+ is_enabled && msrv.current().is_none()
}
})
}
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index 91ec120..3021f21 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -207,16 +207,7 @@
if cx.tcx.res_generics_def_id(path_segment.res).is_some() {
let generics = cx.tcx.generics_of(def_id);
- let own_count = generics.own_params.len()
- - usize::from(generics.host_effect_index.is_some_and(|index| {
- // Check that the host index actually belongs to this resolution.
- // E.g. for `Add::add`, host_effect_index is `Some(2)`, but it's part of the parent `Add`
- // trait's generics.
- // Add params: [Self#0, Rhs#1, host#2] parent_count=0, count=3
- // Add::add params: [] parent_count=3, count=3
- // (3..3).contains(&host_effect_index) => false
- (generics.parent_count..generics.count()).contains(&index)
- }));
+ let own_count = generics.own_params.len();
let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && own_count == 0 {
Certainty::Certain(None)
} else {
@@ -310,8 +301,7 @@
// Check that all type parameters appear in the functions input types.
(0..(generics.parent_count + generics.own_params.len()) as u32).all(|index| {
- Some(index as usize) == generics.host_effect_index
- || fn_sig
+ fn_sig
.inputs()
.iter()
.any(|input_ty| contains_param(*input_ty.skip_binder(), index))
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 0293130..8db6502 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -346,13 +346,13 @@
.cx
.qpath_res(p, hir_id)
.opt_def_id()
- .map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {},
+ .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {},
ExprKind::MethodCall(..)
if self
.cx
.typeck_results()
.type_dependent_def_id(e.hir_id)
- .map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {},
+ .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {},
ExprKind::Binary(_, lhs, rhs)
if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty()
&& self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {},
diff --git a/src/tools/clippy/tests/ui/author.rs b/src/tools/clippy/tests/ui-internal/author.rs
similarity index 72%
rename from src/tools/clippy/tests/ui/author.rs
rename to src/tools/clippy/tests/ui-internal/author.rs
index 0a1be35..eb1f3e3 100644
--- a/src/tools/clippy/tests/ui/author.rs
+++ b/src/tools/clippy/tests/ui-internal/author.rs
@@ -1,3 +1,5 @@
+#![warn(clippy::author)]
+
fn main() {
#[clippy::author]
let x: char = 0x45 as char;
diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui-internal/author.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author.stdout
rename to src/tools/clippy/tests/ui-internal/author.stdout
diff --git a/src/tools/clippy/tests/ui/author/blocks.rs b/src/tools/clippy/tests/ui-internal/author/blocks.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/blocks.rs
rename to src/tools/clippy/tests/ui-internal/author/blocks.rs
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui-internal/author/blocks.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/blocks.stdout
rename to src/tools/clippy/tests/ui-internal/author/blocks.stdout
diff --git a/src/tools/clippy/tests/ui/author/call.rs b/src/tools/clippy/tests/ui-internal/author/call.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/call.rs
rename to src/tools/clippy/tests/ui-internal/author/call.rs
diff --git a/src/tools/clippy/tests/ui/author/call.stdout b/src/tools/clippy/tests/ui-internal/author/call.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/call.stdout
rename to src/tools/clippy/tests/ui-internal/author/call.stdout
diff --git a/src/tools/clippy/tests/ui/author/if.rs b/src/tools/clippy/tests/ui-internal/author/if.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/if.rs
rename to src/tools/clippy/tests/ui-internal/author/if.rs
diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui-internal/author/if.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/if.stdout
rename to src/tools/clippy/tests/ui-internal/author/if.stdout
diff --git a/src/tools/clippy/tests/ui/author/issue_3849.rs b/src/tools/clippy/tests/ui-internal/author/issue_3849.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/issue_3849.rs
rename to src/tools/clippy/tests/ui-internal/author/issue_3849.rs
diff --git a/src/tools/clippy/tests/ui/author/issue_3849.stdout b/src/tools/clippy/tests/ui-internal/author/issue_3849.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/issue_3849.stdout
rename to src/tools/clippy/tests/ui-internal/author/issue_3849.stdout
diff --git a/src/tools/clippy/tests/ui/author/loop.rs b/src/tools/clippy/tests/ui-internal/author/loop.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/loop.rs
rename to src/tools/clippy/tests/ui-internal/author/loop.rs
diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui-internal/author/loop.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/loop.stdout
rename to src/tools/clippy/tests/ui-internal/author/loop.stdout
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.rs b/src/tools/clippy/tests/ui-internal/author/macro_in_closure.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/macro_in_closure.rs
rename to src/tools/clippy/tests/ui-internal/author/macro_in_closure.rs
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui-internal/author/macro_in_closure.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/macro_in_closure.stdout
rename to src/tools/clippy/tests/ui-internal/author/macro_in_closure.stdout
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.rs b/src/tools/clippy/tests/ui-internal/author/macro_in_loop.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/macro_in_loop.rs
rename to src/tools/clippy/tests/ui-internal/author/macro_in_loop.rs
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui-internal/author/macro_in_loop.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/macro_in_loop.stdout
rename to src/tools/clippy/tests/ui-internal/author/macro_in_loop.stdout
diff --git a/src/tools/clippy/tests/ui/author/matches.rs b/src/tools/clippy/tests/ui-internal/author/matches.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/matches.rs
rename to src/tools/clippy/tests/ui-internal/author/matches.rs
diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui-internal/author/matches.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/matches.stdout
rename to src/tools/clippy/tests/ui-internal/author/matches.stdout
diff --git a/src/tools/clippy/tests/ui/author/repeat.rs b/src/tools/clippy/tests/ui-internal/author/repeat.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/repeat.rs
rename to src/tools/clippy/tests/ui-internal/author/repeat.rs
diff --git a/src/tools/clippy/tests/ui/author/repeat.stdout b/src/tools/clippy/tests/ui-internal/author/repeat.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/repeat.stdout
rename to src/tools/clippy/tests/ui-internal/author/repeat.stdout
diff --git a/src/tools/clippy/tests/ui/author/struct.rs b/src/tools/clippy/tests/ui-internal/author/struct.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/author/struct.rs
rename to src/tools/clippy/tests/ui-internal/author/struct.rs
diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui-internal/author/struct.stdout
similarity index 100%
rename from src/tools/clippy/tests/ui/author/struct.stdout
rename to src/tools/clippy/tests/ui-internal/author/struct.stdout
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index 146b04a..0de53a7 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -1,7 +1,6 @@
//@no-rustfix
#![feature(repr128)]
-#![feature(isqrt)]
#![allow(incomplete_features)]
#![warn(
clippy::cast_precision_loss,
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index 7824bdf..452482f 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -1,5 +1,5 @@
error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
- --> tests/ui/cast.rs:26:5
+ --> tests/ui/cast.rs:25:5
|
LL | x0 as f32;
| ^^^^^^^^^
@@ -8,37 +8,37 @@
= help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
- --> tests/ui/cast.rs:30:5
+ --> tests/ui/cast.rs:29:5
|
LL | x1 as f32;
| ^^^^^^^^^
error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
- --> tests/ui/cast.rs:32:5
+ --> tests/ui/cast.rs:31:5
|
LL | x1 as f64;
| ^^^^^^^^^
error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
- --> tests/ui/cast.rs:35:5
+ --> tests/ui/cast.rs:34:5
|
LL | x2 as f32;
| ^^^^^^^^^
error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
- --> tests/ui/cast.rs:38:5
+ --> tests/ui/cast.rs:37:5
|
LL | x3 as f32;
| ^^^^^^^^^
error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
- --> tests/ui/cast.rs:40:5
+ --> tests/ui/cast.rs:39:5
|
LL | x3 as f64;
| ^^^^^^^^^
error: casting `f32` to `i32` may truncate the value
- --> tests/ui/cast.rs:43:5
+ --> tests/ui/cast.rs:42:5
|
LL | 1f32 as i32;
| ^^^^^^^^^^^
@@ -48,7 +48,7 @@
= help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]`
error: casting `f32` to `u32` may truncate the value
- --> tests/ui/cast.rs:45:5
+ --> tests/ui/cast.rs:44:5
|
LL | 1f32 as u32;
| ^^^^^^^^^^^
@@ -56,7 +56,7 @@
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:45:5
+ --> tests/ui/cast.rs:44:5
|
LL | 1f32 as u32;
| ^^^^^^^^^^^
@@ -65,7 +65,7 @@
= help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]`
error: casting `f64` to `f32` may truncate the value
- --> tests/ui/cast.rs:49:5
+ --> tests/ui/cast.rs:48:5
|
LL | 1f64 as f32;
| ^^^^^^^^^^^
@@ -73,7 +73,7 @@
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `i32` to `i8` may truncate the value
- --> tests/ui/cast.rs:51:5
+ --> tests/ui/cast.rs:50:5
|
LL | 1i32 as i8;
| ^^^^^^^^^^
@@ -85,7 +85,7 @@
| ~~~~~~~~~~~~~~~~~~
error: casting `i32` to `u8` may truncate the value
- --> tests/ui/cast.rs:53:5
+ --> tests/ui/cast.rs:52:5
|
LL | 1i32 as u8;
| ^^^^^^^^^^
@@ -97,7 +97,7 @@
| ~~~~~~~~~~~~~~~~~~
error: casting `f64` to `isize` may truncate the value
- --> tests/ui/cast.rs:55:5
+ --> tests/ui/cast.rs:54:5
|
LL | 1f64 as isize;
| ^^^^^^^^^^^^^
@@ -105,7 +105,7 @@
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f64` to `usize` may truncate the value
- --> tests/ui/cast.rs:57:5
+ --> tests/ui/cast.rs:56:5
|
LL | 1f64 as usize;
| ^^^^^^^^^^^^^
@@ -113,13 +113,13 @@
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f64` to `usize` may lose the sign of the value
- --> tests/ui/cast.rs:57:5
+ --> tests/ui/cast.rs:56:5
|
LL | 1f64 as usize;
| ^^^^^^^^^^^^^
error: casting `u32` to `u16` may truncate the value
- --> tests/ui/cast.rs:60:5
+ --> tests/ui/cast.rs:59:5
|
LL | 1f32 as u32 as u16;
| ^^^^^^^^^^^^^^^^^^
@@ -131,7 +131,7 @@
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
error: casting `f32` to `u32` may truncate the value
- --> tests/ui/cast.rs:60:5
+ --> tests/ui/cast.rs:59:5
|
LL | 1f32 as u32 as u16;
| ^^^^^^^^^^^
@@ -139,13 +139,13 @@
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:60:5
+ --> tests/ui/cast.rs:59:5
|
LL | 1f32 as u32 as u16;
| ^^^^^^^^^^^
error: casting `i32` to `i8` may truncate the value
- --> tests/ui/cast.rs:65:22
+ --> tests/ui/cast.rs:64:22
|
LL | let _x: i8 = 1i32 as _;
| ^^^^^^^^^
@@ -157,7 +157,7 @@
| ~~~~~~~~~~~~~~~
error: casting `f32` to `i32` may truncate the value
- --> tests/ui/cast.rs:67:9
+ --> tests/ui/cast.rs:66:9
|
LL | 1f32 as i32;
| ^^^^^^^^^^^
@@ -165,7 +165,7 @@
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f64` to `i32` may truncate the value
- --> tests/ui/cast.rs:69:9
+ --> tests/ui/cast.rs:68:9
|
LL | 1f64 as i32;
| ^^^^^^^^^^^
@@ -173,7 +173,7 @@
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f32` to `u8` may truncate the value
- --> tests/ui/cast.rs:71:9
+ --> tests/ui/cast.rs:70:9
|
LL | 1f32 as u8;
| ^^^^^^^^^^
@@ -181,13 +181,13 @@
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
error: casting `f32` to `u8` may lose the sign of the value
- --> tests/ui/cast.rs:71:9
+ --> tests/ui/cast.rs:70:9
|
LL | 1f32 as u8;
| ^^^^^^^^^^
error: casting `u8` to `i8` may wrap around the value
- --> tests/ui/cast.rs:76:5
+ --> tests/ui/cast.rs:75:5
|
LL | 1u8 as i8;
| ^^^^^^^^^
@@ -196,31 +196,31 @@
= help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
error: casting `u16` to `i16` may wrap around the value
- --> tests/ui/cast.rs:79:5
+ --> tests/ui/cast.rs:78:5
|
LL | 1u16 as i16;
| ^^^^^^^^^^^
error: casting `u32` to `i32` may wrap around the value
- --> tests/ui/cast.rs:81:5
+ --> tests/ui/cast.rs:80:5
|
LL | 1u32 as i32;
| ^^^^^^^^^^^
error: casting `u64` to `i64` may wrap around the value
- --> tests/ui/cast.rs:83:5
+ --> tests/ui/cast.rs:82:5
|
LL | 1u64 as i64;
| ^^^^^^^^^^^
error: casting `usize` to `isize` may wrap around the value
- --> tests/ui/cast.rs:85:5
+ --> tests/ui/cast.rs:84:5
|
LL | 1usize as isize;
| ^^^^^^^^^^^^^^^
error: casting `usize` to `i8` may truncate the value
- --> tests/ui/cast.rs:88:5
+ --> tests/ui/cast.rs:87:5
|
LL | 1usize as i8;
| ^^^^^^^^^^^^
@@ -232,7 +232,7 @@
| ~~~~~~~~~~~~~~~~~~~~
error: casting `usize` to `i16` may truncate the value
- --> tests/ui/cast.rs:91:5
+ --> tests/ui/cast.rs:90:5
|
LL | 1usize as i16;
| ^^^^^^^^^^^^^
@@ -244,7 +244,7 @@
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers
- --> tests/ui/cast.rs:91:5
+ --> tests/ui/cast.rs:90:5
|
LL | 1usize as i16;
| ^^^^^^^^^^^^^
@@ -253,7 +253,7 @@
= note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
- --> tests/ui/cast.rs:96:5
+ --> tests/ui/cast.rs:95:5
|
LL | 1usize as i32;
| ^^^^^^^^^^^^^
@@ -265,19 +265,19 @@
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
- --> tests/ui/cast.rs:96:5
+ --> tests/ui/cast.rs:95:5
|
LL | 1usize as i32;
| ^^^^^^^^^^^^^
error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers
- --> tests/ui/cast.rs:100:5
+ --> tests/ui/cast.rs:99:5
|
LL | 1usize as i64;
| ^^^^^^^^^^^^^
error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers
- --> tests/ui/cast.rs:105:5
+ --> tests/ui/cast.rs:104:5
|
LL | 1u16 as isize;
| ^^^^^^^^^^^^^
@@ -286,13 +286,13 @@
= note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
- --> tests/ui/cast.rs:109:5
+ --> tests/ui/cast.rs:108:5
|
LL | 1u32 as isize;
| ^^^^^^^^^^^^^
error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
- --> tests/ui/cast.rs:112:5
+ --> tests/ui/cast.rs:111:5
|
LL | 1u64 as isize;
| ^^^^^^^^^^^^^
@@ -304,55 +304,55 @@
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
- --> tests/ui/cast.rs:112:5
+ --> tests/ui/cast.rs:111:5
|
LL | 1u64 as isize;
| ^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:117:5
+ --> tests/ui/cast.rs:116:5
|
LL | -1i32 as u32;
| ^^^^^^^^^^^^
error: casting `isize` to `usize` may lose the sign of the value
- --> tests/ui/cast.rs:120:5
+ --> tests/ui/cast.rs:119:5
|
LL | -1isize as usize;
| ^^^^^^^^^^^^^^^^
error: casting `i8` to `u8` may lose the sign of the value
- --> tests/ui/cast.rs:131:5
+ --> tests/ui/cast.rs:130:5
|
LL | (i8::MIN).abs() as u8;
| ^^^^^^^^^^^^^^^^^^^^^
error: casting `i64` to `u64` may lose the sign of the value
- --> tests/ui/cast.rs:135:5
+ --> tests/ui/cast.rs:134:5
|
LL | (-1i64).abs() as u64;
| ^^^^^^^^^^^^^^^^^^^^
error: casting `isize` to `usize` may lose the sign of the value
- --> tests/ui/cast.rs:136:5
+ --> tests/ui/cast.rs:135:5
|
LL | (-1isize).abs() as usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i64` to `u64` may lose the sign of the value
- --> tests/ui/cast.rs:143:5
+ --> tests/ui/cast.rs:142:5
|
LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i64` to `u64` may lose the sign of the value
- --> tests/ui/cast.rs:158:5
+ --> tests/ui/cast.rs:157:5
|
LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i64` to `i8` may truncate the value
- --> tests/ui/cast.rs:209:5
+ --> tests/ui/cast.rs:208:5
|
LL | (-99999999999i64).min(1) as i8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -364,7 +364,7 @@
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: casting `u64` to `u8` may truncate the value
- --> tests/ui/cast.rs:223:5
+ --> tests/ui/cast.rs:222:5
|
LL | 999999u64.clamp(0, 256) as u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -376,7 +376,7 @@
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: casting `main::E2` to `u8` may truncate the value
- --> tests/ui/cast.rs:246:21
+ --> tests/ui/cast.rs:245:21
|
LL | let _ = self as u8;
| ^^^^^^^^^^
@@ -388,7 +388,7 @@
| ~~~~~~~~~~~~~~~~~~
error: casting `main::E2::B` to `u8` will truncate the value
- --> tests/ui/cast.rs:248:21
+ --> tests/ui/cast.rs:247:21
|
LL | let _ = Self::B as u8;
| ^^^^^^^^^^^^^
@@ -397,7 +397,7 @@
= help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]`
error: casting `main::E5` to `i8` may truncate the value
- --> tests/ui/cast.rs:290:21
+ --> tests/ui/cast.rs:289:21
|
LL | let _ = self as i8;
| ^^^^^^^^^^
@@ -409,13 +409,13 @@
| ~~~~~~~~~~~~~~~~~~
error: casting `main::E5::A` to `i8` will truncate the value
- --> tests/ui/cast.rs:292:21
+ --> tests/ui/cast.rs:291:21
|
LL | let _ = Self::A as i8;
| ^^^^^^^^^^^^^
error: casting `main::E6` to `i16` may truncate the value
- --> tests/ui/cast.rs:309:21
+ --> tests/ui/cast.rs:308:21
|
LL | let _ = self as i16;
| ^^^^^^^^^^^
@@ -427,7 +427,7 @@
| ~~~~~~~~~~~~~~~~~~~
error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
- --> tests/ui/cast.rs:328:21
+ --> tests/ui/cast.rs:327:21
|
LL | let _ = self as usize;
| ^^^^^^^^^^^^^
@@ -439,7 +439,7 @@
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `main::E10` to `u16` may truncate the value
- --> tests/ui/cast.rs:375:21
+ --> tests/ui/cast.rs:374:21
|
LL | let _ = self as u16;
| ^^^^^^^^^^^
@@ -451,7 +451,7 @@
| ~~~~~~~~~~~~~~~~~~~
error: casting `u32` to `u8` may truncate the value
- --> tests/ui/cast.rs:386:13
+ --> tests/ui/cast.rs:385:13
|
LL | let c = (q >> 16) as u8;
| ^^^^^^^^^^^^^^^
@@ -463,7 +463,7 @@
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `u32` to `u8` may truncate the value
- --> tests/ui/cast.rs:390:13
+ --> tests/ui/cast.rs:389:13
|
LL | let c = (q / 1000) as u8;
| ^^^^^^^^^^^^^^^^
@@ -475,85 +475,85 @@
| ~~~~~~~~~~~~~~~~~~~~~~
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:402:9
+ --> tests/ui/cast.rs:401:9
|
LL | (x * x) as u32;
| ^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:407:32
+ --> tests/ui/cast.rs:406:32
|
LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:409:5
+ --> tests/ui/cast.rs:408:5
|
LL | (2_i32).checked_pow(3).unwrap() as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:410:5
+ --> tests/ui/cast.rs:409:5
|
LL | (-2_i32).pow(3) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:415:5
+ --> tests/ui/cast.rs:414:5
|
LL | (-5_i32 % 2) as u32;
| ^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:417:5
+ --> tests/ui/cast.rs:416:5
|
LL | (-5_i32 % -2) as u32;
| ^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:420:5
+ --> tests/ui/cast.rs:419:5
|
LL | (-2_i32 >> 1) as u32;
| ^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:424:5
+ --> tests/ui/cast.rs:423:5
|
LL | (x * x) as u32;
| ^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:425:5
+ --> tests/ui/cast.rs:424:5
|
LL | (x * x * x) as u32;
| ^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
- --> tests/ui/cast.rs:429:5
+ --> tests/ui/cast.rs:428:5
|
LL | (y * y * y * y * -2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
- --> tests/ui/cast.rs:431:5
+ --> tests/ui/cast.rs:430:5
|
LL | (y * y * y / y * 2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
- --> tests/ui/cast.rs:432:5
+ --> tests/ui/cast.rs:431:5
|
LL | (y * y / y * 2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
- --> tests/ui/cast.rs:434:5
+ --> tests/ui/cast.rs:433:5
|
LL | (y / y * y * -2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: equal expressions as operands to `/`
- --> tests/ui/cast.rs:434:6
+ --> tests/ui/cast.rs:433:6
|
LL | (y / y * y * -2) as u16;
| ^^^^^
@@ -561,97 +561,97 @@
= note: `#[deny(clippy::eq_op)]` on by default
error: casting `i16` to `u16` may lose the sign of the value
- --> tests/ui/cast.rs:437:5
+ --> tests/ui/cast.rs:436:5
|
LL | (y + y + y + -2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
- --> tests/ui/cast.rs:439:5
+ --> tests/ui/cast.rs:438:5
|
LL | (y + y + y + 2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
- --> tests/ui/cast.rs:443:5
+ --> tests/ui/cast.rs:442:5
|
LL | (z + -2) as u16;
| ^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
- --> tests/ui/cast.rs:445:5
+ --> tests/ui/cast.rs:444:5
|
LL | (z + z + 2) as u16;
| ^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:448:9
+ --> tests/ui/cast.rs:447:9
|
LL | (a * a * b * b * c * c) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:449:9
+ --> tests/ui/cast.rs:448:9
|
LL | (a * b * c) as u32;
| ^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:451:9
+ --> tests/ui/cast.rs:450:9
|
LL | (a * -b * c) as u32;
| ^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:453:9
+ --> tests/ui/cast.rs:452:9
|
LL | (a * b * c * c) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:454:9
+ --> tests/ui/cast.rs:453:9
|
LL | (a * -2) as u32;
| ^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:456:9
+ --> tests/ui/cast.rs:455:9
|
LL | (a * b * c * -2) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:458:9
+ --> tests/ui/cast.rs:457:9
|
LL | (a / b) as u32;
| ^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:459:9
+ --> tests/ui/cast.rs:458:9
|
LL | (a / b * c) as u32;
| ^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:461:9
+ --> tests/ui/cast.rs:460:9
|
LL | (a / b + b * c) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:463:9
+ --> tests/ui/cast.rs:462:9
|
LL | a.saturating_pow(3) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:465:9
+ --> tests/ui/cast.rs:464:9
|
LL | (a.abs() * b.pow(2) / c.abs()) as u32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> tests/ui/cast.rs:473:21
+ --> tests/ui/cast.rs:472:21
|
LL | let _ = i32::MIN as u32; // cast_sign_loss
| ^^^^^^^^^^^^^^^
@@ -662,7 +662,7 @@
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
error: casting `u32` to `u8` may truncate the value
- --> tests/ui/cast.rs:474:21
+ --> tests/ui/cast.rs:473:21
|
LL | let _ = u32::MAX as u8; // cast_possible_truncation
| ^^^^^^^^^^^^^^
@@ -678,7 +678,7 @@
| ~~~~~~~~~~~~~~~~~~~~~~
error: casting `f64` to `f32` may truncate the value
- --> tests/ui/cast.rs:475:21
+ --> tests/ui/cast.rs:474:21
|
LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -690,7 +690,7 @@
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
- --> tests/ui/cast.rs:484:5
+ --> tests/ui/cast.rs:483:5
|
LL | bar.unwrap().unwrap() as usize
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -702,13 +702,13 @@
|
error: casting `i64` to `usize` may lose the sign of the value
- --> tests/ui/cast.rs:484:5
+ --> tests/ui/cast.rs:483:5
|
LL | bar.unwrap().unwrap() as usize
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `u64` to `u8` may truncate the value
- --> tests/ui/cast.rs:499:5
+ --> tests/ui/cast.rs:498:5
|
LL | (256 & 999999u64) as u8;
| ^^^^^^^^^^^^^^^^^^^^^^^
@@ -720,7 +720,7 @@
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: casting `u64` to `u8` may truncate the value
- --> tests/ui/cast.rs:501:5
+ --> tests/ui/cast.rs:500:5
|
LL | (255 % 999999u64) as u8;
| ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/no_lints.rs b/src/tools/clippy/tests/ui/no_lints.rs
new file mode 100644
index 0000000..a8467bb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/no_lints.rs
@@ -0,0 +1,3 @@
+#![deny(clippy::all)]
+
+fn main() {}
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index b810fd8..0d6e07a 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -54,7 +54,7 @@
#![allow(enum_intrinsics_non_enums)]
#![allow(non_fmt_panics)]
#![allow(named_arguments_used_positionally)]
-#![allow(temporary_cstring_as_ptr)]
+#![allow(dangling_pointers_from_temporaries)]
#![allow(undropped_manually_drops)]
#![allow(unknown_lints)]
#![allow(unused_labels)]
@@ -120,7 +120,7 @@
#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
-#![warn(temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
+#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
#![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
#![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
#![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 46d9f0f..b906079 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,11 +1,17 @@
+error: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+ --> tests/ui/rename.rs:57:10
+ |
+LL | #![allow(temporary_cstring_as_ptr)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
+ |
+ = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
+
error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
--> tests/ui/rename.rs:63:9
|
LL | #![warn(clippy::almost_complete_letter_range)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
- |
- = note: `-D renamed-and-removed-lints` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
--> tests/ui/rename.rs:64:9
@@ -361,11 +367,11 @@
LL | #![warn(clippy::positional_named_format_parameters)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
-error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
+error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
--> tests/ui/rename.rs:123:9
|
LL | #![warn(clippy::temporary_cstring_as_ptr)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
--> tests/ui/rename.rs:124:9
@@ -397,5 +403,5 @@
LL | #![warn(clippy::reverse_range_loop)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
-error: aborting due to 66 previous errors
+error: aborting due to 67 previous errors
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index ff05994..69ac464 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -376,6 +376,7 @@
pub only_modified: bool,
pub target_cfgs: OnceLock<TargetCfgs>,
+ pub builtin_cfg_names: OnceLock<HashSet<String>>,
pub nocapture: bool,
@@ -387,6 +388,9 @@
/// True if the profiler runtime is enabled for this target.
/// Used by the "needs-profiler-runtime" directive in test files.
pub profiler_runtime: bool,
+
+ /// Command for visual diff display, e.g. `diff-tool --color=always`.
+ pub diff_command: Option<String>,
}
impl Config {
@@ -440,6 +444,11 @@
self.target_cfg().panic == PanicStrategy::Unwind
}
+ /// Get the list of builtin, 'well known' cfg names
+ pub fn builtin_cfg_names(&self) -> &HashSet<String> {
+ self.builtin_cfg_names.get_or_init(|| builtin_cfg_names(self))
+ }
+
pub fn has_threads(&self) -> bool {
// Wasm targets don't have threads unless `-threads` is in the target
// name, such as `wasm32-wasip1-threads`.
@@ -651,6 +660,18 @@
Big,
}
+fn builtin_cfg_names(config: &Config) -> HashSet<String> {
+ rustc_output(
+ config,
+ &["--print=check-cfg", "-Zunstable-options", "--check-cfg=cfg()"],
+ Default::default(),
+ )
+ .lines()
+ .map(|l| if let Some((name, _)) = l.split_once('=') { name.to_string() } else { l.to_string() })
+ .chain(std::iter::once(String::from("test")))
+ .collect()
+}
+
fn rustc_output(config: &Config, args: &[&str], envs: HashMap<String, String>) -> String {
let mut command = Command::new(&config.rustc_path);
add_dylib_path(&mut command, iter::once(&config.compile_lib_path));
diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/directive-list.rs
similarity index 100%
rename from src/tools/compiletest/src/command-list.rs
rename to src/tools/compiletest/src/directive-list.rs
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index d75cdef..a3bf36c 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -709,11 +709,11 @@
Some(DirectiveLine { line_number, revision, raw_directive })
}
-// To prevent duplicating the list of commmands between `compiletest`,`htmldocck` and `jsondocck`,
+// To prevent duplicating the list of directives between `compiletest`,`htmldocck` and `jsondocck`,
// we put it into a common file which is included in rust code and parsed here.
// FIXME: This setup is temporary until we figure out how to improve this situation.
// See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
-include!("command-list.rs");
+include!("directive-list.rs");
const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[
"count",
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 7d6ede9..490df31 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -175,6 +175,12 @@
"git-merge-commit-email",
"email address used for finding merge commits",
"EMAIL",
+ )
+ .optopt(
+ "",
+ "compiletest-diff-tool",
+ "What custom diff tool to use for displaying compiletest tests.",
+ "COMMAND",
);
let (argv0, args_) = args.split_first().unwrap();
@@ -356,6 +362,7 @@
force_rerun: matches.opt_present("force-rerun"),
target_cfgs: OnceLock::new(),
+ builtin_cfg_names: OnceLock::new(),
nocapture: matches.opt_present("nocapture"),
@@ -364,6 +371,7 @@
git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),
profiler_runtime: matches.opt_present("profiler-runtime"),
+ diff_command: matches.opt_str("compiletest-diff-tool"),
}
}
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 36c5106..a8a71c1 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -59,7 +59,7 @@
use std::sync::Mutex;
use windows::Win32::System::Diagnostics::Debug::{
- SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE,
+ SEM_FAILCRITICALERRORS, SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE,
};
static LOCK: Mutex<()> = Mutex::new(());
@@ -67,13 +67,21 @@
// Error mode is a global variable, so lock it so only one thread will change it
let _lock = LOCK.lock().unwrap();
- // Tell Windows to not show any UI on errors (such as terminating abnormally).
- // This is important for running tests, since some of them use abnormal
- // termination by design. This mode is inherited by all child processes.
+ // Tell Windows to not show any UI on errors (such as terminating abnormally). This is important
+ // for running tests, since some of them use abnormal termination by design. This mode is
+ // inherited by all child processes.
+ //
+ // Note that `run-make` tests require `SEM_FAILCRITICALERRORS` in addition to suppress Windows
+ // Error Reporting (WER) error dialogues that come from "critical failures" such as missing
+ // DLLs.
+ //
+ // See <https://github.com/rust-lang/rust/issues/132092> and
+ // <https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-seterrormode?redirectedfrom=MSDN>.
unsafe {
- let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags
+ // read inherited flags
+ let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS);
let old_mode = THREAD_ERROR_MODE(old_mode);
- SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX);
+ SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS);
let r = f();
SetErrorMode(old_mode);
r
@@ -478,6 +486,9 @@
"error: redundant cfg argument `{normalized_revision}` is already created by the revision"
);
}
+ if self.config.builtin_cfg_names().contains(&normalized_revision) {
+ panic!("error: revision `{normalized_revision}` collides with a builtin cfg");
+ }
cmd.args(cfg_arg);
}
@@ -1085,6 +1096,10 @@
self.config.target.contains("vxworks") && !self.is_vxworks_pure_static()
}
+ fn has_aux_dir(&self) -> bool {
+ !self.props.aux.builds.is_empty() || !self.props.aux.crates.is_empty()
+ }
+
fn aux_output_dir(&self) -> PathBuf {
let aux_dir = self.aux_output_dir_name();
@@ -1638,7 +1653,11 @@
}
if let LinkToAux::Yes = link_to_aux {
- rustc.arg("-L").arg(self.aux_output_dir_name());
+ // if we pass an `-L` argument to a directory that doesn't exist,
+ // macOS ld emits warnings which disrupt the .stderr files
+ if self.has_aux_dir() {
+ rustc.arg("-L").arg(self.aux_output_dir_name());
+ }
}
rustc.args(&self.props.compile_flags);
@@ -2459,7 +2478,7 @@
}
}
- fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize {
+ fn compare_output(&self, stream: &str, actual: &str, expected: &str) -> usize {
let are_different = match (self.force_color_svg(), expected.find('\n'), actual.find('\n')) {
// FIXME: We ignore the first line of SVG files
// because the width parameter is non-deterministic.
@@ -2499,56 +2518,66 @@
(expected, actual)
};
- if !self.config.bless {
- if expected.is_empty() {
- println!("normalized {}:\n{}\n", kind, actual);
- } else {
- println!("diff of {}:\n", kind);
- print!("{}", write_diff(expected, actual, 3));
- }
- }
-
- let mode = self.config.compare_mode.as_ref().map_or("", |m| m.to_str());
- let output_file = self
+ // Write the actual output to a file in build/
+ let test_name = self.config.compare_mode.as_ref().map_or("", |m| m.to_str());
+ let actual_path = self
.output_base_name()
.with_extra_extension(self.revision.unwrap_or(""))
- .with_extra_extension(mode)
- .with_extra_extension(kind);
+ .with_extra_extension(test_name)
+ .with_extra_extension(stream);
- let mut files = vec![output_file];
- if self.config.bless {
+ if let Err(err) = fs::write(&actual_path, &actual) {
+ self.fatal(&format!("failed to write {stream} to `{actual_path:?}`: {err}",));
+ }
+ println!("Saved the actual {stream} to {actual_path:?}");
+
+ let expected_path =
+ expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream);
+
+ if !self.config.bless {
+ if expected.is_empty() {
+ println!("normalized {}:\n{}\n", stream, actual);
+ } else {
+ println!("diff of {stream}:\n");
+ if let Some(diff_command) = self.config.diff_command.as_deref() {
+ let mut args = diff_command.split_whitespace();
+ let name = args.next().unwrap();
+ match Command::new(name)
+ .args(args)
+ .args([&expected_path, &actual_path])
+ .output()
+ {
+ Err(err) => {
+ self.fatal(&format!(
+ "failed to call custom diff command `{diff_command}`: {err}"
+ ));
+ }
+ Ok(output) => {
+ let output = String::from_utf8_lossy(&output.stdout);
+ print!("{output}");
+ }
+ }
+ } else {
+ print!("{}", write_diff(expected, actual, 3));
+ }
+ }
+ } else {
// Delete non-revision .stderr/.stdout file if revisions are used.
// Without this, we'd just generate the new files and leave the old files around.
if self.revision.is_some() {
let old =
- expected_output_path(self.testpaths, None, &self.config.compare_mode, kind);
+ expected_output_path(self.testpaths, None, &self.config.compare_mode, stream);
self.delete_file(&old);
}
- files.push(expected_output_path(
- self.testpaths,
- self.revision,
- &self.config.compare_mode,
- kind,
- ));
- }
- for output_file in &files {
- if actual.is_empty() {
- self.delete_file(output_file);
- } else if let Err(err) = fs::write(&output_file, &actual) {
- self.fatal(&format!(
- "failed to write {} to `{}`: {}",
- kind,
- output_file.display(),
- err,
- ));
+ if let Err(err) = fs::write(&expected_path, &actual) {
+ self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}"));
}
+ println!("Blessing the {stream} of {test_name} in {expected_path:?}");
}
- println!("\nThe actual {0} differed from the expected {0}.", kind);
- for output_file in files {
- println!("Actual {} saved to {}", kind, output_file.display());
- }
+ println!("\nThe actual {0} differed from the expected {0}.", stream);
+
if self.config.bless { 0 } else { 1 }
}
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
index f8ffd0f..04bc2d7 100644
--- a/src/tools/compiletest/src/runtest/run_make.rs
+++ b/src/tools/compiletest/src/runtest/run_make.rs
@@ -2,7 +2,7 @@
use std::process::{Command, Output, Stdio};
use std::{env, fs};
-use super::{ProcRes, TestCx};
+use super::{ProcRes, TestCx, disable_error_reporting};
use crate::util::{copy_dir_all, dylib_env_var};
impl TestCx<'_> {
@@ -329,6 +329,7 @@
.arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
.arg("--edition=2021")
.arg(&self.testpaths.file.join("rmake.rs"))
+ .arg("-Cprefer-dynamic")
// Provide necessary library search paths for rustc.
.env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap());
@@ -514,8 +515,8 @@
}
}
- let (Output { stdout, stderr, status }, truncated) =
- self.read2_abbreviated(cmd.spawn().expect("failed to spawn `rmake`"));
+ let proc = disable_error_reporting(|| cmd.spawn().expect("failed to spawn `rmake`"));
+ let (Output { stdout, stderr, status }, truncated) = self.read2_abbreviated(proc);
if !status.success() {
let res = ProcRes {
status,
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index b264405..c08bbbc 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -123,7 +123,7 @@
// FIXME: This setup is temporary until we figure out how to improve this situation.
// See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
-include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/command-list.rs"));
+include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/directive-list.rs"));
/// Get a list of commands from a file. Does the work of ensuring the commands
/// are syntactically valid.
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 8b0916f..2e49131 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -1,11 +1,7 @@
name: CI
on:
- push:
- # Run in PRs and for bors, but not on master.
- branches:
- - 'auto'
- - 'try'
+ merge_group:
pull_request:
branches:
- 'master'
@@ -38,7 +34,7 @@
# The `style` job only runs on Linux; this makes sure the Windows-host-specific
# code is also covered by clippy.
- name: Check clippy
- if: matrix.os == 'windows-latest'
+ if: ${{ matrix.os == 'windows-latest' }}
run: ./miri clippy -- -D warnings
- name: Test Miri
@@ -62,27 +58,25 @@
- name: rustdoc
run: RUSTDOCFLAGS="-Dwarnings" ./miri doc --document-private-items
- # These jobs doesn't actually test anything, but they're only used to tell
- # bors the build completed, as there is no practical way to detect when a
- # workflow is successful listening to webhooks only.
- #
+ # Summary job for the merge queue.
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
- end-success:
- name: bors build finished
- runs-on: ubuntu-latest
+ # And they should be added below in `cron-fail-notify` as well.
+ conclusion:
needs: [build, style]
- if: github.event.pusher.name == 'bors' && success()
- steps:
- - name: mark the job as a success
- run: exit 0
- end-failure:
- name: bors build finished
+ # We need to ensure this job does *not* get skipped if its dependencies fail,
+ # because a skipped job is considered a success by GitHub. So we have to
+ # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
+ # when the workflow is canceled manually.
+ if: ${{ !cancelled() }}
runs-on: ubuntu-latest
- needs: [build, style]
- if: github.event.pusher.name == 'bors' && (failure() || cancelled())
steps:
- - name: mark the job as a failure
- run: exit 1
+ # Manually check the status of all dependencies. `if: failure()` does not work.
+ - name: Conclusion
+ run: |
+ # Print the dependent jobs to see them in the CI log
+ jq -C <<< '${{ toJson(needs) }}'
+ # Check if all jobs that we depend on (in the needs array) were successful.
+ jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
cron-fail-notify:
name: cronjob failure notification
@@ -93,7 +87,7 @@
# ... and create a PR.
pull-requests: write
needs: [build, style]
- if: github.event_name == 'schedule' && failure()
+ if: ${{ github.event_name == 'schedule' && failure() }}
steps:
# Send a Zulip notification
- name: Install zulip-send
@@ -145,7 +139,7 @@
git push -u origin $BRANCH
- name: Create Pull Request
run: |
- PR=$(gh pr create -B master --title 'Automatic Rustup' --body '')
+ PR=$(gh pr create -B master --title 'Automatic Rustup' --body 'Please close and re-open this PR to trigger CI, then enable auto-merge.')
~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
--stream miri --subject "Miri Build Failure ($(date -u +%Y-%m))" \
--message "A PR doing a rustc-pull [has been automatically created]($PR) for your convenience."
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index ad1b2f4..4e7cbc5 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -154,7 +154,7 @@
TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe
TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe
- TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap pthread --skip threadname
+ TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap threadname pthread
TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm
TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std
TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 8b9e7ef..133edd3 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-17a19e684cdf3ca088af8b4da6a6209d128913f4
+814df6e50eaf89b90793e7d9618bb60f1f18377a
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
index 1684abe..5624c4c 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
@@ -424,7 +424,11 @@
}
#[inline(never)] // This is only called on fatal code paths
- pub(super) fn protector_error(&self, item: &Item, kind: ProtectorKind) -> InterpErrorKind<'tcx> {
+ pub(super) fn protector_error(
+ &self,
+ item: &Item,
+ kind: ProtectorKind,
+ ) -> InterpErrorKind<'tcx> {
let protected = match kind {
ProtectorKind::WeakProtector => "weakly protected",
ProtectorKind::StrongProtector => "strongly protected",
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 09ec2cb..776d256 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -145,6 +145,21 @@
this.write_scalar(Scalar::from_bool(branch), dest)?;
}
+ "floorf16" | "ceilf16" | "truncf16" | "roundf16" | "rintf16" => {
+ let [f] = check_arg_count(args)?;
+ let f = this.read_scalar(f)?.to_f16()?;
+ let mode = match intrinsic_name {
+ "floorf16" => Round::TowardNegative,
+ "ceilf16" => Round::TowardPositive,
+ "truncf16" => Round::TowardZero,
+ "roundf16" => Round::NearestTiesToAway,
+ "rintf16" => Round::NearestTiesToEven,
+ _ => bug!(),
+ };
+ let res = f.round_to_integral(mode).value;
+ let res = this.adjust_nan(res, &[f]);
+ this.write_scalar(res, dest)?;
+ }
"floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => {
let [f] = check_arg_count(args)?;
let f = this.read_scalar(f)?.to_f32()?;
@@ -175,6 +190,21 @@
let res = this.adjust_nan(res, &[f]);
this.write_scalar(res, dest)?;
}
+ "floorf128" | "ceilf128" | "truncf128" | "roundf128" | "rintf128" => {
+ let [f] = check_arg_count(args)?;
+ let f = this.read_scalar(f)?.to_f128()?;
+ let mode = match intrinsic_name {
+ "floorf128" => Round::TowardNegative,
+ "ceilf128" => Round::TowardPositive,
+ "truncf128" => Round::TowardZero,
+ "roundf128" => Round::NearestTiesToAway,
+ "rintf128" => Round::NearestTiesToEven,
+ _ => bug!(),
+ };
+ let res = f.round_to_integral(mode).value;
+ let res = this.adjust_nan(res, &[f]);
+ this.write_scalar(res, dest)?;
+ }
#[rustfmt::skip]
| "sinf32"
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index 0799b93..f15b83a 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -1,7 +1,8 @@
use either::Either;
use rustc_apfloat::{Float, Round};
+use rustc_middle::ty::FloatTy;
use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::{mir, ty, ty::FloatTy};
+use rustc_middle::{mir, ty};
use rustc_span::{Symbol, sym};
use rustc_target::abi::{Endian, HasDataLayout};
@@ -630,12 +631,8 @@
let (right, right_len) = this.project_to_simd(right)?;
let (dest, dest_len) = this.project_to_simd(dest)?;
- let index = generic_args[2]
- .expect_const()
- .try_to_valtree()
- .unwrap()
- .0
- .unwrap_branch();
+ let index =
+ generic_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch();
let index_len = index.len();
assert_eq!(left_len, right_len);
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 660f2e4..938d1ca 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -147,7 +147,7 @@
pub use crate::shims::EmulateItemResult;
pub use crate::shims::env::{EnvVars, EvalContextExt as _};
pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _};
-pub use crate::shims::io_error::{EvalContextExt as _, LibcError};
+pub use crate::shims::io_error::{EvalContextExt as _, IoError, LibcError};
pub use crate::shims::os_str::EvalContextExt as _;
pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};
pub use crate::shims::time::EvalContextExt as _;
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index f6f91e5..12f8fac 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -447,8 +447,7 @@
} else {
// If this does not fit in an isize, return null and, on Unix, set errno.
if this.target_os_is_unix() {
- let einval = this.eval_libc("ENOMEM");
- this.set_last_error(einval)?;
+ this.set_last_error(LibcError("ENOMEM"))?;
}
this.write_null(dest)?;
}
@@ -464,8 +463,7 @@
} else {
// On size overflow, return null and, on Unix, set errno.
if this.target_os_is_unix() {
- let einval = this.eval_libc("ENOMEM");
- this.set_last_error(einval)?;
+ this.set_last_error(LibcError("ENOMEM"))?;
}
this.write_null(dest)?;
}
@@ -486,8 +484,7 @@
} else {
// If this does not fit in an isize, return null and, on Unix, set errno.
if this.target_os_is_unix() {
- let einval = this.eval_libc("ENOMEM");
- this.set_last_error(einval)?;
+ this.set_last_error(LibcError("ENOMEM"))?;
}
this.write_null(dest)?;
}
diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs
index 38aa181..04491f0 100644
--- a/src/tools/miri/src/shims/io_error.rs
+++ b/src/tools/miri/src/shims/io_error.rs
@@ -141,6 +141,16 @@
interp_ok(Scalar::from_i32(-1))
}
+ /// Sets the last OS error and return `-1` as a `i64`-typed Scalar
+ fn set_last_error_and_return_i64(
+ &mut self,
+ err: impl Into<IoError>,
+ ) -> InterpResult<'tcx, Scalar> {
+ let this = self.eval_context_mut();
+ this.set_last_error(err)?;
+ interp_ok(Scalar::from_i64(-1))
+ }
+
/// Gets the last error variable.
fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index 12c7679..6436823 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -81,9 +81,7 @@
} else if relative_clocks.contains(&clk_id) {
this.machine.clock.now().duration_since(this.machine.clock.epoch())
} else {
- let einval = this.eval_libc("EINVAL");
- this.set_last_error(einval)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EINVAL"));
};
let tv_sec = duration.as_secs();
@@ -109,9 +107,7 @@
// Using tz is obsolete and should always be null
let tz = this.read_pointer(tz_op)?;
if !this.ptr_is_null(tz)? {
- let einval = this.eval_libc("EINVAL");
- this.set_last_error(einval)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EINVAL"));
}
let duration = system_time_to_duration(&SystemTime::now())?;
@@ -323,9 +319,7 @@
let duration = match this.read_timespec(&req)? {
Some(duration) => duration,
None => {
- let einval = this.eval_libc("EINVAL");
- this.set_last_error(einval)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EINVAL"));
}
};
diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs
index 583a1f6..b6f0495 100644
--- a/src/tools/miri/src/shims/unix/android/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs
@@ -1,6 +1,7 @@
use rustc_span::Symbol;
use rustc_target::spec::abi::Abi;
+use crate::shims::unix::android::thread::prctl;
use crate::*;
pub fn is_dyn_sym(_name: &str) -> bool {
@@ -25,6 +26,9 @@
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
+ // Threading
+ "prctl" => prctl(this, link_name, abi, args, dest)?,
+
_ => return interp_ok(EmulateItemResult::NotSupported),
}
interp_ok(EmulateItemResult::NeedsReturn)
diff --git a/src/tools/miri/src/shims/unix/android/mod.rs b/src/tools/miri/src/shims/unix/android/mod.rs
index 09c6507..1f2a74b 100644
--- a/src/tools/miri/src/shims/unix/android/mod.rs
+++ b/src/tools/miri/src/shims/unix/android/mod.rs
@@ -1 +1,2 @@
pub mod foreign_items;
+pub mod thread;
diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs
new file mode 100644
index 0000000..6f5f0f7
--- /dev/null
+++ b/src/tools/miri/src/shims/unix/android/thread.rs
@@ -0,0 +1,57 @@
+use rustc_span::Symbol;
+use rustc_target::abi::Size;
+use rustc_target::spec::abi::Abi;
+
+use crate::helpers::check_min_arg_count;
+use crate::shims::unix::thread::EvalContextExt as _;
+use crate::*;
+
+const TASK_COMM_LEN: usize = 16;
+
+pub fn prctl<'tcx>(
+ this: &mut MiriInterpCx<'tcx>,
+ link_name: Symbol,
+ abi: Abi,
+ args: &[OpTy<'tcx>],
+ dest: &MPlaceTy<'tcx>,
+) -> InterpResult<'tcx> {
+ // We do not use `check_shim` here because `prctl` is variadic. The argument
+ // count is checked bellow.
+ this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
+
+ // FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch.
+ let pr_set_name = 15;
+ let pr_get_name = 16;
+
+ let [op] = check_min_arg_count("prctl", args)?;
+ let res = match this.read_scalar(op)?.to_i32()? {
+ op if op == pr_set_name => {
+ let [_, name] = check_min_arg_count("prctl(PR_SET_NAME, ...)", args)?;
+ let name = this.read_scalar(name)?;
+ let thread = this.pthread_self()?;
+ // The Linux kernel silently truncates long names.
+ // https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html
+ let res =
+ this.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?;
+ assert!(res);
+ Scalar::from_u32(0)
+ }
+ op if op == pr_get_name => {
+ let [_, name] = check_min_arg_count("prctl(PR_GET_NAME, ...)", args)?;
+ let name = this.read_scalar(name)?;
+ let thread = this.pthread_self()?;
+ let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, this);
+ this.check_ptr_access(
+ name.to_pointer(this)?,
+ Size::from_bytes(TASK_COMM_LEN),
+ CheckInAllocMsg::MemoryAccessTest,
+ )?;
+ let res = this.pthread_getname_np(thread, name, len, /* truncate*/ false)?;
+ assert!(res);
+ Scalar::from_u32(0)
+ }
+ op => throw_unsup_format!("Miri does not support `prctl` syscall with op={}", op),
+ };
+ this.write_scalar(res, dest)?;
+ interp_ok(())
+}
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index e391464..f3db566 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -423,7 +423,7 @@
let this = self.eval_context_mut();
let Some(fd) = this.machine.fds.get(old_fd_num) else {
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
};
interp_ok(Scalar::from_i32(this.machine.fds.insert(fd)))
}
@@ -432,7 +432,7 @@
let this = self.eval_context_mut();
let Some(fd) = this.machine.fds.get(old_fd_num) else {
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
};
if new_fd_num != old_fd_num {
// Close new_fd if it is previously opened.
@@ -448,7 +448,7 @@
fn flock(&mut self, fd_num: i32, op: i32) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let Some(fd) = this.machine.fds.get(fd_num) else {
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
};
// We need to check that there aren't unsupported options in `op`.
@@ -498,11 +498,11 @@
// `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
// always sets this flag when opening a file. However we still need to check that the
// file itself is open.
- interp_ok(Scalar::from_i32(if this.machine.fds.is_fd_num(fd_num) {
- this.eval_libc_i32("FD_CLOEXEC")
+ if !this.machine.fds.is_fd_num(fd_num) {
+ this.set_last_error_and_return_i32(LibcError("EBADF"))
} else {
- this.fd_not_found()?
- }))
+ interp_ok(this.eval_libc("FD_CLOEXEC"))
+ }
}
cmd if cmd == f_dupfd || cmd == f_dupfd_cloexec => {
// Note that we always assume the FD_CLOEXEC flag is set for every open file, in part
@@ -521,7 +521,7 @@
if let Some(fd) = this.machine.fds.get(fd_num) {
interp_ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start)))
} else {
- interp_ok(Scalar::from_i32(this.fd_not_found()?))
+ this.set_last_error_and_return_i32(LibcError("EBADF"))
}
}
cmd if this.tcx.sess.target.os == "macos"
@@ -547,7 +547,7 @@
let fd_num = this.read_scalar(fd_op)?.to_i32()?;
let Some(fd) = this.machine.fds.remove(fd_num) else {
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
};
let result = fd.close(this.machine.communicate(), this)?;
// return `0` if close is successful
@@ -555,17 +555,6 @@
interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
}
- /// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets
- /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses
- /// `T: From<i32>` instead of `i32` directly because some fs functions return different integer
- /// types (like `read`, that returns an `i64`).
- fn fd_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> {
- let this = self.eval_context_mut();
- let ebadf = this.eval_libc("EBADF");
- this.set_last_error(ebadf)?;
- interp_ok((-1).into())
- }
-
/// Read data from `fd` into buffer specified by `buf` and `count`.
///
/// If `offset` is `None`, reads data from current cursor position associated with `fd`
@@ -599,9 +588,7 @@
// We temporarily dup the FD to be able to retain mutable access to `this`.
let Some(fd) = this.machine.fds.get(fd_num) else {
trace!("read: FD not found");
- let res: i32 = this.fd_not_found()?;
- this.write_int(res, dest)?;
- return interp_ok(());
+ return this.set_last_error_and_return(LibcError("EBADF"), dest);
};
trace!("read: FD mapped to {fd:?}");
@@ -646,9 +633,7 @@
// We temporarily dup the FD to be able to retain mutable access to `this`.
let Some(fd) = this.machine.fds.get(fd_num) else {
- let res: i32 = this.fd_not_found()?;
- this.write_int(res, dest)?;
- return interp_ok(());
+ return this.set_last_error_and_return(LibcError("EBADF"), dest);
};
match offset {
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 7ba9898..355c93c 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -362,8 +362,7 @@
// FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray
match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
None => {
- let enmem = this.eval_libc("ENOMEM");
- this.set_last_error(enmem)?;
+ this.set_last_error(LibcError("ENOMEM"))?;
this.write_null(dest)?;
}
Some(len) => {
@@ -653,13 +652,10 @@
let chunk_size = CpuAffinityMask::chunk_size(this);
if this.ptr_is_null(mask)? {
- let efault = this.eval_libc("EFAULT");
- this.set_last_error(efault)?;
- this.write_int(-1, dest)?;
+ this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
} else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
// we only copy whole chunks of size_of::<c_ulong>()
- this.set_last_error(LibcError("EINVAL"))?;
- this.write_int(-1, dest)?;
+ this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
} else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
let cpuset = cpuset.clone();
// we only copy whole chunks of size_of::<c_ulong>()
@@ -668,9 +664,7 @@
this.write_null(dest)?;
} else {
// The thread whose ID is pid could not be found
- let esrch = this.eval_libc("ESRCH");
- this.set_last_error(esrch)?;
- this.write_int(-1, dest)?;
+ this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
}
}
"sched_setaffinity" => {
@@ -695,9 +689,7 @@
};
if this.ptr_is_null(mask)? {
- let efault = this.eval_libc("EFAULT");
- this.set_last_error(efault)?;
- this.write_int(-1, dest)?;
+ this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
} else {
// NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
// Any unspecified bytes are treated as zero here (none of the CPUs are configured).
@@ -713,8 +705,7 @@
}
None => {
// The intersection between the mask and the available CPUs was empty.
- this.set_last_error(LibcError("EINVAL"))?;
- this.write_int(-1, dest)?;
+ this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
}
}
}
@@ -770,9 +761,7 @@
// macOS: https://keith.github.io/xcode-man-pages/getentropy.2.html
// Solaris/Illumos: https://illumos.org/man/3C/getentropy
if bufsize > 256 {
- let err = this.eval_libc("EIO");
- this.set_last_error(err)?;
- this.write_int(-1, dest)?;
+ this.set_last_error_and_return(LibcError("EIO"), dest)?;
} else {
this.gen_random(buf, bufsize)?;
this.write_null(dest)?;
diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
index 5204e57..71953ac 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -29,6 +29,7 @@
this.read_scalar(thread)?,
this.read_scalar(name)?,
max_len,
+ /* truncate */ false,
)?;
}
"pthread_get_name_np" => {
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 4b3ae8e..f7436d7 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -149,6 +149,7 @@
// to handle possible errors correctly.
let result = self.file.sync_all();
// Now we actually close the file and return the result.
+ drop(*self);
interp_ok(result)
} else {
// We drop the file, this closes it but ignores any errors
@@ -157,6 +158,7 @@
// `/dev/urandom` which are read-only. Check
// https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
// for a deeper discussion.
+ drop(*self);
interp_ok(Ok(()))
}
}
@@ -229,6 +231,8 @@
TRUE => Ok(()),
FALSE => {
let mut err = io::Error::last_os_error();
+ // This only runs on Windows hosts so we can use `raw_os_error`.
+ // We have to be careful not to forward that error code to target code.
let code: u32 = err.raw_os_error().unwrap().try_into().unwrap();
if matches!(code, ERROR_IO_PENDING | ERROR_LOCK_VIOLATION) {
if lock_nb {
@@ -337,15 +341,10 @@
_ => interp_ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()),
}
}
- Err(e) =>
- match e.raw_os_error() {
- Some(error) => interp_ok(error),
- None =>
- throw_unsup_format!(
- "the error {} couldn't be converted to a return value",
- e
- ),
- },
+ Err(_) => {
+ // Fallback on error
+ interp_ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into())
+ }
}
}
}
@@ -528,8 +527,7 @@
let o_tmpfile = this.eval_libc_i32("O_TMPFILE");
if flag & o_tmpfile == o_tmpfile {
// if the flag contains `O_TMPFILE` then we return a graceful error
- this.set_last_error(LibcError("EOPNOTSUPP"))?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EOPNOTSUPP"));
}
}
@@ -548,9 +546,7 @@
// O_NOFOLLOW only fails when the trailing component is a symlink;
// the entire rest of the path can still contain symlinks.
if path.is_symlink() {
- let eloop = this.eval_libc("ELOOP");
- this.set_last_error(eloop)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("ELOOP"));
}
}
mirror |= o_nofollow;
@@ -565,8 +561,7 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`open`", reject_with)?;
- this.set_last_error(ErrorKind::PermissionDenied)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
}
let fd = options
@@ -584,8 +579,7 @@
let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
if offset < 0 {
// Negative offsets return `EINVAL`.
- this.set_last_error(LibcError("EINVAL"))?;
- return interp_ok(Scalar::from_i64(-1));
+ return this.set_last_error_and_return_i64(LibcError("EINVAL"));
} else {
SeekFrom::Start(u64::try_from(offset).unwrap())
}
@@ -594,14 +588,13 @@
} else if whence == this.eval_libc_i32("SEEK_END") {
SeekFrom::End(i64::try_from(offset).unwrap())
} else {
- this.set_last_error(LibcError("EINVAL"))?;
- return interp_ok(Scalar::from_i64(-1));
+ return this.set_last_error_and_return_i64(LibcError("EINVAL"));
};
let communicate = this.machine.communicate();
let Some(fd) = this.machine.fds.get(fd_num) else {
- return interp_ok(Scalar::from_i64(this.fd_not_found()?));
+ return this.set_last_error_and_return_i64(LibcError("EBADF"));
};
let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap());
drop(fd);
@@ -618,8 +611,7 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`unlink`", reject_with)?;
- this.set_last_error(ErrorKind::PermissionDenied)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
}
let result = remove_file(path).map(|_| 0);
@@ -649,8 +641,7 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`symlink`", reject_with)?;
- this.set_last_error(ErrorKind::PermissionDenied)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
}
let result = create_link(&target, &linkpath).map(|_| 0);
@@ -674,15 +665,13 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`stat`", reject_with)?;
- let eacc = this.eval_libc("EACCES");
- this.set_last_error(eacc)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EACCES"));
}
// `stat` always follows symlinks.
let metadata = match FileMetadata::from_path(this, &path, true)? {
- Some(metadata) => metadata,
- None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
+ Ok(metadata) => metadata,
+ Err(err) => return this.set_last_error_and_return_i32(err),
};
interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
@@ -706,14 +695,12 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`lstat`", reject_with)?;
- let eacc = this.eval_libc("EACCES");
- this.set_last_error(eacc)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EACCES"));
}
let metadata = match FileMetadata::from_path(this, &path, false)? {
- Some(metadata) => metadata,
- None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
+ Ok(metadata) => metadata,
+ Err(err) => return this.set_last_error_and_return_i32(err),
};
interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
@@ -736,12 +723,12 @@
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`fstat`", reject_with)?;
// Set error code as "EBADF" (bad fd)
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
}
let metadata = match FileMetadata::from_fd_num(this, fd)? {
- Some(metadata) => metadata,
- None => return interp_ok(Scalar::from_i32(-1)),
+ Ok(metadata) => metadata,
+ Err(err) => return this.set_last_error_and_return_i32(err),
};
interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
}
@@ -766,9 +753,7 @@
// If the statxbuf or pathname pointers are null, the function fails with `EFAULT`.
if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? {
- let efault = this.eval_libc("EFAULT");
- this.set_last_error(efault)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EFAULT"));
}
let statxbuf = this.deref_pointer_as(statxbuf_op, this.libc_ty_layout("statx"))?;
@@ -801,16 +786,15 @@
let ecode = if path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD") {
// since `path` is provided, either absolute or
// relative to CWD, `EACCES` is the most relevant.
- this.eval_libc("EACCES")
+ LibcError("EACCES")
} else {
// `dirfd` is set to target file, and `path` is empty
// (or we would have hit the `throw_unsup_format`
// above). `EACCES` would violate the spec.
assert!(empty_path_flag);
- this.eval_libc("EBADF")
+ LibcError("EBADF")
};
- this.set_last_error(ecode)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(ecode);
}
// the `_mask_op` parameter specifies the file information that the caller requested.
@@ -831,8 +815,8 @@
FileMetadata::from_path(this, &path, follow_symlink)?
};
let metadata = match metadata {
- Some(metadata) => metadata,
- None => return interp_ok(Scalar::from_i32(-1)),
+ Ok(metadata) => metadata,
+ Err(err) => return this.set_last_error_and_return_i32(err),
};
// The `mode` field specifies the type of the file and the permissions over the file for
@@ -939,9 +923,7 @@
let newpath_ptr = this.read_pointer(newpath_op)?;
if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? {
- let efault = this.eval_libc("EFAULT");
- this.set_last_error(efault)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EFAULT"));
}
let oldpath = this.read_path_from_c_str(oldpath_ptr)?;
@@ -950,8 +932,7 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`rename`", reject_with)?;
- this.set_last_error(ErrorKind::PermissionDenied)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
}
let result = rename(oldpath, newpath).map(|_| 0);
@@ -974,8 +955,7 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`mkdir`", reject_with)?;
- this.set_last_error(ErrorKind::PermissionDenied)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
}
#[cfg_attr(not(unix), allow(unused_mut))]
@@ -1002,8 +982,7 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`rmdir`", reject_with)?;
- this.set_last_error(ErrorKind::PermissionDenied)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
}
let result = remove_dir(path).map(|_| 0i32);
@@ -1019,8 +998,7 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`opendir`", reject_with)?;
- let eacc = this.eval_libc("EACCES");
- this.set_last_error(eacc)?;
+ this.set_last_error(LibcError("EACCES"))?;
return interp_ok(Scalar::null_ptr(this));
}
@@ -1052,8 +1030,7 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`readdir`", reject_with)?;
- let eacc = this.eval_libc("EBADF");
- this.set_last_error(eacc)?;
+ this.set_last_error(LibcError("EBADF"))?;
return interp_ok(Scalar::null_ptr(this));
}
@@ -1152,14 +1129,14 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`readdir_r`", reject_with)?;
- // Set error code as "EBADF" (bad fd)
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ // Return error code, do *not* set `errno`.
+ return interp_ok(this.eval_libc("EBADF"));
}
let open_dir = this.machine.dirs.streams.get_mut(&dirp).ok_or_else(|| {
err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir")
})?;
- interp_ok(Scalar::from_i32(match open_dir.read_dir.next() {
+ interp_ok(match open_dir.read_dir.next() {
Some(Ok(dir_entry)) => {
// Write into entry, write pointer to result, return 0 on success.
// The name is written with write_os_str_to_c_str, while the rest of the
@@ -1237,25 +1214,18 @@
let result_place = this.deref_pointer(result_op)?;
this.write_scalar(this.read_scalar(entry_op)?, &result_place)?;
- 0
+ Scalar::from_i32(0)
}
None => {
// end of stream: return 0, assign *result=NULL
this.write_null(&this.deref_pointer(result_op)?)?;
- 0
+ Scalar::from_i32(0)
}
- Some(Err(e)) =>
- match e.raw_os_error() {
- // return positive error number on error
- Some(error) => error,
- None => {
- throw_unsup_format!(
- "the error {} couldn't be converted to a return value",
- e
- )
- }
- },
- }))
+ Some(Err(e)) => {
+ // return positive error number on error (do *not* set last error)
+ this.io_error_to_errnum(e)?
+ }
+ })
}
fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -1264,20 +1234,21 @@
let dirp = this.read_target_usize(dirp_op)?;
// Reject if isolation is enabled.
- interp_ok(Scalar::from_i32(
- if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
- this.reject_in_isolation("`closedir`", reject_with)?;
- this.fd_not_found()?
- } else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) {
- if let Some(entry) = open_dir.entry {
- this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
- }
- drop(open_dir);
- 0
- } else {
- this.fd_not_found()?
- },
- ))
+ if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
+ this.reject_in_isolation("`closedir`", reject_with)?;
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
+ }
+
+ let Some(mut open_dir) = this.machine.dirs.streams.remove(&dirp) else {
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
+ };
+ if let Some(entry) = open_dir.entry.take() {
+ this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
+ }
+ // We drop the `open_dir`, which will close the host dir handle.
+ drop(open_dir);
+
+ interp_ok(Scalar::from_i32(0))
}
fn ftruncate64(&mut self, fd_num: i32, length: i128) -> InterpResult<'tcx, Scalar> {
@@ -1287,11 +1258,11 @@
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`ftruncate64`", reject_with)?;
// Set error code as "EBADF" (bad fd)
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
}
let Some(fd) = this.machine.fds.get(fd_num) else {
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
};
// FIXME: Support ftruncate64 for all FDs
@@ -1307,14 +1278,12 @@
interp_ok(Scalar::from_i32(result))
} else {
drop(fd);
- this.set_last_error(LibcError("EINVAL"))?;
- interp_ok(Scalar::from_i32(-1))
+ this.set_last_error_and_return_i32(LibcError("EINVAL"))
}
} else {
drop(fd);
// The file is not writable
- this.set_last_error(LibcError("EINVAL"))?;
- interp_ok(Scalar::from_i32(-1))
+ this.set_last_error_and_return_i32(LibcError("EINVAL"))
}
}
@@ -1332,7 +1301,7 @@
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`fsync`", reject_with)?;
// Set error code as "EBADF" (bad fd)
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
}
self.ffullsync_fd(fd)
@@ -1341,7 +1310,7 @@
fn ffullsync_fd(&mut self, fd_num: i32) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let Some(fd) = this.machine.fds.get(fd_num) else {
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
};
// Only regular files support synchronization.
let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1361,11 +1330,11 @@
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`fdatasync`", reject_with)?;
// Set error code as "EBADF" (bad fd)
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
}
let Some(fd) = this.machine.fds.get(fd) else {
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
};
// Only regular files support synchronization.
let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1391,26 +1360,24 @@
let flags = this.read_scalar(flags_op)?.to_i32()?;
if offset < 0 || nbytes < 0 {
- this.set_last_error(LibcError("EINVAL"))?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EINVAL"));
}
let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE")
| this.eval_libc_i32("SYNC_FILE_RANGE_WRITE")
| this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_AFTER");
if flags & allowed_flags != flags {
- this.set_last_error(LibcError("EINVAL"))?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EINVAL"));
}
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`sync_file_range`", reject_with)?;
// Set error code as "EBADF" (bad fd)
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
}
let Some(fd) = this.machine.fds.get(fd) else {
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
};
// Only regular files support synchronization.
let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1436,8 +1403,7 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`readlink`", reject_with)?;
- let eacc = this.eval_libc("EACCES");
- this.set_last_error(eacc)?;
+ this.set_last_error(LibcError("EACCES"))?;
return interp_ok(-1);
}
@@ -1475,11 +1441,11 @@
if fd.is_tty(this.machine.communicate()) {
return interp_ok(Scalar::from_i32(1));
} else {
- this.eval_libc("ENOTTY")
+ LibcError("ENOTTY")
}
} else {
// FD does not exist
- this.eval_libc("EBADF")
+ LibcError("EBADF")
};
this.set_last_error(error)?;
interp_ok(Scalar::from_i32(0))
@@ -1499,8 +1465,7 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`realpath`", reject_with)?;
- let eacc = this.eval_libc("EACCES");
- this.set_last_error(eacc)?;
+ this.set_last_error(LibcError("EACCES"))?;
return interp_ok(Scalar::from_target_usize(0, this));
}
@@ -1530,8 +1495,7 @@
// Note that we do not explicitly handle `FILENAME_MAX`
// (different from `PATH_MAX` above) as it is Linux-specific and
// seems like a bit of a mess anyway: <https://eklitzke.org/path-max-is-tricky>.
- let enametoolong = this.eval_libc("ENAMETOOLONG");
- this.set_last_error(enametoolong)?;
+ this.set_last_error(LibcError("ENAMETOOLONG"))?;
return interp_ok(Scalar::from_target_usize(0, this));
}
processed_ptr
@@ -1574,9 +1538,7 @@
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`mkstemp`", reject_with)?;
- let eacc = this.eval_libc("EACCES");
- this.set_last_error(eacc)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EACCES"));
}
// Get the bytes of the suffix we expect in _target_ encoding.
@@ -1592,8 +1554,7 @@
// If we don't find the suffix, it is an error.
if last_six_char_bytes != suffix_bytes {
- this.set_last_error(LibcError("EINVAL"))?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EINVAL"));
}
// At this point we know we have 6 ASCII 'X' characters as a suffix.
@@ -1658,17 +1619,14 @@
_ => {
// "On error, -1 is returned, and errno is set to
// indicate the error"
- this.set_last_error(e)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(e);
}
},
}
}
// We ran out of attempts to create the file, return an error.
- let eexist = this.eval_libc("EEXIST");
- this.set_last_error(eexist)?;
- interp_ok(Scalar::from_i32(-1))
+ this.set_last_error_and_return_i32(LibcError("EEXIST"))
}
}
@@ -1702,7 +1660,7 @@
ecx: &mut MiriInterpCx<'tcx>,
path: &Path,
follow_symlink: bool,
- ) -> InterpResult<'tcx, Option<FileMetadata>> {
+ ) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
let metadata =
if follow_symlink { std::fs::metadata(path) } else { std::fs::symlink_metadata(path) };
@@ -1712,9 +1670,9 @@
fn from_fd_num<'tcx>(
ecx: &mut MiriInterpCx<'tcx>,
fd_num: i32,
- ) -> InterpResult<'tcx, Option<FileMetadata>> {
+ ) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
let Some(fd) = ecx.machine.fds.get(fd_num) else {
- return ecx.fd_not_found().map(|_: i32| None);
+ return interp_ok(Err(LibcError("EBADF")));
};
let file = &fd
@@ -1734,12 +1692,11 @@
fn from_meta<'tcx>(
ecx: &mut MiriInterpCx<'tcx>,
metadata: Result<std::fs::Metadata, std::io::Error>,
- ) -> InterpResult<'tcx, Option<FileMetadata>> {
+ ) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
let metadata = match metadata {
Ok(metadata) => metadata,
Err(e) => {
- ecx.set_last_error(e)?;
- return interp_ok(None);
+ return interp_ok(Err(e.into()));
}
};
@@ -1762,6 +1719,6 @@
let modified = extract_sec_and_nsec(metadata.modified())?;
// FIXME: Provide more fields using platform specific methods.
- interp_ok(Some(FileMetadata { mode, size, created, accessed, modified }))
+ interp_ok(Ok(FileMetadata { mode, size, created, accessed, modified }))
}
}
diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs
index cafc716..de10866 100644
--- a/src/tools/miri/src/shims/unix/linux/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux/epoll.rs
@@ -256,23 +256,14 @@
let epollhup = this.eval_libc_u32("EPOLLHUP");
let epollerr = this.eval_libc_u32("EPOLLERR");
- // Fail on unsupported operations.
- if op & epoll_ctl_add != epoll_ctl_add
- && op & epoll_ctl_mod != epoll_ctl_mod
- && op & epoll_ctl_del != epoll_ctl_del
- {
- throw_unsup_format!("epoll_ctl: encountered unknown unsupported operation {:#x}", op);
- }
-
// Throw EINVAL if epfd and fd have the same value.
if epfd_value == fd {
- this.set_last_error(LibcError("EINVAL"))?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EINVAL"));
}
// Check if epfd is a valid epoll file descriptor.
let Some(epfd) = this.machine.fds.get(epfd_value) else {
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
};
let epoll_file_description = epfd
.downcast::<Epoll>()
@@ -282,7 +273,7 @@
let ready_list = &epoll_file_description.ready_list;
let Some(fd_ref) = this.machine.fds.get(fd) else {
- return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+ return this.set_last_error_and_return_i32(LibcError("EBADF"));
};
let id = fd_ref.get_id();
@@ -332,15 +323,11 @@
// Check the existence of fd in the interest list.
if op == epoll_ctl_add {
if interest_list.contains_key(&epoll_key) {
- let eexist = this.eval_libc("EEXIST");
- this.set_last_error(eexist)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EEXIST"));
}
} else {
if !interest_list.contains_key(&epoll_key) {
- let enoent = this.eval_libc("ENOENT");
- this.set_last_error(enoent)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("ENOENT"));
}
}
@@ -368,15 +355,13 @@
// Notification will be returned for current epfd if there is event in the file
// descriptor we registered.
check_and_update_one_event_interest(&fd_ref, interest, id, this)?;
- return interp_ok(Scalar::from_i32(0));
+ interp_ok(Scalar::from_i32(0))
} else if op == epoll_ctl_del {
let epoll_key = (id, fd);
// Remove epoll_event_interest from interest_list.
let Some(epoll_interest) = interest_list.remove(&epoll_key) else {
- let enoent = this.eval_libc("ENOENT");
- this.set_last_error(enoent)?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("ENOENT"));
};
// All related Weak<EpollEventInterest> will fail to upgrade after the drop.
drop(epoll_interest);
@@ -394,9 +379,10 @@
.unwrap()
.retain(|event| event.upgrade().is_some());
- return interp_ok(Scalar::from_i32(0));
+ interp_ok(Scalar::from_i32(0))
+ } else {
+ throw_unsup_format!("unsupported epoll_ctl operation: {op}");
}
- interp_ok(Scalar::from_i32(-1))
}
/// The `epoll_wait()` system call waits for events on the `Epoll`
@@ -447,9 +433,7 @@
let timeout = this.read_scalar(timeout)?.to_i32()?;
if epfd_value <= 0 || maxevents <= 0 {
- this.set_last_error(LibcError("EINVAL"))?;
- this.write_int(-1, dest)?;
- return interp_ok(());
+ return this.set_last_error_and_return(LibcError("EINVAL"), dest);
}
// This needs to come after the maxevents value check, or else maxevents.try_into().unwrap()
@@ -460,9 +444,7 @@
)?;
let Some(epfd) = this.machine.fds.get(epfd_value) else {
- let result_value: i32 = this.fd_not_found()?;
- this.write_int(result_value, dest)?;
- return interp_ok(());
+ return this.set_last_error_and_return(LibcError("EBADF"), dest);
};
// Create a weak ref of epfd and pass it to callback so we will make sure that epfd
// is not close after the thread unblocks.
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index e73bde1..6616a98 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -84,6 +84,7 @@
this.read_scalar(thread)?,
this.read_scalar(name)?,
TASK_COMM_LEN,
+ /* truncate */ false,
)?;
let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") };
this.write_scalar(res, dest)?;
diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs
index 4f2e17d..d5f9669 100644
--- a/src/tools/miri/src/shims/unix/linux/mem.rs
+++ b/src/tools/miri/src/shims/unix/linux/mem.rs
@@ -24,7 +24,7 @@
// old_address must be a multiple of the page size
#[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero
if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 {
- this.set_last_error(this.eval_libc("EINVAL"))?;
+ this.set_last_error(LibcError("EINVAL"))?;
return interp_ok(this.eval_libc("MAP_FAILED"));
}
@@ -38,7 +38,7 @@
if flags & this.eval_libc_i32("MREMAP_MAYMOVE") == 0 {
// We only support MREMAP_MAYMOVE, so not passing the flag is just a failure
- this.set_last_error(this.eval_libc("EINVAL"))?;
+ this.set_last_error(LibcError("EINVAL"))?;
return interp_ok(this.eval_libc("MAP_FAILED"));
}
diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs
index 941011b..c258be7 100644
--- a/src/tools/miri/src/shims/unix/linux/sync.rs
+++ b/src/tools/miri/src/shims/unix/linux/sync.rs
@@ -63,8 +63,7 @@
};
if bitset == 0 {
- this.set_last_error(LibcError("EINVAL"))?;
- this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
+ this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
return interp_ok(());
}
@@ -75,9 +74,7 @@
let duration = match this.read_timespec(&timeout)? {
Some(duration) => duration,
None => {
- this.set_last_error(LibcError("EINVAL"))?;
- this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
- return interp_ok(());
+ return this.set_last_error_and_return(LibcError("EINVAL"), dest);
}
};
let timeout_clock = if op & futex_realtime == futex_realtime {
@@ -153,14 +150,12 @@
Scalar::from_target_isize(0, this), // retval_succ
Scalar::from_target_isize(-1, this), // retval_timeout
dest.clone(),
- this.eval_libc("ETIMEDOUT"),
+ this.eval_libc("ETIMEDOUT"), // errno_timeout
);
} else {
// The futex value doesn't match the expected value, so we return failure
// right away without sleeping: -1 and errno set to EAGAIN.
- let eagain = this.eval_libc("EAGAIN");
- this.set_last_error(eagain)?;
- this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
+ return this.set_last_error_and_return(LibcError("EAGAIN"), dest);
}
}
// FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
@@ -180,9 +175,7 @@
u32::MAX
};
if bitset == 0 {
- this.set_last_error(LibcError("EINVAL"))?;
- this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
- return interp_ok(());
+ return this.set_last_error_and_return(LibcError("EINVAL"), dest);
}
// Together with the SeqCst fence in futex_wait, this makes sure that futex_wait
// will see the latest value on addr which could be changed by our caller
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index b199992..cd07bc9 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -181,6 +181,7 @@
thread,
this.read_scalar(name)?,
this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?.try_into().unwrap(),
+ /* truncate */ false,
)? {
Scalar::from_u32(0)
} else {
diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs
index 9273748..9371edf 100644
--- a/src/tools/miri/src/shims/unix/mem.rs
+++ b/src/tools/miri/src/shims/unix/mem.rs
@@ -57,11 +57,11 @@
// First, we do some basic argument validation as required by mmap
if (flags & (map_private | map_shared)).count_ones() != 1 {
- this.set_last_error(this.eval_libc("EINVAL"))?;
+ this.set_last_error(LibcError("EINVAL"))?;
return interp_ok(this.eval_libc("MAP_FAILED"));
}
if length == 0 {
- this.set_last_error(this.eval_libc("EINVAL"))?;
+ this.set_last_error(LibcError("EINVAL"))?;
return interp_ok(this.eval_libc("MAP_FAILED"));
}
@@ -103,11 +103,11 @@
let align = this.machine.page_align();
let Some(map_length) = length.checked_next_multiple_of(this.machine.page_size) else {
- this.set_last_error(this.eval_libc("EINVAL"))?;
+ this.set_last_error(LibcError("EINVAL"))?;
return interp_ok(this.eval_libc("MAP_FAILED"));
};
if map_length > this.target_usize_max() {
- this.set_last_error(this.eval_libc("EINVAL"))?;
+ this.set_last_error(LibcError("EINVAL"))?;
return interp_ok(this.eval_libc("MAP_FAILED"));
}
@@ -134,16 +134,14 @@
// as a dealloc.
#[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero
if addr.addr().bytes() % this.machine.page_size != 0 {
- this.set_last_error(this.eval_libc("EINVAL"))?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EINVAL"));
}
let Some(length) = length.checked_next_multiple_of(this.machine.page_size) else {
- this.set_last_error(this.eval_libc("EINVAL"))?;
- return interp_ok(Scalar::from_i32(-1));
+ return this.set_last_error_and_return_i32(LibcError("EINVAL"));
};
if length > this.target_usize_max() {
- this.set_last_error(this.eval_libc("EINVAL"))?;
+ this.set_last_error(LibcError("EINVAL"))?;
return interp_ok(this.eval_libc("MAP_FAILED"));
}
diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
index 7f3d0f0..c9c1b01 100644
--- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
@@ -30,6 +30,7 @@
this.read_scalar(thread)?,
this.read_scalar(name)?,
max_len,
+ /* truncate */ false,
)?;
let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") };
this.write_scalar(res, dest)?;
diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs
index 7f97afc..51256d8 100644
--- a/src/tools/miri/src/shims/unix/thread.rs
+++ b/src/tools/miri/src/shims/unix/thread.rs
@@ -64,23 +64,29 @@
}
/// Set the name of the specified thread. If the name including the null terminator
- /// is longer than `name_max_len`, then `false` is returned.
+ /// is longer or equals to `name_max_len`, then if `truncate` is set the truncated name
+ /// is used as the thread name, otherwise `false` is returned.
fn pthread_setname_np(
&mut self,
thread: Scalar,
name: Scalar,
name_max_len: usize,
+ truncate: bool,
) -> InterpResult<'tcx, bool> {
let this = self.eval_context_mut();
let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?;
let thread = ThreadId::try_from(thread).unwrap();
let name = name.to_pointer(this)?;
- let name = this.read_c_str(name)?.to_owned();
+ let mut name = this.read_c_str(name)?.to_owned();
// Comparing with `>=` to account for null terminator.
if name.len() >= name_max_len {
- return interp_ok(false);
+ if truncate {
+ name.truncate(name_max_len.saturating_sub(1));
+ } else {
+ return interp_ok(false);
+ }
}
this.set_thread_name(thread, name);
diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs
index f886108..f7566a8 100644
--- a/src/tools/miri/src/shims/windows/sync.rs
+++ b/src/tools/miri/src/shims/windows/sync.rs
@@ -202,7 +202,7 @@
Scalar::from_i32(1), // retval_succ
Scalar::from_i32(0), // retval_timeout
dest.clone(),
- this.eval_windows("c", "ERROR_TIMEOUT"),
+ this.eval_windows("c", "ERROR_TIMEOUT"), // errno_timeout
);
}
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index 64bfc84..0a5e9f6 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
-version = 3
+version = 4
[[package]]
name = "addr2line"
@@ -128,9 +128,9 @@
[[package]]
name = "libc"
-version = "0.2.158"
+version = "0.2.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
[[package]]
name = "linux-raw-sys"
diff --git a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs
new file mode 100644
index 0000000..4b73186
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs
@@ -0,0 +1,10 @@
+//! Ensure we report UB when the buffer is smaller than 16 bytes (even if the thread
+//! name would fit in the smaller buffer).
+//@only-target: android # Miri supports prctl for Android only
+
+fn main() {
+ let mut buf = vec![0u8; 15];
+ unsafe {
+ libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::<libc::c_char>()); //~ ERROR: memory access failed: expected a pointer to 16 bytes of memory, but got alloc952 which is only 15 bytes from the end of the allocation
+ }
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr
new file mode 100644
index 0000000..275a38e
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr
@@ -0,0 +1,21 @@
+error: Undefined Behavior: memory access failed: expected a pointer to 16 bytes of memory, but got ALLOC which is only 15 bytes from the end of the allocation
+ --> tests/fail-dep/libc/prctl-threadname.rs:LL:CC
+ |
+LL | libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::<libc::c_char>());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 16 bytes of memory, but got ALLOC which is only 15 bytes from the end of the allocation
+ |
+ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+ = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+help: ALLOC was allocated here:
+ --> tests/fail-dep/libc/prctl-threadname.rs:LL:CC
+ |
+LL | let mut buf = vec![0u8; 15];
+ | ^^^^^^^^^^^^^
+ = note: BACKTRACE (of the first span):
+ = note: inside `main` at tests/fail-dep/libc/prctl-threadname.rs:LL:CC
+ = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs
index f4c0094..55491da 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs
@@ -1,7 +1,7 @@
//! This is a regression test for <https://github.com/rust-lang/miri/issues/3947>: we had some
//! faulty logic around `release_clock` that led to this code not reporting a data race.
//@ignore-target: windows # no libc socketpair on Windows
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0
use std::thread;
fn main() {
diff --git a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr
index c2c6ce9..9b4890c 100644
--- a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr
+++ b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr
@@ -23,7 +23,7 @@
|
LL | match me.resume(()) {
| ^^^^^^^^^^^^^
- = note: inside `<std::boxed::Box<CoroutineIteratorAdapter<{static coroutine@tests/fail/coroutine-pinned-moved.rs:LL:CC}>> as std::iter::Iterator>::next` at RUSTLIB/alloc/src/boxed.rs:LL:CC
+ = note: inside `std::boxed::iter::<impl std::iter::Iterator for std::boxed::Box<CoroutineIteratorAdapter<{static coroutine@tests/fail/coroutine-pinned-moved.rs:LL:CC}>>>::next` at RUSTLIB/alloc/src/boxed/iter.rs:LL:CC
note: inside `main`
--> tests/fail/coroutine-pinned-moved.rs:LL:CC
|
diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
index d4479f3..c91f4ec 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
+++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
@@ -1,4 +1,3 @@
-
// Ensure that a `ptr::without_provenance` ptr is truly invalid.
fn main() {
let x = 42;
diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs
new file mode 100644
index 0000000..b69f7ee
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs
@@ -0,0 +1,16 @@
+#![feature(explicit_tail_calls)]
+#![allow(incomplete_features)]
+
+fn g(x: *const i32) {
+ let _val = unsafe { *x }; //~ERROR: has been freed, so this pointer is dangling
+}
+
+fn f(_x: *const i32) {
+ let local = 0;
+ let ptr = &local as *const i32;
+ become g(ptr)
+}
+
+fn main() {
+ f(std::ptr::null());
+}
diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr
new file mode 100644
index 0000000..6acd69a
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr
@@ -0,0 +1,30 @@
+error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
+ --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+ |
+LL | let _val = unsafe { *x };
+ | ^^ memory access failed: ALLOC has been freed, so this pointer is dangling
+ |
+ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+ = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+help: ALLOC was allocated here:
+ --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+ |
+LL | let local = 0;
+ | ^^^^^
+help: ALLOC was deallocated here:
+ --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+ |
+LL | }
+ | ^
+ = note: BACKTRACE (of the first span):
+ = note: inside `g` at tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+note: inside `main`
+ --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+ |
+LL | f(std::ptr::null());
+ | ^^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs b/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs
new file mode 100644
index 0000000..87ae375
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs
@@ -0,0 +1,74 @@
+//@only-target: android # Miri supports prctl for Android only
+use std::ffi::{CStr, CString};
+use std::thread;
+
+// The Linux kernel all names 16 bytes long including the null terminator.
+const MAX_THREAD_NAME_LEN: usize = 16;
+
+fn main() {
+ // The short name should be shorter than 16 bytes which POSIX promises
+ // for thread names. The length includes a null terminator.
+ let short_name = "test_named".to_owned();
+ let long_name = std::iter::once("test_named_thread_truncation")
+ .chain(std::iter::repeat(" yada").take(100))
+ .collect::<String>();
+
+ fn set_thread_name(name: &CStr) -> i32 {
+ unsafe { libc::prctl(libc::PR_SET_NAME, name.as_ptr().cast::<libc::c_char>()) }
+ }
+
+ fn get_thread_name(name: &mut [u8]) -> i32 {
+ assert!(name.len() >= MAX_THREAD_NAME_LEN);
+ unsafe { libc::prctl(libc::PR_GET_NAME, name.as_mut_ptr().cast::<libc::c_char>()) }
+ }
+
+ // Set name via Rust API, get it via prctl.
+ let long_name2 = long_name.clone();
+ thread::Builder::new()
+ .name(long_name.clone())
+ .spawn(move || {
+ let mut buf = vec![0u8; MAX_THREAD_NAME_LEN];
+ assert_eq!(get_thread_name(&mut buf), 0);
+ let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+ let truncated_name = &long_name2[..long_name2.len().min(MAX_THREAD_NAME_LEN - 1)];
+ assert_eq!(cstr.to_bytes(), truncated_name.as_bytes());
+ })
+ .unwrap()
+ .join()
+ .unwrap();
+
+ // Set name via prctl and get it again (short name).
+ thread::Builder::new()
+ .spawn(move || {
+ // Set short thread name.
+ let cstr = CString::new(short_name.clone()).unwrap();
+ assert!(cstr.to_bytes_with_nul().len() <= MAX_THREAD_NAME_LEN); // this should fit
+ assert_eq!(set_thread_name(&cstr), 0);
+
+ let mut buf = vec![0u8; MAX_THREAD_NAME_LEN];
+ assert_eq!(get_thread_name(&mut buf), 0);
+ let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+ assert_eq!(cstr.to_bytes(), short_name.as_bytes());
+ })
+ .unwrap()
+ .join()
+ .unwrap();
+
+ // Set name via prctl and get it again (long name).
+ thread::Builder::new()
+ .spawn(move || {
+ // Set full thread name.
+ let cstr = CString::new(long_name.clone()).unwrap();
+ assert!(cstr.to_bytes_with_nul().len() > MAX_THREAD_NAME_LEN);
+ // Names are truncated by the Linux kernel.
+ assert_eq!(set_thread_name(&cstr), 0);
+
+ let mut buf = vec![0u8; MAX_THREAD_NAME_LEN];
+ assert_eq!(get_thread_name(&mut buf), 0);
+ let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+ assert_eq!(cstr.to_bytes(), &long_name.as_bytes()[..(MAX_THREAD_NAME_LEN - 1)]);
+ })
+ .unwrap()
+ .join()
+ .unwrap();
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
index 404ef7c..0e5b501 100644
--- a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
+++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
@@ -1,4 +1,5 @@
//@ignore-target: windows # No pthreads on Windows
+//@ignore-target: android # No pthread_{get,set}_name on Android
use std::ffi::{CStr, CString};
use std::thread;
@@ -65,6 +66,22 @@
}
}
+ // Set name via Rust API, get it via pthreads.
+ let long_name2 = long_name.clone();
+ thread::Builder::new()
+ .name(long_name.clone())
+ .spawn(move || {
+ let mut buf = vec![0u8; long_name2.len() + 1];
+ assert_eq!(get_thread_name(&mut buf), 0);
+ let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+ let truncated_name = &long_name2[..long_name2.len().min(MAX_THREAD_NAME_LEN - 1)];
+ assert_eq!(cstr.to_bytes(), truncated_name.as_bytes());
+ })
+ .unwrap()
+ .join()
+ .unwrap();
+
+ // Set name via pthread and get it again (short name).
thread::Builder::new()
.spawn(move || {
// Set short thread name.
@@ -130,6 +147,7 @@
.join()
.unwrap();
+ // Set name via pthread and get it again (long name).
thread::Builder::new()
.spawn(move || {
// Set full thread name.
diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs
index 306e9ab..61410f7 100644
--- a/src/tools/miri/tests/pass/dyn-upcast.rs
+++ b/src/tools/miri/tests/pass/dyn-upcast.rs
@@ -433,7 +433,8 @@
}
fn drop_principal() {
- use std::{alloc::Layout, any::Any};
+ use std::alloc::Layout;
+ use std::any::Any;
const fn yeet_principal(x: Box<dyn Any + Send>) -> Box<dyn Send> {
x
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 853d3e8..66843ca 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -157,13 +157,18 @@
assert_eq(-{ 5.0_f128 }, -5.0_f128);
// infinities, NaN
- // FIXME(f16_f128): add when constants and `is_infinite` are available
+ assert!((5.0_f16 / 0.0).is_infinite());
+ assert_ne!({ 5.0_f16 / 0.0 }, { -5.0_f16 / 0.0 });
assert!((5.0_f32 / 0.0).is_infinite());
assert_ne!({ 5.0_f32 / 0.0 }, { -5.0_f32 / 0.0 });
assert!((5.0_f64 / 0.0).is_infinite());
assert_ne!({ 5.0_f64 / 0.0 }, { 5.0_f64 / -0.0 });
+ assert!((5.0_f128 / 0.0).is_infinite());
+ assert_ne!({ 5.0_f128 / 0.0 }, { 5.0_f128 / -0.0 });
+ assert_ne!(f16::NAN, f16::NAN);
assert_ne!(f32::NAN, f32::NAN);
assert_ne!(f64::NAN, f64::NAN);
+ assert_ne!(f128::NAN, f128::NAN);
// negative zero
let posz = 0.0f16;
@@ -215,9 +220,14 @@
assert!((black_box(-1.0f128) % 1.0).is_sign_negative());
assert!((black_box(-1.0f128) % -1.0).is_sign_negative());
- // FIXME(f16_f128): add when `abs` is available
+ assert_eq!((-1.0f16).abs(), 1.0f16);
+ assert_eq!(34.2f16.abs(), 34.2f16);
assert_eq!((-1.0f32).abs(), 1.0f32);
+ assert_eq!(34.2f32.abs(), 34.2f32);
+ assert_eq!((-1.0f64).abs(), 1.0f64);
assert_eq!(34.2f64.abs(), 34.2f64);
+ assert_eq!((-1.0f128).abs(), 1.0f128);
+ assert_eq!(34.2f128.abs(), 34.2f128);
}
/// Test casts from floats to ints and back
@@ -654,6 +664,14 @@
}
fn ops() {
+ // f16 min/max
+ assert_eq((1.0_f16).max(-1.0), 1.0);
+ assert_eq((1.0_f16).min(-1.0), -1.0);
+ assert_eq(f16::NAN.min(9.0), 9.0);
+ assert_eq(f16::NAN.max(-9.0), -9.0);
+ assert_eq((9.0_f16).min(f16::NAN), 9.0);
+ assert_eq((-9.0_f16).max(f16::NAN), -9.0);
+
// f32 min/max
assert_eq((1.0 as f32).max(-1.0), 1.0);
assert_eq((1.0 as f32).min(-1.0), -1.0);
@@ -670,6 +688,21 @@
assert_eq((9.0 as f64).min(f64::NAN), 9.0);
assert_eq((-9.0 as f64).max(f64::NAN), -9.0);
+ // f128 min/max
+ assert_eq((1.0_f128).max(-1.0), 1.0);
+ assert_eq((1.0_f128).min(-1.0), -1.0);
+ assert_eq(f128::NAN.min(9.0), 9.0);
+ assert_eq(f128::NAN.max(-9.0), -9.0);
+ assert_eq((9.0_f128).min(f128::NAN), 9.0);
+ assert_eq((-9.0_f128).max(f128::NAN), -9.0);
+
+ // f16 copysign
+ assert_eq(3.5_f16.copysign(0.42), 3.5_f16);
+ assert_eq(3.5_f16.copysign(-0.42), -3.5_f16);
+ assert_eq((-3.5_f16).copysign(0.42), 3.5_f16);
+ assert_eq((-3.5_f16).copysign(-0.42), -3.5_f16);
+ assert!(f16::NAN.copysign(1.0).is_nan());
+
// f32 copysign
assert_eq(3.5_f32.copysign(0.42), 3.5_f32);
assert_eq(3.5_f32.copysign(-0.42), -3.5_f32);
@@ -683,6 +716,13 @@
assert_eq((-3.5_f64).copysign(0.42), 3.5_f64);
assert_eq((-3.5_f64).copysign(-0.42), -3.5_f64);
assert!(f64::NAN.copysign(1.0).is_nan());
+
+ // f128 copysign
+ assert_eq(3.5_f128.copysign(0.42), 3.5_f128);
+ assert_eq(3.5_f128.copysign(-0.42), -3.5_f128);
+ assert_eq((-3.5_f128).copysign(0.42), 3.5_f128);
+ assert_eq((-3.5_f128).copysign(-0.42), -3.5_f128);
+ assert!(f128::NAN.copysign(1.0).is_nan());
}
/// Tests taken from rustc test suite.
@@ -807,6 +847,18 @@
fn rounding() {
// Test cases taken from the library's tests for this feature
+ // f16
+ assert_eq(2.5f16.round_ties_even(), 2.0f16);
+ assert_eq(1.0f16.round_ties_even(), 1.0f16);
+ assert_eq(1.3f16.round_ties_even(), 1.0f16);
+ assert_eq(1.5f16.round_ties_even(), 2.0f16);
+ assert_eq(1.7f16.round_ties_even(), 2.0f16);
+ assert_eq(0.0f16.round_ties_even(), 0.0f16);
+ assert_eq((-0.0f16).round_ties_even(), -0.0f16);
+ assert_eq((-1.0f16).round_ties_even(), -1.0f16);
+ assert_eq((-1.3f16).round_ties_even(), -1.0f16);
+ assert_eq((-1.5f16).round_ties_even(), -2.0f16);
+ assert_eq((-1.7f16).round_ties_even(), -2.0f16);
// f32
assert_eq(2.5f32.round_ties_even(), 2.0f32);
assert_eq(1.0f32.round_ties_even(), 1.0f32);
@@ -831,23 +883,59 @@
assert_eq((-1.3f64).round_ties_even(), -1.0f64);
assert_eq((-1.5f64).round_ties_even(), -2.0f64);
assert_eq((-1.7f64).round_ties_even(), -2.0f64);
+ // f128
+ assert_eq(2.5f128.round_ties_even(), 2.0f128);
+ assert_eq(1.0f128.round_ties_even(), 1.0f128);
+ assert_eq(1.3f128.round_ties_even(), 1.0f128);
+ assert_eq(1.5f128.round_ties_even(), 2.0f128);
+ assert_eq(1.7f128.round_ties_even(), 2.0f128);
+ assert_eq(0.0f128.round_ties_even(), 0.0f128);
+ assert_eq((-0.0f128).round_ties_even(), -0.0f128);
+ assert_eq((-1.0f128).round_ties_even(), -1.0f128);
+ assert_eq((-1.3f128).round_ties_even(), -1.0f128);
+ assert_eq((-1.5f128).round_ties_even(), -2.0f128);
+ assert_eq((-1.7f128).round_ties_even(), -2.0f128);
+ assert_eq!(3.8f16.floor(), 3.0f16);
+ assert_eq!((-1.1f16).floor(), -2.0f16);
assert_eq!(3.8f32.floor(), 3.0f32);
+ assert_eq!((-1.1f32).floor(), -2.0f32);
+ assert_eq!(3.8f64.floor(), 3.0f64);
assert_eq!((-1.1f64).floor(), -2.0f64);
+ assert_eq!(3.8f128.floor(), 3.0f128);
+ assert_eq!((-1.1f128).floor(), -2.0f128);
+ assert_eq!(3.8f16.ceil(), 4.0f16);
+ assert_eq!((-2.3f16).ceil(), -2.0f16);
+ assert_eq!(3.8f32.ceil(), 4.0f32);
assert_eq!((-2.3f32).ceil(), -2.0f32);
assert_eq!(3.8f64.ceil(), 4.0f64);
+ assert_eq!((-2.3f64).ceil(), -2.0f64);
+ assert_eq!(3.8f128.ceil(), 4.0f128);
+ assert_eq!((-2.3f128).ceil(), -2.0f128);
+ assert_eq!(0.1f16.trunc(), 0.0f16);
+ assert_eq!((-0.1f16).trunc(), 0.0f16);
assert_eq!(0.1f32.trunc(), 0.0f32);
+ assert_eq!((-0.1f32).trunc(), 0.0f32);
+ assert_eq!(0.1f64.trunc(), 0.0f64);
assert_eq!((-0.1f64).trunc(), 0.0f64);
+ assert_eq!(0.1f128.trunc(), 0.0f128);
+ assert_eq!((-0.1f128).trunc(), 0.0f128);
+ assert_eq!(3.3_f16.round(), 3.0);
+ assert_eq!(2.5_f16.round(), 3.0);
assert_eq!(3.3_f32.round(), 3.0);
assert_eq!(2.5_f32.round(), 3.0);
assert_eq!(3.9_f64.round(), 4.0);
assert_eq!(2.5_f64.round(), 3.0);
+ assert_eq!(3.9_f128.round(), 4.0);
+ assert_eq!(2.5_f128.round(), 3.0);
}
fn mul_add() {
+ // FIXME(f16_f128): add when supported
+
assert_eq!(3.0f32.mul_add(2.0f32, 5.0f32), 11.0);
assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E);
assert_eq!(3.0f64.mul_add(2.0, 5.0), 11.0);
@@ -983,7 +1071,7 @@
use std::intrinsics::{fadd_fast, fdiv_fast, fmul_fast, frem_fast, fsub_fast};
#[inline(never)]
- pub fn test_operations_f64(a: f64, b: f64) {
+ pub fn test_operations_f16(a: f16, b: f16) {
// make sure they all map to the correct operation
unsafe {
assert_eq!(fadd_fast(a, b), a + b);
@@ -1006,10 +1094,38 @@
}
}
- test_operations_f64(1., 2.);
- test_operations_f64(10., 5.);
+ #[inline(never)]
+ pub fn test_operations_f64(a: f64, b: f64) {
+ // make sure they all map to the correct operation
+ unsafe {
+ assert_eq!(fadd_fast(a, b), a + b);
+ assert_eq!(fsub_fast(a, b), a - b);
+ assert_eq!(fmul_fast(a, b), a * b);
+ assert_eq!(fdiv_fast(a, b), a / b);
+ assert_eq!(frem_fast(a, b), a % b);
+ }
+ }
+
+ #[inline(never)]
+ pub fn test_operations_f128(a: f128, b: f128) {
+ // make sure they all map to the correct operation
+ unsafe {
+ assert_eq!(fadd_fast(a, b), a + b);
+ assert_eq!(fsub_fast(a, b), a - b);
+ assert_eq!(fmul_fast(a, b), a * b);
+ assert_eq!(fdiv_fast(a, b), a / b);
+ assert_eq!(frem_fast(a, b), a % b);
+ }
+ }
+
+ test_operations_f16(11., 2.);
+ test_operations_f16(10., 15.);
test_operations_f32(11., 2.);
test_operations_f32(10., 15.);
+ test_operations_f64(1., 2.);
+ test_operations_f64(10., 5.);
+ test_operations_f128(1., 2.);
+ test_operations_f128(10., 5.);
}
fn test_algebraic() {
@@ -1018,7 +1134,7 @@
};
#[inline(never)]
- pub fn test_operations_f64(a: f64, b: f64) {
+ pub fn test_operations_f16(a: f16, b: f16) {
// make sure they all map to the correct operation
assert_eq!(fadd_algebraic(a, b), a + b);
assert_eq!(fsub_algebraic(a, b), a - b);
@@ -1037,15 +1153,41 @@
assert_eq!(frem_algebraic(a, b), a % b);
}
- test_operations_f64(1., 2.);
- test_operations_f64(10., 5.);
+ #[inline(never)]
+ pub fn test_operations_f64(a: f64, b: f64) {
+ // make sure they all map to the correct operation
+ assert_eq!(fadd_algebraic(a, b), a + b);
+ assert_eq!(fsub_algebraic(a, b), a - b);
+ assert_eq!(fmul_algebraic(a, b), a * b);
+ assert_eq!(fdiv_algebraic(a, b), a / b);
+ assert_eq!(frem_algebraic(a, b), a % b);
+ }
+
+ #[inline(never)]
+ pub fn test_operations_f128(a: f128, b: f128) {
+ // make sure they all map to the correct operation
+ assert_eq!(fadd_algebraic(a, b), a + b);
+ assert_eq!(fsub_algebraic(a, b), a - b);
+ assert_eq!(fmul_algebraic(a, b), a * b);
+ assert_eq!(fdiv_algebraic(a, b), a / b);
+ assert_eq!(frem_algebraic(a, b), a % b);
+ }
+
+ test_operations_f16(11., 2.);
+ test_operations_f16(10., 15.);
test_operations_f32(11., 2.);
test_operations_f32(10., 15.);
+ test_operations_f64(1., 2.);
+ test_operations_f64(10., 5.);
+ test_operations_f128(1., 2.);
+ test_operations_f128(10., 5.);
}
fn test_fmuladd() {
use std::intrinsics::{fmuladdf32, fmuladdf64};
+ // FIXME(f16_f128): add when supported
+
#[inline(never)]
pub fn test_operations_f32(a: f32, b: f32, c: f32) {
assert_approx_eq!(unsafe { fmuladdf32(a, b, c) }, a * b + c);
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index d3605cd..3affa19 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -13,3 +13,6 @@
build_helper = { path = "../build_helper" }
serde_json = "1.0"
libc = "0.2"
+
+[lib]
+crate-type = ["lib", "dylib"]
diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index 6b58173..9e09527 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -224,6 +224,12 @@
impl CompletedProcess {
#[must_use]
#[track_caller]
+ pub fn stdout(&self) -> Vec<u8> {
+ self.output.stdout.clone()
+ }
+
+ #[must_use]
+ #[track_caller]
pub fn stdout_utf8(&self) -> String {
String::from_utf8(self.output.stdout.clone()).expect("stdout is not valid UTF-8")
}
@@ -236,11 +242,23 @@
#[must_use]
#[track_caller]
+ pub fn stderr(&self) -> Vec<u8> {
+ self.output.stderr.clone()
+ }
+
+ #[must_use]
+ #[track_caller]
pub fn stderr_utf8(&self) -> String {
String::from_utf8(self.output.stderr.clone()).expect("stderr is not valid UTF-8")
}
#[must_use]
+ #[track_caller]
+ pub fn invalid_stderr_utf8(&self) -> String {
+ String::from_utf8_lossy(&self.output.stderr.clone()).to_string()
+ }
+
+ #[must_use]
pub fn status(&self) -> ExitStatus {
self.output.status
}
diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs
index 38a9ac9..9a6e35d 100644
--- a/src/tools/run-make-support/src/external_deps/llvm.rs
+++ b/src/tools/run-make-support/src/external_deps/llvm.rs
@@ -60,6 +60,18 @@
LlvmPdbutil::new()
}
+/// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available
+/// at `$LLVM_BIN_DIR/llvm-dis`.
+pub fn llvm_dis() -> LlvmDis {
+ LlvmDis::new()
+}
+
+/// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available
+/// at `$LLVM_BIN_DIR/llvm-objcopy`.
+pub fn llvm_objcopy() -> LlvmObjcopy {
+ LlvmObjcopy::new()
+}
+
/// A `llvm-readobj` invocation builder.
#[derive(Debug)]
#[must_use]
@@ -123,6 +135,20 @@
cmd: Command,
}
+/// A `llvm-dis` invocation builder.
+#[derive(Debug)]
+#[must_use]
+pub struct LlvmDis {
+ cmd: Command,
+}
+
+/// A `llvm-objcopy` invocation builder.
+#[derive(Debug)]
+#[must_use]
+pub struct LlvmObjcopy {
+ cmd: Command,
+}
+
crate::macros::impl_common_helpers!(LlvmReadobj);
crate::macros::impl_common_helpers!(LlvmProfdata);
crate::macros::impl_common_helpers!(LlvmFilecheck);
@@ -132,6 +158,8 @@
crate::macros::impl_common_helpers!(LlvmBcanalyzer);
crate::macros::impl_common_helpers!(LlvmDwarfdump);
crate::macros::impl_common_helpers!(LlvmPdbutil);
+crate::macros::impl_common_helpers!(LlvmDis);
+crate::macros::impl_common_helpers!(LlvmObjcopy);
/// Generate the path to the bin directory of LLVM.
#[must_use]
@@ -390,3 +418,41 @@
self
}
}
+
+impl LlvmObjcopy {
+ /// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available
+ /// at `$LLVM_BIN_DIR/llvm-objcopy`.
+ pub fn new() -> Self {
+ let llvm_objcopy = llvm_bin_dir().join("llvm-objcopy");
+ let cmd = Command::new(llvm_objcopy);
+ Self { cmd }
+ }
+
+ /// Dump the contents of `section` into the file at `path`.
+ #[track_caller]
+ pub fn dump_section<S: AsRef<str>, P: AsRef<Path>>(
+ &mut self,
+ section_name: S,
+ path: P,
+ ) -> &mut Self {
+ self.cmd.arg("--dump-section");
+ self.cmd.arg(format!("{}={}", section_name.as_ref(), path.as_ref().to_str().unwrap()));
+ self
+ }
+}
+
+impl LlvmDis {
+ /// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available
+ /// at `$LLVM_BIN_DIR/llvm-dis`.
+ pub fn new() -> Self {
+ let llvm_dis = llvm_bin_dir().join("llvm-dis");
+ let cmd = Command::new(llvm_dis);
+ Self { cmd }
+ }
+
+ /// Provide an input file.
+ pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+ self.cmd.arg(path.as_ref());
+ self
+ }
+}
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 15d813c..368b98c 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -49,14 +49,17 @@
// These rely on external dependencies.
pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc};
-pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_optimized, build_native_static_lib_cxx};
+pub use c_build::{
+ build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx,
+ build_native_static_lib_optimized,
+};
pub use cargo::cargo;
pub use clang::{clang, Clang};
pub use htmldocck::htmldocck;
pub use llvm::{
- llvm_ar, llvm_bcanalyzer, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objdump, llvm_profdata,
- llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDwarfdump, LlvmFilecheck, LlvmNm, LlvmObjdump,
- LlvmProfdata, LlvmReadobj,
+ llvm_ar, llvm_bcanalyzer, llvm_dis, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objcopy,
+ llvm_objdump, llvm_profdata, llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDis, LlvmDwarfdump,
+ LlvmFilecheck, LlvmNm, LlvmObjcopy, LlvmObjdump, LlvmProfdata, LlvmReadobj,
};
pub use python::python_command;
pub use rustc::{aux_build, bare_rustc, rustc, rustc_path, Rustc};
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index 5cf4a8f..d82e460 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -1,14 +1,10 @@
-# Please make sure that the `needs` fields for both `end-success` and `end-failure`
+# Please make sure that the `needs` field for the `conclusion` job
# are updated when adding new jobs!
name: CI
on:
pull_request:
- push:
- branches:
- - auto
- - try
- - automation/bors/try
+ merge_group:
env:
CARGO_INCREMENTAL: 0
@@ -237,20 +233,21 @@
- name: check for typos
run: typos
- end-success:
- name: bors build finished
- if: github.event.pusher.name == 'bors' && success()
- runs-on: ubuntu-latest
+ conclusion:
needs: [rust, rust-cross, typescript, typo-check]
- steps:
- - name: Mark the job as successful
- run: exit 0
-
- end-failure:
- name: bors build finished
- if: github.event.pusher.name == 'bors' && !success()
+ # We need to ensure this job does *not* get skipped if its dependencies fail,
+ # because a skipped job is considered a success by GitHub. So we have to
+ # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
+ # when the workflow is canceled manually.
+ #
+ # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
+ if: ${{ !cancelled() }}
runs-on: ubuntu-latest
- needs: [rust, rust-cross, typescript, typo-check]
steps:
- - name: Mark the job as a failure
- run: exit 1
+ # Manually check the status of all dependencies. `if: failure()` does not work.
+ - name: Conclusion
+ run: |
+ # Print the dependent jobs to see them in the CI log
+ jq -C <<< '${{ toJson(needs) }}'
+ # Check if all jobs that we depend on (in the needs array) were successful.
+ jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
diff --git a/src/tools/rust-analyzer/.gitignore b/src/tools/rust-analyzer/.gitignore
index 68c87a6..c4470a4 100644
--- a/src/tools/rust-analyzer/.gitignore
+++ b/src/tools/rust-analyzer/.gitignore
@@ -1,6 +1,5 @@
-/target/
+target/
/dist/
-crates/*/target
**/*.rs.bk
**/*.rs.pending-snap
.idea/*
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index fd56957..695c37f 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -164,6 +164,7 @@
"rustc-hash 2.0.0",
"syntax",
"syntax-bridge",
+ "tracing",
"tt",
]
@@ -556,6 +557,7 @@
"syntax-bridge",
"test-fixture",
"test-utils",
+ "text-size",
"tracing",
"triomphe",
"tt",
@@ -670,7 +672,6 @@
"syntax",
"test-fixture",
"test-utils",
- "text-edit",
"toolchain",
"tracing",
"triomphe",
@@ -692,7 +693,6 @@
"syntax",
"test-fixture",
"test-utils",
- "text-edit",
"tracing",
]
@@ -711,7 +711,6 @@
"syntax",
"test-fixture",
"test-utils",
- "text-edit",
"tracing",
]
@@ -743,7 +742,6 @@
"syntax",
"test-fixture",
"test-utils",
- "text-edit",
"tracing",
"triomphe",
]
@@ -765,7 +763,6 @@
"syntax",
"test-fixture",
"test-utils",
- "text-edit",
"tracing",
]
@@ -784,7 +781,6 @@
"syntax",
"test-fixture",
"test-utils",
- "text-edit",
"triomphe",
]
@@ -1497,9 +1493,9 @@
[[package]]
name = "ra-ap-rustc_abi"
-version = "0.73.0"
+version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "879ece0781e3c1cb670b9f29775c81a43a16db789d1296fad6bc5c74065b2fac"
+checksum = "d5bc2cfc7264d84215a08875ef90a1d35f76b5c9ad1993515d2da7e4e40b2b4b"
dependencies = [
"bitflags 2.6.0",
"ra-ap-rustc_index",
@@ -1508,9 +1504,9 @@
[[package]]
name = "ra-ap-rustc_index"
-version = "0.73.0"
+version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6910087ff89bb9f3db114bfcd86b5139042731fe7278d3ff4ceaa69a140154a7"
+checksum = "e8929140697812e5dd09e19cf446d85146332363f0dbc125d4214834c34ead96"
dependencies = [
"arrayvec",
"ra-ap-rustc_index_macros",
@@ -1519,9 +1515,9 @@
[[package]]
name = "ra-ap-rustc_index_macros"
-version = "0.73.0"
+version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b6f7bd12b678fbb37444ba77f3b0cfc13b7394a6dc7b0c799491fc9df0a9997"
+checksum = "514a3f5d04c8b4a2750f29746cc9abb1f78deb7e72e4ad1dc95bbc608f3db157"
dependencies = [
"proc-macro2",
"quote",
@@ -1530,9 +1526,9 @@
[[package]]
name = "ra-ap-rustc_lexer"
-version = "0.73.0"
+version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "119bc05b5b6bc3e7f5b67ce8b8080e185da94bd83c447f91b6b3f3ecf60cbab1"
+checksum = "276fcb1205da071a0cd64416f3f0e198043c11f176c5b501a45dbf0cb33979f2"
dependencies = [
"unicode-properties",
"unicode-xid",
@@ -1540,9 +1536,9 @@
[[package]]
name = "ra-ap-rustc_parse_format"
-version = "0.73.0"
+version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ed6150ae71d905c064dc88d7824ebb0fa81083f45d7477cba7b57176f2f635"
+checksum = "961b30b22cfac296b14b72e9f95e79c16cebc8c926872755fb1568a6c4243a62"
dependencies = [
"ra-ap-rustc_index",
"ra-ap-rustc_lexer",
@@ -1550,9 +1546,9 @@
[[package]]
name = "ra-ap-rustc_pattern_analysis"
-version = "0.73.0"
+version = "0.75.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e830862a0ec85fce211d34735315686bb8d6a12d418d6d735fb534aa1cd3293"
+checksum = "614232513814a4b714fea7f11345d31c0c277bca3089bb6ca1ec20870bfc022a"
dependencies = [
"ra-ap-rustc_index",
"rustc-hash 2.0.0",
@@ -1884,9 +1880,9 @@
[[package]]
name = "smol_str"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66eaf762c5af19db3108300515c8aa7a50efc90ff745f4c62288052ebf9fdd25"
+checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d"
dependencies = [
"borsh",
"serde",
@@ -1978,7 +1974,6 @@
"smol_str",
"stdx",
"test-utils",
- "text-edit",
"tracing",
"triomphe",
]
@@ -2027,14 +2022,6 @@
]
[[package]]
-name = "text-edit"
-version = "0.0.0"
-dependencies = [
- "itertools",
- "text-size",
-]
-
-[[package]]
name = "text-size"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 9db62de..3aa93b7 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -4,7 +4,7 @@
resolver = "2"
[workspace.package]
-rust-version = "1.81"
+rust-version = "1.82"
edition = "2021"
license = "MIT OR Apache-2.0"
authors = ["rust-analyzer team"]
@@ -79,17 +79,16 @@
stdx = { path = "./crates/stdx", version = "0.0.0" }
syntax = { path = "./crates/syntax", version = "0.0.0" }
syntax-bridge = { path = "./crates/syntax-bridge", version = "0.0.0" }
-text-edit = { path = "./crates/text-edit", version = "0.0.0" }
toolchain = { path = "./crates/toolchain", version = "0.0.0" }
tt = { path = "./crates/tt", version = "0.0.0" }
vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
vfs = { path = "./crates/vfs", version = "0.0.0" }
-ra-ap-rustc_lexer = { version = "0.73", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.73", default-features = false }
-ra-ap-rustc_index = { version = "0.73", default-features = false }
-ra-ap-rustc_abi = { version = "0.73", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.73", default-features = false }
+ra-ap-rustc_lexer = { version = "0.75", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.75", default-features = false }
+ra-ap-rustc_index = { version = "0.75", default-features = false }
+ra-ap-rustc_abi = { version = "0.75", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.75", default-features = false }
# local crates that aren't published to crates.io. These should not have versions.
test-fixture = { path = "./crates/test-fixture" }
@@ -145,7 +144,7 @@
"union",
"const_generics",
] }
-smol_str = "0.3.1"
+smol_str = "0.3.2"
snap = "1.1.0"
text-size = "1.1.1"
tracing = "0.1.40"
diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
index 29b7ad6..040bddbd 100644
--- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
@@ -14,6 +14,7 @@
[dependencies]
rustc-hash.workspace = true
+tracing.workspace = true
# locals deps
tt = { workspace = true, optional = true }
diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
index c2d4008..6a6213a 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
@@ -9,7 +9,7 @@
use rustc_hash::FxHashSet;
-use intern::Symbol;
+use intern::{sym, Symbol};
pub use cfg_expr::{CfgAtom, CfgExpr};
pub use dnf::DnfExpr;
@@ -24,11 +24,17 @@
/// of key and value in `key_values`.
///
/// See: <https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options>
-#[derive(Clone, PartialEq, Eq, Default)]
+#[derive(Clone, PartialEq, Eq)]
pub struct CfgOptions {
enabled: FxHashSet<CfgAtom>,
}
+impl Default for CfgOptions {
+ fn default() -> Self {
+ Self { enabled: FxHashSet::from_iter([CfgAtom::Flag(sym::true_.clone())]) }
+ }
+}
+
impl fmt::Debug for CfgOptions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut items = self
@@ -54,23 +60,37 @@
}
pub fn insert_atom(&mut self, key: Symbol) {
- self.enabled.insert(CfgAtom::Flag(key));
+ self.insert_any_atom(CfgAtom::Flag(key));
}
pub fn insert_key_value(&mut self, key: Symbol, value: Symbol) {
- self.enabled.insert(CfgAtom::KeyValue { key, value });
+ self.insert_any_atom(CfgAtom::KeyValue { key, value });
}
pub fn apply_diff(&mut self, diff: CfgDiff) {
for atom in diff.enable {
- self.enabled.insert(atom);
+ self.insert_any_atom(atom);
}
for atom in diff.disable {
+ let (CfgAtom::Flag(sym) | CfgAtom::KeyValue { key: sym, .. }) = &atom;
+ if *sym == sym::true_ || *sym == sym::false_ {
+ tracing::error!("cannot remove `true` or `false` from cfg");
+ continue;
+ }
self.enabled.remove(&atom);
}
}
+ fn insert_any_atom(&mut self, atom: CfgAtom) {
+ let (CfgAtom::Flag(sym) | CfgAtom::KeyValue { key: sym, .. }) = &atom;
+ if *sym == sym::true_ || *sym == sym::false_ {
+ tracing::error!("cannot insert `true` or `false` to cfg");
+ return;
+ }
+ self.enabled.insert(atom);
+ }
+
pub fn get_cfg_keys(&self) -> impl Iterator<Item = &Symbol> {
self.enabled.iter().map(|it| match it {
CfgAtom::Flag(key) => key,
@@ -88,7 +108,7 @@
impl Extend<CfgAtom> for CfgOptions {
fn extend<T: IntoIterator<Item = CfgAtom>>(&mut self, iter: T) {
- iter.into_iter().for_each(|cfg_flag| _ = self.enabled.insert(cfg_flag));
+ iter.into_iter().for_each(|cfg_flag| self.insert_any_atom(cfg_flag));
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index c8ba5da..375f18d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -29,6 +29,7 @@
hashbrown.workspace = true
triomphe.workspace = true
rustc_apfloat = "0.2.0"
+text-size.workspace = true
ra-ap-rustc_parse_format.workspace = true
ra-ap-rustc_abi.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index 9535b5a..5a386f6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -10,6 +10,7 @@
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
+use either::Either;
use hir_expand::{name::Name, ExpandError, InFile};
use la_arena::{Arena, ArenaMap, Idx, RawIdx};
use rustc_hash::FxHashMap;
@@ -22,15 +23,33 @@
db::DefDatabase,
expander::Expander,
hir::{
- dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat,
+ dummy_expr_id, Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label,
+ LabelId, Pat, PatId, RecordFieldPat, Statement,
},
item_tree::AttrOwner,
nameres::DefMap,
path::{ModPath, Path},
src::HasSource,
+ type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap},
BlockId, DefWithBodyId, HasModule, Lookup,
};
+/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct HygieneId(pub(crate) span::SyntaxContextId);
+
+impl HygieneId {
+ pub const ROOT: Self = Self(span::SyntaxContextId::ROOT);
+
+ pub fn new(ctx: span::SyntaxContextId) -> Self {
+ Self(ctx)
+ }
+
+ pub(crate) fn is_root(self) -> bool {
+ self.0.is_root()
+ }
+}
+
/// The body of an item (function, const etc.).
#[derive(Debug, Eq, PartialEq)]
pub struct Body {
@@ -51,8 +70,25 @@
pub self_param: Option<BindingId>,
/// The `ExprId` of the actual body expression.
pub body_expr: ExprId,
+ pub types: TypesMap,
/// Block expressions in this body that may contain inner items.
block_scopes: Vec<BlockId>,
+
+ /// A map from binding to its hygiene ID.
+ ///
+ /// Bindings that don't come from macro expansion are not allocated to save space, so not all bindings appear here.
+ /// If a binding does not appear here it has `SyntaxContextId::ROOT`.
+ ///
+ /// Note that this may not be the direct `SyntaxContextId` of the binding's expansion, because transparent
+ /// expansions are attributed to their parent expansion (recursively).
+ binding_hygiene: FxHashMap<BindingId, HygieneId>,
+ /// A map from an variable usages to their hygiene ID.
+ ///
+ /// Expressions that can be recorded here are single segment path, although not all single segments path refer
+ /// to variables and have hygiene (some refer to items, we don't know at this stage).
+ expr_hygiene: FxHashMap<ExprId, HygieneId>,
+ /// A map from a destructuring assignment possible variable usages to their hygiene ID.
+ pat_hygiene: FxHashMap<PatId, HygieneId>,
}
pub type ExprPtr = AstPtr<ast::Expr>;
@@ -67,9 +103,12 @@
pub type FieldPtr = AstPtr<ast::RecordExprField>;
pub type FieldSource = InFile<FieldPtr>;
-pub type PatFieldPtr = AstPtr<ast::RecordPatField>;
+pub type PatFieldPtr = AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>;
pub type PatFieldSource = InFile<PatFieldPtr>;
+pub type ExprOrPatPtr = AstPtr<Either<ast::Expr, ast::Pat>>;
+pub type ExprOrPatSource = InFile<ExprOrPatPtr>;
+
/// An item body together with the mapping from syntax nodes to HIR expression
/// IDs. This is needed to go from e.g. a position in a file to the HIR
/// expression containing it; but for type inference etc., we want to operate on
@@ -83,11 +122,13 @@
/// this properly for macros.
#[derive(Default, Debug, Eq, PartialEq)]
pub struct BodySourceMap {
- expr_map: FxHashMap<ExprSource, ExprId>,
+ // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
+ // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
+ expr_map: FxHashMap<ExprSource, ExprOrPatId>,
expr_map_back: ArenaMap<ExprId, ExprSource>,
pat_map: FxHashMap<PatSource, PatId>,
- pat_map_back: ArenaMap<PatId, PatSource>,
+ pat_map_back: ArenaMap<PatId, ExprOrPatSource>,
label_map: FxHashMap<LabelSource, LabelId>,
label_map_back: ArenaMap<LabelId, LabelSource>,
@@ -100,10 +141,13 @@
field_map_back: FxHashMap<ExprId, FieldSource>,
pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
+ types: TypesSourceMap,
+
+ // FIXME: Make this a sane struct.
template_map: Option<
Box<(
// format_args!
- FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,
+ FxHashMap<ExprId, (HygieneId, Vec<(syntax::TextRange, Name)>)>,
// asm!
FxHashMap<ExprId, Vec<Vec<(syntax::TextRange, usize)>>>,
)>,
@@ -261,6 +305,10 @@
pats,
bindings,
binding_owners,
+ binding_hygiene,
+ expr_hygiene,
+ pat_hygiene,
+ types,
} = self;
block_scopes.shrink_to_fit();
exprs.shrink_to_fit();
@@ -268,6 +316,10 @@
pats.shrink_to_fit();
bindings.shrink_to_fit();
binding_owners.shrink_to_fit();
+ binding_hygiene.shrink_to_fit();
+ expr_hygiene.shrink_to_fit();
+ pat_hygiene.shrink_to_fit();
+ types.shrink_to_fit();
}
pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
@@ -286,7 +338,8 @@
| Pat::Path(..)
| Pat::ConstBlock(..)
| Pat::Wild
- | Pat::Missing => {}
+ | Pat::Missing
+ | Pat::Expr(_) => {}
&Pat::Bind { subpat, .. } => {
if let Some(subpat) = subpat {
f(subpat);
@@ -322,6 +375,162 @@
None => true,
}
}
+
+ pub fn walk_child_exprs(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) {
+ let expr = &self[expr_id];
+ match expr {
+ Expr::Continue { .. }
+ | Expr::Const(_)
+ | Expr::Missing
+ | Expr::Path(_)
+ | Expr::OffsetOf(_)
+ | Expr::Literal(_)
+ | Expr::Underscore => {}
+ Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
+ AsmOperand::In { expr, .. }
+ | AsmOperand::Out { expr: Some(expr), .. }
+ | AsmOperand::InOut { expr, .. } => f(*expr),
+ AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
+ f(*in_expr);
+ if let Some(out_expr) = out_expr {
+ f(*out_expr);
+ }
+ }
+ AsmOperand::Out { expr: None, .. }
+ | AsmOperand::Const(_)
+ | AsmOperand::Label(_)
+ | AsmOperand::Sym(_) => (),
+ }),
+ Expr::If { condition, then_branch, else_branch } => {
+ f(*condition);
+ f(*then_branch);
+ if let &Some(else_branch) = else_branch {
+ f(else_branch);
+ }
+ }
+ Expr::Let { expr, .. } => {
+ f(*expr);
+ }
+ Expr::Block { statements, tail, .. }
+ | Expr::Unsafe { statements, tail, .. }
+ | Expr::Async { statements, tail, .. } => {
+ for stmt in statements.iter() {
+ match stmt {
+ Statement::Let { initializer, else_branch, pat, .. } => {
+ if let &Some(expr) = initializer {
+ f(expr);
+ }
+ if let &Some(expr) = else_branch {
+ f(expr);
+ }
+ self.walk_exprs_in_pat(*pat, &mut f);
+ }
+ Statement::Expr { expr: expression, .. } => f(*expression),
+ Statement::Item(_) => (),
+ }
+ }
+ if let &Some(expr) = tail {
+ f(expr);
+ }
+ }
+ Expr::Loop { body, .. } => f(*body),
+ Expr::Call { callee, args, .. } => {
+ f(*callee);
+ args.iter().copied().for_each(f);
+ }
+ Expr::MethodCall { receiver, args, .. } => {
+ f(*receiver);
+ args.iter().copied().for_each(f);
+ }
+ Expr::Match { expr, arms } => {
+ f(*expr);
+ arms.iter().map(|arm| arm.expr).for_each(f);
+ }
+ Expr::Break { expr, .. }
+ | Expr::Return { expr }
+ | Expr::Yield { expr }
+ | Expr::Yeet { expr } => {
+ if let &Some(expr) = expr {
+ f(expr);
+ }
+ }
+ Expr::Become { expr } => f(*expr),
+ Expr::RecordLit { fields, spread, .. } => {
+ for field in fields.iter() {
+ f(field.expr);
+ }
+ if let &Some(expr) = spread {
+ f(expr);
+ }
+ }
+ Expr::Closure { body, .. } => {
+ f(*body);
+ }
+ Expr::BinaryOp { lhs, rhs, .. } => {
+ f(*lhs);
+ f(*rhs);
+ }
+ Expr::Range { lhs, rhs, .. } => {
+ if let &Some(lhs) = rhs {
+ f(lhs);
+ }
+ if let &Some(rhs) = lhs {
+ f(rhs);
+ }
+ }
+ Expr::Index { base, index, .. } => {
+ f(*base);
+ f(*index);
+ }
+ Expr::Field { expr, .. }
+ | Expr::Await { expr }
+ | Expr::Cast { expr, .. }
+ | Expr::Ref { expr, .. }
+ | Expr::UnaryOp { expr, .. }
+ | Expr::Box { expr } => {
+ f(*expr);
+ }
+ Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
+ Expr::Array(a) => match a {
+ Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
+ Array::Repeat { initializer, repeat } => {
+ f(*initializer);
+ f(*repeat)
+ }
+ },
+ &Expr::Assignment { target, value } => {
+ self.walk_exprs_in_pat(target, &mut f);
+ f(value);
+ }
+ }
+ }
+
+ pub fn walk_exprs_in_pat(&self, pat_id: PatId, f: &mut impl FnMut(ExprId)) {
+ self.walk_pats(pat_id, &mut |pat| {
+ if let Pat::Expr(expr) | Pat::ConstBlock(expr) = self[pat] {
+ f(expr);
+ }
+ });
+ }
+
+ fn binding_hygiene(&self, binding: BindingId) -> HygieneId {
+ self.binding_hygiene.get(&binding).copied().unwrap_or(HygieneId::ROOT)
+ }
+
+ pub fn expr_path_hygiene(&self, expr: ExprId) -> HygieneId {
+ self.expr_hygiene.get(&expr).copied().unwrap_or(HygieneId::ROOT)
+ }
+
+ pub fn pat_path_hygiene(&self, pat: PatId) -> HygieneId {
+ self.pat_hygiene.get(&pat).copied().unwrap_or(HygieneId::ROOT)
+ }
+
+ pub fn expr_or_pat_path_hygiene(&self, id: ExprOrPatId) -> HygieneId {
+ match id {
+ ExprOrPatId::ExprId(id) => self.expr_path_hygiene(id),
+ ExprOrPatId::PatId(id) => self.pat_path_hygiene(id),
+ }
+ }
}
impl Default for Body {
@@ -336,6 +545,10 @@
block_scopes: Default::default(),
binding_owners: Default::default(),
self_param: Default::default(),
+ binding_hygiene: Default::default(),
+ expr_hygiene: Default::default(),
+ pat_hygiene: Default::default(),
+ types: Default::default(),
}
}
}
@@ -372,14 +585,29 @@
}
}
+impl Index<TypeRefId> for Body {
+ type Output = TypeRef;
+
+ fn index(&self, b: TypeRefId) -> &TypeRef {
+ &self.types[b]
+ }
+}
+
// FIXME: Change `node_` prefix to something more reasonable.
// Perhaps `expr_syntax` and `expr_id`?
impl BodySourceMap {
+ pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
+ match id {
+ ExprOrPatId::ExprId(id) => self.expr_syntax(id).map(|it| it.map(AstPtr::wrap_left)),
+ ExprOrPatId::PatId(id) => self.pat_syntax(id),
+ }
+ }
+
pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
}
- pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
+ pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprOrPatId> {
let src = node.map(AstPtr::new);
self.expr_map.get(&src).cloned()
}
@@ -395,7 +623,7 @@
self.expansions.iter().map(|(&a, &b)| (a, b))
}
- pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
+ pub fn pat_syntax(&self, pat: PatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
}
@@ -428,7 +656,7 @@
self.pat_field_map_back[&pat]
}
- pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprId> {
+ pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprOrPatId> {
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::MacroExpr>).map(AstPtr::upcast);
self.expr_map.get(&src).copied()
}
@@ -442,9 +670,11 @@
pub fn implicit_format_args(
&self,
node: InFile<&ast::FormatArgsExpr>,
- ) -> Option<&[(syntax::TextRange, Name)]> {
+ ) -> Option<(HygieneId, &[(syntax::TextRange, Name)])> {
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
- self.template_map.as_ref()?.0.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref)
+ let (hygiene, names) =
+ self.template_map.as_ref()?.0.get(&self.expr_map.get(&src)?.as_expr()?)?;
+ Some((*hygiene, &**names))
}
pub fn asm_template_args(
@@ -452,8 +682,8 @@
node: InFile<&ast::AsmExpr>,
) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> {
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
- let expr = self.expr_map.get(&src)?;
- Some(*expr).zip(self.template_map.as_ref()?.1.get(expr).map(std::ops::Deref::deref))
+ let expr = self.expr_map.get(&src)?.as_expr()?;
+ Some(expr).zip(self.template_map.as_ref()?.1.get(&expr).map(std::ops::Deref::deref))
}
/// Get a reference to the body source map's diagnostics.
@@ -476,6 +706,7 @@
template_map,
diagnostics,
binding_definitions,
+ types,
} = self;
if let Some(template_map) = template_map {
template_map.0.shrink_to_fit();
@@ -492,14 +723,6 @@
expansions.shrink_to_fit();
diagnostics.shrink_to_fit();
binding_definitions.shrink_to_fit();
- }
-
- pub fn template_map(
- &self,
- ) -> Option<&(
- FxHashMap<Idx<Expr>, Vec<(tt::TextRange, Name)>>,
- FxHashMap<Idx<Expr>, Vec<Vec<(tt::TextRange, usize)>>>,
- )> {
- self.template_map.as_deref()
+ types.shrink_to_fit();
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 9c54757..0b108b5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -9,9 +9,10 @@
use either::Either;
use hir_expand::{
name::{AsName, Name},
- InFile,
+ span_map::{ExpansionSpanMap, SpanMap},
+ InFile, MacroDefId,
};
-use intern::{sym, Interned, Symbol};
+use intern::{sym, Symbol};
use rustc_hash::FxHashMap;
use span::AstIdMap;
use stdx::never;
@@ -22,10 +23,11 @@
},
AstNode, AstPtr, AstToken as _, SyntaxNodePtr,
};
+use text_size::TextSize;
use triomphe::Arc;
use crate::{
- body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr},
+ body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, HygieneId, LabelPtr, PatPtr},
builtin_type::BuiltinUint,
data::adt::StructKind,
db::DefDatabase,
@@ -37,8 +39,8 @@
FormatPlaceholder, FormatSign, FormatTrait,
},
Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,
- Expr, ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability, OffsetOf, Pat,
- PatId, RecordFieldPat, RecordLitField, Statement,
+ Expr, ExprId, Item, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
+ OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
},
item_scope::BuiltinShadowMode,
lang_item::LangItem,
@@ -46,7 +48,7 @@
nameres::{DefMap, MacroSubNs},
path::{GenericArgs, Path},
type_ref::{Mutability, Rawness, TypeRef},
- AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro,
+ AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, MacroId, ModuleDefId, UnresolvedMacro,
};
type FxIndexSet<K> = indexmap::IndexSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
@@ -60,6 +62,17 @@
krate: CrateId,
is_async_fn: bool,
) -> (Body, BodySourceMap) {
+ // We cannot leave the root span map empty and let any identifier from it be treated as root,
+ // because when inside nested macros `SyntaxContextId`s from the outer macro will be interleaved
+ // with the inner macro, and that will cause confusion because they won't be the same as `ROOT`
+ // even though they should be the same. Also, when the body comes from multiple expansions, their
+ // hygiene is different.
+ let span_map = expander.current_file_id().macro_file().map(|_| {
+ let SpanMap::ExpansionSpanMap(span_map) = expander.span_map(db) else {
+ panic!("in a macro file there should be `ExpansionSpanMap`");
+ };
+ Arc::clone(span_map)
+ });
ExprCollector {
db,
owner,
@@ -70,11 +83,12 @@
body: Body::default(),
expander,
current_try_block_label: None,
- is_lowering_assignee_expr: false,
is_lowering_coroutine: false,
label_ribs: Vec::new(),
current_binding_owner: None,
awaitable_context: None,
+ current_span_map: span_map,
+ current_block_legacy_macro_defs_count: FxHashMap::default(),
}
.collect(params, body, is_async_fn)
}
@@ -89,9 +103,14 @@
body: Body,
source_map: BodySourceMap,
- is_lowering_assignee_expr: bool,
is_lowering_coroutine: bool,
+ /// Legacy (`macro_rules!`) macros can have multiple definitions and shadow each other,
+ /// and we need to find the current definition. So we track the number of definitions we saw.
+ current_block_legacy_macro_defs_count: FxHashMap<Name, usize>,
+
+ current_span_map: Option<Arc<ExpansionSpanMap>>,
+
current_try_block_label: Option<LabelId>,
// points to the expression that a try expression will target (replaces current_try_block_label)
// catch_scope: Option<ExprId>,
@@ -110,31 +129,27 @@
#[derive(Clone, Debug)]
struct LabelRib {
kind: RibKind,
- // Once we handle macro hygiene this will need to be a map
- label: Option<(Name, LabelId)>,
}
impl LabelRib {
fn new(kind: RibKind) -> Self {
- LabelRib { kind, label: None }
- }
- fn new_normal(label: (Name, LabelId)) -> Self {
- LabelRib { kind: RibKind::Normal, label: Some(label) }
+ LabelRib { kind }
}
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
enum RibKind {
- Normal,
+ Normal(Name, LabelId, HygieneId),
Closure,
Constant,
+ MacroDef(Box<MacroDefId>),
}
impl RibKind {
/// This rib forbids referring to labels defined in upwards ribs.
- fn is_label_barrier(self) -> bool {
+ fn is_label_barrier(&self) -> bool {
match self {
- RibKind::Normal => false,
+ RibKind::Normal(..) | RibKind::MacroDef(_) => false,
RibKind::Closure | RibKind::Constant => true,
}
}
@@ -147,7 +162,7 @@
#[derive(Debug, Default)]
struct BindingList {
- map: FxHashMap<Name, BindingId>,
+ map: FxHashMap<(Name, HygieneId), BindingId>,
is_used: FxHashMap<BindingId, bool>,
reject_new: bool,
}
@@ -157,9 +172,16 @@
&mut self,
ec: &mut ExprCollector<'_>,
name: Name,
+ hygiene: HygieneId,
mode: BindingAnnotation,
) -> BindingId {
- let id = *self.map.entry(name).or_insert_with_key(|n| ec.alloc_binding(n.clone(), mode));
+ let id = *self.map.entry((name, hygiene)).or_insert_with_key(|(name, _)| {
+ let id = ec.alloc_binding(name.clone(), mode);
+ if !hygiene.is_root() {
+ ec.body.binding_hygiene.insert(id, hygiene);
+ }
+ id
+ });
if ec.body.bindings[id].mode != mode {
ec.body.bindings[id].problems = Some(BindingProblems::BoundInconsistently);
}
@@ -213,6 +235,13 @@
Name::new_symbol_root(sym::self_.clone()),
BindingAnnotation::new(is_mutable, false),
);
+ let hygiene = self_param
+ .name()
+ .map(|name| self.hygiene_id_for(name.syntax().text_range().start()))
+ .unwrap_or(HygieneId::ROOT);
+ if !hygiene.is_root() {
+ self.body.binding_hygiene.insert(binding_id, hygiene);
+ }
self.body.self_param = Some(binding_id);
self.source_map.self_param = Some(self.expander.in_file(AstPtr::new(&self_param)));
}
@@ -245,8 +274,8 @@
(self.body, self.source_map)
}
- fn ctx(&self) -> LowerCtx<'_> {
- self.expander.ctx(self.db)
+ fn ctx(&mut self) -> LowerCtx<'_> {
+ self.expander.ctx(self.db, &mut self.body.types, &mut self.source_map.types)
}
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
@@ -290,13 +319,14 @@
})
}
Some(ast::BlockModifier::Label(label)) => {
- let label = self.collect_label(label);
- self.with_labeled_rib(label, |this| {
+ let label_hygiene = self.hygiene_id_for(label.syntax().text_range().start());
+ let label_id = self.collect_label(label);
+ self.with_labeled_rib(label_id, label_hygiene, |this| {
this.collect_block_(e, |id, statements, tail| Expr::Block {
id,
statements,
tail,
- label: Some(label),
+ label: Some(label_id),
})
})
}
@@ -338,9 +368,14 @@
None => self.collect_block(e),
},
ast::Expr::LoopExpr(e) => {
- let label = e.label().map(|label| self.collect_label(label));
+ let label = e.label().map(|label| {
+ (
+ self.hygiene_id_for(label.syntax().text_range().start()),
+ self.collect_label(label),
+ )
+ });
let body = self.collect_labelled_block_opt(label, e.loop_body());
- self.alloc_expr(Expr::Loop { body, label }, syntax_ptr)
+ self.alloc_expr(Expr::Loop { body, label: label.map(|it| it.1) }, syntax_ptr)
}
ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e),
ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),
@@ -359,14 +394,7 @@
} else {
Box::default()
};
- self.alloc_expr(
- Expr::Call {
- callee,
- args,
- is_assignee_expr: self.is_lowering_assignee_expr,
- },
- syntax_ptr,
- )
+ self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
}
}
ast::Expr::MethodCallExpr(e) => {
@@ -407,12 +435,15 @@
self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
}
ast::Expr::PathExpr(e) => {
- let path = e
- .path()
- .and_then(|path| self.expander.parse_path(self.db, path))
- .map(Expr::Path)
- .unwrap_or(Expr::Missing);
- self.alloc_expr(path, syntax_ptr)
+ let (path, hygiene) = self
+ .collect_expr_path(e)
+ .map(|(path, hygiene)| (Expr::Path(path), hygiene))
+ .unwrap_or((Expr::Missing, HygieneId::ROOT));
+ let expr_id = self.alloc_expr(path, syntax_ptr);
+ if !hygiene.is_root() {
+ self.body.expr_hygiene.insert(expr_id, hygiene);
+ }
+ expr_id
}
ast::Expr::ContinueExpr(e) => {
let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
@@ -433,7 +464,7 @@
let inner = self.collect_expr_opt(e.expr());
// make the paren expr point to the inner expression as well for IDE resolution
let src = self.expander.in_file(syntax_ptr);
- self.source_map.expr_map.insert(src, inner);
+ self.source_map.expr_map.insert(src, inner.into());
inner
}
ast::Expr::ReturnExpr(e) => {
@@ -455,9 +486,7 @@
self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)
}
ast::Expr::RecordExpr(e) => {
- let path =
- e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
- let is_assignee_expr = self.is_lowering_assignee_expr;
+ let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new);
let record_lit = if let Some(nfl) = e.record_expr_field_list() {
let fields = nfl
.fields()
@@ -476,16 +505,9 @@
})
.collect();
let spread = nfl.spread().map(|s| self.collect_expr(s));
- let ellipsis = nfl.dotdot_token().is_some();
- Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr }
+ Expr::RecordLit { path, fields, spread }
} else {
- Expr::RecordLit {
- path,
- fields: Box::default(),
- spread: None,
- ellipsis: false,
- is_assignee_expr,
- }
+ Expr::RecordLit { path, fields: Box::default(), spread: None }
};
self.alloc_expr(record_lit, syntax_ptr)
@@ -511,7 +533,7 @@
ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
ast::Expr::CastExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
- let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
+ let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty());
self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
}
ast::Expr::RefExpr(e) => {
@@ -550,16 +572,13 @@
arg_types.reserve_exact(num_params);
for param in pl.params() {
let pat = this.collect_pat_top(param.pat());
- let type_ref =
- param.ty().map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
+ let type_ref = param.ty().map(|it| TypeRef::from_ast(&this.ctx(), it));
args.push(pat);
arg_types.push(type_ref);
}
}
- let ret_type = e
- .ret_type()
- .and_then(|r| r.ty())
- .map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
+ let ret_type =
+ e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&this.ctx(), it));
let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
let prev_try_block_label = this.current_try_block_label.take();
@@ -602,12 +621,14 @@
ast::Expr::BinExpr(e) => {
let op = e.op_kind();
if let Some(ast::BinaryOp::Assignment { op: None }) = op {
- self.is_lowering_assignee_expr = true;
+ let target = self.collect_expr_as_pat_opt(e.lhs());
+ let value = self.collect_expr_opt(e.rhs());
+ self.alloc_expr(Expr::Assignment { target, value }, syntax_ptr)
+ } else {
+ let lhs = self.collect_expr_opt(e.lhs());
+ let rhs = self.collect_expr_opt(e.rhs());
+ self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
}
- let lhs = self.collect_expr_opt(e.lhs());
- self.is_lowering_assignee_expr = false;
- let rhs = self.collect_expr_opt(e.rhs());
- self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
}
ast::Expr::TupleExpr(e) => {
let mut exprs: Vec<_> = e.fields().map(|expr| self.collect_expr(expr)).collect();
@@ -617,13 +638,7 @@
exprs.insert(0, self.missing_expr());
}
- self.alloc_expr(
- Expr::Tuple {
- exprs: exprs.into_boxed_slice(),
- is_assignee_expr: self.is_lowering_assignee_expr,
- },
- syntax_ptr,
- )
+ self.alloc_expr(Expr::Tuple { exprs: exprs.into_boxed_slice() }, syntax_ptr)
}
ast::Expr::ArrayExpr(e) => {
let kind = e.kind();
@@ -631,13 +646,7 @@
match kind {
ArrayExprKind::ElementList(e) => {
let elements = e.map(|expr| self.collect_expr(expr)).collect();
- self.alloc_expr(
- Expr::Array(Array::ElementList {
- elements,
- is_assignee_expr: self.is_lowering_assignee_expr,
- }),
- syntax_ptr,
- )
+ self.alloc_expr(Expr::Array(Array::ElementList { elements }), syntax_ptr)
}
ArrayExprKind::Repeat { initializer, repeat } => {
let initializer = self.collect_expr_opt(initializer);
@@ -664,8 +673,7 @@
ast::Expr::IndexExpr(e) => {
let base = self.collect_expr_opt(e.base());
let index = self.collect_expr_opt(e.index());
- let is_assignee_expr = self.is_lowering_assignee_expr;
- self.alloc_expr(Expr::Index { base, index, is_assignee_expr }, syntax_ptr)
+ self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
}
ast::Expr::RangeExpr(e) => {
let lhs = e.start().map(|lhs| self.collect_expr(lhs));
@@ -688,7 +696,7 @@
// Make the macro-call point to its expanded expression so we can query
// semantics on syntax pointers to the macro
let src = self.expander.in_file(syntax_ptr);
- self.source_map.expr_map.insert(src, id);
+ self.source_map.expr_map.insert(src, id.into());
id
}
None => self.alloc_expr(Expr::Missing, syntax_ptr),
@@ -697,7 +705,7 @@
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr),
ast::Expr::OffsetOfExpr(e) => {
- let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
+ let container = TypeRef::from_ast_opt(&self.ctx(), e.ty());
let fields = e.fields().map(|it| it.as_name()).collect();
self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
}
@@ -705,6 +713,200 @@
})
}
+ fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
+ self.expander.parse_path(self.db, path, &mut self.body.types, &mut self.source_map.types)
+ }
+
+ fn collect_expr_path(&mut self, e: ast::PathExpr) -> Option<(Path, HygieneId)> {
+ e.path().and_then(|path| {
+ let path = self.parse_path(path)?;
+ // Need to enable `mod_path.len() < 1` for `self`.
+ let may_be_variable = matches!(&path, Path::BarePath(mod_path) if mod_path.len() <= 1);
+ let hygiene = if may_be_variable {
+ self.hygiene_id_for(e.syntax().text_range().start())
+ } else {
+ HygieneId::ROOT
+ };
+ Some((path, hygiene))
+ })
+ }
+
+ fn collect_expr_as_pat_opt(&mut self, expr: Option<ast::Expr>) -> PatId {
+ match expr {
+ Some(expr) => self.collect_expr_as_pat(expr),
+ _ => self.missing_pat(),
+ }
+ }
+
+ fn collect_expr_as_pat(&mut self, expr: ast::Expr) -> PatId {
+ self.maybe_collect_expr_as_pat(&expr).unwrap_or_else(|| {
+ let src = self.expander.in_file(AstPtr::new(&expr).wrap_left());
+ let expr = self.collect_expr(expr);
+ // Do not use `alloc_pat_from_expr()` here, it will override the entry in `expr_map`.
+ let id = self.body.pats.alloc(Pat::Expr(expr));
+ self.source_map.pat_map_back.insert(id, src);
+ id
+ })
+ }
+
+ fn maybe_collect_expr_as_pat(&mut self, expr: &ast::Expr) -> Option<PatId> {
+ self.check_cfg(expr)?;
+ let syntax_ptr = AstPtr::new(expr);
+
+ let result = match expr {
+ ast::Expr::UnderscoreExpr(_) => self.alloc_pat_from_expr(Pat::Wild, syntax_ptr),
+ ast::Expr::ParenExpr(e) => {
+ // We special-case `(..)` for consistency with patterns.
+ if let Some(ast::Expr::RangeExpr(range)) = e.expr() {
+ if range.is_range_full() {
+ return Some(self.alloc_pat_from_expr(
+ Pat::Tuple { args: Box::default(), ellipsis: Some(0) },
+ syntax_ptr,
+ ));
+ }
+ }
+ return e.expr().and_then(|expr| self.maybe_collect_expr_as_pat(&expr));
+ }
+ ast::Expr::TupleExpr(e) => {
+ let (ellipsis, args) = collect_tuple(self, e.fields());
+ self.alloc_pat_from_expr(Pat::Tuple { args, ellipsis }, syntax_ptr)
+ }
+ ast::Expr::ArrayExpr(e) => {
+ if e.semicolon_token().is_some() {
+ return None;
+ }
+
+ let mut elements = e.exprs();
+ let prefix = elements
+ .by_ref()
+ .map_while(|elem| collect_possibly_rest(self, elem).left())
+ .collect();
+ let suffix = elements.map(|elem| self.collect_expr_as_pat(elem)).collect();
+ self.alloc_pat_from_expr(Pat::Slice { prefix, slice: None, suffix }, syntax_ptr)
+ }
+ ast::Expr::CallExpr(e) => {
+ let path = collect_path(self, e.expr()?)?;
+ let path = path.path().and_then(|path| self.parse_path(path)).map(Box::new);
+ let (ellipsis, args) = collect_tuple(self, e.arg_list()?.args());
+ self.alloc_pat_from_expr(Pat::TupleStruct { path, args, ellipsis }, syntax_ptr)
+ }
+ ast::Expr::PathExpr(e) => {
+ let (path, hygiene) = self
+ .collect_expr_path(e.clone())
+ .map(|(path, hygiene)| (Pat::Path(path), hygiene))
+ .unwrap_or((Pat::Missing, HygieneId::ROOT));
+ let pat_id = self.alloc_pat_from_expr(path, syntax_ptr);
+ if !hygiene.is_root() {
+ self.body.pat_hygiene.insert(pat_id, hygiene);
+ }
+ pat_id
+ }
+ ast::Expr::MacroExpr(e) => {
+ let e = e.macro_call()?;
+ let macro_ptr = AstPtr::new(&e);
+ let src = self.expander.in_file(AstPtr::new(expr));
+ let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
+ this.collect_expr_as_pat_opt(expansion)
+ });
+ self.source_map.expr_map.insert(src, id.into());
+ id
+ }
+ ast::Expr::RecordExpr(e) => {
+ let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new);
+ let record_field_list = e.record_expr_field_list()?;
+ let ellipsis = record_field_list.dotdot_token().is_some();
+ // FIXME: Report an error here if `record_field_list.spread().is_some()`.
+ let args = record_field_list
+ .fields()
+ .filter_map(|f| {
+ self.check_cfg(&f)?;
+ let field_expr = f.expr()?;
+ let pat = self.collect_expr_as_pat(field_expr);
+ let name = f.field_name()?.as_name();
+ let src = self.expander.in_file(AstPtr::new(&f).wrap_left());
+ self.source_map.pat_field_map_back.insert(pat, src);
+ Some(RecordFieldPat { name, pat })
+ })
+ .collect();
+ self.alloc_pat_from_expr(Pat::Record { path, args, ellipsis }, syntax_ptr)
+ }
+ _ => return None,
+ };
+ return Some(result);
+
+ fn collect_path(this: &mut ExprCollector<'_>, expr: ast::Expr) -> Option<ast::PathExpr> {
+ match expr {
+ ast::Expr::PathExpr(e) => Some(e),
+ ast::Expr::MacroExpr(mac) => {
+ let call = mac.macro_call()?;
+ {
+ let macro_ptr = AstPtr::new(&call);
+ this.collect_macro_call(call, macro_ptr, true, |this, expanded_path| {
+ collect_path(this, expanded_path?)
+ })
+ }
+ }
+ _ => None,
+ }
+ }
+
+ fn collect_possibly_rest(
+ this: &mut ExprCollector<'_>,
+ expr: ast::Expr,
+ ) -> Either<PatId, ()> {
+ match &expr {
+ ast::Expr::RangeExpr(e) if e.is_range_full() => Either::Right(()),
+ ast::Expr::MacroExpr(mac) => match mac.macro_call() {
+ Some(call) => {
+ let macro_ptr = AstPtr::new(&call);
+ let pat = this.collect_macro_call(
+ call,
+ macro_ptr,
+ true,
+ |this, expanded_expr| match expanded_expr {
+ Some(expanded_pat) => collect_possibly_rest(this, expanded_pat),
+ None => Either::Left(this.missing_pat()),
+ },
+ );
+ if let Either::Left(pat) = pat {
+ let src = this.expander.in_file(AstPtr::new(&expr).wrap_left());
+ this.source_map.pat_map_back.insert(pat, src);
+ }
+ pat
+ }
+ None => {
+ let ptr = AstPtr::new(&expr);
+ Either::Left(this.alloc_pat_from_expr(Pat::Missing, ptr))
+ }
+ },
+ _ => Either::Left(this.collect_expr_as_pat(expr)),
+ }
+ }
+
+ fn collect_tuple(
+ this: &mut ExprCollector<'_>,
+ fields: ast::AstChildren<ast::Expr>,
+ ) -> (Option<u32>, Box<[la_arena::Idx<Pat>]>) {
+ let mut ellipsis = None;
+ let args = fields
+ .enumerate()
+ .filter_map(|(idx, elem)| {
+ match collect_possibly_rest(this, elem) {
+ Either::Left(pat) => Some(pat),
+ Either::Right(()) => {
+ if ellipsis.is_none() {
+ ellipsis = Some(idx as u32);
+ }
+ // FIXME: Report an error here otherwise.
+ None
+ }
+ }
+ })
+ .collect();
+ (ellipsis, args)
+ }
+ }
+
fn initialize_binding_owner(
&mut self,
syntax_ptr: AstPtr<ast::Expr>,
@@ -744,7 +946,7 @@
let old_label = self.current_try_block_label.replace(label);
let ptr = AstPtr::new(&e).upcast();
- let (btail, expr_id) = self.with_labeled_rib(label, |this| {
+ let (btail, expr_id) = self.with_labeled_rib(label, HygieneId::ROOT, |this| {
let mut btail = None;
let block = this.collect_block_(e, |id, statements, tail| {
btail = tail;
@@ -755,17 +957,13 @@
let callee = self.alloc_expr_desugared_with_ptr(Expr::Path(try_from_output), ptr);
let next_tail = match btail {
- Some(tail) => self.alloc_expr_desugared_with_ptr(
- Expr::Call { callee, args: Box::new([tail]), is_assignee_expr: false },
- ptr,
- ),
+ Some(tail) => self
+ .alloc_expr_desugared_with_ptr(Expr::Call { callee, args: Box::new([tail]) }, ptr),
None => {
- let unit = self.alloc_expr_desugared_with_ptr(
- Expr::Tuple { exprs: Box::new([]), is_assignee_expr: false },
- ptr,
- );
+ let unit =
+ self.alloc_expr_desugared_with_ptr(Expr::Tuple { exprs: Box::new([]) }, ptr);
self.alloc_expr_desugared_with_ptr(
- Expr::Call { callee, args: Box::new([unit]), is_assignee_expr: false },
+ Expr::Call { callee, args: Box::new([unit]) },
ptr,
)
}
@@ -792,7 +990,9 @@
/// FIXME: Rustc wraps the condition in a construct equivalent to `{ let _t = <cond>; _t }`
/// to preserve drop semantics. We should probably do the same in future.
fn collect_while_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::WhileExpr) -> ExprId {
- let label = e.label().map(|label| self.collect_label(label));
+ let label = e.label().map(|label| {
+ (self.hygiene_id_for(label.syntax().text_range().start()), self.collect_label(label))
+ });
let body = self.collect_labelled_block_opt(label, e.loop_body());
// Labels can also be used in the condition expression, like this:
@@ -809,9 +1009,9 @@
// }
// ```
let condition = match label {
- Some(label) => {
- self.with_labeled_rib(label, |this| this.collect_expr_opt(e.condition()))
- }
+ Some((label_hygiene, label)) => self.with_labeled_rib(label, label_hygiene, |this| {
+ this.collect_expr_opt(e.condition())
+ }),
None => self.collect_expr_opt(e.condition()),
};
@@ -820,7 +1020,7 @@
Expr::If { condition, then_branch: body, else_branch: Some(break_expr) },
syntax_ptr,
);
- self.alloc_expr(Expr::Loop { body: if_expr, label }, syntax_ptr)
+ self.alloc_expr(Expr::Loop { body: if_expr, label: label.map(|it| it.1) }, syntax_ptr)
}
/// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into:
@@ -851,15 +1051,11 @@
let head = self.collect_expr_opt(e.iterable());
let into_iter_fn_expr = self.alloc_expr(Expr::Path(into_iter_fn), syntax_ptr);
let iterator = self.alloc_expr(
- Expr::Call {
- callee: into_iter_fn_expr,
- args: Box::new([head]),
- is_assignee_expr: false,
- },
+ Expr::Call { callee: into_iter_fn_expr, args: Box::new([head]) },
syntax_ptr,
);
let none_arm = MatchArm {
- pat: self.alloc_pat_desugared(Pat::Path(Box::new(option_none))),
+ pat: self.alloc_pat_desugared(Pat::Path(option_none)),
guard: None,
expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr),
};
@@ -868,7 +1064,9 @@
args: Box::new([self.collect_pat_top(e.pat())]),
ellipsis: None,
};
- let label = e.label().map(|label| self.collect_label(label));
+ let label = e.label().map(|label| {
+ (self.hygiene_id_for(label.syntax().text_range().start()), self.collect_label(label))
+ });
let some_arm = MatchArm {
pat: self.alloc_pat_desugared(some_pat),
guard: None,
@@ -884,11 +1082,7 @@
);
let iter_next_fn_expr = self.alloc_expr(Expr::Path(iter_next_fn), syntax_ptr);
let iter_next_expr = self.alloc_expr(
- Expr::Call {
- callee: iter_next_fn_expr,
- args: Box::new([iter_expr_mut]),
- is_assignee_expr: false,
- },
+ Expr::Call { callee: iter_next_fn_expr, args: Box::new([iter_expr_mut]) },
syntax_ptr,
);
let loop_inner = self.alloc_expr(
@@ -904,7 +1098,8 @@
},
syntax_ptr,
);
- let loop_outer = self.alloc_expr(Expr::Loop { body: loop_inner, label }, syntax_ptr);
+ let loop_outer = self
+ .alloc_expr(Expr::Loop { body: loop_inner, label: label.map(|it| it.1) }, syntax_ptr);
let iter_binding = self.alloc_binding(iter_name, BindingAnnotation::Mutable);
let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None });
self.add_definition_to_binding(iter_binding, iter_pat);
@@ -942,10 +1137,8 @@
};
let operand = self.collect_expr_opt(e.expr());
let try_branch = self.alloc_expr(Expr::Path(try_branch), syntax_ptr);
- let expr = self.alloc_expr(
- Expr::Call { callee: try_branch, args: Box::new([operand]), is_assignee_expr: false },
- syntax_ptr,
- );
+ let expr = self
+ .alloc_expr(Expr::Call { callee: try_branch, args: Box::new([operand]) }, syntax_ptr);
let continue_name = Name::generate_new_name(self.body.bindings.len());
let continue_binding =
self.alloc_binding(continue_name.clone(), BindingAnnotation::Unannotated);
@@ -975,10 +1168,8 @@
expr: {
let it = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr);
let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr);
- let result = self.alloc_expr(
- Expr::Call { callee, args: Box::new([it]), is_assignee_expr: false },
- syntax_ptr,
- );
+ let result =
+ self.alloc_expr(Expr::Call { callee, args: Box::new([it]) }, syntax_ptr);
self.alloc_expr(
match self.current_try_block_label {
Some(label) => Expr::Break { expr: Some(result), label: Some(label) },
@@ -1065,7 +1256,14 @@
// FIXME: Report parse errors here
}
+ let SpanMap::ExpansionSpanMap(new_span_map) = self.expander.span_map(self.db)
+ else {
+ panic!("just expanded a macro, ExpansionSpanMap should be available");
+ };
+ let old_span_map =
+ mem::replace(&mut self.current_span_map, Some(new_span_map.clone()));
let id = collector(self, Some(expansion.tree()));
+ self.current_span_map = old_span_map;
self.ast_id_map = prev_ast_id_map;
self.expander.exit(mark);
id
@@ -1108,7 +1306,7 @@
// Make the macro-call point to its expanded expression so we can query
// semantics on syntax pointers to the macro
let src = self.expander.in_file(syntax_ptr);
- self.source_map.expr_map.insert(src, tail);
+ self.source_map.expr_map.insert(src, tail.into());
})
}
@@ -1119,8 +1317,7 @@
return;
}
let pat = self.collect_pat_top(stmt.pat());
- let type_ref =
- stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
+ let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
let initializer = stmt.initializer().map(|e| self.collect_expr(e));
let else_branch = stmt
.let_else()
@@ -1145,10 +1342,46 @@
statements.push(Statement::Expr { expr, has_semi });
}
}
- ast::Stmt::Item(_item) => statements.push(Statement::Item),
+ ast::Stmt::Item(ast::Item::MacroDef(macro_)) => {
+ let Some(name) = macro_.name() else {
+ statements.push(Statement::Item(Item::Other));
+ return;
+ };
+ let name = name.as_name();
+ let macro_id = self.def_map.modules[DefMap::ROOT].scope.get(&name).take_macros();
+ self.collect_macro_def(statements, macro_id);
+ }
+ ast::Stmt::Item(ast::Item::MacroRules(macro_)) => {
+ let Some(name) = macro_.name() else {
+ statements.push(Statement::Item(Item::Other));
+ return;
+ };
+ let name = name.as_name();
+ let macro_defs_count =
+ self.current_block_legacy_macro_defs_count.entry(name.clone()).or_insert(0);
+ let macro_id = self.def_map.modules[DefMap::ROOT]
+ .scope
+ .get_legacy_macro(&name)
+ .and_then(|it| it.get(*macro_defs_count))
+ .copied();
+ *macro_defs_count += 1;
+ self.collect_macro_def(statements, macro_id);
+ }
+ ast::Stmt::Item(_item) => statements.push(Statement::Item(Item::Other)),
}
}
+ fn collect_macro_def(&mut self, statements: &mut Vec<Statement>, macro_id: Option<MacroId>) {
+ let Some(macro_id) = macro_id else {
+ never!("def map should have macro definition, but it doesn't");
+ statements.push(Statement::Item(Item::Other));
+ return;
+ };
+ let macro_id = self.db.macro_def(macro_id);
+ statements.push(Statement::Item(Item::MacroDef(Box::new(macro_id))));
+ self.label_ribs.push(LabelRib::new(RibKind::MacroDef(Box::new(macro_id))));
+ }
+
fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
self.collect_block_(block, |id, statements, tail| Expr::Block {
id,
@@ -1194,6 +1427,7 @@
};
let prev_def_map = mem::replace(&mut self.def_map, def_map);
let prev_local_module = mem::replace(&mut self.expander.module, module);
+ let prev_legacy_macros_count = mem::take(&mut self.current_block_legacy_macro_defs_count);
let mut statements = Vec::new();
block.statements().for_each(|s| self.collect_stmt(&mut statements, s));
@@ -1216,6 +1450,7 @@
self.def_map = prev_def_map;
self.expander.module = prev_local_module;
+ self.current_block_legacy_macro_defs_count = prev_legacy_macros_count;
expr_id
}
@@ -1228,11 +1463,13 @@
fn collect_labelled_block_opt(
&mut self,
- label: Option<LabelId>,
+ label: Option<(HygieneId, LabelId)>,
expr: Option<ast::BlockExpr>,
) -> ExprId {
match label {
- Some(label) => self.with_labeled_rib(label, |this| this.collect_block_opt(expr)),
+ Some((hygiene, label)) => {
+ self.with_labeled_rib(label, hygiene, |this| this.collect_block_opt(expr))
+ }
None => self.collect_block_opt(expr),
}
}
@@ -1250,6 +1487,10 @@
let pattern = match &pat {
ast::Pat::IdentPat(bp) => {
let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
+ let hygiene = bp
+ .name()
+ .map(|name| self.hygiene_id_for(name.syntax().text_range().start()))
+ .unwrap_or(HygieneId::ROOT);
let annotation =
BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
@@ -1285,12 +1526,12 @@
}
// shadowing statics is an error as well, so we just ignore that case here
_ => {
- let id = binding_list.find(self, name, annotation);
+ let id = binding_list.find(self, name, hygiene, annotation);
(Some(id), Pat::Bind { id, subpat })
}
}
} else {
- let id = binding_list.find(self, name, annotation);
+ let id = binding_list.find(self, name, hygiene, annotation);
(Some(id), Pat::Bind { id, subpat })
};
@@ -1302,8 +1543,7 @@
return pat;
}
ast::Pat::TupleStructPat(p) => {
- let path =
- p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+ let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
let (args, ellipsis) = self.collect_tuple_pat(
p.fields(),
comma_follows_token(p.l_paren_token()),
@@ -1317,8 +1557,7 @@
Pat::Ref { pat, mutability }
}
ast::Pat::PathPat(p) => {
- let path =
- p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+ let path = p.path().and_then(|path| self.parse_path(path));
path.map(Pat::Path).unwrap_or(Pat::Missing)
}
ast::Pat::OrPat(p) => 'b: {
@@ -1348,6 +1587,10 @@
for (id, _) in current_is_used.into_iter() {
binding_list.check_is_used(self, id);
}
+ if let &[pat] = &*pats {
+ // Leading pipe without real OR pattern. Leaving an one-item OR pattern may confuse later stages.
+ return pat;
+ }
Pat::Or(pats.into())
}
ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat(), binding_list),
@@ -1361,8 +1604,7 @@
}
ast::Pat::WildcardPat(_) => Pat::Wild,
ast::Pat::RecordPat(p) => {
- let path =
- p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+ let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
let record_pat_field_list =
&p.record_pat_field_list().expect("every struct should have a field list");
let args = record_pat_field_list
@@ -1372,7 +1614,7 @@
let ast_pat = f.pat()?;
let pat = self.collect_pat(ast_pat, binding_list);
let name = f.field_name()?.as_name();
- let src = self.expander.in_file(AstPtr::new(&f));
+ let src = self.expander.in_file(AstPtr::new(&f).wrap_right());
self.source_map.pat_field_map_back.insert(pat, src);
Some(RecordFieldPat { name, pat })
})
@@ -1569,20 +1811,51 @@
lifetime: Option<ast::Lifetime>,
) -> Result<Option<LabelId>, BodyDiagnostic> {
let Some(lifetime) = lifetime else { return Ok(None) };
+ let (mut hygiene_id, mut hygiene_info) = match &self.current_span_map {
+ None => (HygieneId::ROOT, None),
+ Some(span_map) => {
+ let span = span_map.span_at(lifetime.syntax().text_range().start());
+ let ctx = self.db.lookup_intern_syntax_context(span.ctx);
+ let hygiene_id = HygieneId::new(ctx.opaque_and_semitransparent);
+ let hygiene_info = ctx.outer_expn.map(|expansion| {
+ let expansion = self.db.lookup_intern_macro_call(expansion);
+ (ctx.parent, expansion.def)
+ });
+ (hygiene_id, hygiene_info)
+ }
+ };
let name = Name::new_lifetime(&lifetime);
for (rib_idx, rib) in self.label_ribs.iter().enumerate().rev() {
- if let Some((label_name, id)) = &rib.label {
- if *label_name == name {
- return if self.is_label_valid_from_rib(rib_idx) {
- Ok(Some(*id))
- } else {
- Err(BodyDiagnostic::UnreachableLabel {
- name,
- node: self.expander.in_file(AstPtr::new(&lifetime)),
- })
- };
+ match &rib.kind {
+ RibKind::Normal(label_name, id, label_hygiene) => {
+ if *label_name == name && *label_hygiene == hygiene_id {
+ return if self.is_label_valid_from_rib(rib_idx) {
+ Ok(Some(*id))
+ } else {
+ Err(BodyDiagnostic::UnreachableLabel {
+ name,
+ node: self.expander.in_file(AstPtr::new(&lifetime)),
+ })
+ };
+ }
}
+ RibKind::MacroDef(macro_id) => {
+ if let Some((parent_ctx, label_macro_id)) = hygiene_info {
+ if label_macro_id == **macro_id {
+ // A macro is allowed to refer to labels from before its declaration.
+ // Therefore, if we got to the rib of its declaration, give up its hygiene
+ // and use its parent expansion.
+ let parent_ctx = self.db.lookup_intern_syntax_context(parent_ctx);
+ hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent);
+ hygiene_info = parent_ctx.outer_expn.map(|expansion| {
+ let expansion = self.db.lookup_intern_macro_call(expansion);
+ (parent_ctx.parent, expansion.def)
+ });
+ }
+ }
+ }
+ _ => {}
}
}
@@ -1596,28 +1869,44 @@
!self.label_ribs[rib_index + 1..].iter().any(|rib| rib.kind.is_label_barrier())
}
+ fn pop_label_rib(&mut self) {
+ // We need to pop all macro defs, plus one rib.
+ while let Some(LabelRib { kind: RibKind::MacroDef(_) }) = self.label_ribs.pop() {
+ // Do nothing.
+ }
+ }
+
fn with_label_rib<T>(&mut self, kind: RibKind, f: impl FnOnce(&mut Self) -> T) -> T {
self.label_ribs.push(LabelRib::new(kind));
let res = f(self);
- self.label_ribs.pop();
+ self.pop_label_rib();
res
}
- fn with_labeled_rib<T>(&mut self, label: LabelId, f: impl FnOnce(&mut Self) -> T) -> T {
- self.label_ribs.push(LabelRib::new_normal((self.body[label].name.clone(), label)));
+ fn with_labeled_rib<T>(
+ &mut self,
+ label: LabelId,
+ hygiene: HygieneId,
+ f: impl FnOnce(&mut Self) -> T,
+ ) -> T {
+ self.label_ribs.push(LabelRib::new(RibKind::Normal(
+ self.body[label].name.clone(),
+ label,
+ hygiene,
+ )));
let res = f(self);
- self.label_ribs.pop();
+ self.pop_label_rib();
res
}
fn with_opt_labeled_rib<T>(
&mut self,
- label: Option<LabelId>,
+ label: Option<(HygieneId, LabelId)>,
f: impl FnOnce(&mut Self) -> T,
) -> T {
match label {
None => f(self),
- Some(label) => self.with_labeled_rib(label, f),
+ Some((hygiene, label)) => self.with_labeled_rib(label, hygiene, f),
}
}
// endregion: labels
@@ -1666,28 +1955,39 @@
_ => None,
});
let mut mappings = vec![];
- let fmt = match template.and_then(|it| self.expand_macros_to_string(it)) {
+ let (fmt, hygiene) = match template.and_then(|it| self.expand_macros_to_string(it)) {
Some((s, is_direct_literal)) => {
let call_ctx = self.expander.syntax_context();
- format_args::parse(
+ let hygiene = self.hygiene_id_for(s.syntax().text_range().start());
+ let fmt = format_args::parse(
&s,
fmt_snippet,
args,
is_direct_literal,
- |name| self.alloc_expr_desugared(Expr::Path(Path::from(name))),
+ |name| {
+ let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name)));
+ if !hygiene.is_root() {
+ self.body.expr_hygiene.insert(expr_id, hygiene);
+ }
+ expr_id
+ },
|name, span| {
if let Some(span) = span {
mappings.push((span, name))
}
},
call_ctx,
- )
+ );
+ (fmt, hygiene)
}
- None => FormatArgs {
- template: Default::default(),
- arguments: args.finish(),
- orphans: Default::default(),
- },
+ None => (
+ FormatArgs {
+ template: Default::default(),
+ arguments: args.finish(),
+ orphans: Default::default(),
+ },
+ HygieneId::ROOT,
+ ),
};
// Create a list of all _unique_ (argument, format trait) combinations.
@@ -1723,10 +2023,8 @@
}
})
.collect();
- let lit_pieces = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
- elements: lit_pieces,
- is_assignee_expr: false,
- }));
+ let lit_pieces =
+ self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces }));
let lit_pieces = self.alloc_expr_desugared(Expr::Ref {
expr: lit_pieces,
rawness: Rawness::Ref,
@@ -1743,10 +2041,7 @@
Some(self.make_format_spec(placeholder, &mut argmap))
})
.collect();
- let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
- elements,
- is_assignee_expr: false,
- }));
+ let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements }));
self.alloc_expr_desugared(Expr::Ref {
expr: array,
rawness: Rawness::Ref,
@@ -1756,10 +2051,8 @@
let arguments = &*fmt.arguments.arguments;
let args = if arguments.is_empty() {
- let expr = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
- elements: Box::default(),
- is_assignee_expr: false,
- }));
+ let expr = self
+ .alloc_expr_desugared(Expr::Array(Array::ElementList { elements: Box::default() }));
self.alloc_expr_desugared(Expr::Ref {
expr,
rawness: Rawness::Ref,
@@ -1786,10 +2079,8 @@
self.make_argument(arg, ty)
})
.collect();
- let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
- elements: args,
- is_assignee_expr: false,
- }));
+ let array =
+ self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
self.alloc_expr_desugared(Expr::Ref {
expr: array,
rawness: Rawness::Ref,
@@ -1822,11 +2113,8 @@
let new_v1_formatted = self.alloc_expr_desugared(Expr::Path(new_v1_formatted));
let unsafe_arg_new = self.alloc_expr_desugared(Expr::Path(unsafe_arg_new));
- let unsafe_arg_new = self.alloc_expr_desugared(Expr::Call {
- callee: unsafe_arg_new,
- args: Box::default(),
- is_assignee_expr: false,
- });
+ let unsafe_arg_new =
+ self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() });
let unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
id: None,
// We collect the unused expressions here so that we still infer them instead of
@@ -1843,11 +2131,14 @@
Expr::Call {
callee: new_v1_formatted,
args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
- is_assignee_expr: false,
},
syntax_ptr,
);
- self.source_map.template_map.get_or_insert_with(Default::default).0.insert(idx, mappings);
+ self.source_map
+ .template_map
+ .get_or_insert_with(Default::default)
+ .0
+ .insert(idx, (hygiene, mappings));
idx
}
@@ -1938,7 +2229,6 @@
self.alloc_expr_desugared(Expr::Call {
callee: format_placeholder_new,
args: Box::new([position, fill, align, flags, precision, width]),
- is_assignee_expr: false,
})
}
@@ -1980,11 +2270,7 @@
Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)),
None => self.missing_expr(),
};
- self.alloc_expr_desugared(Expr::Call {
- callee: count_is,
- args: Box::new([args]),
- is_assignee_expr: false,
- })
+ self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]) })
}
Some(FormatCount::Argument(arg)) => {
if let Ok(arg_index) = arg.index {
@@ -2005,7 +2291,6 @@
self.alloc_expr_desugared(Expr::Call {
callee: count_param,
args: Box::new([args]),
- is_assignee_expr: false,
})
} else {
// FIXME: This drops arg causing it to potentially not be resolved/type checked
@@ -2054,11 +2339,7 @@
Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)),
None => self.missing_expr(),
};
- self.alloc_expr_desugared(Expr::Call {
- callee: new_fn,
- args: Box::new([arg]),
- is_assignee_expr: false,
- })
+ self.alloc_expr_desugared(Expr::Call { callee: new_fn, args: Box::new([arg]) })
}
// endregion: format
@@ -2082,7 +2363,7 @@
let src = self.expander.in_file(ptr);
let id = self.body.exprs.alloc(expr);
self.source_map.expr_map_back.insert(id, src);
- self.source_map.expr_map.insert(src, id);
+ self.source_map.expr_map.insert(src, id.into());
id
}
// FIXME: desugared exprs don't have ptr, that's wrong and should be fixed.
@@ -2110,10 +2391,17 @@
binding
}
+ fn alloc_pat_from_expr(&mut self, pat: Pat, ptr: ExprPtr) -> PatId {
+ let src = self.expander.in_file(ptr);
+ let id = self.body.pats.alloc(pat);
+ self.source_map.expr_map.insert(src, id.into());
+ self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_left));
+ id
+ }
fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
let src = self.expander.in_file(ptr);
let id = self.body.pats.alloc(pat);
- self.source_map.pat_map_back.insert(id, src);
+ self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_right));
self.source_map.pat_map.insert(src, id);
id
}
@@ -2151,6 +2439,17 @@
self.awaitable_context = orig;
res
}
+
+ /// If this returns `HygieneId::ROOT`, do not allocate to save space.
+ fn hygiene_id_for(&self, span_start: TextSize) -> HygieneId {
+ match &self.current_span_map {
+ None => HygieneId::ROOT,
+ Some(span_map) => {
+ let ctx = span_map.span_at(span_start).ctx;
+ HygieneId(self.db.lookup_intern_syntax_context(ctx).opaque_and_semitransparent)
+ }
+ }
+ }
}
fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
index 4213370..c1b58db 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
@@ -158,9 +158,7 @@
AsmOperand::Const(self.collect_expr_opt(c.expr()))
}
ast::AsmOperand::AsmSym(s) => {
- let Some(path) =
- s.path().and_then(|p| self.expander.parse_path(self.db, p))
- else {
+ let Some(path) = s.path().and_then(|p| self.parse_path(p)) else {
continue;
};
AsmOperand::Sym(path)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index 37167fc..f8b6eef 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -11,7 +11,6 @@
Statement,
},
pretty::{print_generic_args, print_path, print_type_ref},
- type_ref::TypeRef,
};
use super::*;
@@ -69,20 +68,20 @@
};
if let DefWithBodyId::FunctionId(it) = owner {
p.buf.push('(');
- let function_data = &db.function_data(it);
+ let function_data = db.function_data(it);
let (mut params, ret_type) = (function_data.params.iter(), &function_data.ret_type);
if let Some(self_param) = body.self_param {
p.print_binding(self_param);
p.buf.push_str(": ");
if let Some(ty) = params.next() {
- p.print_type_ref(ty);
+ p.print_type_ref(*ty, &function_data.types_map);
p.buf.push_str(", ");
}
}
body.params.iter().zip(params).for_each(|(¶m, ty)| {
p.print_pat(param);
p.buf.push_str(": ");
- p.print_type_ref(ty);
+ p.print_type_ref(*ty, &function_data.types_map);
p.buf.push_str(", ");
});
// remove the last ", " in param list
@@ -92,7 +91,7 @@
p.buf.push(')');
// return type
p.buf.push_str(" -> ");
- p.print_type_ref(ret_type);
+ p.print_type_ref(*ret_type, &function_data.types_map);
p.buf.push(' ');
}
p.print_expr(body.body_expr);
@@ -242,7 +241,7 @@
Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"),
Expr::OffsetOf(offset_of) => {
w!(self, "builtin#offset_of(");
- self.print_type_ref(&offset_of.container);
+ self.print_type_ref(offset_of.container, &self.body.types);
let edition = self.edition;
w!(
self,
@@ -277,7 +276,7 @@
w!(self, "loop ");
self.print_expr(*body);
}
- Expr::Call { callee, args, is_assignee_expr: _ } => {
+ Expr::Call { callee, args } => {
self.print_expr(*callee);
w!(self, "(");
if !args.is_empty() {
@@ -296,7 +295,7 @@
if let Some(args) = generic_args {
w!(self, "::<");
let edition = self.edition;
- print_generic_args(self.db, args, self, edition).unwrap();
+ print_generic_args(self.db, args, &self.body.types, self, edition).unwrap();
w!(self, ">");
}
w!(self, "(");
@@ -372,7 +371,7 @@
self.print_expr(*expr);
}
}
- Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
+ Expr::RecordLit { path, fields, spread } => {
match path {
Some(path) => self.print_path(path),
None => w!(self, "�"),
@@ -391,9 +390,6 @@
p.print_expr(*spread);
wln!(p);
}
- if *ellipsis {
- wln!(p, "..");
- }
});
w!(self, "}}");
}
@@ -408,7 +404,7 @@
Expr::Cast { expr, type_ref } => {
self.print_expr(*expr);
w!(self, " as ");
- self.print_type_ref(type_ref);
+ self.print_type_ref(*type_ref, &self.body.types);
}
Expr::Ref { expr, rawness, mutability } => {
w!(self, "&");
@@ -466,7 +462,7 @@
w!(self, ") ");
}
}
- Expr::Index { base, index, is_assignee_expr: _ } => {
+ Expr::Index { base, index } => {
self.print_expr(*base);
w!(self, "[");
self.print_expr(*index);
@@ -496,18 +492,18 @@
self.print_pat(*pat);
if let Some(ty) = ty {
w!(self, ": ");
- self.print_type_ref(ty);
+ self.print_type_ref(*ty, &self.body.types);
}
}
w!(self, "|");
if let Some(ret_ty) = ret_type {
w!(self, " -> ");
- self.print_type_ref(ret_ty);
+ self.print_type_ref(*ret_ty, &self.body.types);
}
self.whitespace();
self.print_expr(*body);
}
- Expr::Tuple { exprs, is_assignee_expr: _ } => {
+ Expr::Tuple { exprs } => {
w!(self, "(");
for expr in exprs.iter() {
self.print_expr(*expr);
@@ -519,7 +515,7 @@
w!(self, "[");
if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) {
self.indented(|p| match arr {
- Array::ElementList { elements, is_assignee_expr: _ } => {
+ Array::ElementList { elements } => {
for elem in elements.iter() {
p.print_expr(*elem);
w!(p, ", ");
@@ -551,6 +547,11 @@
Expr::Const(id) => {
w!(self, "const {{ /* {id:?} */ }}");
}
+ &Expr::Assignment { target, value } => {
+ self.print_pat(target);
+ w!(self, " = ");
+ self.print_expr(value);
+ }
}
}
@@ -719,6 +720,9 @@
w!(self, "const ");
self.print_expr(*c);
}
+ Pat::Expr(expr) => {
+ self.print_expr(*expr);
+ }
}
}
@@ -729,7 +733,7 @@
self.print_pat(*pat);
if let Some(ty) = type_ref {
w!(self, ": ");
- self.print_type_ref(ty);
+ self.print_type_ref(*ty, &self.body.types);
}
if let Some(init) = initializer {
w!(self, " = ");
@@ -748,7 +752,7 @@
}
wln!(self);
}
- Statement::Item => (),
+ Statement::Item(_) => (),
}
}
@@ -787,14 +791,14 @@
}
}
- fn print_type_ref(&mut self, ty: &TypeRef) {
+ fn print_type_ref(&mut self, ty: TypeRefId, map: &TypesMap) {
let edition = self.edition;
- print_type_ref(self.db, ty, self, edition).unwrap();
+ print_type_ref(self.db, ty, map, self, edition).unwrap();
}
fn print_path(&mut self, path: &Path) {
let edition = self.edition;
- print_path(self.db, path, self, edition).unwrap();
+ print_path(self.db, path, &self.body.types, self, edition).unwrap();
}
fn print_binding(&mut self, id: BindingId) {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
index bf201ca..63a7a9a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
@@ -1,12 +1,12 @@
//! Name resolution for expressions.
-use hir_expand::name::Name;
+use hir_expand::{name::Name, MacroDefId};
use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx};
use triomphe::Arc;
use crate::{
- body::Body,
+ body::{Body, HygieneId},
db::DefDatabase,
- hir::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement},
+ hir::{Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement},
BlockId, ConstBlockId, DefWithBodyId,
};
@@ -22,6 +22,7 @@
#[derive(Debug, PartialEq, Eq)]
pub struct ScopeEntry {
name: Name,
+ hygiene: HygieneId,
binding: BindingId,
}
@@ -30,6 +31,10 @@
&self.name
}
+ pub(crate) fn hygiene(&self) -> HygieneId {
+ self.hygiene
+ }
+
pub fn binding(&self) -> BindingId {
self.binding
}
@@ -40,6 +45,8 @@
parent: Option<ScopeId>,
block: Option<BlockId>,
label: Option<(LabelId, Name)>,
+ // FIXME: We can compress this with an enum for this and `label`/`block` if memory usage matters.
+ macro_def: Option<Box<MacroDefId>>,
entries: IdxRange<ScopeEntry>,
}
@@ -62,6 +69,12 @@
self.scopes[scope].block
}
+ /// If `scope` refers to a macro def scope, returns the corresponding `MacroId`.
+ #[allow(clippy::borrowed_box)] // If we return `&MacroDefId` we need to move it, this way we just clone the `Box`.
+ pub fn macro_def(&self, scope: ScopeId) -> Option<&Box<MacroDefId>> {
+ self.scopes[scope].macro_def.as_ref()
+ }
+
/// If `scope` refers to a labeled expression scope, returns the corresponding `Label`.
pub fn label(&self, scope: ScopeId) -> Option<(LabelId, Name)> {
self.scopes[scope].label.clone()
@@ -102,7 +115,7 @@
};
let mut root = scopes.root_scope();
if let Some(self_param) = body.self_param {
- scopes.add_bindings(body, root, self_param);
+ scopes.add_bindings(body, root, self_param, body.binding_hygiene(self_param));
}
scopes.add_params_bindings(body, root, &body.params);
compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root, resolve_const_block);
@@ -114,6 +127,7 @@
parent: None,
block: None,
label: None,
+ macro_def: None,
entries: empty_entries(self.scope_entries.len()),
})
}
@@ -123,6 +137,7 @@
parent: Some(parent),
block: None,
label: None,
+ macro_def: None,
entries: empty_entries(self.scope_entries.len()),
})
}
@@ -132,6 +147,7 @@
parent: Some(parent),
block: None,
label,
+ macro_def: None,
entries: empty_entries(self.scope_entries.len()),
})
}
@@ -146,21 +162,38 @@
parent: Some(parent),
block,
label,
+ macro_def: None,
entries: empty_entries(self.scope_entries.len()),
})
}
- fn add_bindings(&mut self, body: &Body, scope: ScopeId, binding: BindingId) {
+ fn new_macro_def_scope(&mut self, parent: ScopeId, macro_id: Box<MacroDefId>) -> ScopeId {
+ self.scopes.alloc(ScopeData {
+ parent: Some(parent),
+ block: None,
+ label: None,
+ macro_def: Some(macro_id),
+ entries: empty_entries(self.scope_entries.len()),
+ })
+ }
+
+ fn add_bindings(
+ &mut self,
+ body: &Body,
+ scope: ScopeId,
+ binding: BindingId,
+ hygiene: HygieneId,
+ ) {
let Binding { name, .. } = &body.bindings[binding];
- let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding });
+ let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding, hygiene });
self.scopes[scope].entries =
IdxRange::new_inclusive(self.scopes[scope].entries.start()..=entry);
}
fn add_pat_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
let pattern = &body[pat];
- if let Pat::Bind { id, .. } = pattern {
- self.add_bindings(body, scope, *id);
+ if let Pat::Bind { id, .. } = *pattern {
+ self.add_bindings(body, scope, id, body.binding_hygiene(id));
}
pattern.walk_child_pats(|pat| self.add_pat_bindings(body, scope, pat));
@@ -206,7 +239,10 @@
Statement::Expr { expr, .. } => {
compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
}
- Statement::Item => (),
+ Statement::Item(Item::MacroDef(macro_id)) => {
+ *scope = scopes.new_macro_def_scope(*scope, macro_id.clone());
+ }
+ Statement::Item(Item::Other) => (),
}
}
if let Some(expr) = tail {
@@ -282,7 +318,7 @@
*scope = scopes.new_scope(*scope);
scopes.add_pat_bindings(body, *scope, pat);
}
- e => e.walk_child_exprs(|e| compute_expr_scopes(scopes, e, scope)),
+ _ => body.walk_child_exprs(expr, |e| compute_expr_scopes(scopes, e, scope)),
};
}
@@ -333,6 +369,8 @@
let expr_id = source_map
.node_expr(InFile { file_id: file_id.into(), value: &marker.into() })
+ .unwrap()
+ .as_expr()
.unwrap();
let scope = scopes.scope_for(expr_id);
@@ -488,8 +526,11 @@
let expr_scope = {
let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap();
- let expr_id =
- source_map.node_expr(InFile { file_id: file_id.into(), value: &expr_ast }).unwrap();
+ let expr_id = source_map
+ .node_expr(InFile { file_id: file_id.into(), value: &expr_ast })
+ .unwrap()
+ .as_expr()
+ .unwrap();
scopes.scope_for(expr_id).unwrap()
};
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
index dd3e79c..3b29d98 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
@@ -370,3 +370,37 @@
}"#]]
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
}
+
+#[test]
+fn destructuring_assignment_tuple_macro() {
+ // This is a funny one. `let m!()() = Bar()` is an error in rustc, because `m!()()` isn't a valid pattern,
+ // but in destructuring assignment it is valid, because `m!()()` is a valid expression, and destructuring
+ // assignments start their lives as expressions. So we have to do the same.
+
+ let (db, body, def) = lower(
+ r#"
+struct Bar();
+
+macro_rules! m {
+ () => { Bar };
+}
+
+fn foo() {
+ m!()() = Bar();
+}
+"#,
+ );
+
+ let (_, source_map) = db.body_with_source_map(def);
+ assert_eq!(source_map.diagnostics(), &[]);
+
+ for (_, def_map) in body.blocks(&db) {
+ assert_eq!(def_map.diagnostics(), &[]);
+ }
+
+ expect![[r#"
+ fn foo() -> () {
+ Bar() = Bar();
+ }"#]]
+ .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 263fad5..f49018e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -6,7 +6,7 @@
use hir_expand::{
name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind,
};
-use intern::{sym, Interned, Symbol};
+use intern::{sym, Symbol};
use la_arena::{Idx, RawIdx};
use smallvec::SmallVec;
use syntax::{ast, Parse};
@@ -25,7 +25,7 @@
DefMap, MacroSubNs,
},
path::ImportAlias,
- type_ref::{TraitRef, TypeBound, TypeRef},
+ type_ref::{TraitRef, TypeBound, TypeRefId, TypesMap},
visibility::RawVisibility,
AssocItemId, AstIdWithPath, ConstId, ConstLoc, ExternCrateId, FunctionId, FunctionLoc,
HasModule, ImplId, Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId,
@@ -35,13 +35,14 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionData {
pub name: Name,
- pub params: Box<[Interned<TypeRef>]>,
- pub ret_type: Interned<TypeRef>,
+ pub params: Box<[TypeRefId]>,
+ pub ret_type: TypeRefId,
pub attrs: Attrs,
pub visibility: RawVisibility,
pub abi: Option<Symbol>,
pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
pub rustc_allow_incoherent_impl: bool,
+ pub types_map: Arc<TypesMap>,
flags: FnFlags,
}
@@ -110,13 +111,14 @@
.filter(|&(idx, _)| {
item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options)
})
- .filter_map(|(_, param)| param.type_ref.clone())
+ .filter_map(|(_, param)| param.type_ref)
.collect(),
- ret_type: func.ret_type.clone(),
+ ret_type: func.ret_type,
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
visibility,
abi: func.abi.clone(),
legacy_const_generics_indices,
+ types_map: func.types_map.clone(),
flags,
rustc_allow_incoherent_impl,
})
@@ -182,13 +184,14 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeAliasData {
pub name: Name,
- pub type_ref: Option<Interned<TypeRef>>,
+ pub type_ref: Option<TypeRefId>,
pub visibility: RawVisibility,
pub is_extern: bool,
pub rustc_has_incoherent_inherent_impls: bool,
pub rustc_allow_incoherent_impl: bool,
/// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
- pub bounds: Box<[Interned<TypeBound>]>,
+ pub bounds: Box<[TypeBound]>,
+ pub types_map: Arc<TypesMap>,
}
impl TypeAliasData {
@@ -216,12 +219,13 @@
Arc::new(TypeAliasData {
name: typ.name.clone(),
- type_ref: typ.type_ref.clone(),
+ type_ref: typ.type_ref,
visibility,
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
rustc_has_incoherent_inherent_impls,
rustc_allow_incoherent_impl,
bounds: typ.bounds.clone(),
+ types_map: typ.types_map.clone(),
})
}
}
@@ -343,13 +347,14 @@
#[derive(Debug, PartialEq, Eq)]
pub struct ImplData {
- pub target_trait: Option<Interned<TraitRef>>,
- pub self_ty: Interned<TypeRef>,
+ pub target_trait: Option<TraitRef>,
+ pub self_ty: TypeRefId,
pub items: Box<[AssocItemId]>,
pub is_negative: bool,
pub is_unsafe: bool,
// box it as the vec is usually empty anyways
pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
+ pub types_map: Arc<TypesMap>,
}
impl ImplData {
@@ -368,7 +373,7 @@
let item_tree = tree_id.item_tree(db);
let impl_def = &item_tree[tree_id.value];
let target_trait = impl_def.target_trait.clone();
- let self_ty = impl_def.self_ty.clone();
+ let self_ty = impl_def.self_ty;
let is_negative = impl_def.is_negative;
let is_unsafe = impl_def.is_unsafe;
@@ -387,6 +392,7 @@
is_negative,
is_unsafe,
macro_calls,
+ types_map: impl_def.types_map.clone(),
}),
DefDiagnostics::new(diagnostics),
)
@@ -532,10 +538,11 @@
pub struct ConstData {
/// `None` for `const _: () = ();`
pub name: Option<Name>,
- pub type_ref: Interned<TypeRef>,
+ pub type_ref: TypeRefId,
pub visibility: RawVisibility,
pub rustc_allow_incoherent_impl: bool,
pub has_body: bool,
+ pub types_map: Arc<TypesMap>,
}
impl ConstData {
@@ -556,10 +563,11 @@
Arc::new(ConstData {
name: konst.name.clone(),
- type_ref: konst.type_ref.clone(),
+ type_ref: konst.type_ref,
visibility,
rustc_allow_incoherent_impl,
has_body: konst.has_body,
+ types_map: konst.types_map.clone(),
})
}
}
@@ -567,12 +575,13 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StaticData {
pub name: Name,
- pub type_ref: Interned<TypeRef>,
+ pub type_ref: TypeRefId,
pub visibility: RawVisibility,
pub mutable: bool,
pub is_extern: bool,
pub has_safe_kw: bool,
pub has_unsafe_kw: bool,
+ pub types_map: Arc<TypesMap>,
}
impl StaticData {
@@ -583,12 +592,13 @@
Arc::new(StaticData {
name: statik.name.clone(),
- type_ref: statik.type_ref.clone(),
+ type_ref: statik.type_ref,
visibility: item_tree[statik.visibility].clone(),
mutable: statik.mutable,
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
has_safe_kw: statik.has_safe_kw,
has_unsafe_kw: statik.has_unsafe_kw,
+ types_map: statik.types_map.clone(),
})
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
index ba54451..068ebb3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
@@ -6,7 +6,7 @@
use either::Either;
use hir_expand::name::Name;
-use intern::{sym, Interned};
+use intern::sym;
use la_arena::Arena;
use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
use triomphe::Arc;
@@ -21,7 +21,7 @@
lang_item::LangItem,
nameres::diagnostics::{DefDiagnostic, DefDiagnostics},
tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
- type_ref::TypeRef,
+ type_ref::{TypeRefId, TypesMap},
visibility::RawVisibility,
EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
};
@@ -73,8 +73,8 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VariantData {
- Record(Arena<FieldData>),
- Tuple(Arena<FieldData>),
+ Record { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
+ Tuple { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
Unit,
}
@@ -82,7 +82,7 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldData {
pub name: Name,
- pub type_ref: Interned<TypeRef>,
+ pub type_ref: TypeRefId,
pub visibility: RawVisibility,
}
@@ -208,7 +208,7 @@
}
let strukt = &item_tree[loc.id.value];
- let (data, diagnostics) = lower_fields(
+ let (fields, diagnostics) = lower_fields(
db,
krate,
loc.container.local_id,
@@ -219,12 +219,13 @@
&strukt.fields,
None,
);
+ let types_map = strukt.types_map.clone();
(
Arc::new(StructData {
name: strukt.name.clone(),
variant_data: Arc::new(match strukt.shape {
- FieldsShape::Record => VariantData::Record(data),
- FieldsShape::Tuple => VariantData::Tuple(data),
+ FieldsShape::Record => VariantData::Record { fields, types_map },
+ FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
FieldsShape::Unit => VariantData::Unit,
}),
repr,
@@ -258,7 +259,7 @@
}
let union = &item_tree[loc.id.value];
- let (data, diagnostics) = lower_fields(
+ let (fields, diagnostics) = lower_fields(
db,
krate,
loc.container.local_id,
@@ -269,10 +270,11 @@
&union.fields,
None,
);
+ let types_map = union.types_map.clone();
(
Arc::new(StructData {
name: union.name.clone(),
- variant_data: Arc::new(VariantData::Record(data)),
+ variant_data: Arc::new(VariantData::Record { fields, types_map }),
repr,
visibility: item_tree[union.visibility].clone(),
flags,
@@ -360,7 +362,7 @@
let item_tree = loc.id.item_tree(db);
let variant = &item_tree[loc.id.value];
- let (data, diagnostics) = lower_fields(
+ let (fields, diagnostics) = lower_fields(
db,
krate,
container.local_id,
@@ -371,13 +373,14 @@
&variant.fields,
Some(item_tree[loc.parent.lookup(db).id.value].visibility),
);
+ let types_map = variant.types_map.clone();
(
Arc::new(EnumVariantData {
name: variant.name.clone(),
variant_data: Arc::new(match variant.shape {
- FieldsShape::Record => VariantData::Record(data),
- FieldsShape::Tuple => VariantData::Tuple(data),
+ FieldsShape::Record => VariantData::Record { fields, types_map },
+ FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
FieldsShape::Unit => VariantData::Unit,
}),
}),
@@ -390,11 +393,20 @@
pub fn fields(&self) -> &Arena<FieldData> {
const EMPTY: &Arena<FieldData> = &Arena::new();
match &self {
- VariantData::Record(fields) | VariantData::Tuple(fields) => fields,
+ VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => fields,
_ => EMPTY,
}
}
+ pub fn types_map(&self) -> &TypesMap {
+ match &self {
+ VariantData::Record { types_map, .. } | VariantData::Tuple { types_map, .. } => {
+ types_map
+ }
+ VariantData::Unit => TypesMap::EMPTY,
+ }
+ }
+
// FIXME: Linear lookup
pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
@@ -402,8 +414,8 @@
pub fn kind(&self) -> StructKind {
match self {
- VariantData::Record(_) => StructKind::Record,
- VariantData::Tuple(_) => StructKind::Tuple,
+ VariantData::Record { .. } => StructKind::Record,
+ VariantData::Tuple { .. } => StructKind::Tuple,
VariantData::Unit => StructKind::Unit,
}
}
@@ -463,7 +475,7 @@
) -> FieldData {
FieldData {
name: field.name.clone(),
- type_ref: field.type_ref.clone(),
+ type_ref: field.type_ref,
visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index aeda302..d7e83ce 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -2,7 +2,7 @@
use base_db::{ra_salsa, CrateId, SourceDatabase, Upcast};
use either::Either;
use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId};
-use intern::{sym, Interned};
+use intern::sym;
use la_arena::ArenaMap;
use span::{EditionedFileId, MacroCallId};
use syntax::{ast, AstPtr};
@@ -18,9 +18,10 @@
},
generics::GenericParams,
import_map::ImportMap,
- item_tree::{AttrOwner, ItemTree},
+ item_tree::{AttrOwner, ItemTree, ItemTreeSourceMaps},
lang_item::{self, LangItem, LangItemTarget, LangItems},
nameres::{diagnostics::DefDiagnostics, DefMap},
+ type_ref::TypesSourceMap,
visibility::{self, Visibility},
AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId,
@@ -91,6 +92,18 @@
#[ra_salsa::invoke(ItemTree::block_item_tree_query)]
fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
+ #[ra_salsa::invoke(ItemTree::file_item_tree_with_source_map_query)]
+ fn file_item_tree_with_source_map(
+ &self,
+ file_id: HirFileId,
+ ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
+
+ #[ra_salsa::invoke(ItemTree::block_item_tree_with_source_map_query)]
+ fn block_item_tree_with_source_map(
+ &self,
+ block_id: BlockId,
+ ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
+
#[ra_salsa::invoke(DefMap::crate_def_map_query)]
fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>;
@@ -187,7 +200,14 @@
fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
#[ra_salsa::invoke(GenericParams::generic_params_query)]
- fn generic_params(&self, def: GenericDefId) -> Interned<GenericParams>;
+ fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>;
+
+ /// If this returns `None` for the source map, that means it is the same as with the item tree.
+ #[ra_salsa::invoke(GenericParams::generic_params_with_source_map_query)]
+ fn generic_params_with_source_map(
+ &self,
+ def: GenericDefId,
+ ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>);
// region:attrs
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
index 6d8b444..d430733 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
@@ -14,6 +14,7 @@
use syntax::{ast, Parse};
use triomphe::Arc;
+use crate::type_ref::{TypesMap, TypesSourceMap};
use crate::{
attr::Attrs, db::DefDatabase, lower::LowerCtx, path::Path, AsMacroCall, MacroId, ModuleId,
UnresolvedMacro,
@@ -49,6 +50,10 @@
}
}
+ pub(crate) fn span_map(&self, db: &dyn DefDatabase) -> &SpanMap {
+ self.span_map.get_or_init(|| db.span_map(self.current_file_id))
+ }
+
pub fn krate(&self) -> CrateId {
self.module.krate
}
@@ -110,8 +115,19 @@
mark.bomb.defuse();
}
- pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> {
- LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone())
+ pub fn ctx<'a>(
+ &self,
+ db: &'a dyn DefDatabase,
+ types_map: &'a mut TypesMap,
+ types_source_map: &'a mut TypesSourceMap,
+ ) -> LowerCtx<'a> {
+ LowerCtx::with_span_map_cell(
+ db,
+ self.current_file_id,
+ self.span_map.clone(),
+ types_map,
+ types_source_map,
+ )
}
pub(crate) fn in_file<T>(&self, value: T) -> InFile<T> {
@@ -138,8 +154,20 @@
self.current_file_id
}
- pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
- let ctx = LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone());
+ pub(crate) fn parse_path(
+ &mut self,
+ db: &dyn DefDatabase,
+ path: ast::Path,
+ types_map: &mut TypesMap,
+ types_source_map: &mut TypesSourceMap,
+ ) -> Option<Path> {
+ let ctx = LowerCtx::with_span_map_cell(
+ db,
+ self.current_file_id,
+ self.span_map.clone(),
+ types_map,
+ types_source_map,
+ );
Path::from_src(&ctx, path)
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index f5e03e5..a615abd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -1025,7 +1025,7 @@
check_found_path(
r#"
mod bar {
- mod foo { pub(super) struct S; }
+ mod foo { pub(crate) struct S; }
pub(crate) use foo::*;
}
$0
@@ -1047,7 +1047,7 @@
check_found_path(
r#"
mod bar {
- mod foo { pub(super) struct S; }
+ mod foo { pub(crate) struct S; }
pub(crate) use foo::S as U;
}
$0
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index 6c34ee0..6b79850 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -3,16 +3,18 @@
//! generic parameters. See also the `Generics` type and the `generics_of` query
//! in rustc.
-use std::ops;
+use std::{ops, sync::LazyLock};
use either::Either;
use hir_expand::{
name::{AsName, Name},
ExpandResult,
};
-use intern::Interned;
use la_arena::{Arena, RawIdx};
-use stdx::impl_from;
+use stdx::{
+ impl_from,
+ thin_vec::{EmptyOptimizedThinVec, ThinVec},
+};
use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
use triomphe::Arc;
@@ -22,7 +24,11 @@
item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
lower::LowerCtx,
nameres::{DefMap, MacroSubNs},
- type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
+ path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
+ type_ref::{
+ ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap,
+ TypesSourceMap,
+ },
AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
};
@@ -37,7 +43,7 @@
/// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just
/// make it always be a value, giving impl trait a special name.
pub name: Option<Name>,
- pub default: Option<Interned<TypeRef>>,
+ pub default: Option<TypeRefId>,
pub provenance: TypeParamProvenance,
}
@@ -51,7 +57,7 @@
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct ConstParamData {
pub name: Name,
- pub ty: Interned<TypeRef>,
+ pub ty: TypeRefId,
pub default: Option<ConstRef>,
}
@@ -161,6 +167,7 @@
type_or_consts: Arena<TypeOrConstParamData>,
lifetimes: Arena<LifetimeParamData>,
where_predicates: Box<[WherePredicate]>,
+ pub types_map: TypesMap,
}
impl ops::Index<LocalTypeOrConstParamId> for GenericParams {
@@ -183,24 +190,14 @@
/// associated type bindings like `Iterator<Item = u32>`.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum WherePredicate {
- TypeBound {
- target: WherePredicateTypeTarget,
- bound: Interned<TypeBound>,
- },
- Lifetime {
- target: LifetimeRef,
- bound: LifetimeRef,
- },
- ForLifetime {
- lifetimes: Box<[Name]>,
- target: WherePredicateTypeTarget,
- bound: Interned<TypeBound>,
- },
+ TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
+ Lifetime { target: LifetimeRef, bound: LifetimeRef },
+ ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum WherePredicateTypeTarget {
- TypeRef(Interned<TypeRef>),
+ TypeRef(TypeRefId),
/// For desugared where predicates that can directly refer to a type param.
TypeOrConstParam(LocalTypeOrConstParamId),
}
@@ -300,7 +297,14 @@
pub(crate) fn generic_params_query(
db: &dyn DefDatabase,
def: GenericDefId,
- ) -> Interned<GenericParams> {
+ ) -> Arc<GenericParams> {
+ db.generic_params_with_source_map(def).0
+ }
+
+ pub(crate) fn generic_params_with_source_map_query(
+ db: &dyn DefDatabase,
+ def: GenericDefId,
+ ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>) {
let _p = tracing::info_span!("generic_params_query").entered();
let krate = def.krate(db);
@@ -309,7 +313,7 @@
// Returns the generic parameters that are enabled under the current `#[cfg]` options
let enabled_params =
- |params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
+ |params: &Arc<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
@@ -325,7 +329,7 @@
if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone()
} else {
- Interned::new(GenericParams {
+ Arc::new(GenericParams {
type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone())
.unwrap_or_else(|| {
@@ -347,6 +351,7 @@
.collect()
}),
where_predicates: params.where_predicates.clone(),
+ types_map: params.types_map.clone(),
})
}
};
@@ -357,18 +362,18 @@
Data = impl ItemTreeLoc<Id = Id>,
>,
enabled_params: impl Fn(
- &Interned<GenericParams>,
+ &Arc<GenericParams>,
&ItemTree,
GenericModItem,
- ) -> Interned<GenericParams>,
- ) -> Interned<GenericParams>
+ ) -> Arc<GenericParams>,
+ ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>)
where
FileItemTreeId<Id>: Into<GenericModItem>,
{
let id = id.lookup(db).item_tree_id();
let tree = id.item_tree(db);
let item = &tree[id.value];
- enabled_params(item.generic_params(), &tree, id.value.into())
+ (enabled_params(item.generic_params(), &tree, id.value.into()), None)
}
match def {
@@ -383,28 +388,37 @@
let module = loc.container.module(db);
let func_data = db.function_data(id);
if func_data.params.is_empty() {
- enabled_params
+ (enabled_params, None)
} else {
+ let source_maps = loc.id.item_tree_with_source_map(db).1;
+ let item_source_maps = source_maps.function(loc.id.value);
let mut generic_params = GenericParamsCollector {
type_or_consts: enabled_params.type_or_consts.clone(),
lifetimes: enabled_params.lifetimes.clone(),
where_predicates: enabled_params.where_predicates.clone().into(),
};
+ let (mut types_map, mut types_source_maps) =
+ (enabled_params.types_map.clone(), item_source_maps.generics().clone());
// Don't create an `Expander` if not needed since this
// could cause a reparse after the `ItemTree` has been created due to the spanmap.
let mut expander = None;
- for param in func_data.params.iter() {
+ for ¶m in func_data.params.iter() {
generic_params.fill_implicit_impl_trait_args(
db,
+ &mut types_map,
+ &mut types_source_maps,
&mut expander,
&mut || {
(module.def_map(db), Expander::new(db, loc.id.file_id(), module))
},
param,
+ &item.types_map,
+ item_source_maps.item(),
);
}
- Interned::new(generic_params.finish())
+ let generics = generic_params.finish(types_map, &mut types_source_maps);
+ (generics, Some(Arc::new(types_source_maps)))
}
}
GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params),
@@ -414,11 +428,15 @@
GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
- GenericDefId::ConstId(_) => Interned::new(GenericParams {
- type_or_consts: Default::default(),
- lifetimes: Default::default(),
- where_predicates: Default::default(),
- }),
+ GenericDefId::ConstId(_) => (
+ Arc::new(GenericParams {
+ type_or_consts: Default::default(),
+ lifetimes: Default::default(),
+ where_predicates: Default::default(),
+ types_map: Default::default(),
+ }),
+ None,
+ ),
}
}
}
@@ -452,7 +470,7 @@
&mut self,
lower_ctx: &LowerCtx<'_>,
type_bounds: Option<ast::TypeBoundList>,
- target: Either<TypeRef, LifetimeRef>,
+ target: Either<TypeRefId, LifetimeRef>,
) {
for bound in type_bounds.iter().flat_map(|type_bound_list| type_bound_list.bounds()) {
self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone());
@@ -473,16 +491,15 @@
ast::TypeOrConstParam::Type(type_param) => {
let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
// FIXME: Use `Path::from_src`
- let default = type_param
- .default_type()
- .map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it)));
+ let default =
+ type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it));
let param = TypeParamData {
name: Some(name.clone()),
default,
provenance: TypeParamProvenance::TypeParamList,
};
let idx = self.type_or_consts.alloc(param.into());
- let type_ref = TypeRef::Path(name.into());
+ let type_ref = lower_ctx.alloc_type_ref_desugared(TypeRef::Path(name.into()));
self.fill_bounds(
lower_ctx,
type_param.type_bound_list(),
@@ -492,12 +509,10 @@
}
ast::TypeOrConstParam::Const(const_param) => {
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
- let ty = const_param
- .ty()
- .map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
+ let ty = TypeRef::from_ast_opt(lower_ctx, const_param.ty());
let param = ConstParamData {
name,
- ty: Interned::new(ty),
+ ty,
default: ConstRef::from_const_param(lower_ctx, &const_param),
};
let idx = self.type_or_consts.alloc(param.into());
@@ -557,7 +572,7 @@
lower_ctx: &LowerCtx<'_>,
bound: ast::TypeBound,
hrtb_lifetimes: Option<&[Name]>,
- target: Either<TypeRef, LifetimeRef>,
+ target: Either<TypeRefId, LifetimeRef>,
) {
let bound = TypeBound::from_ast(lower_ctx, bound);
self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
@@ -565,12 +580,12 @@
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(),
- target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
- bound: Interned::new(bound),
+ target: WherePredicateTypeTarget::TypeRef(type_ref),
+ bound,
},
None => WherePredicate::TypeBound {
- target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
- bound: Interned::new(bound),
+ target: WherePredicateTypeTarget::TypeRef(type_ref),
+ bound,
},
},
(Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
@@ -581,7 +596,7 @@
self.where_predicates.push(predicate);
}
- fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) {
+ fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<ThinVec<TypeBound>>) {
for bounds in impl_bounds {
let param = TypeParamData {
name: None,
@@ -589,10 +604,10 @@
provenance: TypeParamProvenance::ArgumentImplTrait,
};
let param_id = self.type_or_consts.alloc(param.into());
- for bound in bounds {
+ for bound in &bounds {
self.where_predicates.push(WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
- bound,
+ bound: bound.clone(),
});
}
}
@@ -601,12 +616,16 @@
fn fill_implicit_impl_trait_args(
&mut self,
db: &dyn DefDatabase,
+ generics_types_map: &mut TypesMap,
+ generics_types_source_map: &mut TypesSourceMap,
// FIXME: Change this back to `LazyCell` if https://github.com/rust-lang/libs-team/issues/429 is accepted.
exp: &mut Option<(Arc<DefMap>, Expander)>,
exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Expander),
- type_ref: &TypeRef,
+ type_ref: TypeRefId,
+ types_map: &TypesMap,
+ types_source_map: &TypesSourceMap,
) {
- type_ref.walk(&mut |type_ref| {
+ TypeRef::walk(type_ref, types_map, &mut |type_ref| {
if let TypeRef::ImplTrait(bounds) = type_ref {
let param = TypeParamData {
name: None,
@@ -615,12 +634,20 @@
};
let param_id = self.type_or_consts.alloc(param.into());
for bound in bounds {
+ let bound = copy_type_bound(
+ bound,
+ types_map,
+ types_source_map,
+ generics_types_map,
+ generics_types_source_map,
+ );
self.where_predicates.push(WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
- bound: bound.clone(),
+ bound,
});
}
}
+
if let TypeRef::Macro(mc) = type_ref {
let macro_call = mc.to_node(db.upcast());
let (def_map, expander) = exp.get_or_insert_with(&mut *exp_fill);
@@ -641,23 +668,217 @@
if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) =
expander.enter_expand(db, macro_call, resolver)
{
- let ctx = expander.ctx(db);
+ let (mut macro_types_map, mut macro_types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let ctx = expander.ctx(db, &mut macro_types_map, &mut macro_types_source_map);
let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
- self.fill_implicit_impl_trait_args(db, &mut *exp, exp_fill, &type_ref);
+ self.fill_implicit_impl_trait_args(
+ db,
+ generics_types_map,
+ generics_types_source_map,
+ &mut *exp,
+ exp_fill,
+ type_ref,
+ ¯o_types_map,
+ ¯o_types_source_map,
+ );
exp.get_or_insert_with(&mut *exp_fill).1.exit(mark);
}
}
});
}
- pub(crate) fn finish(self) -> GenericParams {
- let Self { mut lifetimes, mut type_or_consts, where_predicates } = self;
+ pub(crate) fn finish(
+ self,
+ mut generics_types_map: TypesMap,
+ generics_types_source_map: &mut TypesSourceMap,
+ ) -> Arc<GenericParams> {
+ let Self { mut lifetimes, mut type_or_consts, mut where_predicates } = self;
+
+ if lifetimes.is_empty() && type_or_consts.is_empty() && where_predicates.is_empty() {
+ static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| {
+ Arc::new(GenericParams {
+ lifetimes: Arena::new(),
+ type_or_consts: Arena::new(),
+ where_predicates: Box::default(),
+ types_map: TypesMap::default(),
+ })
+ });
+ return Arc::clone(&EMPTY);
+ }
+
lifetimes.shrink_to_fit();
type_or_consts.shrink_to_fit();
- GenericParams {
+ where_predicates.shrink_to_fit();
+ generics_types_map.shrink_to_fit();
+ generics_types_source_map.shrink_to_fit();
+ Arc::new(GenericParams {
type_or_consts,
lifetimes,
where_predicates: where_predicates.into_boxed_slice(),
+ types_map: generics_types_map,
+ })
+ }
+}
+
+/// Copies a `TypeRef` from a `TypesMap` (accompanied with `TypesSourceMap`) into another `TypesMap`
+/// (and `TypesSourceMap`).
+fn copy_type_ref(
+ type_ref: TypeRefId,
+ from: &TypesMap,
+ from_source_map: &TypesSourceMap,
+ to: &mut TypesMap,
+ to_source_map: &mut TypesSourceMap,
+) -> TypeRefId {
+ let result = match &from[type_ref] {
+ TypeRef::Fn(fn_) => {
+ let params = fn_.params().iter().map(|(name, param_type)| {
+ (name.clone(), copy_type_ref(*param_type, from, from_source_map, to, to_source_map))
+ });
+ TypeRef::Fn(FnType::new(fn_.is_varargs(), fn_.is_unsafe(), fn_.abi().clone(), params))
}
+ TypeRef::Tuple(types) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(
+ types.iter().map(|&t| copy_type_ref(t, from, from_source_map, to, to_source_map)),
+ )),
+ &TypeRef::RawPtr(type_ref, mutbl) => TypeRef::RawPtr(
+ copy_type_ref(type_ref, from, from_source_map, to, to_source_map),
+ mutbl,
+ ),
+ TypeRef::Reference(ref_) => TypeRef::Reference(Box::new(RefType {
+ ty: copy_type_ref(ref_.ty, from, from_source_map, to, to_source_map),
+ lifetime: ref_.lifetime.clone(),
+ mutability: ref_.mutability,
+ })),
+ TypeRef::Array(array) => TypeRef::Array(Box::new(ArrayType {
+ ty: copy_type_ref(array.ty, from, from_source_map, to, to_source_map),
+ len: array.len.clone(),
+ })),
+ &TypeRef::Slice(type_ref) => {
+ TypeRef::Slice(copy_type_ref(type_ref, from, from_source_map, to, to_source_map))
+ }
+ TypeRef::ImplTrait(bounds) => TypeRef::ImplTrait(ThinVec::from_iter(copy_type_bounds(
+ bounds,
+ from,
+ from_source_map,
+ to,
+ to_source_map,
+ ))),
+ TypeRef::DynTrait(bounds) => TypeRef::DynTrait(ThinVec::from_iter(copy_type_bounds(
+ bounds,
+ from,
+ from_source_map,
+ to,
+ to_source_map,
+ ))),
+ TypeRef::Path(path) => {
+ TypeRef::Path(copy_path(path, from, from_source_map, to, to_source_map))
+ }
+ TypeRef::Never => TypeRef::Never,
+ TypeRef::Placeholder => TypeRef::Placeholder,
+ TypeRef::Macro(macro_call) => TypeRef::Macro(*macro_call),
+ TypeRef::Error => TypeRef::Error,
+ };
+ let id = to.types.alloc(result);
+ if let Some(&ptr) = from_source_map.types_map_back.get(id) {
+ to_source_map.types_map_back.insert(id, ptr);
+ }
+ id
+}
+
+fn copy_path(
+ path: &Path,
+ from: &TypesMap,
+ from_source_map: &TypesSourceMap,
+ to: &mut TypesMap,
+ to_source_map: &mut TypesSourceMap,
+) -> Path {
+ match path {
+ Path::BarePath(mod_path) => Path::BarePath(mod_path.clone()),
+ Path::Normal(path) => {
+ let type_anchor = path
+ .type_anchor()
+ .map(|type_ref| copy_type_ref(type_ref, from, from_source_map, to, to_source_map));
+ let mod_path = path.mod_path().clone();
+ let generic_args = path.generic_args().iter().map(|generic_args| {
+ copy_generic_args(generic_args, from, from_source_map, to, to_source_map)
+ });
+ Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args))
+ }
+ Path::LangItem(lang_item, name) => Path::LangItem(*lang_item, name.clone()),
+ }
+}
+
+fn copy_generic_args(
+ generic_args: &Option<GenericArgs>,
+ from: &TypesMap,
+ from_source_map: &TypesSourceMap,
+ to: &mut TypesMap,
+ to_source_map: &mut TypesSourceMap,
+) -> Option<GenericArgs> {
+ generic_args.as_ref().map(|generic_args| {
+ let args = generic_args
+ .args
+ .iter()
+ .map(|arg| match arg {
+ &GenericArg::Type(ty) => {
+ GenericArg::Type(copy_type_ref(ty, from, from_source_map, to, to_source_map))
+ }
+ GenericArg::Lifetime(lifetime) => GenericArg::Lifetime(lifetime.clone()),
+ GenericArg::Const(konst) => GenericArg::Const(konst.clone()),
+ })
+ .collect();
+ let bindings = generic_args
+ .bindings
+ .iter()
+ .map(|binding| {
+ let name = binding.name.clone();
+ let args =
+ copy_generic_args(&binding.args, from, from_source_map, to, to_source_map);
+ let type_ref = binding.type_ref.map(|type_ref| {
+ copy_type_ref(type_ref, from, from_source_map, to, to_source_map)
+ });
+ let bounds =
+ copy_type_bounds(&binding.bounds, from, from_source_map, to, to_source_map)
+ .collect();
+ AssociatedTypeBinding { name, args, type_ref, bounds }
+ })
+ .collect();
+ GenericArgs {
+ args,
+ has_self_type: generic_args.has_self_type,
+ bindings,
+ desugared_from_fn: generic_args.desugared_from_fn,
+ }
+ })
+}
+
+fn copy_type_bounds<'a>(
+ bounds: &'a [TypeBound],
+ from: &'a TypesMap,
+ from_source_map: &'a TypesSourceMap,
+ to: &'a mut TypesMap,
+ to_source_map: &'a mut TypesSourceMap,
+) -> impl stdx::thin_vec::TrustedLen<Item = TypeBound> + 'a {
+ bounds.iter().map(|bound| copy_type_bound(bound, from, from_source_map, to, to_source_map))
+}
+
+fn copy_type_bound(
+ bound: &TypeBound,
+ from: &TypesMap,
+ from_source_map: &TypesSourceMap,
+ to: &mut TypesMap,
+ to_source_map: &mut TypesSourceMap,
+) -> TypeBound {
+ match bound {
+ TypeBound::Path(path, modifier) => {
+ TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier)
+ }
+ TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime(
+ lifetimes.clone(),
+ copy_path(path, from, from_source_map, to, to_source_map),
+ ),
+ TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()),
+ TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()),
+ TypeBound::Error => TypeBound::Error,
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
index d9358a2..8596346 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -17,16 +17,17 @@
use std::fmt;
-use hir_expand::name::Name;
-use intern::{Interned, Symbol};
+use hir_expand::{name::Name, MacroDefId};
+use intern::Symbol;
use la_arena::{Idx, RawIdx};
use rustc_apfloat::ieee::{Half as f16, Quad as f128};
use syntax::ast;
+use type_ref::TypeRefId;
use crate::{
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
path::{GenericArgs, Path},
- type_ref::{Mutability, Rawness, TypeRef},
+ type_ref::{Mutability, Rawness},
BlockId, ConstBlockId,
};
@@ -48,6 +49,22 @@
ExprId(ExprId),
PatId(PatId),
}
+
+impl ExprOrPatId {
+ pub fn as_expr(self) -> Option<ExprId> {
+ match self {
+ Self::ExprId(v) => Some(v),
+ _ => None,
+ }
+ }
+
+ pub fn as_pat(self) -> Option<PatId> {
+ match self {
+ Self::PatId(v) => Some(v),
+ _ => None,
+ }
+ }
+}
stdx::impl_from!(ExprId, PatId for ExprOrPatId);
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -204,7 +221,6 @@
Call {
callee: ExprId,
args: Box<[ExprId]>,
- is_assignee_expr: bool,
},
MethodCall {
receiver: ExprId,
@@ -239,8 +255,6 @@
path: Option<Box<Path>>,
fields: Box<[RecordLitField]>,
spread: Option<ExprId>,
- ellipsis: bool,
- is_assignee_expr: bool,
},
Field {
expr: ExprId,
@@ -251,7 +265,7 @@
},
Cast {
expr: ExprId,
- type_ref: Interned<TypeRef>,
+ type_ref: TypeRefId,
},
Ref {
expr: ExprId,
@@ -265,11 +279,17 @@
expr: ExprId,
op: UnaryOp,
},
+ /// `op` cannot be bare `=` (but can be `op=`), these are lowered to `Assignment` instead.
BinaryOp {
lhs: ExprId,
rhs: ExprId,
op: Option<BinaryOp>,
},
+ // Assignments need a special treatment because of destructuring assignment.
+ Assignment {
+ target: PatId,
+ value: ExprId,
+ },
Range {
lhs: Option<ExprId>,
rhs: Option<ExprId>,
@@ -278,19 +298,17 @@
Index {
base: ExprId,
index: ExprId,
- is_assignee_expr: bool,
},
Closure {
args: Box<[PatId]>,
- arg_types: Box<[Option<Interned<TypeRef>>]>,
- ret_type: Option<Interned<TypeRef>>,
+ arg_types: Box<[Option<TypeRefId>]>,
+ ret_type: Option<TypeRefId>,
body: ExprId,
closure_kind: ClosureKind,
capture_by: CaptureBy,
},
Tuple {
exprs: Box<[ExprId]>,
- is_assignee_expr: bool,
},
Array(Array),
Literal(Literal),
@@ -301,7 +319,7 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OffsetOf {
- pub container: Interned<TypeRef>,
+ pub container: TypeRefId,
pub fields: Box<[Name]>,
}
@@ -446,7 +464,7 @@
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Array {
- ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
+ ElementList { elements: Box<[ExprId]> },
Repeat { initializer: ExprId, repeat: ExprId },
}
@@ -467,7 +485,7 @@
pub enum Statement {
Let {
pat: PatId,
- type_ref: Option<Interned<TypeRef>>,
+ type_ref: Option<TypeRefId>,
initializer: Option<ExprId>,
else_branch: Option<ExprId>,
},
@@ -475,133 +493,13 @@
expr: ExprId,
has_semi: bool,
},
- // At the moment, we only use this to figure out if a return expression
- // is really the last statement of a block. See #16566
- Item,
+ Item(Item),
}
-impl Expr {
- pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
- match self {
- Expr::Missing => {}
- Expr::Path(_) | Expr::OffsetOf(_) => {}
- Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
- AsmOperand::In { expr, .. }
- | AsmOperand::Out { expr: Some(expr), .. }
- | AsmOperand::InOut { expr, .. } => f(*expr),
- AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
- f(*in_expr);
- if let Some(out_expr) = out_expr {
- f(*out_expr);
- }
- }
- AsmOperand::Out { expr: None, .. }
- | AsmOperand::Const(_)
- | AsmOperand::Label(_)
- | AsmOperand::Sym(_) => (),
- }),
- Expr::If { condition, then_branch, else_branch } => {
- f(*condition);
- f(*then_branch);
- if let &Some(else_branch) = else_branch {
- f(else_branch);
- }
- }
- Expr::Let { expr, .. } => {
- f(*expr);
- }
- Expr::Const(_) => (),
- Expr::Block { statements, tail, .. }
- | Expr::Unsafe { statements, tail, .. }
- | Expr::Async { statements, tail, .. } => {
- for stmt in statements.iter() {
- match stmt {
- Statement::Let { initializer, else_branch, .. } => {
- if let &Some(expr) = initializer {
- f(expr);
- }
- if let &Some(expr) = else_branch {
- f(expr);
- }
- }
- Statement::Expr { expr: expression, .. } => f(*expression),
- Statement::Item => (),
- }
- }
- if let &Some(expr) = tail {
- f(expr);
- }
- }
- Expr::Loop { body, .. } => f(*body),
- Expr::Call { callee, args, .. } => {
- f(*callee);
- args.iter().copied().for_each(f);
- }
- Expr::MethodCall { receiver, args, .. } => {
- f(*receiver);
- args.iter().copied().for_each(f);
- }
- Expr::Match { expr, arms } => {
- f(*expr);
- arms.iter().map(|arm| arm.expr).for_each(f);
- }
- Expr::Continue { .. } => {}
- Expr::Break { expr, .. }
- | Expr::Return { expr }
- | Expr::Yield { expr }
- | Expr::Yeet { expr } => {
- if let &Some(expr) = expr {
- f(expr);
- }
- }
- Expr::Become { expr } => f(*expr),
- Expr::RecordLit { fields, spread, .. } => {
- for field in fields.iter() {
- f(field.expr);
- }
- if let &Some(expr) = spread {
- f(expr);
- }
- }
- Expr::Closure { body, .. } => {
- f(*body);
- }
- Expr::BinaryOp { lhs, rhs, .. } => {
- f(*lhs);
- f(*rhs);
- }
- Expr::Range { lhs, rhs, .. } => {
- if let &Some(lhs) = rhs {
- f(lhs);
- }
- if let &Some(rhs) = lhs {
- f(rhs);
- }
- }
- Expr::Index { base, index, .. } => {
- f(*base);
- f(*index);
- }
- Expr::Field { expr, .. }
- | Expr::Await { expr }
- | Expr::Cast { expr, .. }
- | Expr::Ref { expr, .. }
- | Expr::UnaryOp { expr, .. }
- | Expr::Box { expr } => {
- f(*expr);
- }
- Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
- Expr::Array(a) => match a {
- Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
- Array::Repeat { initializer, repeat } => {
- f(*initializer);
- f(*repeat)
- }
- },
- Expr::Literal(_) => {}
- Expr::Underscore => {}
- }
- }
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Item {
+ MacroDef(Box<MacroDefId>),
+ Other,
}
/// Explicit binding annotations given in the HIR for a binding. Note
@@ -665,18 +563,49 @@
pub enum Pat {
Missing,
Wild,
- Tuple { args: Box<[PatId]>, ellipsis: Option<u32> },
+ Tuple {
+ args: Box<[PatId]>,
+ ellipsis: Option<u32>,
+ },
Or(Box<[PatId]>),
- Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
- Range { start: Option<Box<LiteralOrConst>>, end: Option<Box<LiteralOrConst>> },
- Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
- Path(Box<Path>),
+ Record {
+ path: Option<Box<Path>>,
+ args: Box<[RecordFieldPat]>,
+ ellipsis: bool,
+ },
+ Range {
+ start: Option<Box<LiteralOrConst>>,
+ end: Option<Box<LiteralOrConst>>,
+ },
+ Slice {
+ prefix: Box<[PatId]>,
+ slice: Option<PatId>,
+ suffix: Box<[PatId]>,
+ },
+ /// This might refer to a variable if a single segment path (specifically, on destructuring assignment).
+ Path(Path),
Lit(ExprId),
- Bind { id: BindingId, subpat: Option<PatId> },
- TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<u32> },
- Ref { pat: PatId, mutability: Mutability },
- Box { inner: PatId },
+ Bind {
+ id: BindingId,
+ subpat: Option<PatId>,
+ },
+ TupleStruct {
+ path: Option<Box<Path>>,
+ args: Box<[PatId]>,
+ ellipsis: Option<u32>,
+ },
+ Ref {
+ pat: PatId,
+ mutability: Mutability,
+ },
+ Box {
+ inner: PatId,
+ },
ConstBlock(ExprId),
+ /// An expression inside a pattern. That can only occur inside assignments.
+ ///
+ /// E.g. in `(a, *b) = (1, &mut 2)`, `*b` is an expression.
+ Expr(ExprId),
}
impl Pat {
@@ -687,7 +616,8 @@
| Pat::Path(..)
| Pat::ConstBlock(..)
| Pat::Wild
- | Pat::Missing => {}
+ | Pat::Missing
+ | Pat::Expr(_) => {}
Pat::Bind { subpat, .. } => {
subpat.iter().copied().for_each(f);
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
index b74cd90..2582340 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
@@ -2,22 +2,27 @@
//! be directly created from an ast::TypeRef, without further queries.
use core::fmt;
-use std::fmt::Write;
+use std::{fmt::Write, ops::Index};
use hir_expand::{
db::ExpandDatabase,
name::{AsName, Name},
- AstId,
+ AstId, InFile,
};
-use intern::{sym, Interned, Symbol};
+use intern::{sym, Symbol};
+use la_arena::{Arena, ArenaMap, Idx};
use span::Edition;
-use syntax::ast::{self, HasGenericArgs, HasName, IsString};
+use stdx::thin_vec::{thin_vec_with_header_struct, EmptyOptimizedThinVec, ThinVec};
+use syntax::{
+ ast::{self, HasGenericArgs, HasName, IsString},
+ AstPtr,
+};
use crate::{
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
hir::Literal,
lower::LowerCtx,
- path::Path,
+ path::{GenericArg, Path},
};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -104,35 +109,90 @@
}
}
+thin_vec_with_header_struct! {
+ pub new(pub(crate)) struct FnType, FnTypeHeader {
+ pub params: [(Option<Name>, TypeRefId)],
+ pub is_varargs: bool,
+ pub is_unsafe: bool,
+ pub abi: Option<Symbol>; ref,
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct ArrayType {
+ pub ty: TypeRefId,
+ // FIXME: This should be Ast<ConstArg>
+ pub len: ConstRef,
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct RefType {
+ pub ty: TypeRefId,
+ pub lifetime: Option<LifetimeRef>,
+ pub mutability: Mutability,
+}
+
/// Compare ty::Ty
-///
-/// Note: Most users of `TypeRef` that end up in the salsa database intern it using
-/// `Interned<TypeRef>` to save space. But notably, nested `TypeRef`s are not interned, since that
-/// does not seem to save any noticeable amount of memory.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum TypeRef {
Never,
Placeholder,
- Tuple(Vec<TypeRef>),
+ Tuple(EmptyOptimizedThinVec<TypeRefId>),
Path(Path),
- RawPtr(Box<TypeRef>, Mutability),
- Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
- // FIXME: This should be Array(Box<TypeRef>, Ast<ConstArg>),
- Array(Box<TypeRef>, ConstRef),
- Slice(Box<TypeRef>),
+ RawPtr(TypeRefId, Mutability),
+ Reference(Box<RefType>),
+ Array(Box<ArrayType>),
+ Slice(TypeRefId),
/// A fn pointer. Last element of the vector is the return type.
- Fn(
- Box<[(Option<Name>, TypeRef)]>,
- bool, /*varargs*/
- bool, /*is_unsafe*/
- Option<Symbol>, /* abi */
- ),
- ImplTrait(Vec<Interned<TypeBound>>),
- DynTrait(Vec<Interned<TypeBound>>),
+ Fn(FnType),
+ ImplTrait(ThinVec<TypeBound>),
+ DynTrait(ThinVec<TypeBound>),
Macro(AstId<ast::MacroCall>),
Error,
}
+#[cfg(target_arch = "x86_64")]
+const _: () = assert!(size_of::<TypeRef>() == 16);
+
+pub type TypeRefId = Idx<TypeRef>;
+
+#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
+pub struct TypesMap {
+ pub(crate) types: Arena<TypeRef>,
+}
+
+impl TypesMap {
+ pub const EMPTY: &TypesMap = &TypesMap { types: Arena::new() };
+
+ pub(crate) fn shrink_to_fit(&mut self) {
+ let TypesMap { types } = self;
+ types.shrink_to_fit();
+ }
+}
+
+impl Index<TypeRefId> for TypesMap {
+ type Output = TypeRef;
+
+ fn index(&self, index: TypeRefId) -> &Self::Output {
+ &self.types[index]
+ }
+}
+
+pub type TypePtr = AstPtr<ast::Type>;
+pub type TypeSource = InFile<TypePtr>;
+
+#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
+pub struct TypesSourceMap {
+ pub(crate) types_map_back: ArenaMap<TypeRefId, TypeSource>,
+}
+
+impl TypesSourceMap {
+ pub(crate) fn shrink_to_fit(&mut self) {
+ let TypesSourceMap { types_map_back } = self;
+ types_map_back.shrink_to_fit();
+ }
+}
+
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct LifetimeRef {
pub name: Name,
@@ -157,12 +217,22 @@
Path(Path, TraitBoundModifier),
ForLifetime(Box<[Name]>, Path),
Lifetime(LifetimeRef),
+ Use(Box<[UseArgRef]>),
Error,
}
+#[cfg(target_pointer_width = "64")]
+const _: [(); 32] = [(); ::std::mem::size_of::<TypeBound>()];
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub enum UseArgRef {
+ Name(Name),
+ Lifetime(LifetimeRef),
+}
+
/// A modifier on a bound, currently this is only used for `?Sized`, where the
/// modifier is `Maybe`.
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum TraitBoundModifier {
None,
Maybe,
@@ -170,12 +240,12 @@
impl TypeRef {
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
- pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self {
- match node {
- ast::Type::ParenType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
- ast::Type::TupleType(inner) => {
- TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
- }
+ pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> TypeRefId {
+ let ty = match &node {
+ ast::Type::ParenType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
+ ast::Type::TupleType(inner) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(
+ Vec::from_iter(inner.fields().map(|it| TypeRef::from_ast(ctx, it))),
+ )),
ast::Type::NeverType(..) => TypeRef::Never,
ast::Type::PathType(inner) => {
// FIXME: Use `Path::from_src`
@@ -188,20 +258,21 @@
ast::Type::PtrType(inner) => {
let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
let mutability = Mutability::from_mutable(inner.mut_token().is_some());
- TypeRef::RawPtr(Box::new(inner_ty), mutability)
+ TypeRef::RawPtr(inner_ty, mutability)
}
ast::Type::ArrayType(inner) => {
let len = ConstRef::from_const_arg(ctx, inner.const_arg());
- TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len)
+ TypeRef::Array(Box::new(ArrayType {
+ ty: TypeRef::from_ast_opt(ctx, inner.ty()),
+ len,
+ }))
}
- ast::Type::SliceType(inner) => {
- TypeRef::Slice(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())))
- }
+ ast::Type::SliceType(inner) => TypeRef::Slice(TypeRef::from_ast_opt(ctx, inner.ty())),
ast::Type::RefType(inner) => {
let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(<));
let mutability = Mutability::from_mutable(inner.mut_token().is_some());
- TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
+ TypeRef::Reference(Box::new(RefType { ty: inner_ty, lifetime, mutability }))
}
ast::Type::InferType(_inner) => TypeRef::Placeholder,
ast::Type::FnPtrType(inner) => {
@@ -209,7 +280,7 @@
.ret_type()
.and_then(|rt| rt.ty())
.map(|it| TypeRef::from_ast(ctx, it))
- .unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
+ .unwrap_or_else(|| ctx.alloc_type_ref_desugared(TypeRef::unit()));
let mut is_varargs = false;
let mut params = if let Some(pl) = inner.param_list() {
if let Some(param) = pl.params().last() {
@@ -241,10 +312,10 @@
let abi = inner.abi().map(lower_abi);
params.push((None, ret_ty));
- TypeRef::Fn(params.into(), is_varargs, inner.unsafe_token().is_some(), abi)
+ TypeRef::Fn(FnType::new(is_varargs, inner.unsafe_token().is_some(), abi, params))
}
// for types are close enough for our purposes to the inner type for now...
- ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
+ ast::Type::ForType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
ast::Type::ImplTraitType(inner) => {
if ctx.outer_impl_trait() {
// Disallow nested impl traits
@@ -261,74 +332,74 @@
Some(mc) => TypeRef::Macro(ctx.ast_id(&mc)),
None => TypeRef::Error,
},
- }
+ };
+ ctx.alloc_type_ref(ty, AstPtr::new(&node))
}
- pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> Self {
+ pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> TypeRefId {
match node {
Some(node) => TypeRef::from_ast(ctx, node),
- None => TypeRef::Error,
+ None => ctx.alloc_error_type(),
}
}
pub(crate) fn unit() -> TypeRef {
- TypeRef::Tuple(Vec::new())
+ TypeRef::Tuple(EmptyOptimizedThinVec::empty())
}
- pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
- go(self, f);
+ pub fn walk(this: TypeRefId, map: &TypesMap, f: &mut impl FnMut(&TypeRef)) {
+ go(this, f, map);
- fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
+ fn go(type_ref: TypeRefId, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
+ let type_ref = &map[type_ref];
f(type_ref);
match type_ref {
- TypeRef::Fn(params, _, _, _) => {
- params.iter().for_each(|(_, param_type)| go(param_type, f))
+ TypeRef::Fn(fn_) => {
+ fn_.params().iter().for_each(|&(_, param_type)| go(param_type, f, map))
}
- TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
- TypeRef::RawPtr(type_ref, _)
- | TypeRef::Reference(type_ref, ..)
- | TypeRef::Array(type_ref, _)
- | TypeRef::Slice(type_ref) => go(type_ref, f),
+ TypeRef::Tuple(types) => types.iter().for_each(|&t| go(t, f, map)),
+ TypeRef::RawPtr(type_ref, _) | TypeRef::Slice(type_ref) => go(*type_ref, f, map),
+ TypeRef::Reference(it) => go(it.ty, f, map),
+ TypeRef::Array(it) => go(it.ty, f, map),
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
for bound in bounds {
- match bound.as_ref() {
+ match bound {
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
- go_path(path, f)
+ go_path(path, f, map)
}
- TypeBound::Lifetime(_) | TypeBound::Error => (),
+ TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
}
}
}
- TypeRef::Path(path) => go_path(path, f),
+ TypeRef::Path(path) => go_path(path, f, map),
TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
};
}
- fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
+ fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
if let Some(type_ref) = path.type_anchor() {
- go(type_ref, f);
+ go(type_ref, f, map);
}
for segment in path.segments().iter() {
if let Some(args_and_bindings) = segment.args_and_bindings {
for arg in args_and_bindings.args.iter() {
match arg {
- crate::path::GenericArg::Type(type_ref) => {
- go(type_ref, f);
+ GenericArg::Type(type_ref) => {
+ go(*type_ref, f, map);
}
- crate::path::GenericArg::Const(_)
- | crate::path::GenericArg::Lifetime(_) => {}
+ GenericArg::Const(_) | GenericArg::Lifetime(_) => {}
}
}
for binding in args_and_bindings.bindings.iter() {
- if let Some(type_ref) = &binding.type_ref {
- go(type_ref, f);
+ if let Some(type_ref) = binding.type_ref {
+ go(type_ref, f, map);
}
for bound in binding.bounds.iter() {
- match bound.as_ref() {
+ match bound {
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
- go_path(path, f)
+ go_path(path, f, map)
}
- TypeBound::Lifetime(_) | TypeBound::Error => (),
+ TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
}
}
}
@@ -341,11 +412,13 @@
pub(crate) fn type_bounds_from_ast(
lower_ctx: &LowerCtx<'_>,
type_bounds_opt: Option<ast::TypeBoundList>,
-) -> Vec<Interned<TypeBound>> {
+) -> ThinVec<TypeBound> {
if let Some(type_bounds) = type_bounds_opt {
- type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect()
+ ThinVec::from_iter(Vec::from_iter(
+ type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)),
+ ))
} else {
- vec![]
+ ThinVec::from_iter([])
}
}
@@ -380,7 +453,16 @@
None => TypeBound::Error,
}
}
- ast::TypeBoundKind::Use(_) => TypeBound::Error,
+ ast::TypeBoundKind::Use(gal) => TypeBound::Use(
+ gal.use_bound_generic_args()
+ .map(|p| match p {
+ ast::UseBoundGenericArg::Lifetime(l) => {
+ UseArgRef::Lifetime(LifetimeRef::new(&l))
+ }
+ ast::UseBoundGenericArg::NameRef(n) => UseArgRef::Name(n.as_name()),
+ })
+ .collect(),
+ ),
ast::TypeBoundKind::Lifetime(lifetime) => {
TypeBound::Lifetime(LifetimeRef::new(&lifetime))
}
@@ -391,7 +473,7 @@
match self {
TypeBound::Path(p, m) => Some((p, m)),
TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)),
- TypeBound::Lifetime(_) | TypeBound::Error => None,
+ TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None,
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 7cb833f..b5bf2fe 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -61,7 +61,7 @@
db::DefDatabase,
generics::GenericParams,
path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
- type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
+ type_ref::{Mutability, TraitRef, TypeBound, TypeRefId, TypesMap, TypesSourceMap},
visibility::{RawVisibility, VisibilityExplicitness},
BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
};
@@ -100,14 +100,20 @@
impl ItemTree {
pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
- let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
- static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
+ db.file_item_tree_with_source_map(file_id).0
+ }
- let syntax = db.parse_or_expand(file_id);
+ pub(crate) fn file_item_tree_with_source_map_query(
+ db: &dyn DefDatabase,
+ file_id: HirFileId,
+ ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
+ let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
+ static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
let ctx = lower::Ctx::new(db, file_id);
+ let syntax = db.parse_or_expand(file_id);
let mut top_attrs = None;
- let mut item_tree = match_ast! {
+ let (mut item_tree, source_maps) = match_ast! {
match syntax {
ast::SourceFile(file) => {
top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.span_map()));
@@ -137,42 +143,55 @@
{
EMPTY
.get_or_init(|| {
- Arc::new(ItemTree {
- top_level: SmallVec::new_const(),
- attrs: FxHashMap::default(),
- data: None,
- })
+ (
+ Arc::new(ItemTree {
+ top_level: SmallVec::new_const(),
+ attrs: FxHashMap::default(),
+ data: None,
+ }),
+ Arc::default(),
+ )
})
.clone()
} else {
item_tree.shrink_to_fit();
- Arc::new(item_tree)
+ (Arc::new(item_tree), Arc::new(source_maps))
}
}
pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
+ db.block_item_tree_with_source_map(block).0
+ }
+
+ pub(crate) fn block_item_tree_with_source_map_query(
+ db: &dyn DefDatabase,
+ block: BlockId,
+ ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
- static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
+ static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
let loc = block.lookup(db);
let block = loc.ast_id.to_node(db.upcast());
let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
- let mut item_tree = ctx.lower_block(&block);
+ let (mut item_tree, source_maps) = ctx.lower_block(&block);
if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
{
EMPTY
.get_or_init(|| {
- Arc::new(ItemTree {
- top_level: SmallVec::new_const(),
- attrs: FxHashMap::default(),
- data: None,
- })
+ (
+ Arc::new(ItemTree {
+ top_level: SmallVec::new_const(),
+ attrs: FxHashMap::default(),
+ data: None,
+ }),
+ Arc::default(),
+ )
})
.clone()
} else {
item_tree.shrink_to_fit();
- Arc::new(item_tree)
+ (Arc::new(item_tree), Arc::new(source_maps))
}
}
@@ -309,6 +328,160 @@
vis: ItemVisibilities,
}
+#[derive(Default, Debug, Eq, PartialEq)]
+pub struct ItemTreeSourceMaps {
+ all_concatenated: Box<[TypesSourceMap]>,
+ structs_offset: u32,
+ unions_offset: u32,
+ enum_generics_offset: u32,
+ variants_offset: u32,
+ consts_offset: u32,
+ statics_offset: u32,
+ trait_generics_offset: u32,
+ trait_alias_generics_offset: u32,
+ impls_offset: u32,
+ type_aliases_offset: u32,
+}
+
+#[derive(Clone, Copy)]
+pub struct GenericItemSourceMap<'a>(&'a [TypesSourceMap; 2]);
+
+impl<'a> GenericItemSourceMap<'a> {
+ #[inline]
+ pub fn item(self) -> &'a TypesSourceMap {
+ &self.0[0]
+ }
+
+ #[inline]
+ pub fn generics(self) -> &'a TypesSourceMap {
+ &self.0[1]
+ }
+}
+
+#[derive(Default, Debug, Eq, PartialEq)]
+pub struct GenericItemSourceMapBuilder {
+ pub item: TypesSourceMap,
+ pub generics: TypesSourceMap,
+}
+
+#[derive(Default, Debug, Eq, PartialEq)]
+struct ItemTreeSourceMapsBuilder {
+ functions: Vec<GenericItemSourceMapBuilder>,
+ structs: Vec<GenericItemSourceMapBuilder>,
+ unions: Vec<GenericItemSourceMapBuilder>,
+ enum_generics: Vec<TypesSourceMap>,
+ variants: Vec<TypesSourceMap>,
+ consts: Vec<TypesSourceMap>,
+ statics: Vec<TypesSourceMap>,
+ trait_generics: Vec<TypesSourceMap>,
+ trait_alias_generics: Vec<TypesSourceMap>,
+ impls: Vec<GenericItemSourceMapBuilder>,
+ type_aliases: Vec<GenericItemSourceMapBuilder>,
+}
+
+impl ItemTreeSourceMapsBuilder {
+ fn build(self) -> ItemTreeSourceMaps {
+ let ItemTreeSourceMapsBuilder {
+ functions,
+ structs,
+ unions,
+ enum_generics,
+ variants,
+ consts,
+ statics,
+ trait_generics,
+ trait_alias_generics,
+ impls,
+ type_aliases,
+ } = self;
+ let structs_offset = functions.len() as u32 * 2;
+ let unions_offset = structs_offset + (structs.len() as u32 * 2);
+ let enum_generics_offset = unions_offset + (unions.len() as u32 * 2);
+ let variants_offset = enum_generics_offset + (enum_generics.len() as u32);
+ let consts_offset = variants_offset + (variants.len() as u32);
+ let statics_offset = consts_offset + (consts.len() as u32);
+ let trait_generics_offset = statics_offset + (statics.len() as u32);
+ let trait_alias_generics_offset = trait_generics_offset + (trait_generics.len() as u32);
+ let impls_offset = trait_alias_generics_offset + (trait_alias_generics.len() as u32);
+ let type_aliases_offset = impls_offset + (impls.len() as u32 * 2);
+ let all_concatenated = generics_concat(functions)
+ .chain(generics_concat(structs))
+ .chain(generics_concat(unions))
+ .chain(enum_generics)
+ .chain(variants)
+ .chain(consts)
+ .chain(statics)
+ .chain(trait_generics)
+ .chain(trait_alias_generics)
+ .chain(generics_concat(impls))
+ .chain(generics_concat(type_aliases))
+ .collect();
+ return ItemTreeSourceMaps {
+ all_concatenated,
+ structs_offset,
+ unions_offset,
+ enum_generics_offset,
+ variants_offset,
+ consts_offset,
+ statics_offset,
+ trait_generics_offset,
+ trait_alias_generics_offset,
+ impls_offset,
+ type_aliases_offset,
+ };
+
+ fn generics_concat(
+ source_maps: Vec<GenericItemSourceMapBuilder>,
+ ) -> impl Iterator<Item = TypesSourceMap> {
+ source_maps.into_iter().flat_map(|it| [it.item, it.generics])
+ }
+ }
+}
+
+impl ItemTreeSourceMaps {
+ #[inline]
+ fn generic_item(&self, offset: u32, index: u32) -> GenericItemSourceMap<'_> {
+ GenericItemSourceMap(
+ self.all_concatenated[(offset + (index * 2)) as usize..][..2].try_into().unwrap(),
+ )
+ }
+
+ #[inline]
+ fn non_generic_item(&self, offset: u32, index: u32) -> &TypesSourceMap {
+ &self.all_concatenated[(offset + index) as usize]
+ }
+
+ #[inline]
+ pub fn function(&self, index: FileItemTreeId<Function>) -> GenericItemSourceMap<'_> {
+ self.generic_item(0, index.0.into_raw().into_u32())
+ }
+}
+
+macro_rules! index_item_source_maps {
+ ( $( $name:ident; $field:ident[$tree_id:ident]; $fn:ident; $ret:ty, )* ) => {
+ impl ItemTreeSourceMaps {
+ $(
+ #[inline]
+ pub fn $name(&self, index: FileItemTreeId<$tree_id>) -> $ret {
+ self.$fn(self.$field, index.0.into_raw().into_u32())
+ }
+ )*
+ }
+ };
+}
+index_item_source_maps! {
+ strukt; structs_offset[Struct]; generic_item; GenericItemSourceMap<'_>,
+ union; unions_offset[Union]; generic_item; GenericItemSourceMap<'_>,
+ enum_generic; enum_generics_offset[Enum]; non_generic_item; &TypesSourceMap,
+ variant; variants_offset[Variant]; non_generic_item; &TypesSourceMap,
+ konst; consts_offset[Const]; non_generic_item; &TypesSourceMap,
+ statik; statics_offset[Static]; non_generic_item; &TypesSourceMap,
+ trait_generic; trait_generics_offset[Trait]; non_generic_item; &TypesSourceMap,
+ trait_alias_generic; trait_alias_generics_offset[TraitAlias]; non_generic_item; &TypesSourceMap,
+ impl_; impls_offset[Impl]; generic_item; GenericItemSourceMap<'_>,
+ type_alias; type_aliases_offset[TypeAlias]; generic_item; GenericItemSourceMap<'_>,
+}
+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum AttrOwner {
/// Attributes on an item.
@@ -364,7 +537,7 @@
fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
}
pub trait GenericsItemTreeNode: ItemTreeNode {
- fn generic_params(&self) -> &Interned<GenericParams>;
+ fn generic_params(&self) -> &Arc<GenericParams>;
}
pub struct FileItemTreeId<N>(Idx<N>);
@@ -429,6 +602,16 @@
}
}
+ pub fn item_tree_with_source_map(
+ &self,
+ db: &dyn DefDatabase,
+ ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
+ match self.block {
+ Some(block) => db.block_item_tree_with_source_map(block),
+ None => db.file_item_tree_with_source_map(self.file),
+ }
+ }
+
pub fn file_id(self) -> HirFileId {
self.file
}
@@ -461,6 +644,13 @@
self.tree.item_tree(db)
}
+ pub fn item_tree_with_source_map(
+ self,
+ db: &dyn DefDatabase,
+ ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
+ self.tree.item_tree_with_source_map(db)
+ }
+
pub fn resolved<R>(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R
where
ItemTree: Index<FileItemTreeId<N>, Output = N>,
@@ -593,7 +783,7 @@
$(
impl GenericsItemTreeNode for $typ {
- fn generic_params(&self) -> &Interned<GenericParams> {
+ fn generic_params(&self) -> &Arc<GenericParams> {
&self.$generic_params
}
}
@@ -731,17 +921,18 @@
pub struct Function {
pub name: Name,
pub visibility: RawVisibilityId,
- pub explicit_generic_params: Interned<GenericParams>,
+ pub explicit_generic_params: Arc<GenericParams>,
pub abi: Option<Symbol>,
pub params: Box<[Param]>,
- pub ret_type: Interned<TypeRef>,
+ pub ret_type: TypeRefId,
pub ast_id: FileAstId<ast::Fn>,
+ pub types_map: Arc<TypesMap>,
pub(crate) flags: FnFlags,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Param {
- pub type_ref: Option<Interned<TypeRef>>,
+ pub type_ref: Option<TypeRefId>,
}
bitflags::bitflags! {
@@ -762,26 +953,28 @@
pub struct Struct {
pub name: Name,
pub visibility: RawVisibilityId,
- pub generic_params: Interned<GenericParams>,
+ pub generic_params: Arc<GenericParams>,
pub fields: Box<[Field]>,
pub shape: FieldsShape,
pub ast_id: FileAstId<ast::Struct>,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Union {
pub name: Name,
pub visibility: RawVisibilityId,
- pub generic_params: Interned<GenericParams>,
+ pub generic_params: Arc<GenericParams>,
pub fields: Box<[Field]>,
pub ast_id: FileAstId<ast::Union>,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Enum {
pub name: Name,
pub visibility: RawVisibilityId,
- pub generic_params: Interned<GenericParams>,
+ pub generic_params: Arc<GenericParams>,
pub variants: Range<FileItemTreeId<Variant>>,
pub ast_id: FileAstId<ast::Enum>,
}
@@ -792,6 +985,7 @@
pub fields: Box<[Field]>,
pub shape: FieldsShape,
pub ast_id: FileAstId<ast::Variant>,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -805,7 +999,7 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Field {
pub name: Name,
- pub type_ref: Interned<TypeRef>,
+ pub type_ref: TypeRefId,
pub visibility: RawVisibilityId,
}
@@ -814,9 +1008,10 @@
/// `None` for `const _: () = ();`
pub name: Option<Name>,
pub visibility: RawVisibilityId,
- pub type_ref: Interned<TypeRef>,
+ pub type_ref: TypeRefId,
pub ast_id: FileAstId<ast::Const>,
pub has_body: bool,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -827,15 +1022,16 @@
pub mutable: bool,
pub has_safe_kw: bool,
pub has_unsafe_kw: bool,
- pub type_ref: Interned<TypeRef>,
+ pub type_ref: TypeRefId,
pub ast_id: FileAstId<ast::Static>,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Trait {
pub name: Name,
pub visibility: RawVisibilityId,
- pub generic_params: Interned<GenericParams>,
+ pub generic_params: Arc<GenericParams>,
pub is_auto: bool,
pub is_unsafe: bool,
pub items: Box<[AssocItem]>,
@@ -846,19 +1042,20 @@
pub struct TraitAlias {
pub name: Name,
pub visibility: RawVisibilityId,
- pub generic_params: Interned<GenericParams>,
+ pub generic_params: Arc<GenericParams>,
pub ast_id: FileAstId<ast::TraitAlias>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Impl {
- pub generic_params: Interned<GenericParams>,
- pub target_trait: Option<Interned<TraitRef>>,
- pub self_ty: Interned<TypeRef>,
+ pub generic_params: Arc<GenericParams>,
+ pub target_trait: Option<TraitRef>,
+ pub self_ty: TypeRefId,
pub is_negative: bool,
pub is_unsafe: bool,
pub items: Box<[AssocItem]>,
pub ast_id: FileAstId<ast::Impl>,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -866,10 +1063,11 @@
pub name: Name,
pub visibility: RawVisibilityId,
/// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
- pub bounds: Box<[Interned<TypeBound>]>,
- pub generic_params: Interned<GenericParams>,
- pub type_ref: Option<Interned<TypeRef>>,
+ pub bounds: Box<[TypeBound]>,
+ pub generic_params: Arc<GenericParams>,
+ pub type_ref: Option<TypeRefId>,
pub ast_id: FileAstId<ast::TypeAlias>,
+ pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -968,6 +1166,11 @@
self.expand_impl(None, &mut cb)
}
+ /// The [`UseTreeKind`] of this `UseTree`.
+ pub fn kind(&self) -> &UseTreeKind {
+ &self.kind
+ }
+
fn expand_impl(
&self,
prefix: Option<ModPath>,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index 431a7f6..bd17fce 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -1,12 +1,18 @@
//! AST -> `ItemTree` lowering code.
-use std::collections::hash_map::Entry;
+use std::{cell::OnceCell, collections::hash_map::Entry};
-use hir_expand::{mod_path::path, name::AsName, span_map::SpanMapRef, HirFileId};
+use hir_expand::{
+ mod_path::path,
+ name::AsName,
+ span_map::{SpanMap, SpanMapRef},
+ HirFileId,
+};
use intern::{sym, Symbol};
use la_arena::Arena;
use rustc_hash::FxHashMap;
use span::{AstIdMap, SyntaxContextId};
+use stdx::thin_vec::ThinVec;
use syntax::{
ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
AstNode,
@@ -18,14 +24,19 @@
generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
item_tree::{
AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldParent,
- FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, Impl,
- ImportAlias, Interned, ItemTree, ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem,
+ FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericItemSourceMapBuilder,
+ GenericModItem, Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData,
+ ItemTreeSourceMaps, ItemTreeSourceMapsBuilder, Macro2, MacroCall, MacroRules, Mod, ModItem,
ModKind, ModPath, Mutability, Name, Param, Path, Range, RawAttrs, RawIdx, RawVisibilityId,
Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
Variant,
},
+ lower::LowerCtx,
path::AssociatedTypeBinding,
- type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef},
+ type_ref::{
+ LifetimeRef, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId,
+ TypesMap, TypesSourceMap,
+ },
visibility::RawVisibility,
LocalLifetimeParamId, LocalTypeOrConstParamId,
};
@@ -40,7 +51,9 @@
source_ast_id_map: Arc<AstIdMap>,
generic_param_attr_buffer:
FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>,
- body_ctx: crate::lower::LowerCtx<'a>,
+ span_map: OnceCell<SpanMap>,
+ file: HirFileId,
+ source_maps: ItemTreeSourceMapsBuilder,
}
impl<'a> Ctx<'a> {
@@ -50,22 +63,49 @@
tree: ItemTree::default(),
generic_param_attr_buffer: FxHashMap::default(),
source_ast_id_map: db.ast_id_map(file),
- body_ctx: crate::lower::LowerCtx::new(db, file),
+ file,
+ span_map: OnceCell::new(),
+ source_maps: ItemTreeSourceMapsBuilder::default(),
}
}
pub(super) fn span_map(&self) -> SpanMapRef<'_> {
- self.body_ctx.span_map()
+ self.span_map.get_or_init(|| self.db.span_map(self.file)).as_ref()
}
- pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
+ fn body_ctx<'b, 'c>(
+ &self,
+ types_map: &'b mut TypesMap,
+ types_source_map: &'b mut TypesSourceMap,
+ ) -> LowerCtx<'c>
+ where
+ 'a: 'c,
+ 'b: 'c,
+ {
+ // FIXME: This seems a bit wasteful that if `LowerCtx` will initialize the span map we won't benefit.
+ LowerCtx::with_span_map_cell(
+ self.db,
+ self.file,
+ self.span_map.clone(),
+ types_map,
+ types_source_map,
+ )
+ }
+
+ pub(super) fn lower_module_items(
+ mut self,
+ item_owner: &dyn HasModuleItem,
+ ) -> (ItemTree, ItemTreeSourceMaps) {
self.tree.top_level =
item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
assert!(self.generic_param_attr_buffer.is_empty());
- self.tree
+ (self.tree, self.source_maps.build())
}
- pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree {
+ pub(super) fn lower_macro_stmts(
+ mut self,
+ stmts: ast::MacroStmts,
+ ) -> (ItemTree, ItemTreeSourceMaps) {
self.tree.top_level = stmts
.statements()
.filter_map(|stmt| {
@@ -96,10 +136,10 @@
}
assert!(self.generic_param_attr_buffer.is_empty());
- self.tree
+ (self.tree, self.source_maps.build())
}
- pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
+ pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> (ItemTree, ItemTreeSourceMaps) {
self.tree
.attrs
.insert(AttrOwner::TopLevel, RawAttrs::new(self.db.upcast(), block, self.span_map()));
@@ -125,7 +165,7 @@
}
assert!(self.generic_param_attr_buffer.is_empty());
- self.tree
+ (self.tree, self.source_maps.build())
}
fn data(&mut self) -> &mut ItemTreeData {
@@ -144,7 +184,7 @@
ast::Item::Module(ast) => self.lower_module(ast)?.into(),
ast::Item::Trait(ast) => self.lower_trait(ast)?.into(),
ast::Item::TraitAlias(ast) => self.lower_trait_alias(ast)?.into(),
- ast::Item::Impl(ast) => self.lower_impl(ast)?.into(),
+ ast::Item::Impl(ast) => self.lower_impl(ast).into(),
ast::Item::Use(ast) => self.lower_use(ast)?.into(),
ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(),
ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(),
@@ -159,12 +199,14 @@
}
fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
- match self.tree.attrs.entry(item) {
- Entry::Occupied(mut entry) => {
- *entry.get_mut() = entry.get().merge(attrs);
- }
- Entry::Vacant(entry) => {
- entry.insert(attrs);
+ if !attrs.is_empty() {
+ match self.tree.attrs.entry(item) {
+ Entry::Occupied(mut entry) => {
+ *entry.get_mut() = entry.get().merge(attrs);
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(attrs);
+ }
}
}
}
@@ -190,13 +232,31 @@
}
fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let visibility = self.lower_visibility(strukt);
let name = strukt.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(strukt);
- let (fields, kind, attrs) = self.lower_fields(&strukt.kind());
- let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
- let res = Struct { name, visibility, generic_params, fields, shape: kind, ast_id };
+ let (fields, kind, attrs) = self.lower_fields(&strukt.kind(), &body_ctx);
+ let (generic_params, generics_source_map) =
+ self.lower_generic_params(HasImplicitSelf::No, strukt);
+ types_map.shrink_to_fit();
+ types_source_map.shrink_to_fit();
+ let res = Struct {
+ name,
+ visibility,
+ generic_params,
+ fields,
+ shape: kind,
+ ast_id,
+ types_map: Arc::new(types_map),
+ };
let id = id(self.data().structs.alloc(res));
+ self.source_maps.structs.push(GenericItemSourceMapBuilder {
+ item: types_source_map,
+ generics: generics_source_map,
+ });
for (idx, attr) in attrs {
self.add_attrs(
AttrOwner::Field(
@@ -213,6 +273,7 @@
fn lower_fields(
&mut self,
strukt_kind: &ast::StructKind,
+ body_ctx: &LowerCtx<'_>,
) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
match strukt_kind {
ast::StructKind::Record(it) => {
@@ -220,7 +281,7 @@
let mut attrs = vec![];
for (i, field) in it.fields().enumerate() {
- let data = self.lower_record_field(&field);
+ let data = self.lower_record_field(&field, body_ctx);
fields.push(data);
let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
if !attr.is_empty() {
@@ -234,7 +295,7 @@
let mut attrs = vec![];
for (i, field) in it.fields().enumerate() {
- let data = self.lower_tuple_field(i, &field);
+ let data = self.lower_tuple_field(i, &field, body_ctx);
fields.push(data);
let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
if !attr.is_empty() {
@@ -247,35 +308,59 @@
}
}
- fn lower_record_field(&mut self, field: &ast::RecordField) -> Field {
+ fn lower_record_field(&mut self, field: &ast::RecordField, body_ctx: &LowerCtx<'_>) -> Field {
let name = match field.name() {
Some(name) => name.as_name(),
None => Name::missing(),
};
let visibility = self.lower_visibility(field);
- let type_ref = self.lower_type_ref_opt(field.ty());
+ let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
Field { name, type_ref, visibility }
}
- fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
+ fn lower_tuple_field(
+ &mut self,
+ idx: usize,
+ field: &ast::TupleField,
+ body_ctx: &LowerCtx<'_>,
+ ) -> Field {
let name = Name::new_tuple_field(idx);
let visibility = self.lower_visibility(field);
- let type_ref = self.lower_type_ref_opt(field.ty());
+ let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
Field { name, type_ref, visibility }
}
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let visibility = self.lower_visibility(union);
let name = union.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(union);
let (fields, _, attrs) = match union.record_field_list() {
- Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
+ Some(record_field_list) => {
+ self.lower_fields(&StructKind::Record(record_field_list), &body_ctx)
+ }
None => (Box::default(), FieldsShape::Record, Vec::default()),
};
- let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
- let res = Union { name, visibility, generic_params, fields, ast_id };
+ let (generic_params, generics_source_map) =
+ self.lower_generic_params(HasImplicitSelf::No, union);
+ types_map.shrink_to_fit();
+ types_source_map.shrink_to_fit();
+ let res = Union {
+ name,
+ visibility,
+ generic_params,
+ fields,
+ ast_id,
+ types_map: Arc::new(types_map),
+ };
let id = id(self.data().unions.alloc(res));
+ self.source_maps.unions.push(GenericItemSourceMapBuilder {
+ item: types_source_map,
+ generics: generics_source_map,
+ });
for (idx, attr) in attrs {
self.add_attrs(
AttrOwner::Field(
@@ -299,9 +384,11 @@
FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
}
};
- let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
+ let (generic_params, generics_source_map) =
+ self.lower_generic_params(HasImplicitSelf::No, enum_);
let res = Enum { name, visibility, generic_params, variants, ast_id };
let id = id(self.data().enums.alloc(res));
+ self.source_maps.enum_generics.push(generics_source_map);
self.write_generic_params_attributes(id.into());
Some(id)
}
@@ -320,14 +407,20 @@
}
fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> {
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let name = match variant.name() {
Some(name) => name.as_name(),
None => Name::missing(),
};
- let (fields, kind, attrs) = self.lower_fields(&variant.kind());
+ let (fields, kind, attrs) = self.lower_fields(&variant.kind(), &body_ctx);
let ast_id = self.source_ast_id_map.ast_id(variant);
- let res = Variant { name, fields, shape: kind, ast_id };
+ types_map.shrink_to_fit();
+ types_source_map.shrink_to_fit();
+ let res = Variant { name, fields, shape: kind, ast_id, types_map: Arc::new(types_map) };
let id = self.data().variants.alloc(res);
+ self.source_maps.variants.push(types_source_map);
for (idx, attr) in attrs {
self.add_attrs(
AttrOwner::Field(
@@ -341,6 +434,10 @@
}
fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+
let visibility = self.lower_visibility(func);
let name = func.name()?.as_name();
@@ -360,27 +457,31 @@
RawAttrs::new(self.db.upcast(), &self_param, self.span_map()),
);
let self_type = match self_param.ty() {
- Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
+ Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
None => {
- let self_type =
- TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into());
+ let self_type = body_ctx.alloc_type_ref_desugared(TypeRef::Path(
+ Name::new_symbol_root(sym::Self_.clone()).into(),
+ ));
match self_param.kind() {
ast::SelfParamKind::Owned => self_type,
- ast::SelfParamKind::Ref => TypeRef::Reference(
- Box::new(self_type),
- self_param.lifetime().as_ref().map(LifetimeRef::new),
- Mutability::Shared,
+ ast::SelfParamKind::Ref => body_ctx.alloc_type_ref_desugared(
+ TypeRef::Reference(Box::new(RefType {
+ ty: self_type,
+ lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new),
+ mutability: Mutability::Shared,
+ })),
),
- ast::SelfParamKind::MutRef => TypeRef::Reference(
- Box::new(self_type),
- self_param.lifetime().as_ref().map(LifetimeRef::new),
- Mutability::Mut,
+ ast::SelfParamKind::MutRef => body_ctx.alloc_type_ref_desugared(
+ TypeRef::Reference(Box::new(RefType {
+ ty: self_type,
+ lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new),
+ mutability: Mutability::Mut,
+ })),
),
}
}
};
- let type_ref = Interned::new(self_type);
- params.push(Param { type_ref: Some(type_ref) });
+ params.push(Param { type_ref: Some(self_type) });
has_self_param = true;
}
for param in param_list.params() {
@@ -391,9 +492,8 @@
Param { type_ref: None }
}
None => {
- let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
- let ty = Interned::new(type_ref);
- Param { type_ref: Some(ty) }
+ let type_ref = TypeRef::from_ast_opt(&body_ctx, param.ty());
+ Param { type_ref: Some(type_ref) }
}
};
params.push(param);
@@ -402,17 +502,17 @@
let ret_type = match func.ret_type() {
Some(rt) => match rt.ty() {
- Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
- None if rt.thin_arrow_token().is_some() => TypeRef::Error,
- None => TypeRef::unit(),
+ Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
+ None if rt.thin_arrow_token().is_some() => body_ctx.alloc_error_type(),
+ None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
},
- None => TypeRef::unit(),
+ None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
};
let ret_type = if func.async_token().is_some() {
let future_impl = desugar_future_path(ret_type);
- let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None));
- TypeRef::ImplTrait(vec![ty_bound])
+ let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None);
+ body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound])))
} else {
ret_type
};
@@ -447,18 +547,27 @@
flags |= FnFlags::IS_VARARGS;
}
+ types_map.shrink_to_fit();
+ types_source_map.shrink_to_fit();
+ let (generic_params, generics_source_map) =
+ self.lower_generic_params(HasImplicitSelf::No, func);
let res = Function {
name,
visibility,
- explicit_generic_params: self.lower_generic_params(HasImplicitSelf::No, func),
+ explicit_generic_params: generic_params,
abi,
params: params.into_boxed_slice(),
- ret_type: Interned::new(ret_type),
+ ret_type,
ast_id,
+ types_map: Arc::new(types_map),
flags,
};
let id = id(self.data().functions.alloc(res));
+ self.source_maps.functions.push(GenericItemSourceMapBuilder {
+ item: types_source_map,
+ generics: generics_source_map,
+ });
for (idx, attr) in attrs {
self.add_attrs(AttrOwner::Param(id, Idx::from_raw(RawIdx::from_u32(idx as u32))), attr);
}
@@ -470,37 +579,82 @@
&mut self,
type_alias: &ast::TypeAlias,
) -> Option<FileItemTreeId<TypeAlias>> {
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let name = type_alias.name()?.as_name();
- let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it));
+ let type_ref = type_alias.ty().map(|it| TypeRef::from_ast(&body_ctx, it));
let visibility = self.lower_visibility(type_alias);
- let bounds = self.lower_type_bounds(type_alias);
+ let bounds = self.lower_type_bounds(type_alias, &body_ctx);
let ast_id = self.source_ast_id_map.ast_id(type_alias);
- let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias);
- let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id };
+ let (generic_params, generics_source_map) =
+ self.lower_generic_params(HasImplicitSelf::No, type_alias);
+ types_map.shrink_to_fit();
+ types_source_map.shrink_to_fit();
+ let res = TypeAlias {
+ name,
+ visibility,
+ bounds,
+ generic_params,
+ type_ref,
+ ast_id,
+ types_map: Arc::new(types_map),
+ };
let id = id(self.data().type_aliases.alloc(res));
+ self.source_maps.type_aliases.push(GenericItemSourceMapBuilder {
+ item: types_source_map,
+ generics: generics_source_map,
+ });
self.write_generic_params_attributes(id.into());
Some(id)
}
fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let name = static_.name()?.as_name();
- let type_ref = self.lower_type_ref_opt(static_.ty());
+ let type_ref = TypeRef::from_ast_opt(&body_ctx, static_.ty());
let visibility = self.lower_visibility(static_);
let mutable = static_.mut_token().is_some();
let has_safe_kw = static_.safe_token().is_some();
let has_unsafe_kw = static_.unsafe_token().is_some();
let ast_id = self.source_ast_id_map.ast_id(static_);
- let res =
- Static { name, visibility, mutable, type_ref, ast_id, has_safe_kw, has_unsafe_kw };
+ types_map.shrink_to_fit();
+ types_source_map.shrink_to_fit();
+ let res = Static {
+ name,
+ visibility,
+ mutable,
+ type_ref,
+ ast_id,
+ has_safe_kw,
+ has_unsafe_kw,
+ types_map: Arc::new(types_map),
+ };
+ self.source_maps.statics.push(types_source_map);
Some(id(self.data().statics.alloc(res)))
}
fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let name = konst.name().map(|it| it.as_name());
- let type_ref = self.lower_type_ref_opt(konst.ty());
+ let type_ref = TypeRef::from_ast_opt(&body_ctx, konst.ty());
let visibility = self.lower_visibility(konst);
let ast_id = self.source_ast_id_map.ast_id(konst);
- let res = Const { name, visibility, type_ref, ast_id, has_body: konst.body().is_some() };
+ types_map.shrink_to_fit();
+ types_source_map.shrink_to_fit();
+ let res = Const {
+ name,
+ visibility,
+ type_ref,
+ ast_id,
+ has_body: konst.body().is_some(),
+ types_map: Arc::new(types_map),
+ };
+ self.source_maps.consts.push(types_source_map);
id(self.data().consts.alloc(res))
}
@@ -539,10 +693,11 @@
.filter_map(|item_node| self.lower_assoc_item(&item_node))
.collect();
- let generic_params =
+ let (generic_params, generics_source_map) =
self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id };
let id = id(self.data().traits.alloc(def));
+ self.source_maps.trait_generics.push(generics_source_map);
self.write_generic_params_attributes(id.into());
Some(id)
}
@@ -554,24 +709,29 @@
let name = trait_alias_def.name()?.as_name();
let visibility = self.lower_visibility(trait_alias_def);
let ast_id = self.source_ast_id_map.ast_id(trait_alias_def);
- let generic_params = self.lower_generic_params(
+ let (generic_params, generics_source_map) = self.lower_generic_params(
HasImplicitSelf::Yes(trait_alias_def.type_bound_list()),
trait_alias_def,
);
let alias = TraitAlias { name, visibility, generic_params, ast_id };
let id = id(self.data().trait_aliases.alloc(alias));
+ self.source_maps.trait_alias_generics.push(generics_source_map);
self.write_generic_params_attributes(id.into());
Some(id)
}
- fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
+ fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> {
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+
let ast_id = self.source_ast_id_map.ast_id(impl_def);
// FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
// as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
// equals itself.
- let self_ty = self.lower_type_ref(&impl_def.self_ty()?);
- let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
+ let self_ty = TypeRef::from_ast_opt(&body_ctx, impl_def.self_ty());
+ let target_trait = impl_def.trait_().and_then(|tr| TraitRef::from_ast(&body_ctx, tr));
let is_negative = impl_def.excl_token().is_some();
let is_unsafe = impl_def.unsafe_token().is_some();
@@ -584,12 +744,27 @@
.collect();
// Note that trait impls don't get implicit `Self` unlike traits, because here they are a
// type alias rather than a type parameter, so this is handled by the resolver.
- let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
- let res =
- Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id };
+ let (generic_params, generics_source_map) =
+ self.lower_generic_params(HasImplicitSelf::No, impl_def);
+ types_map.shrink_to_fit();
+ types_source_map.shrink_to_fit();
+ let res = Impl {
+ generic_params,
+ target_trait,
+ self_ty,
+ is_negative,
+ is_unsafe,
+ items,
+ ast_id,
+ types_map: Arc::new(types_map),
+ };
let id = id(self.data().impls.alloc(res));
+ self.source_maps.impls.push(GenericItemSourceMapBuilder {
+ item: types_source_map,
+ generics: generics_source_map,
+ });
self.write_generic_params_attributes(id.into());
- Some(id)
+ id
}
fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
@@ -692,14 +867,17 @@
&mut self,
has_implicit_self: HasImplicitSelf,
node: &dyn ast::HasGenericParams,
- ) -> Interned<GenericParams> {
+ ) -> (Arc<GenericParams>, TypesSourceMap) {
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
debug_assert!(self.generic_param_attr_buffer.is_empty(),);
let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
param| {
- let attrs = RawAttrs::new(self.db.upcast(), ¶m, self.body_ctx.span_map());
+ let attrs = RawAttrs::new(self.db.upcast(), ¶m, body_ctx.span_map());
debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
};
- self.body_ctx.take_impl_traits_bounds();
+ body_ctx.take_impl_traits_bounds();
let mut generics = GenericParamsCollector::default();
if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
@@ -715,23 +893,29 @@
// add super traits as bounds on Self
// i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
generics.fill_bounds(
- &self.body_ctx,
+ &body_ctx,
bounds,
- Either::Left(TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into())),
+ Either::Left(body_ctx.alloc_type_ref_desugared(TypeRef::Path(
+ Name::new_symbol_root(sym::Self_.clone()).into(),
+ ))),
);
}
- generics.fill(&self.body_ctx, node, add_param_attrs);
+ generics.fill(&body_ctx, node, add_param_attrs);
- Interned::new(generics.finish())
+ let generics = generics.finish(types_map, &mut types_source_map);
+ (generics, types_source_map)
}
- fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned<TypeBound>]> {
+ fn lower_type_bounds(
+ &mut self,
+ node: &dyn ast::HasTypeBounds,
+ body_ctx: &LowerCtx<'_>,
+ ) -> Box<[TypeBound]> {
match node.type_bound_list() {
- Some(bound_list) => bound_list
- .bounds()
- .map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it)))
- .collect(),
+ Some(bound_list) => {
+ bound_list.bounds().map(|it| TypeBound::from_ast(body_ctx, it)).collect()
+ }
None => Box::default(),
}
}
@@ -743,23 +927,6 @@
self.data().vis.alloc(vis)
}
- fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Interned<TraitRef>> {
- let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?;
- Some(Interned::new(trait_ref))
- }
-
- fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Interned<TypeRef> {
- let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone());
- Interned::new(tyref)
- }
-
- fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Interned<TypeRef> {
- match type_ref.map(|ty| self.lower_type_ref(&ty)) {
- Some(it) => it,
- None => Interned::new(TypeRef::Error),
- }
- }
-
fn next_variant_idx(&self) -> Idx<Variant> {
Idx::from_raw(RawIdx::from(
self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
@@ -767,7 +934,7 @@
}
}
-fn desugar_future_path(orig: TypeRef) -> Path {
+fn desugar_future_path(orig: TypeRefId) -> Path {
let path = path![core::future::Future];
let mut generic_args: Vec<_> =
std::iter::repeat(None).take(path.segments().len() - 1).collect();
@@ -777,10 +944,7 @@
type_ref: Some(orig),
bounds: Box::default(),
};
- generic_args.push(Some(Interned::new(GenericArgs {
- bindings: Box::new([binding]),
- ..GenericArgs::empty()
- })));
+ generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));
Path::from_known_path(path, generic_args)
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index 9dce28b..b6816a1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -10,11 +10,12 @@
item_tree::{
AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent,
FieldsShape, FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl,
- Interned, ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path,
- RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound,
- TypeRef, Union, Use, UseTree, UseTreeKind, Variant,
+ ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path, RawAttrs,
+ RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, Union, Use,
+ UseTree, UseTreeKind, Variant,
},
pretty::{print_path, print_type_bounds, print_type_ref},
+ type_ref::{TypeRefId, TypesMap},
visibility::RawVisibility,
};
@@ -121,7 +122,13 @@
};
}
- fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) {
+ fn print_fields(
+ &mut self,
+ parent: FieldParent,
+ kind: FieldsShape,
+ fields: &[Field],
+ map: &TypesMap,
+ ) {
let edition = self.edition;
match kind {
FieldsShape::Record => {
@@ -135,7 +142,7 @@
);
this.print_visibility(*visibility);
w!(this, "{}: ", name.display(self.db.upcast(), edition));
- this.print_type_ref(type_ref);
+ this.print_type_ref(*type_ref, map);
wln!(this, ",");
}
});
@@ -151,7 +158,7 @@
);
this.print_visibility(*visibility);
w!(this, "{}: ", name.display(self.db.upcast(), edition));
- this.print_type_ref(type_ref);
+ this.print_type_ref(*type_ref, map);
wln!(this, ",");
}
});
@@ -167,20 +174,21 @@
kind: FieldsShape,
fields: &[Field],
params: &GenericParams,
+ map: &TypesMap,
) {
match kind {
FieldsShape::Record => {
if self.print_where_clause(params) {
wln!(self);
}
- self.print_fields(parent, kind, fields);
+ self.print_fields(parent, kind, fields, map);
}
FieldsShape::Unit => {
self.print_where_clause(params);
- self.print_fields(parent, kind, fields);
+ self.print_fields(parent, kind, fields, map);
}
FieldsShape::Tuple => {
- self.print_fields(parent, kind, fields);
+ self.print_fields(parent, kind, fields, map);
self.print_where_clause(params);
}
}
@@ -262,6 +270,7 @@
params,
ret_type,
ast_id,
+ types_map,
flags,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
@@ -298,7 +307,7 @@
w!(this, "self: ");
}
if let Some(type_ref) = type_ref {
- this.print_type_ref(type_ref);
+ this.print_type_ref(*type_ref, types_map);
} else {
wln!(this, "...");
}
@@ -307,7 +316,7 @@
});
}
w!(self, ") -> ");
- self.print_type_ref(ret_type);
+ self.print_type_ref(*ret_type, types_map);
self.print_where_clause(explicit_generic_params);
if flags.contains(FnFlags::HAS_BODY) {
wln!(self, " {{ ... }}");
@@ -316,8 +325,15 @@
}
}
ModItem::Struct(it) => {
- let Struct { visibility, name, fields, shape: kind, generic_params, ast_id } =
- &self.tree[it];
+ let Struct {
+ visibility,
+ name,
+ fields,
+ shape: kind,
+ generic_params,
+ ast_id,
+ types_map,
+ } = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "struct {}", name.display(self.db.upcast(), self.edition));
@@ -327,6 +343,7 @@
*kind,
fields,
generic_params,
+ types_map,
);
if matches!(kind, FieldsShape::Record) {
wln!(self);
@@ -335,7 +352,8 @@
}
}
ModItem::Union(it) => {
- let Union { name, visibility, fields, generic_params, ast_id } = &self.tree[it];
+ let Union { name, visibility, fields, generic_params, ast_id, types_map } =
+ &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "union {}", name.display(self.db.upcast(), self.edition));
@@ -345,6 +363,7 @@
FieldsShape::Record,
fields,
generic_params,
+ types_map,
);
wln!(self);
}
@@ -358,18 +377,20 @@
let edition = self.edition;
self.indented(|this| {
for variant in FileItemTreeId::range_iter(variants.clone()) {
- let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant];
+ let Variant { name, fields, shape: kind, ast_id, types_map } =
+ &this.tree[variant];
this.print_ast_id(ast_id.erase());
this.print_attrs_of(variant, "\n");
w!(this, "{}", name.display(self.db.upcast(), edition));
- this.print_fields(FieldParent::Variant(variant), *kind, fields);
+ this.print_fields(FieldParent::Variant(variant), *kind, fields, types_map);
wln!(this, ",");
}
});
wln!(self, "}}");
}
ModItem::Const(it) => {
- let Const { name, visibility, type_ref, ast_id, has_body: _ } = &self.tree[it];
+ let Const { name, visibility, type_ref, ast_id, has_body: _, types_map } =
+ &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "const ");
@@ -378,7 +399,7 @@
None => w!(self, "_"),
}
w!(self, ": ");
- self.print_type_ref(type_ref);
+ self.print_type_ref(*type_ref, types_map);
wln!(self, " = _;");
}
ModItem::Static(it) => {
@@ -390,6 +411,7 @@
ast_id,
has_safe_kw,
has_unsafe_kw,
+ types_map,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
@@ -404,7 +426,7 @@
w!(self, "mut ");
}
w!(self, "{}: ", name.display(self.db.upcast(), self.edition));
- self.print_type_ref(type_ref);
+ self.print_type_ref(*type_ref, types_map);
w!(self, " = _;");
wln!(self);
}
@@ -449,6 +471,7 @@
items,
generic_params,
ast_id,
+ types_map,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
if *is_unsafe {
@@ -461,10 +484,10 @@
w!(self, "!");
}
if let Some(tr) = target_trait {
- self.print_path(&tr.path);
+ self.print_path(&tr.path, types_map);
w!(self, " for ");
}
- self.print_type_ref(self_ty);
+ self.print_type_ref(*self_ty, types_map);
self.print_where_clause_and_opening_brace(generic_params);
self.indented(|this| {
for item in &**items {
@@ -474,19 +497,26 @@
wln!(self, "}}");
}
ModItem::TypeAlias(it) => {
- let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id } =
- &self.tree[it];
+ let TypeAlias {
+ name,
+ visibility,
+ bounds,
+ type_ref,
+ generic_params,
+ ast_id,
+ types_map,
+ } = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "type {}", name.display(self.db.upcast(), self.edition));
self.print_generic_params(generic_params, it.into());
if !bounds.is_empty() {
w!(self, ": ");
- self.print_type_bounds(bounds);
+ self.print_type_bounds(bounds, types_map);
}
if let Some(ty) = type_ref {
w!(self, " = ");
- self.print_type_ref(ty);
+ self.print_type_ref(*ty, types_map);
}
self.print_where_clause(generic_params);
w!(self, ";");
@@ -543,19 +573,19 @@
self.blank();
}
- fn print_type_ref(&mut self, type_ref: &TypeRef) {
+ fn print_type_ref(&mut self, type_ref: TypeRefId, map: &TypesMap) {
let edition = self.edition;
- print_type_ref(self.db, type_ref, self, edition).unwrap();
+ print_type_ref(self.db, type_ref, map, self, edition).unwrap();
}
- fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
+ fn print_type_bounds(&mut self, bounds: &[TypeBound], map: &TypesMap) {
let edition = self.edition;
- print_type_bounds(self.db, bounds, self, edition).unwrap();
+ print_type_bounds(self.db, bounds, map, self, edition).unwrap();
}
- fn print_path(&mut self, path: &Path) {
+ fn print_path(&mut self, path: &Path, map: &TypesMap) {
let edition = self.edition;
- print_path(self.db, path, self, edition).unwrap();
+ print_path(self.db, path, map, self, edition).unwrap();
}
fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
@@ -586,7 +616,7 @@
},
TypeOrConstParamData::ConstParamData(konst) => {
w!(self, "const {}: ", konst.name.display(self.db.upcast(), self.edition));
- self.print_type_ref(&konst.ty);
+ self.print_type_ref(konst.ty, ¶ms.types_map);
}
}
}
@@ -640,14 +670,16 @@
};
match target {
- WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
+ WherePredicateTypeTarget::TypeRef(ty) => {
+ this.print_type_ref(*ty, ¶ms.types_map)
+ }
WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
Some(name) => w!(this, "{}", name.display(self.db.upcast(), edition)),
None => w!(this, "_anon_{}", id.into_raw()),
},
}
w!(this, ": ");
- this.print_type_bounds(std::slice::from_ref(bound));
+ this.print_type_bounds(std::slice::from_ref(bound), ¶ms.types_map);
}
});
true
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 157c9ef..f6ed826 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -1531,11 +1531,3 @@
pub struct UnresolvedMacro {
pub path: hir_expand::mod_path::ModPath,
}
-
-intern::impl_internable!(
- crate::type_ref::TypeRef,
- crate::type_ref::TraitRef,
- crate::type_ref::TypeBound,
- crate::path::GenericArgs,
- generics::GenericParams,
-);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
index e4786a1..df58479 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
@@ -5,43 +5,53 @@
span_map::{SpanMap, SpanMapRef},
AstId, HirFileId, InFile,
};
-use intern::Interned;
use span::{AstIdMap, AstIdNode};
+use stdx::thin_vec::ThinVec;
use syntax::ast;
use triomphe::Arc;
-use crate::{db::DefDatabase, path::Path, type_ref::TypeBound};
+use crate::{
+ db::DefDatabase,
+ path::Path,
+ type_ref::{TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap},
+};
pub struct LowerCtx<'a> {
pub db: &'a dyn DefDatabase,
file_id: HirFileId,
span_map: OnceCell<SpanMap>,
ast_id_map: OnceCell<Arc<AstIdMap>>,
- impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>,
+ impl_trait_bounds: RefCell<Vec<ThinVec<TypeBound>>>,
// Prevent nested impl traits like `impl Foo<impl Bar>`.
outer_impl_trait: RefCell<bool>,
+ types_map: RefCell<(&'a mut TypesMap, &'a mut TypesSourceMap)>,
}
-pub(crate) struct OuterImplTraitGuard<'a> {
- ctx: &'a LowerCtx<'a>,
+pub(crate) struct OuterImplTraitGuard<'a, 'b> {
+ ctx: &'a LowerCtx<'b>,
old: bool,
}
-impl<'a> OuterImplTraitGuard<'a> {
- fn new(ctx: &'a LowerCtx<'a>, impl_trait: bool) -> Self {
+impl<'a, 'b> OuterImplTraitGuard<'a, 'b> {
+ fn new(ctx: &'a LowerCtx<'b>, impl_trait: bool) -> Self {
let old = ctx.outer_impl_trait.replace(impl_trait);
Self { ctx, old }
}
}
-impl<'a> Drop for OuterImplTraitGuard<'a> {
+impl Drop for OuterImplTraitGuard<'_, '_> {
fn drop(&mut self) {
self.ctx.outer_impl_trait.replace(self.old);
}
}
impl<'a> LowerCtx<'a> {
- pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
+ pub fn new(
+ db: &'a dyn DefDatabase,
+ file_id: HirFileId,
+ types_map: &'a mut TypesMap,
+ types_source_map: &'a mut TypesSourceMap,
+ ) -> Self {
LowerCtx {
db,
file_id,
@@ -49,6 +59,7 @@
ast_id_map: OnceCell::new(),
impl_trait_bounds: RefCell::new(Vec::new()),
outer_impl_trait: RefCell::default(),
+ types_map: RefCell::new((types_map, types_source_map)),
}
}
@@ -56,6 +67,8 @@
db: &'a dyn DefDatabase,
file_id: HirFileId,
span_map: OnceCell<SpanMap>,
+ types_map: &'a mut TypesMap,
+ types_source_map: &'a mut TypesSourceMap,
) -> Self {
LowerCtx {
db,
@@ -64,6 +77,7 @@
ast_id_map: OnceCell::new(),
impl_trait_bounds: RefCell::new(Vec::new()),
outer_impl_trait: RefCell::default(),
+ types_map: RefCell::new((types_map, types_source_map)),
}
}
@@ -82,11 +96,11 @@
)
}
- pub fn update_impl_traits_bounds(&self, bounds: Vec<Interned<TypeBound>>) {
+ pub fn update_impl_traits_bounds(&self, bounds: ThinVec<TypeBound>) {
self.impl_trait_bounds.borrow_mut().push(bounds);
}
- pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> {
+ pub fn take_impl_traits_bounds(&self) -> Vec<ThinVec<TypeBound>> {
self.impl_trait_bounds.take()
}
@@ -94,7 +108,32 @@
*self.outer_impl_trait.borrow()
}
- pub(crate) fn outer_impl_trait_scope(&'a self, impl_trait: bool) -> OuterImplTraitGuard<'a> {
+ pub(crate) fn outer_impl_trait_scope<'b>(
+ &'b self,
+ impl_trait: bool,
+ ) -> OuterImplTraitGuard<'b, 'a> {
OuterImplTraitGuard::new(self, impl_trait)
}
+
+ pub(crate) fn alloc_type_ref(&self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
+ let mut types_map = self.types_map.borrow_mut();
+ let (types_map, types_source_map) = &mut *types_map;
+ let id = types_map.types.alloc(type_ref);
+ types_source_map.types_map_back.insert(id, InFile::new(self.file_id, node));
+ id
+ }
+
+ pub(crate) fn alloc_type_ref_desugared(&self, type_ref: TypeRef) -> TypeRefId {
+ self.types_map.borrow_mut().0.types.alloc(type_ref)
+ }
+
+ pub(crate) fn alloc_error_type(&self) -> TypeRefId {
+ self.types_map.borrow_mut().0.types.alloc(TypeRef::Error)
+ }
+
+ // FIXME: If we alloc while holding this, well... Bad Things will happen. Need to change this
+ // to use proper mutability instead of interior mutability.
+ pub(crate) fn types_map(&self) -> std::cell::Ref<'_, TypesMap> {
+ std::cell::Ref::map(self.types_map.borrow(), |it| &*it.0)
+ }
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index 450a15b..d5b94f0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -122,7 +122,7 @@
let mut expn_text = String::new();
if let Some(err) = exp.err {
- format_to!(expn_text, "/* error: {} */", err.render_to_string(&db).0);
+ format_to!(expn_text, "/* error: {} */", err.render_to_string(&db).message);
}
let (parse, token_map) = exp.value;
if expect_errors {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 22b9c2b..a37e3c7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -31,7 +31,7 @@
item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
item_tree::{
self, AttrOwner, FieldsShape, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
- ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
+ ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind,
},
macro_call_as_call_id, macro_call_as_call_id_with_eager,
nameres::{
@@ -985,12 +985,8 @@
for (name, res) in resolutions {
match name {
Some(name) => {
- changed |= self.push_res_and_update_glob_vis(
- module_id,
- name,
- res.with_visibility(vis),
- import,
- );
+ changed |=
+ self.push_res_and_update_glob_vis(module_id, name, *res, vis, import);
}
None => {
let tr = match res.take_types() {
@@ -1043,10 +1039,11 @@
.collect::<Vec<_>>();
for (glob_importing_module, glob_import_vis, use_) in glob_imports {
+ let vis = glob_import_vis.min(vis, &self.def_map).unwrap_or(glob_import_vis);
self.update_recursive(
glob_importing_module,
resolutions,
- glob_import_vis,
+ vis,
Some(ImportType::Glob(use_)),
depth + 1,
);
@@ -1058,8 +1055,44 @@
module_id: LocalModuleId,
name: &Name,
mut defs: PerNs,
+ vis: Visibility,
def_import_type: Option<ImportType>,
) -> bool {
+ // `extern crate crate_name` things can be re-exported as `pub use crate_name`.
+ // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
+ // or `pub use ::crate_name`.
+ //
+ // This has been historically allowed, but may be not allowed in future
+ // https://github.com/rust-lang/rust/issues/127909
+ if let Some((_, v, it)) = defs.types.as_mut() {
+ let is_extern_crate_reimport_without_prefix = || {
+ let Some(ImportOrExternCrate::ExternCrate(_)) = it else {
+ return false;
+ };
+ let Some(ImportType::Import(id)) = def_import_type else {
+ return false;
+ };
+ let use_id = id.import.lookup(self.db).id;
+ let item_tree = use_id.item_tree(self.db);
+ let use_kind = item_tree[use_id.value].use_tree.kind();
+ let UseTreeKind::Single { path, .. } = use_kind else {
+ return false;
+ };
+ path.segments().len() < 2
+ };
+ if is_extern_crate_reimport_without_prefix() {
+ *v = vis;
+ } else {
+ *v = v.min(vis, &self.def_map).unwrap_or(vis);
+ }
+ }
+ if let Some((_, v, _)) = defs.values.as_mut() {
+ *v = v.min(vis, &self.def_map).unwrap_or(vis);
+ }
+ if let Some((_, v, _)) = defs.macros.as_mut() {
+ *v = v.min(vis, &self.def_map).unwrap_or(vis);
+ }
+
let mut changed = false;
if let Some(ImportType::Glob(_)) = def_import_type {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index 75cab13..29379d0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -10,6 +10,7 @@
//!
//! `ReachedFixedPoint` signals about this.
+use either::Either;
use hir_expand::{name::Name, Lookup};
use span::Edition;
use triomphe::Arc;
@@ -150,17 +151,8 @@
let mut arc;
let mut current_map = self;
- loop {
- let new = current_map.resolve_path_fp_with_macro_single(
- db,
- mode,
- original_module,
- path,
- shadow,
- expected_macro_subns,
- );
- // Merge `new` into `result`.
+ let mut merge = |new: ResolvePathResult| {
result.resolved_def = result.resolved_def.or(new.resolved_def);
if result.reached_fixedpoint == ReachedFixedPoint::No {
result.reached_fixedpoint = new.reached_fixedpoint;
@@ -171,7 +163,9 @@
(Some(old), Some(new)) => Some(old.max(new)),
(None, new) => new,
};
+ };
+ loop {
match current_map.block {
Some(block) if original_module == Self::ROOT => {
// Block modules "inherit" names from its parent module.
@@ -180,8 +174,38 @@
current_map = &arc;
}
// Proper (non-block) modules, including those in block `DefMap`s, don't.
- _ => return result,
+ _ => {
+ if original_module != Self::ROOT && current_map.block.is_some() {
+ // A module inside a block. Do not resolve items declared in upper blocks, but we do need to get
+ // the prelude items (which are not inserted into blocks because they can be overridden there).
+ original_module = Self::ROOT;
+ arc = db.crate_def_map(self.krate);
+ current_map = &arc;
+
+ let new = current_map.resolve_path_fp_in_all_preludes(
+ db,
+ mode,
+ original_module,
+ path,
+ shadow,
+ );
+ merge(new);
+ }
+
+ return result;
+ }
}
+
+ let new = current_map.resolve_path_fp_with_macro_single(
+ db,
+ mode,
+ original_module,
+ path,
+ shadow,
+ expected_macro_subns,
+ );
+
+ merge(new);
}
}
@@ -195,7 +219,7 @@
expected_macro_subns: Option<MacroSubNs>,
) -> ResolvePathResult {
let mut segments = path.segments().iter().enumerate();
- let mut curr_per_ns = match path.kind {
+ let curr_per_ns = match path.kind {
PathKind::DollarCrate(krate) => {
if krate == self.krate {
cov_mark::hit!(macro_dollar_crate_self);
@@ -296,25 +320,96 @@
PerNs::types(module.into(), Visibility::Public, None)
}
- PathKind::Abs => {
- // 2018-style absolute path -- only extern prelude
- let segment = match segments.next() {
- Some((_, segment)) => segment,
+ PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
+ Either::Left(it) => it,
+ Either::Right(reached_fixed_point) => {
+ return ResolvePathResult::empty(reached_fixed_point)
+ }
+ },
+ };
+
+ self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
+ }
+
+ /// Resolves a path only in the preludes, without accounting for item scopes.
+ pub(super) fn resolve_path_fp_in_all_preludes(
+ &self,
+ db: &dyn DefDatabase,
+ mode: ResolveMode,
+ original_module: LocalModuleId,
+ path: &ModPath,
+ shadow: BuiltinShadowMode,
+ ) -> ResolvePathResult {
+ let mut segments = path.segments().iter().enumerate();
+ let curr_per_ns = match path.kind {
+ // plain import or absolute path in 2015: crate-relative with
+ // fallback to extern prelude (with the simplification in
+ // rust-lang/rust#57745)
+ // FIXME there must be a nicer way to write this condition
+ PathKind::Plain | PathKind::Abs
+ if self.data.edition == Edition::Edition2015
+ && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
+ {
+ let (_, segment) = match segments.next() {
+ Some((idx, segment)) => (idx, segment),
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
- if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
- tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
- PerNs::types(
- def.into(),
- Visibility::Public,
- extern_crate.map(ImportOrExternCrate::ExternCrate),
- )
- } else {
- return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
+ tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
+ self.resolve_name_in_extern_prelude(segment)
+ }
+ PathKind::Plain => {
+ let (_, segment) = match segments.next() {
+ Some((idx, segment)) => (idx, segment),
+ None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
+ };
+ tracing::debug!("resolving {:?} in module", segment);
+ self.resolve_name_in_all_preludes(db, segment)
+ }
+ PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
+ Either::Left(it) => it,
+ Either::Right(reached_fixed_point) => {
+ return ResolvePathResult::empty(reached_fixed_point)
}
+ },
+ PathKind::DollarCrate(_) | PathKind::Crate | PathKind::Super(_) => {
+ return ResolvePathResult::empty(ReachedFixedPoint::Yes)
}
};
+ self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
+ }
+
+ /// 2018-style absolute path -- only extern prelude
+ fn resolve_path_abs<'a>(
+ &self,
+ segments: &mut impl Iterator<Item = (usize, &'a Name)>,
+ path: &ModPath,
+ ) -> Either<PerNs, ReachedFixedPoint> {
+ let segment = match segments.next() {
+ Some((_, segment)) => segment,
+ None => return Either::Right(ReachedFixedPoint::Yes),
+ };
+ if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
+ tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
+ Either::Left(PerNs::types(
+ def.into(),
+ Visibility::Public,
+ extern_crate.map(ImportOrExternCrate::ExternCrate),
+ ))
+ } else {
+ Either::Right(ReachedFixedPoint::No) // extern crate declarations can add to the extern prelude
+ }
+ }
+
+ fn resolve_remaining_segments<'a>(
+ &self,
+ segments: impl Iterator<Item = (usize, &'a Name)>,
+ mut curr_per_ns: PerNs,
+ path: &ModPath,
+ db: &dyn DefDatabase,
+ shadow: BuiltinShadowMode,
+ original_module: LocalModuleId,
+ ) -> ResolvePathResult {
for (i, segment) in segments {
let (curr, vis, imp) = match curr_per_ns.take_types_full() {
Some(r) => r,
@@ -475,24 +570,9 @@
// they might been shadowed by local names.
return PerNs::none();
}
- self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
- PerNs::types(
- it.into(),
- Visibility::Public,
- extern_crate.map(ImportOrExternCrate::ExternCrate),
- )
- })
+ self.resolve_name_in_extern_prelude(name)
};
- let macro_use_prelude = || {
- self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
- PerNs::macros(
- it,
- Visibility::Public,
- // FIXME?
- None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
- )
- })
- };
+ let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
let prelude = || {
if self.block.is_some() && module == DefMap::ROOT {
return PerNs::none();
@@ -507,6 +587,38 @@
.or_else(prelude)
}
+ fn resolve_name_in_all_preludes(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
+ // Resolve in:
+ // - extern prelude / macro_use prelude
+ // - std prelude
+ let extern_prelude = self.resolve_name_in_extern_prelude(name);
+ let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
+ let prelude = || self.resolve_in_prelude(db, name);
+
+ extern_prelude.or_else(macro_use_prelude).or_else(prelude)
+ }
+
+ fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
+ self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
+ PerNs::types(
+ it.into(),
+ Visibility::Public,
+ extern_crate.map(ImportOrExternCrate::ExternCrate),
+ )
+ })
+ }
+
+ fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNs {
+ self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
+ PerNs::macros(
+ it,
+ Visibility::Public,
+ // FIXME?
+ None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
+ )
+ })
+ }
+
fn resolve_name_in_crate_root_or_extern_prelude(
&self,
db: &dyn DefDatabase,
@@ -525,16 +637,7 @@
// Don't resolve extern prelude in pseudo-module of a block.
return PerNs::none();
}
- self.data.extern_prelude.get(name).copied().map_or(
- PerNs::none(),
- |(it, extern_crate)| {
- PerNs::types(
- it.into(),
- Visibility::Public,
- extern_crate.map(ImportOrExternCrate::ExternCrate),
- )
- },
- )
+ self.resolve_name_in_extern_prelude(name)
};
from_crate_root.or_else(from_extern_prelude)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index 7b02a89..e1e30e5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -386,6 +386,52 @@
}
#[test]
+fn extern_crate_reexport() {
+ check(
+ r#"
+//- /main.rs crate:main deps:importer
+use importer::*;
+use importer::extern_crate1::exported::*;
+use importer::allowed_reexport::*;
+use importer::extern_crate2::*;
+use importer::not_allowed_reexport1;
+use importer::not_allowed_reexport2;
+
+//- /importer.rs crate:importer deps:extern_crate1,extern_crate2
+extern crate extern_crate1;
+extern crate extern_crate2;
+
+pub use extern_crate1;
+pub use extern_crate1 as allowed_reexport;
+
+pub use ::extern_crate;
+pub use self::extern_crate as not_allowed_reexport1;
+pub use crate::extern_crate as not_allowed_reexport2;
+
+//- /extern_crate1.rs crate:extern_crate1
+pub mod exported {
+ pub struct PublicItem;
+ struct PrivateItem;
+}
+
+pub struct Exported;
+
+//- /extern_crate2.rs crate:extern_crate2
+pub struct NotExported;
+"#,
+ expect![[r#"
+ crate
+ Exported: t v
+ PublicItem: t v
+ allowed_reexport: t
+ exported: t
+ not_allowed_reexport1: _
+ not_allowed_reexport2: _
+ "#]],
+ );
+}
+
+#[test]
fn extern_crate_rename_2015_edition() {
check(
r#"
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
index a269605..543ab41 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
@@ -412,3 +412,42 @@
"#]],
);
}
+
+#[test]
+fn regression_18308() {
+ check(
+ r#"
+use outer::*;
+
+mod outer {
+ mod inner_superglob {
+ pub use super::*;
+ }
+
+ // The importing order matters!
+ pub use inner_superglob::*;
+ use super::glob_target::*;
+}
+
+mod glob_target {
+ pub struct ShouldBePrivate;
+}
+"#,
+ expect![[r#"
+ crate
+ glob_target: t
+ outer: t
+
+ crate::glob_target
+ ShouldBePrivate: t v
+
+ crate::outer
+ ShouldBePrivate: t v
+ inner_superglob: t
+
+ crate::outer::inner_superglob
+ ShouldBePrivate: t v
+ inner_superglob: t
+ "#]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index d319831..d920c10 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -253,7 +253,8 @@
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
assert_eq!(module_data.scope.resolutions().count(), 4);
});
- let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
+ let n_recalculated_item_trees =
+ events.iter().filter(|it| it.contains("item_tree(")).count();
assert_eq!(n_recalculated_item_trees, 6);
let n_reparsed_macros =
events.iter().filter(|it| it.contains("parse_macro_expansion(")).count();
@@ -308,7 +309,7 @@
let events = db.log_executed(|| {
db.file_item_tree(pos.file_id.into());
});
- let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
+ let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree(")).count();
assert_eq!(n_calculated_item_trees, 1);
let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count();
assert_eq!(n_parsed_files, 1);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
index 077863c..dc6947c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -9,11 +9,12 @@
use crate::{
lang_item::LangItemTarget,
lower::LowerCtx,
- type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
+ type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRefId},
};
use hir_expand::name::Name;
use intern::Interned;
use span::Edition;
+use stdx::thin_vec::thin_vec_with_header_struct;
use syntax::ast;
pub use hir_expand::mod_path::{path, ModPath, PathKind};
@@ -47,20 +48,33 @@
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Path {
- /// A normal path
- Normal {
- /// Type based path like `<T>::foo`.
- /// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`.
- type_anchor: Option<Interned<TypeRef>>,
- mod_path: Interned<ModPath>,
- /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`.
- generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>,
- },
+ /// `BarePath` is used when the path has neither generics nor type anchor, since the vast majority of paths
+ /// are in this category, and splitting `Path` this way allows it to be more thin. When the path has either generics
+ /// or type anchor, it is `Path::Normal` with the generics filled with `None` even if there are none (practically
+ /// this is not a problem since many more paths have generics than a type anchor).
+ BarePath(Interned<ModPath>),
+ /// `Path::Normal` may have empty generics and type anchor (but generic args will be filled with `None`).
+ Normal(NormalPath),
/// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
/// links via a normal path since they might be private and not accessible in the usage place.
LangItem(LangItemTarget, Option<Name>),
}
+// This type is being used a lot, make sure it doesn't grow unintentionally.
+#[cfg(target_arch = "x86_64")]
+const _: () = {
+ assert!(size_of::<Path>() == 16);
+ assert!(size_of::<Option<Path>>() == 16);
+};
+
+thin_vec_with_header_struct! {
+ pub new(pub(crate)) struct NormalPath, NormalPathHeader {
+ pub generic_args: [Option<GenericArgs>],
+ pub type_anchor: Option<TypeRefId>,
+ pub mod_path: Interned<ModPath>; ref,
+ }
+}
+
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -86,20 +100,20 @@
pub name: Name,
/// The generic arguments to the associated type. e.g. For `Trait<Assoc<'a, T> = &'a T>`, this
/// would be `['a, T]`.
- pub args: Option<Interned<GenericArgs>>,
+ pub args: Option<GenericArgs>,
/// The type bound to this associated type (in `Item = T`, this would be the
/// `T`). This can be `None` if there are bounds instead.
- pub type_ref: Option<TypeRef>,
+ pub type_ref: Option<TypeRefId>,
/// Bounds for the associated type, like in `Iterator<Item:
/// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
/// feature.)
- pub bounds: Box<[Interned<TypeBound>]>,
+ pub bounds: Box<[TypeBound]>,
}
/// A single generic argument.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GenericArg {
- Type(TypeRef),
+ Type(TypeRefId),
Lifetime(LifetimeRef),
Const(ConstRef),
}
@@ -112,50 +126,49 @@
}
/// Converts a known mod path to `Path`.
- pub fn from_known_path(
- path: ModPath,
- generic_args: impl Into<Box<[Option<Interned<GenericArgs>>]>>,
- ) -> Path {
- let generic_args = generic_args.into();
- assert_eq!(path.len(), generic_args.len());
- Path::Normal {
- type_anchor: None,
- mod_path: Interned::new(path),
- generic_args: Some(generic_args),
- }
+ pub fn from_known_path(path: ModPath, generic_args: Vec<Option<GenericArgs>>) -> Path {
+ Path::Normal(NormalPath::new(None, Interned::new(path), generic_args))
}
/// Converts a known mod path to `Path`.
pub fn from_known_path_with_no_generic(path: ModPath) -> Path {
- Path::Normal { type_anchor: None, mod_path: Interned::new(path), generic_args: None }
+ Path::BarePath(Interned::new(path))
}
+ #[inline]
pub fn kind(&self) -> &PathKind {
match self {
- Path::Normal { mod_path, .. } => &mod_path.kind,
+ Path::BarePath(mod_path) => &mod_path.kind,
+ Path::Normal(path) => &path.mod_path().kind,
Path::LangItem(..) => &PathKind::Abs,
}
}
- pub fn type_anchor(&self) -> Option<&TypeRef> {
+ #[inline]
+ pub fn type_anchor(&self) -> Option<TypeRefId> {
match self {
- Path::Normal { type_anchor, .. } => type_anchor.as_deref(),
- Path::LangItem(..) => None,
+ Path::Normal(path) => path.type_anchor(),
+ Path::LangItem(..) | Path::BarePath(_) => None,
+ }
+ }
+
+ #[inline]
+ pub fn generic_args(&self) -> Option<&[Option<GenericArgs>]> {
+ match self {
+ Path::Normal(path) => Some(path.generic_args()),
+ Path::LangItem(..) | Path::BarePath(_) => None,
}
}
pub fn segments(&self) -> PathSegments<'_> {
match self {
- Path::Normal { mod_path, generic_args, .. } => {
- let s = PathSegments {
- segments: mod_path.segments(),
- generic_args: generic_args.as_deref(),
- };
- if let Some(generic_args) = s.generic_args {
- assert_eq!(s.segments.len(), generic_args.len());
- }
- s
+ Path::BarePath(mod_path) => {
+ PathSegments { segments: mod_path.segments(), generic_args: None }
}
+ Path::Normal(path) => PathSegments {
+ segments: path.mod_path().segments(),
+ generic_args: Some(path.generic_args()),
+ },
Path::LangItem(_, seg) => PathSegments {
segments: seg.as_ref().map_or(&[], |seg| std::slice::from_ref(seg)),
generic_args: None,
@@ -165,34 +178,55 @@
pub fn mod_path(&self) -> Option<&ModPath> {
match self {
- Path::Normal { mod_path, .. } => Some(mod_path),
+ Path::BarePath(mod_path) => Some(mod_path),
+ Path::Normal(path) => Some(path.mod_path()),
Path::LangItem(..) => None,
}
}
pub fn qualifier(&self) -> Option<Path> {
- let Path::Normal { mod_path, generic_args, type_anchor } = self else {
- return None;
- };
- if mod_path.is_ident() {
- return None;
+ match self {
+ Path::BarePath(mod_path) => {
+ if mod_path.is_ident() {
+ return None;
+ }
+ Some(Path::BarePath(Interned::new(ModPath::from_segments(
+ mod_path.kind,
+ mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
+ ))))
+ }
+ Path::Normal(path) => {
+ let mod_path = path.mod_path();
+ if mod_path.is_ident() {
+ return None;
+ }
+ let type_anchor = path.type_anchor();
+ let generic_args = path.generic_args();
+ let qualifier_mod_path = Interned::new(ModPath::from_segments(
+ mod_path.kind,
+ mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
+ ));
+ let qualifier_generic_args = &generic_args[..generic_args.len() - 1];
+ Some(Path::Normal(NormalPath::new(
+ type_anchor,
+ qualifier_mod_path,
+ qualifier_generic_args.iter().cloned(),
+ )))
+ }
+ Path::LangItem(..) => None,
}
- let res = Path::Normal {
- type_anchor: type_anchor.clone(),
- mod_path: Interned::new(ModPath::from_segments(
- mod_path.kind,
- mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
- )),
- generic_args: generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()),
- };
- Some(res)
}
pub fn is_self_type(&self) -> bool {
- let Path::Normal { mod_path, generic_args, type_anchor } = self else {
- return false;
- };
- type_anchor.is_none() && generic_args.as_deref().is_none() && mod_path.is_Self()
+ match self {
+ Path::BarePath(mod_path) => mod_path.is_Self(),
+ Path::Normal(path) => {
+ path.type_anchor().is_none()
+ && path.mod_path().is_Self()
+ && path.generic_args().iter().all(|args| args.is_none())
+ }
+ Path::LangItem(..) => false,
+ }
}
}
@@ -204,7 +238,7 @@
pub struct PathSegments<'a> {
segments: &'a [Name],
- generic_args: Option<&'a [Option<Interned<GenericArgs>>]>,
+ generic_args: Option<&'a [Option<GenericArgs>]>,
}
impl<'a> PathSegments<'a> {
@@ -224,7 +258,7 @@
pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
let res = PathSegment {
name: self.segments.get(idx)?,
- args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_deref()),
+ args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_ref()),
};
Some(res)
}
@@ -244,7 +278,7 @@
self.segments
.iter()
.zip(self.generic_args.into_iter().flatten().chain(iter::repeat(&None)))
- .map(|(name, args)| PathSegment { name, args_and_bindings: args.as_deref() })
+ .map(|(name, args)| PathSegment { name, args_and_bindings: args.as_ref() })
}
}
@@ -268,16 +302,6 @@
impl From<Name> for Path {
fn from(name: Name) -> Path {
- Path::Normal {
- type_anchor: None,
- mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))),
- generic_args: None,
- }
- }
-}
-
-impl From<Name> for Box<Path> {
- fn from(name: Name) -> Box<Path> {
- Box::new(Path::from(name))
+ Path::BarePath(Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))))
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
index 70918a9..c328b9c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
@@ -2,13 +2,14 @@
use std::iter;
-use crate::{lower::LowerCtx, type_ref::ConstRef};
+use crate::{lower::LowerCtx, path::NormalPath, type_ref::ConstRef};
use hir_expand::{
mod_path::resolve_crate_root,
name::{AsName, Name},
};
use intern::{sym, Interned};
+use stdx::thin_vec::EmptyOptimizedThinVec;
use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds};
use crate::{
@@ -51,8 +52,7 @@
segment.param_list(),
segment.ret_type(),
)
- })
- .map(Interned::new);
+ });
if args.is_some() {
generic_args.resize(segments.len(), None);
generic_args.push(args);
@@ -70,16 +70,14 @@
match trait_ref {
// <T>::foo
None => {
- type_anchor = Some(Interned::new(self_type));
+ type_anchor = Some(self_type);
kind = PathKind::Plain;
}
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
Some(trait_ref) => {
- let Path::Normal { mod_path, generic_args: path_generic_args, .. } =
- Path::from_src(ctx, trait_ref.path()?)?
- else {
- return None;
- };
+ let path = Path::from_src(ctx, trait_ref.path()?)?;
+ let mod_path = path.mod_path()?;
+ let path_generic_args = path.generic_args();
let num_segments = mod_path.segments().len();
kind = mod_path.kind;
@@ -95,7 +93,7 @@
// Insert the type reference (T in the above example) as Self parameter for the trait
let last_segment = generic_args.get_mut(segments.len() - num_segments)?;
- *last_segment = Some(Interned::new(match last_segment.take() {
+ *last_segment = Some(match last_segment.take() {
Some(it) => GenericArgs {
args: iter::once(self_type)
.chain(it.args.iter().cloned())
@@ -110,7 +108,7 @@
has_self_type: true,
..GenericArgs::empty()
},
- }));
+ });
}
}
}
@@ -137,7 +135,7 @@
};
}
segments.reverse();
- if !generic_args.is_empty() {
+ if !generic_args.is_empty() || type_anchor.is_some() {
generic_args.resize(segments.len(), None);
generic_args.reverse();
}
@@ -166,11 +164,11 @@
}
let mod_path = Interned::new(ModPath::from_segments(kind, segments));
- return Some(Path::Normal {
- type_anchor,
- mod_path,
- generic_args: if generic_args.is_empty() { None } else { Some(generic_args.into()) },
- });
+ if type_anchor.is_none() && generic_args.is_empty() {
+ return Some(Path::BarePath(mod_path));
+ } else {
+ return Some(Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args)));
+ }
fn qualifier(path: &ast::Path) -> Option<ast::Path> {
if let Some(q) = path.qualifier() {
@@ -194,11 +192,13 @@
match generic_arg {
ast::GenericArg::TypeArg(type_arg) => {
let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty());
- type_ref.walk(&mut |tr| {
+ let types_map = lower_ctx.types_map();
+ TypeRef::walk(type_ref, &types_map, &mut |tr| {
if let TypeRef::ImplTrait(bounds) = tr {
lower_ctx.update_impl_traits_bounds(bounds.clone());
}
});
+ drop(types_map);
args.push(GenericArg::Type(type_ref));
}
ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
@@ -212,20 +212,19 @@
let name = name_ref.as_name();
let args = assoc_type_arg
.generic_arg_list()
- .and_then(|args| lower_generic_args(lower_ctx, args))
- .map(Interned::new);
+ .and_then(|args| lower_generic_args(lower_ctx, args));
let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
- let type_ref = type_ref.inspect(|tr| {
- tr.walk(&mut |tr| {
+ let type_ref = type_ref.inspect(|&tr| {
+ let types_map = lower_ctx.types_map();
+ TypeRef::walk(tr, &types_map, &mut |tr| {
if let TypeRef::ImplTrait(bounds) = tr {
lower_ctx.update_impl_traits_bounds(bounds.clone());
}
});
+ drop(types_map);
});
let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
- l.bounds()
- .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
- .collect()
+ l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
} else {
Box::default()
};
@@ -269,7 +268,9 @@
let type_ref = TypeRef::from_ast_opt(ctx, param.ty());
param_types.push(type_ref);
}
- let args = Box::new([GenericArg::Type(TypeRef::Tuple(param_types))]);
+ let args = Box::new([GenericArg::Type(
+ ctx.alloc_type_ref_desugared(TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(param_types))),
+ )]);
let bindings = if let Some(ret_type) = ret_type {
let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty());
Box::new([AssociatedTypeBinding {
@@ -280,7 +281,7 @@
}])
} else {
// -> ()
- let type_ref = TypeRef::Tuple(Vec::new());
+ let type_ref = ctx.alloc_type_ref_desugared(TypeRef::unit());
Box::new([AssociatedTypeBinding {
name: Name::new_symbol_root(sym::Output.clone()),
args: None,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
index d5ef17a..9ceb82d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
@@ -1,9 +1,11 @@
//! Display and pretty printing routines.
-use std::fmt::{self, Write};
+use std::{
+ fmt::{self, Write},
+ mem,
+};
use hir_expand::mod_path::PathKind;
-use intern::Interned;
use itertools::Itertools;
use span::Edition;
@@ -11,12 +13,15 @@
db::DefDatabase,
lang_item::LangItemTarget,
path::{GenericArg, GenericArgs, Path},
- type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
+ type_ref::{
+ Mutability, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, UseArgRef,
+ },
};
pub(crate) fn print_path(
db: &dyn DefDatabase,
path: &Path,
+ map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
@@ -58,7 +63,7 @@
match path.type_anchor() {
Some(anchor) => {
write!(buf, "<")?;
- print_type_ref(db, anchor, buf, edition)?;
+ print_type_ref(db, anchor, map, buf, edition)?;
write!(buf, ">::")?;
}
None => match path.kind() {
@@ -87,7 +92,7 @@
write!(buf, "{}", segment.name.display(db.upcast(), edition))?;
if let Some(generics) = segment.args_and_bindings {
write!(buf, "::<")?;
- print_generic_args(db, generics, buf, edition)?;
+ print_generic_args(db, generics, map, buf, edition)?;
write!(buf, ">")?;
}
@@ -99,6 +104,7 @@
pub(crate) fn print_generic_args(
db: &dyn DefDatabase,
generics: &GenericArgs,
+ map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
@@ -106,7 +112,7 @@
let args = if generics.has_self_type {
let (self_ty, args) = generics.args.split_first().unwrap();
write!(buf, "Self=")?;
- print_generic_arg(db, self_ty, buf, edition)?;
+ print_generic_arg(db, self_ty, map, buf, edition)?;
first = false;
args
} else {
@@ -117,7 +123,7 @@
write!(buf, ", ")?;
}
first = false;
- print_generic_arg(db, arg, buf, edition)?;
+ print_generic_arg(db, arg, map, buf, edition)?;
}
for binding in generics.bindings.iter() {
if !first {
@@ -127,11 +133,11 @@
write!(buf, "{}", binding.name.display(db.upcast(), edition))?;
if !binding.bounds.is_empty() {
write!(buf, ": ")?;
- print_type_bounds(db, &binding.bounds, buf, edition)?;
+ print_type_bounds(db, &binding.bounds, map, buf, edition)?;
}
- if let Some(ty) = &binding.type_ref {
+ if let Some(ty) = binding.type_ref {
write!(buf, " = ")?;
- print_type_ref(db, ty, buf, edition)?;
+ print_type_ref(db, ty, map, buf, edition)?;
}
}
Ok(())
@@ -140,11 +146,12 @@
pub(crate) fn print_generic_arg(
db: &dyn DefDatabase,
arg: &GenericArg,
+ map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
match arg {
- GenericArg::Type(ty) => print_type_ref(db, ty, buf, edition),
+ GenericArg::Type(ty) => print_type_ref(db, *ty, map, buf, edition),
GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast(), edition)),
GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition)),
}
@@ -152,12 +159,13 @@
pub(crate) fn print_type_ref(
db: &dyn DefDatabase,
- type_ref: &TypeRef,
+ type_ref: TypeRefId,
+ map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
// FIXME: deduplicate with `HirDisplay` impl
- match type_ref {
+ match &map[type_ref] {
TypeRef::Never => write!(buf, "!")?,
TypeRef::Placeholder => write!(buf, "_")?,
TypeRef::Tuple(fields) => {
@@ -166,48 +174,48 @@
if i != 0 {
write!(buf, ", ")?;
}
- print_type_ref(db, field, buf, edition)?;
+ print_type_ref(db, *field, map, buf, edition)?;
}
write!(buf, ")")?;
}
- TypeRef::Path(path) => print_path(db, path, buf, edition)?,
+ TypeRef::Path(path) => print_path(db, path, map, buf, edition)?,
TypeRef::RawPtr(pointee, mtbl) => {
let mtbl = match mtbl {
Mutability::Shared => "*const",
Mutability::Mut => "*mut",
};
write!(buf, "{mtbl} ")?;
- print_type_ref(db, pointee, buf, edition)?;
+ print_type_ref(db, *pointee, map, buf, edition)?;
}
- TypeRef::Reference(pointee, lt, mtbl) => {
- let mtbl = match mtbl {
+ TypeRef::Reference(ref_) => {
+ let mtbl = match ref_.mutability {
Mutability::Shared => "",
Mutability::Mut => "mut ",
};
write!(buf, "&")?;
- if let Some(lt) = lt {
+ if let Some(lt) = &ref_.lifetime {
write!(buf, "{} ", lt.name.display(db.upcast(), edition))?;
}
write!(buf, "{mtbl}")?;
- print_type_ref(db, pointee, buf, edition)?;
+ print_type_ref(db, ref_.ty, map, buf, edition)?;
}
- TypeRef::Array(elem, len) => {
+ TypeRef::Array(array) => {
write!(buf, "[")?;
- print_type_ref(db, elem, buf, edition)?;
- write!(buf, "; {}]", len.display(db.upcast(), edition))?;
+ print_type_ref(db, array.ty, map, buf, edition)?;
+ write!(buf, "; {}]", array.len.display(db.upcast(), edition))?;
}
TypeRef::Slice(elem) => {
write!(buf, "[")?;
- print_type_ref(db, elem, buf, edition)?;
+ print_type_ref(db, *elem, map, buf, edition)?;
write!(buf, "]")?;
}
- TypeRef::Fn(args_and_ret, varargs, is_unsafe, abi) => {
+ TypeRef::Fn(fn_) => {
let ((_, return_type), args) =
- args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
- if *is_unsafe {
+ fn_.params().split_last().expect("TypeRef::Fn is missing return type");
+ if fn_.is_unsafe() {
write!(buf, "unsafe ")?;
}
- if let Some(abi) = abi {
+ if let Some(abi) = fn_.abi() {
buf.write_str("extern ")?;
buf.write_str(abi.as_str())?;
buf.write_char(' ')?;
@@ -217,16 +225,16 @@
if i != 0 {
write!(buf, ", ")?;
}
- print_type_ref(db, typeref, buf, edition)?;
+ print_type_ref(db, *typeref, map, buf, edition)?;
}
- if *varargs {
+ if fn_.is_varargs() {
if !args.is_empty() {
write!(buf, ", ")?;
}
write!(buf, "...")?;
}
write!(buf, ") -> ")?;
- print_type_ref(db, return_type, buf, edition)?;
+ print_type_ref(db, *return_type, map, buf, edition)?;
}
TypeRef::Macro(_ast_id) => {
write!(buf, "<macro>")?;
@@ -234,11 +242,11 @@
TypeRef::Error => write!(buf, "{{unknown}}")?,
TypeRef::ImplTrait(bounds) => {
write!(buf, "impl ")?;
- print_type_bounds(db, bounds, buf, edition)?;
+ print_type_bounds(db, bounds, map, buf, edition)?;
}
TypeRef::DynTrait(bounds) => {
write!(buf, "dyn ")?;
- print_type_bounds(db, bounds, buf, edition)?;
+ print_type_bounds(db, bounds, map, buf, edition)?;
}
}
@@ -247,7 +255,8 @@
pub(crate) fn print_type_bounds(
db: &dyn DefDatabase,
- bounds: &[Interned<TypeBound>],
+ bounds: &[TypeBound],
+ map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
@@ -256,13 +265,13 @@
write!(buf, " + ")?;
}
- match bound.as_ref() {
+ match bound {
TypeBound::Path(path, modifier) => {
match modifier {
TraitBoundModifier::None => (),
TraitBoundModifier::Maybe => write!(buf, "?")?,
}
- print_path(db, path, buf, edition)?;
+ print_path(db, path, map, buf, edition)?;
}
TypeBound::ForLifetime(lifetimes, path) => {
write!(
@@ -270,9 +279,25 @@
"for<{}> ",
lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ")
)?;
- print_path(db, path, buf, edition)?;
+ print_path(db, path, map, buf, edition)?;
}
TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?,
+ TypeBound::Use(args) => {
+ write!(buf, "use<")?;
+ let mut first = true;
+ for arg in args {
+ if !mem::take(&mut first) {
+ write!(buf, ", ")?;
+ }
+ match arg {
+ UseArgRef::Name(it) => write!(buf, "{}", it.display(db.upcast(), edition))?,
+ UseArgRef::Lifetime(it) => {
+ write!(buf, "{}", it.name.display(db.upcast(), edition))?
+ }
+ }
+ }
+ write!(buf, ">")?
+ }
TypeBound::Error => write!(buf, "{{unknown}}")?,
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index f0f2210..26655e4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -3,14 +3,17 @@
use base_db::CrateId;
use hir_expand::{name::Name, MacroDefId};
-use intern::{sym, Interned};
+use intern::sym;
use itertools::Itertools as _;
use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec};
use triomphe::Arc;
use crate::{
- body::scope::{ExprScopes, ScopeId},
+ body::{
+ scope::{ExprScopes, ScopeId},
+ HygieneId,
+ },
builtin_type::BuiltinType,
data::ExternCrateDeclData,
db::DefDatabase,
@@ -21,7 +24,7 @@
nameres::{DefMap, MacroSubNs},
path::{ModPath, Path, PathKind},
per_ns::PerNs,
- type_ref::LifetimeRef,
+ type_ref::{LifetimeRef, TypesMap},
visibility::{RawVisibility, Visibility},
AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule,
@@ -73,13 +76,15 @@
/// All the items and imported names of a module
BlockScope(ModuleItemMap),
/// Brings the generic parameters of an item into scope
- GenericParams { def: GenericDefId, params: Interned<GenericParams> },
+ GenericParams { def: GenericDefId, params: Arc<GenericParams> },
/// Brings `Self` in `impl` block into scope
ImplDefScope(ImplId),
/// Brings `Self` in enum, struct and union definitions into scope
AdtScope(AdtId),
/// Local bindings
ExprScope(ExprScope),
+ /// Macro definition inside bodies that affects all paths after it in the same block.
+ MacroDefScope(Box<MacroDefId>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -162,7 +167,8 @@
path: &Path,
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
let path = match path {
- Path::Normal { mod_path, .. } => mod_path,
+ Path::BarePath(mod_path) => mod_path,
+ Path::Normal(it) => it.mod_path(),
Path::LangItem(l, seg) => {
let type_ns = match *l {
LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
@@ -188,7 +194,7 @@
for scope in self.scopes() {
match scope {
- Scope::ExprScope(_) => continue,
+ Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue,
Scope::GenericParams { params, def } => {
if let Some(id) = params.find_type_by_name(first_name, *def) {
return Some((TypeNs::GenericParam(id), remaining_idx(), None));
@@ -257,9 +263,11 @@
&self,
db: &dyn DefDatabase,
path: &Path,
+ mut hygiene_id: HygieneId,
) -> Option<ResolveValueResult> {
let path = match path {
- Path::Normal { mod_path, .. } => mod_path,
+ Path::BarePath(mod_path) => mod_path,
+ Path::Normal(it) => it.mod_path(),
Path::LangItem(l, None) => {
return Some(ResolveValueResult::ValueNs(
match *l {
@@ -300,14 +308,22 @@
}
if n_segments <= 1 {
+ let mut hygiene_info = if !hygiene_id.is_root() {
+ let ctx = db.lookup_intern_syntax_context(hygiene_id.0);
+ ctx.outer_expn.map(|expansion| {
+ let expansion = db.lookup_intern_macro_call(expansion);
+ (ctx.parent, expansion.def)
+ })
+ } else {
+ None
+ };
for scope in self.scopes() {
match scope {
Scope::ExprScope(scope) => {
- let entry = scope
- .expr_scopes
- .entries(scope.scope_id)
- .iter()
- .find(|entry| entry.name() == first_name);
+ let entry =
+ scope.expr_scopes.entries(scope.scope_id).iter().find(|entry| {
+ entry.name() == first_name && entry.hygiene() == hygiene_id
+ });
if let Some(e) = entry {
return Some(ResolveValueResult::ValueNs(
@@ -316,6 +332,21 @@
));
}
}
+ Scope::MacroDefScope(macro_id) => {
+ if let Some((parent_ctx, label_macro_id)) = hygiene_info {
+ if label_macro_id == **macro_id {
+ // A macro is allowed to refer to variables from before its declaration.
+ // Therefore, if we got to the rib of its declaration, give up its hygiene
+ // and use its parent expansion.
+ let parent_ctx = db.lookup_intern_syntax_context(parent_ctx);
+ hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent);
+ hygiene_info = parent_ctx.outer_expn.map(|expansion| {
+ let expansion = db.lookup_intern_macro_call(expansion);
+ (parent_ctx.parent, expansion.def)
+ });
+ }
+ }
+ }
Scope::GenericParams { params, def } => {
if let Some(id) = params.find_const_by_name(first_name, *def) {
let val = ValueNs::GenericParam(id);
@@ -342,7 +373,7 @@
} else {
for scope in self.scopes() {
match scope {
- Scope::ExprScope(_) => continue,
+ Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue,
Scope::GenericParams { params, def } => {
if let Some(id) = params.find_type_by_name(first_name, *def) {
let ty = TypeNs::GenericParam(id);
@@ -393,8 +424,9 @@
&self,
db: &dyn DefDatabase,
path: &Path,
+ hygiene: HygieneId,
) -> Option<ValueNs> {
- match self.resolve_path_in_value_ns(db, path)? {
+ match self.resolve_path_in_value_ns(db, path, hygiene)? {
ResolveValueResult::ValueNs(it, _) => Some(it),
ResolveValueResult::Partial(..) => None,
}
@@ -590,13 +622,15 @@
pub fn where_predicates_in_scope(
&self,
- ) -> impl Iterator<Item = (&crate::generics::WherePredicate, &GenericDefId)> {
+ ) -> impl Iterator<Item = (&crate::generics::WherePredicate, (&GenericDefId, &TypesMap))> {
self.scopes()
.filter_map(|scope| match scope {
Scope::GenericParams { params, def } => Some((params, def)),
_ => None,
})
- .flat_map(|(params, def)| params.where_predicates().zip(iter::repeat(def)))
+ .flat_map(|(params, def)| {
+ params.where_predicates().zip(iter::repeat((def, ¶ms.types_map)))
+ })
}
pub fn generic_def(&self) -> Option<GenericDefId> {
@@ -606,13 +640,20 @@
})
}
- pub fn generic_params(&self) -> Option<&Interned<GenericParams>> {
+ pub fn generic_params(&self) -> Option<&Arc<GenericParams>> {
self.scopes().find_map(|scope| match scope {
Scope::GenericParams { params, .. } => Some(params),
_ => None,
})
}
+ pub fn all_generic_params(&self) -> impl Iterator<Item = (&GenericParams, &GenericDefId)> {
+ self.scopes().filter_map(|scope| match scope {
+ Scope::GenericParams { params, def } => Some((&**params, def)),
+ _ => None,
+ })
+ }
+
pub fn body_owner(&self) -> Option<DefWithBodyId> {
self.scopes().find_map(|scope| match scope {
Scope::ExprScope(it) => Some(it.owner),
@@ -622,7 +663,7 @@
pub fn type_owner(&self) -> Option<TypeOwnerId> {
self.scopes().find_map(|scope| match scope {
- Scope::BlockScope(_) => None,
+ Scope::BlockScope(_) | Scope::MacroDefScope(_) => None,
&Scope::GenericParams { def, .. } => Some(def.into()),
&Scope::ImplDefScope(id) => Some(id.into()),
&Scope::AdtScope(adt) => Some(adt.into()),
@@ -653,6 +694,9 @@
expr_scopes: &Arc<ExprScopes>,
scope_id: ScopeId,
) {
+ if let Some(macro_id) = expr_scopes.macro_def(scope_id) {
+ resolver.scopes.push(Scope::MacroDefScope(macro_id.clone()));
+ }
resolver.scopes.push(Scope::ExprScope(ExprScope {
owner,
expr_scopes: expr_scopes.clone(),
@@ -670,7 +714,7 @@
}
let start = self.scopes.len();
- let innermost_scope = self.scopes().next();
+ let innermost_scope = self.scopes().find(|scope| !matches!(scope, Scope::MacroDefScope(_)));
match innermost_scope {
Some(&Scope::ExprScope(ExprScope { scope_id, ref expr_scopes, owner })) => {
let expr_scopes = expr_scopes.clone();
@@ -794,6 +838,7 @@
acc.add_local(e.name(), e.binding());
});
}
+ Scope::MacroDefScope(_) => {}
}
}
}
@@ -833,6 +878,9 @@
// already traverses all parents, so this is O(n²). I think we could only store the
// innermost module scope instead?
}
+ if let Some(macro_id) = scopes.macro_def(scope) {
+ r = r.push_scope(Scope::MacroDefScope(macro_id.clone()));
+ }
r = r.push_expr_scope(owner, Arc::clone(&scopes), scope);
}
@@ -1006,12 +1054,12 @@
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
let mut def_map = self.def_map(db);
let mut module_id = self.local_id;
- let mut modules: SmallVec<[_; 1]> = smallvec![];
if !self.is_block_module() {
return Resolver { scopes: vec![], module_scope: ModuleItemMap { def_map, module_id } };
}
+ let mut modules: SmallVec<[_; 1]> = smallvec![];
while let Some(parent) = def_map.parent() {
let block_def_map = mem::replace(&mut def_map, parent.def_map(db));
modules.push(block_def_map);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
index 4db21eb..0c36c88 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
@@ -198,7 +198,10 @@
.filter_map(|node| {
let block = ast::BlockExpr::cast(node)?;
let expr = ast::Expr::from(block);
- let expr_id = source_map.node_expr(InFile::new(position.file_id.into(), &expr))?;
+ let expr_id = source_map
+ .node_expr(InFile::new(position.file_id.into(), &expr))?
+ .as_expr()
+ .unwrap();
let scope = scopes.scope_for(expr_id).unwrap();
Some(scope)
});
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
index 3aeb880..4edb6835 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
@@ -191,6 +191,11 @@
return None;
}
+ let def_block = def_map.block_id();
+ if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
+ return None;
+ }
+
let mut a_ancestors =
iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
let mut b_ancestors =
@@ -210,6 +215,43 @@
}
}
}
+
+ /// Returns the least permissive visibility of `self` and `other`.
+ ///
+ /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only
+ /// visible in unrelated modules).
+ pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
+ match (self, other) {
+ (vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis),
+ (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
+ if mod_a.krate != mod_b.krate {
+ return None;
+ }
+
+ let def_block = def_map.block_id();
+ if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
+ return None;
+ }
+
+ let mut a_ancestors =
+ iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
+ let mut b_ancestors =
+ iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
+
+ if a_ancestors.any(|m| m == mod_b.local_id) {
+ // B is above A
+ return Some(Visibility::Module(mod_a, expl_b));
+ }
+
+ if b_ancestors.any(|m| m == mod_a.local_id) {
+ // A is above B
+ return Some(Visibility::Module(mod_b, expl_a));
+ }
+
+ None
+ }
+ }
+ }
}
/// Whether the item was imported through an explicit `pub(crate) use` or just a `use` without
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index 79cfeb4..12df3cf 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -26,6 +26,7 @@
/// Syntactical attributes, without filtering of `cfg_attr`s.
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct RawAttrs {
+ // FIXME: This can become `Box<[Attr]>` if https://internals.rust-lang.org/t/layout-of-dst-box/21728?u=chrefr is accepted.
entries: Option<ThinArc<(), Attr>>,
}
@@ -169,6 +170,10 @@
};
RawAttrs { entries }
}
+
+ pub fn is_empty(&self) -> bool {
+ self.entries.is_none()
+ }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
index a8191189..f48de80 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
@@ -227,7 +227,7 @@
&'a SyntaxContextData,
);
- impl<'a> std::fmt::Debug for SyntaxContextDebug<'a> {
+ impl std::fmt::Debug for SyntaxContextDebug<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fancy_debug(self.2, self.1, self.0, f)
}
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index 5d5f724..7d2f556 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -165,40 +165,73 @@
}
impl ExpandError {
- pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> (String, bool) {
+ pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> RenderedExpandError {
self.inner.0.render_to_string(db)
}
}
+pub struct RenderedExpandError {
+ pub message: String,
+ pub error: bool,
+ pub kind: &'static str,
+}
+
+impl RenderedExpandError {
+ const GENERAL_KIND: &str = "macro-error";
+}
+
impl ExpandErrorKind {
- pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> (String, bool) {
+ pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> RenderedExpandError {
match self {
- ExpandErrorKind::ProcMacroAttrExpansionDisabled => {
- ("procedural attribute macro expansion is disabled".to_owned(), false)
- }
- ExpandErrorKind::MacroDisabled => {
- ("proc-macro is explicitly disabled".to_owned(), false)
- }
+ ExpandErrorKind::ProcMacroAttrExpansionDisabled => RenderedExpandError {
+ message: "procedural attribute macro expansion is disabled".to_owned(),
+ error: false,
+ kind: "proc-macros-disabled",
+ },
+ ExpandErrorKind::MacroDisabled => RenderedExpandError {
+ message: "proc-macro is explicitly disabled".to_owned(),
+ error: false,
+ kind: "proc-macro-disabled",
+ },
&ExpandErrorKind::MissingProcMacroExpander(def_crate) => {
match db.proc_macros().get_error_for_crate(def_crate) {
- Some((e, hard_err)) => (e.to_owned(), hard_err),
- None => (
- format!(
- "internal error: proc-macro map is missing error entry for crate {def_crate:?}"
- ),
- true,
- ),
+ Some((e, hard_err)) => RenderedExpandError {
+ message: e.to_owned(),
+ error: hard_err,
+ kind: RenderedExpandError::GENERAL_KIND,
+ },
+ None => RenderedExpandError {
+ message: format!("internal error: proc-macro map is missing error entry for crate {def_crate:?}"),
+ error: true,
+ kind: RenderedExpandError::GENERAL_KIND,
+ },
}
}
- ExpandErrorKind::MacroDefinition => {
- ("macro definition has parse errors".to_owned(), true)
- }
- ExpandErrorKind::Mbe(e) => (e.to_string(), true),
- ExpandErrorKind::RecursionOverflow => {
- ("overflow expanding the original macro".to_owned(), true)
- }
- ExpandErrorKind::Other(e) => ((**e).to_owned(), true),
- ExpandErrorKind::ProcMacroPanic(e) => (format!("proc-macro panicked: {e}"), true),
+ ExpandErrorKind::MacroDefinition => RenderedExpandError {
+ message: "macro definition has parse errors".to_owned(),
+ error: true,
+ kind: RenderedExpandError::GENERAL_KIND,
+ },
+ ExpandErrorKind::Mbe(e) => RenderedExpandError {
+ message: e.to_string(),
+ error: true,
+ kind: RenderedExpandError::GENERAL_KIND,
+ },
+ ExpandErrorKind::RecursionOverflow => RenderedExpandError {
+ message: "overflow expanding the original macro".to_owned(),
+ error: true,
+ kind: RenderedExpandError::GENERAL_KIND,
+ },
+ ExpandErrorKind::Other(e) => RenderedExpandError {
+ message: (**e).to_owned(),
+ error: true,
+ kind: RenderedExpandError::GENERAL_KIND,
+ },
+ ExpandErrorKind::ProcMacroPanic(e) => RenderedExpandError {
+ message: format!("proc-macro panicked: {e}"),
+ error: true,
+ kind: RenderedExpandError::GENERAL_KIND,
+ },
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 5431390..267d545 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -18,6 +18,8 @@
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Name {
symbol: Symbol,
+ // If you are making this carry actual hygiene, beware that the special handling for variables and labels
+ // in bodies can go.
ctx: (),
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index 7a3846d..2b53423 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -114,7 +114,7 @@
}
#[allow(private_bounds)]
-impl<'table, 'db, T: TrackAutoderefSteps> Autoderef<'table, 'db, T> {
+impl<T: TrackAutoderefSteps> Autoderef<'_, '_, T> {
pub(crate) fn step_count(&self) -> usize {
self.steps.len()
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index f7bacbd..4bc78af 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -521,7 +521,7 @@
}
}
-impl<'a> ChalkContext<'a> {
+impl ChalkContext<'_> {
fn edition(&self) -> Edition {
self.db.crate_graph()[self.krate].edition
}
@@ -615,8 +615,9 @@
let type_alias_data = db.type_alias_data(type_alias);
let generic_params = generics(db.upcast(), type_alias.into());
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
- let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into())
- .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
+ let ctx =
+ crate::TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, type_alias.into())
+ .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
index e41058a..091cfcd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -3,7 +3,7 @@
use base_db::{ra_salsa::Cycle, CrateId};
use chalk_ir::{cast::Cast, BoundVar, DebruijnIndex};
use hir_def::{
- body::Body,
+ body::{Body, HygieneId},
hir::{Expr, ExprId},
path::Path,
resolver::{Resolver, ValueNs},
@@ -11,7 +11,7 @@
ConstBlockLoc, EnumVariantId, GeneralConstId, StaticId,
};
use hir_expand::Lookup;
-use stdx::{never, IsNoneOr};
+use stdx::never;
use triomphe::Arc;
use crate::{
@@ -80,7 +80,7 @@
debruijn: DebruijnIndex,
expected_ty: Ty,
) -> Option<Const> {
- match resolver.resolve_path_in_value_ns_fully(db.upcast(), path) {
+ match resolver.resolve_path_in_value_ns_fully(db.upcast(), path, HygieneId::ROOT) {
Some(ValueNs::GenericParam(p)) => {
let ty = db.const_param_ty(p);
let value = match mode {
@@ -287,7 +287,7 @@
}
let repr = db.enum_data(loc.parent).repr;
- let is_signed = IsNoneOr::is_none_or(repr.and_then(|repr| repr.int), |int| int.is_signed());
+ let is_signed = repr.and_then(|repr| repr.int).is_none_or(|int| int.is_signed());
let mir_body = db.monomorphized_mir_body(
def,
@@ -319,7 +319,7 @@
return true;
}
let mut r = false;
- body[expr].walk_child_exprs(|idx| r |= has_closure(body, idx));
+ body.walk_child_exprs(expr, |idx| r |= has_closure(body, idx));
r
}
if has_closure(ctx.body, expr) {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
index 7f6b7e3..c9ab0ac 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -309,7 +309,7 @@
/// Check incorrect names for struct fields.
fn validate_struct_fields(&mut self, struct_id: StructId) {
let data = self.db.struct_data(struct_id);
- let VariantData::Record(fields) = data.variant_data.as_ref() else {
+ let VariantData::Record { fields, .. } = data.variant_data.as_ref() else {
return;
};
let edition = self.edition(struct_id);
@@ -469,7 +469,7 @@
/// Check incorrect names for fields of enum variant.
fn validate_enum_variant_fields(&mut self, variant_id: EnumVariantId) {
let variant_data = self.db.enum_variant_data(variant_id);
- let VariantData::Record(fields) = variant_data.variant_data.as_ref() else {
+ let VariantData::Record { fields, .. } = variant_data.variant_data.as_ref() else {
return;
};
let edition = self.edition(variant_id);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index f8b5c7d..92404e3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -289,10 +289,12 @@
match &self.body[scrutinee_expr] {
Expr::UnaryOp { op: UnaryOp::Deref, .. } => false,
Expr::Path(path) => {
- let value_or_partial = self
- .owner
- .resolver(db.upcast())
- .resolve_path_in_value_ns_fully(db.upcast(), path);
+ let value_or_partial =
+ self.owner.resolver(db.upcast()).resolve_path_in_value_ns_fully(
+ db.upcast(),
+ path,
+ self.body.expr_path_hygiene(scrutinee_expr),
+ );
value_or_partial.map_or(true, |v| !matches!(v, ValueNs::StaticId(_)))
}
Expr::Field { expr, .. } => match self.infer.type_of_expr[*expr].kind(Interner) {
@@ -546,10 +548,7 @@
expr: &Expr,
) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> {
let (fields, exhaustive) = match expr {
- Expr::RecordLit { fields, spread, ellipsis, is_assignee_expr, .. } => {
- let exhaustive = if *is_assignee_expr { !*ellipsis } else { spread.is_none() };
- (fields, exhaustive)
- }
+ Expr::RecordLit { fields, spread, .. } => (fields, spread.is_none()),
_ => return None,
};
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
index 4bc07bc..c5d8c95 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
@@ -341,7 +341,7 @@
};
let variant_data = variant.variant_data(f.db.upcast());
- if let VariantData::Record(rec_fields) = &*variant_data {
+ if let VariantData::Record { fields: rec_fields, .. } = &*variant_data {
write!(f, " {{ ")?;
let mut printed = 0;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 1066a28..58de19b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -519,7 +519,7 @@
}
}
-impl<'db> fmt::Debug for MatchCheckCtx<'db> {
+impl fmt::Debug for MatchCheckCtx<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MatchCheckCtx").finish()
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
index bcfc37c..c7f7fb7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -3,7 +3,7 @@
use hir_def::{
body::Body,
- hir::{Expr, ExprId, UnaryOp},
+ hir::{Expr, ExprId, ExprOrPatId, Pat, UnaryOp},
resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs},
type_ref::Rawness,
DefWithBodyId,
@@ -16,7 +16,7 @@
/// Returns `(unsafe_exprs, fn_is_unsafe)`.
///
/// If `fn_is_unsafe` is false, `unsafe_exprs` are hard errors. If true, they're `unsafe_op_in_unsafe_fn`.
-pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>, bool) {
+pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprOrPatId>, bool) {
let _p = tracing::info_span!("missing_unsafe").entered();
let mut res = Vec::new();
@@ -32,7 +32,7 @@
let infer = db.infer(def);
unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| {
if !expr.inside_unsafe_block {
- res.push(expr.expr);
+ res.push(expr.node);
}
});
@@ -40,7 +40,7 @@
}
pub struct UnsafeExpr {
- pub expr: ExprId,
+ pub node: ExprOrPatId,
pub inside_unsafe_block: bool,
}
@@ -75,26 +75,29 @@
inside_unsafe_block: bool,
unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
) {
+ let mut mark_unsafe_path = |path, node| {
+ let g = resolver.update_to_inner_scope(db.upcast(), def, current);
+ let hygiene = body.expr_or_pat_path_hygiene(node);
+ let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path, hygiene);
+ if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
+ let static_data = db.static_data(id);
+ if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) {
+ unsafe_expr_cb(UnsafeExpr { node, inside_unsafe_block });
+ }
+ }
+ resolver.reset_to_guard(g);
+ };
+
let expr = &body.exprs[current];
match expr {
&Expr::Call { callee, .. } => {
if let Some(func) = infer[callee].as_fn_def(db) {
if is_fn_unsafe_to_call(db, func) {
- unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
+ unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block });
}
}
}
- Expr::Path(path) => {
- let g = resolver.update_to_inner_scope(db.upcast(), def, current);
- let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path);
- if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
- let static_data = db.static_data(id);
- if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) {
- unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
- }
- }
- resolver.reset_to_guard(g);
- }
+ Expr::Path(path) => mark_unsafe_path(path, current.into()),
Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => {
if let Expr::Path(_) = body.exprs[*expr] {
// Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`,
@@ -108,23 +111,30 @@
.map(|(func, _)| is_fn_unsafe_to_call(db, func))
.unwrap_or(false)
{
- unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
+ unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block });
}
}
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
if let TyKind::Raw(..) = &infer[*expr].kind(Interner) {
- unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
+ unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block });
}
}
Expr::Unsafe { .. } => {
- return expr.walk_child_exprs(|child| {
+ return body.walk_child_exprs(current, |child| {
walk_unsafe(db, infer, body, resolver, def, child, true, unsafe_expr_cb);
});
}
+ &Expr::Assignment { target, value: _ } => {
+ body.walk_pats(target, &mut |pat| {
+ if let Pat::Path(path) = &body[pat] {
+ mark_unsafe_path(path, pat.into());
+ }
+ });
+ }
_ => {}
}
- expr.walk_child_exprs(|child| {
+ body.walk_child_exprs(current, |child| {
walk_unsafe(db, infer, body, resolver, def, child, inside_unsafe_block, unsafe_expr_cb);
});
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 10f5bcd..277dabe 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -19,7 +19,9 @@
lang_item::{LangItem, LangItemTarget},
nameres::DefMap,
path::{Path, PathKind},
- type_ref::{TraitBoundModifier, TypeBound, TypeRef},
+ type_ref::{
+ TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, TypesSourceMap, UseArgRef,
+ },
visibility::Visibility,
GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId,
ModuleId, TraitId,
@@ -806,7 +808,7 @@
memory_map: &MemoryMap,
) -> Result<(), HirDisplayError> {
match data {
- VariantData::Record(fields) | VariantData::Tuple(fields) => {
+ VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => {
let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
let ty = field_types[id].clone().substitute(Interner, subst);
@@ -817,7 +819,7 @@
render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
};
let mut it = fields.iter();
- if matches!(data, VariantData::Record(_)) {
+ if matches!(data, VariantData::Record { .. }) {
write!(f, " {{")?;
if let Some((id, data)) = it.next() {
write!(f, " {}: ", data.name.display(f.db.upcast(), f.edition()))?;
@@ -1897,100 +1899,150 @@
}
}
-impl HirDisplay for TypeRef {
+pub trait HirDisplayWithTypesMap {
+ fn hir_fmt(
+ &self,
+ f: &mut HirFormatter<'_>,
+ types_map: &TypesMap,
+ ) -> Result<(), HirDisplayError>;
+}
+
+impl<T: ?Sized + HirDisplayWithTypesMap> HirDisplayWithTypesMap for &'_ T {
+ fn hir_fmt(
+ &self,
+ f: &mut HirFormatter<'_>,
+ types_map: &TypesMap,
+ ) -> Result<(), HirDisplayError> {
+ T::hir_fmt(&**self, f, types_map)
+ }
+}
+
+pub fn hir_display_with_types_map<'a, T: HirDisplayWithTypesMap + 'a>(
+ value: T,
+ types_map: &'a TypesMap,
+) -> impl HirDisplay + 'a {
+ TypesMapAdapter(value, types_map)
+}
+
+struct TypesMapAdapter<'a, T>(T, &'a TypesMap);
+
+impl<'a, T> TypesMapAdapter<'a, T> {
+ fn wrap(types_map: &'a TypesMap) -> impl Fn(T) -> TypesMapAdapter<'a, T> {
+ move |value| TypesMapAdapter(value, types_map)
+ }
+}
+
+impl<T: HirDisplayWithTypesMap> HirDisplay for TypesMapAdapter<'_, T> {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
- match self {
+ T::hir_fmt(&self.0, f, self.1)
+ }
+}
+
+impl HirDisplayWithTypesMap for TypeRefId {
+ fn hir_fmt(
+ &self,
+ f: &mut HirFormatter<'_>,
+ types_map: &TypesMap,
+ ) -> Result<(), HirDisplayError> {
+ match &types_map[*self] {
TypeRef::Never => write!(f, "!")?,
TypeRef::Placeholder => write!(f, "_")?,
TypeRef::Tuple(elems) => {
write!(f, "(")?;
- f.write_joined(elems, ", ")?;
+ f.write_joined(elems.iter().map(TypesMapAdapter::wrap(types_map)), ", ")?;
if elems.len() == 1 {
write!(f, ",")?;
}
write!(f, ")")?;
}
- TypeRef::Path(path) => path.hir_fmt(f)?,
+ TypeRef::Path(path) => path.hir_fmt(f, types_map)?,
TypeRef::RawPtr(inner, mutability) => {
let mutability = match mutability {
hir_def::type_ref::Mutability::Shared => "*const ",
hir_def::type_ref::Mutability::Mut => "*mut ",
};
write!(f, "{mutability}")?;
- inner.hir_fmt(f)?;
+ inner.hir_fmt(f, types_map)?;
}
- TypeRef::Reference(inner, lifetime, mutability) => {
- let mutability = match mutability {
+ TypeRef::Reference(ref_) => {
+ let mutability = match ref_.mutability {
hir_def::type_ref::Mutability::Shared => "",
hir_def::type_ref::Mutability::Mut => "mut ",
};
write!(f, "&")?;
- if let Some(lifetime) = lifetime {
+ if let Some(lifetime) = &ref_.lifetime {
write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
}
write!(f, "{mutability}")?;
- inner.hir_fmt(f)?;
+ ref_.ty.hir_fmt(f, types_map)?;
}
- TypeRef::Array(inner, len) => {
+ TypeRef::Array(array) => {
write!(f, "[")?;
- inner.hir_fmt(f)?;
- write!(f, "; {}]", len.display(f.db.upcast(), f.edition()))?;
+ array.ty.hir_fmt(f, types_map)?;
+ write!(f, "; {}]", array.len.display(f.db.upcast(), f.edition()))?;
}
TypeRef::Slice(inner) => {
write!(f, "[")?;
- inner.hir_fmt(f)?;
+ inner.hir_fmt(f, types_map)?;
write!(f, "]")?;
}
- &TypeRef::Fn(ref parameters, is_varargs, is_unsafe, ref abi) => {
- if is_unsafe {
+ TypeRef::Fn(fn_) => {
+ if fn_.is_unsafe() {
write!(f, "unsafe ")?;
}
- if let Some(abi) = abi {
+ if let Some(abi) = fn_.abi() {
f.write_str("extern \"")?;
f.write_str(abi.as_str())?;
f.write_str("\" ")?;
}
write!(f, "fn(")?;
- if let Some(((_, return_type), function_parameters)) = parameters.split_last() {
+ if let Some(((_, return_type), function_parameters)) = fn_.params().split_last() {
for index in 0..function_parameters.len() {
let (param_name, param_type) = &function_parameters[index];
if let Some(name) = param_name {
write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?;
}
- param_type.hir_fmt(f)?;
+ param_type.hir_fmt(f, types_map)?;
if index != function_parameters.len() - 1 {
write!(f, ", ")?;
}
}
- if is_varargs {
- write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
+ if fn_.is_varargs() {
+ write!(f, "{}...", if fn_.params().len() == 1 { "" } else { ", " })?;
}
write!(f, ")")?;
- match &return_type {
+ match &types_map[*return_type] {
TypeRef::Tuple(tup) if tup.is_empty() => {}
_ => {
write!(f, " -> ")?;
- return_type.hir_fmt(f)?;
+ return_type.hir_fmt(f, types_map)?;
}
}
}
}
TypeRef::ImplTrait(bounds) => {
write!(f, "impl ")?;
- f.write_joined(bounds, " + ")?;
+ f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
}
TypeRef::DynTrait(bounds) => {
write!(f, "dyn ")?;
- f.write_joined(bounds, " + ")?;
+ f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
}
TypeRef::Macro(macro_call) => {
- let ctx = hir_def::lower::LowerCtx::new(f.db.upcast(), macro_call.file_id);
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let ctx = hir_def::lower::LowerCtx::new(
+ f.db.upcast(),
+ macro_call.file_id,
+ &mut types_map,
+ &mut types_source_map,
+ );
let macro_call = macro_call.to_node(f.db.upcast());
match macro_call.path() {
Some(path) => match Path::from_src(&ctx, path) {
- Some(path) => path.hir_fmt(f)?,
+ Some(path) => path.hir_fmt(f, &types_map)?,
None => write!(f, "{{macro}}")?,
},
None => write!(f, "{{macro}}")?,
@@ -2003,15 +2055,19 @@
}
}
-impl HirDisplay for TypeBound {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl HirDisplayWithTypesMap for TypeBound {
+ fn hir_fmt(
+ &self,
+ f: &mut HirFormatter<'_>,
+ types_map: &TypesMap,
+ ) -> Result<(), HirDisplayError> {
match self {
TypeBound::Path(path, modifier) => {
match modifier {
TraitBoundModifier::None => (),
TraitBoundModifier::Maybe => write!(f, "?")?,
}
- path.hir_fmt(f)
+ path.hir_fmt(f, types_map)
}
TypeBound::Lifetime(lifetime) => {
write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
@@ -2023,19 +2079,36 @@
"for<{}> ",
lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ")
)?;
- path.hir_fmt(f)
+ path.hir_fmt(f, types_map)
+ }
+ TypeBound::Use(args) => {
+ let edition = f.edition();
+ write!(
+ f,
+ "use<{}> ",
+ args.iter()
+ .map(|it| match it {
+ UseArgRef::Lifetime(lt) => lt.name.display(f.db.upcast(), edition),
+ UseArgRef::Name(n) => n.display(f.db.upcast(), edition),
+ })
+ .format(", ")
+ )
}
TypeBound::Error => write!(f, "{{error}}"),
}
}
}
-impl HirDisplay for Path {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl HirDisplayWithTypesMap for Path {
+ fn hir_fmt(
+ &self,
+ f: &mut HirFormatter<'_>,
+ types_map: &TypesMap,
+ ) -> Result<(), HirDisplayError> {
match (self.type_anchor(), self.kind()) {
(Some(anchor), _) => {
write!(f, "<")?;
- anchor.hir_fmt(f)?;
+ anchor.hir_fmt(f, types_map)?;
write!(f, ">")?;
}
(_, PathKind::Plain) => {}
@@ -2078,7 +2151,7 @@
});
if let Some(ty) = trait_self_ty {
write!(f, "<")?;
- ty.hir_fmt(f)?;
+ ty.hir_fmt(f, types_map)?;
write!(f, " as ")?;
// Now format the path of the trait...
}
@@ -2094,21 +2167,26 @@
if generic_args.desugared_from_fn {
// First argument will be a tuple, which already includes the parentheses.
// If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
- if let hir_def::path::GenericArg::Type(TypeRef::Tuple(v)) =
- &generic_args.args[0]
- {
+ let tuple = match generic_args.args[0] {
+ hir_def::path::GenericArg::Type(ty) => match &types_map[ty] {
+ TypeRef::Tuple(it) => Some(it),
+ _ => None,
+ },
+ _ => None,
+ };
+ if let Some(v) = tuple {
if v.len() == 1 {
write!(f, "(")?;
- v[0].hir_fmt(f)?;
+ v[0].hir_fmt(f, types_map)?;
write!(f, ")")?;
} else {
- generic_args.args[0].hir_fmt(f)?;
+ generic_args.args[0].hir_fmt(f, types_map)?;
}
}
- if let Some(ret) = &generic_args.bindings[0].type_ref {
- if !matches!(ret, TypeRef::Tuple(v) if v.is_empty()) {
+ if let Some(ret) = generic_args.bindings[0].type_ref {
+ if !matches!(&types_map[ret], TypeRef::Tuple(v) if v.is_empty()) {
write!(f, " -> ")?;
- ret.hir_fmt(f)?;
+ ret.hir_fmt(f, types_map)?;
}
}
return Ok(());
@@ -2123,7 +2201,7 @@
} else {
write!(f, ", ")?;
}
- arg.hir_fmt(f)?;
+ arg.hir_fmt(f, types_map)?;
}
for binding in generic_args.bindings.iter() {
if first {
@@ -2136,11 +2214,14 @@
match &binding.type_ref {
Some(ty) => {
write!(f, " = ")?;
- ty.hir_fmt(f)?
+ ty.hir_fmt(f, types_map)?
}
None => {
write!(f, ": ")?;
- f.write_joined(binding.bounds.iter(), " + ")?;
+ f.write_joined(
+ binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)),
+ " + ",
+ )?;
}
}
}
@@ -2162,10 +2243,14 @@
}
}
-impl HirDisplay for hir_def::path::GenericArg {
- fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl HirDisplayWithTypesMap for hir_def::path::GenericArg {
+ fn hir_fmt(
+ &self,
+ f: &mut HirFormatter<'_>,
+ types_map: &TypesMap,
+ ) -> Result<(), HirDisplayError> {
match self {
- hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
+ hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f, types_map),
hir_def::path::GenericArg::Const(c) => {
write!(f, "{}", c.display(f.db.upcast(), f.edition()))
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
index e0d1758..3d21785 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
@@ -266,7 +266,7 @@
trait_self_param_idx: usize,
allow_self_projection: AllowSelfProjection,
}
- impl<'a> TypeVisitor<Interner> for IllegalSelfTypeVisitor<'a> {
+ impl TypeVisitor<Interner> for IllegalSelfTypeVisitor<'_> {
type BreakTy = ();
fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
index 89ca707..c094bc3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
@@ -16,12 +16,13 @@
GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData,
TypeParamProvenance,
},
+ type_ref::TypesMap,
ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId,
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
};
-use intern::Interned;
use itertools::chain;
use stdx::TupleExt;
+use triomphe::Arc;
use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution};
@@ -34,7 +35,7 @@
#[derive(Clone, Debug)]
pub(crate) struct Generics {
def: GenericDefId,
- params: Interned<GenericParams>,
+ params: Arc<GenericParams>,
parent_generics: Option<Box<Generics>>,
has_trait_self_param: bool,
}
@@ -85,6 +86,18 @@
self.iter_self().chain(self.iter_parent())
}
+ pub(crate) fn iter_with_types_map(
+ &self,
+ ) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &TypesMap)> + '_ {
+ self.iter_self().zip(std::iter::repeat(&self.params.types_map)).chain(
+ self.iter_parent().zip(
+ self.parent_generics()
+ .into_iter()
+ .flat_map(|it| std::iter::repeat(&it.params.types_map)),
+ ),
+ )
+ }
+
/// Iterate over the params without parent params.
pub(crate) fn iter_self(
&self,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 88334b4..3685ed5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -33,7 +33,7 @@
};
use either::Either;
use hir_def::{
- body::Body,
+ body::{Body, HygieneId},
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
data::{ConstData, StaticData},
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
@@ -41,7 +41,7 @@
layout::Integer,
path::{ModPath, Path},
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
- type_ref::{LifetimeRef, TypeRef},
+ type_ref::{LifetimeRef, TypeRefId, TypesMap},
AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ImplId, ItemContainerId, Lookup,
TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
};
@@ -228,7 +228,7 @@
id: ExprOrPatId,
},
UnresolvedIdent {
- expr: ExprId,
+ id: ExprOrPatId,
},
// FIXME: This should be emitted in body lowering
BreakOutsideOfLoop {
@@ -482,12 +482,27 @@
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
self.variant_resolutions.get(&id.into()).copied()
}
+ pub fn variant_resolution_for_expr_or_pat(&self, id: ExprOrPatId) -> Option<VariantId> {
+ match id {
+ ExprOrPatId::ExprId(id) => self.variant_resolution_for_expr(id),
+ ExprOrPatId::PatId(id) => self.variant_resolution_for_pat(id),
+ }
+ }
pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<(AssocItemId, Substitution)> {
self.assoc_resolutions.get(&id.into()).cloned()
}
pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<(AssocItemId, Substitution)> {
self.assoc_resolutions.get(&id.into()).cloned()
}
+ pub fn assoc_resolutions_for_expr_or_pat(
+ &self,
+ id: ExprOrPatId,
+ ) -> Option<(AssocItemId, Substitution)> {
+ match id {
+ ExprOrPatId::ExprId(id) => self.assoc_resolutions_for_expr(id),
+ ExprOrPatId::PatId(id) => self.assoc_resolutions_for_pat(id),
+ }
+ }
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
self.type_mismatches.get(&expr.into())
}
@@ -506,6 +521,12 @@
pub fn closure_info(&self, closure: &ClosureId) -> &(Vec<CapturedItem>, FnTrait) {
self.closure_info.get(closure).unwrap()
}
+ pub fn type_of_expr_or_pat(&self, id: ExprOrPatId) -> Option<&Ty> {
+ match id {
+ ExprOrPatId::ExprId(id) => self.type_of_expr.get(id),
+ ExprOrPatId::PatId(id) => self.type_of_pat.get(id),
+ }
+ }
}
impl Index<ExprId> for InferenceResult {
@@ -524,6 +545,14 @@
}
}
+impl Index<ExprOrPatId> for InferenceResult {
+ type Output = Ty;
+
+ fn index(&self, id: ExprOrPatId) -> &Ty {
+ self.type_of_expr_or_pat(id).unwrap_or(&self.standard_types.unknown)
+ }
+}
+
impl Index<BindingId> for InferenceResult {
type Output = Ty;
@@ -561,6 +590,9 @@
diverges: Diverges,
breakables: Vec<BreakableContext>,
+ /// Whether we are inside the pattern of a destructuring assignment.
+ inside_assignment: bool,
+
deferred_cast_checks: Vec<CastCheck>,
// fields related to closure capture
@@ -656,6 +688,7 @@
current_closure: None,
deferred_closures: FxHashMap::default(),
closure_dependencies: FxHashMap::default(),
+ inside_assignment: false,
}
}
@@ -825,7 +858,7 @@
}
fn collect_const(&mut self, data: &ConstData) {
- let return_ty = self.make_ty(&data.type_ref);
+ let return_ty = self.make_ty(data.type_ref, &data.types_map);
// Constants might be defining usage sites of TAITs.
self.make_tait_coercion_table(iter::once(&return_ty));
@@ -834,7 +867,7 @@
}
fn collect_static(&mut self, data: &StaticData) {
- let return_ty = self.make_ty(&data.type_ref);
+ let return_ty = self.make_ty(data.type_ref, &data.types_map);
// Statics might be defining usage sites of TAITs.
self.make_tait_coercion_table(iter::once(&return_ty));
@@ -844,11 +877,11 @@
fn collect_fn(&mut self, func: FunctionId) {
let data = self.db.function_data(func);
- let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into())
- .with_type_param_mode(ParamLoweringMode::Placeholder)
- .with_impl_trait_mode(ImplTraitLoweringMode::Param);
- let mut param_tys =
- data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
+ let mut param_tys = self.with_ty_lowering(&data.types_map, |ctx| {
+ ctx.type_param_mode(ParamLoweringMode::Placeholder)
+ .impl_trait_mode(ImplTraitLoweringMode::Param);
+ data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>()
+ });
// Check if function contains a va_list, if it does then we append it to the parameter types
// that are collected from the function data
if data.is_varargs() {
@@ -883,12 +916,13 @@
tait_candidates.insert(ty);
}
}
- let return_ty = &*data.ret_type;
+ let return_ty = data.ret_type;
- let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into())
- .with_type_param_mode(ParamLoweringMode::Placeholder)
- .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
- let return_ty = ctx.lower_ty(return_ty);
+ let return_ty = self.with_ty_lowering(&data.types_map, |ctx| {
+ ctx.type_param_mode(ParamLoweringMode::Placeholder)
+ .impl_trait_mode(ImplTraitLoweringMode::Opaque)
+ .lower_ty(return_ty)
+ });
let return_ty = self.insert_type_vars(return_ty);
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
@@ -1022,7 +1056,7 @@
non_assocs: FxHashMap<OpaqueTyId, Ty>,
}
- impl<'a, 'b> TypeVisitor<Interner> for TypeAliasImplTraitCollector<'a, 'b> {
+ impl TypeVisitor<Interner> for TypeAliasImplTraitCollector<'_, '_> {
type BreakTy = ();
fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
@@ -1192,20 +1226,43 @@
self.result.diagnostics.push(diagnostic);
}
- fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
- let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
- let ty = ctx.lower_ty(type_ref);
+ fn with_ty_lowering<R>(
+ &self,
+ types_map: &TypesMap,
+ f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
+ ) -> R {
+ let mut ctx = crate::lower::TyLoweringContext::new(
+ self.db,
+ &self.resolver,
+ types_map,
+ self.owner.into(),
+ );
+ f(&mut ctx)
+ }
+
+ fn with_body_ty_lowering<R>(
+ &self,
+ f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
+ ) -> R {
+ self.with_ty_lowering(&self.body.types, f)
+ }
+
+ fn make_ty(&mut self, type_ref: TypeRefId, types_map: &TypesMap) -> Ty {
+ let ty = self.with_ty_lowering(types_map, |ctx| ctx.lower_ty(type_ref));
let ty = self.insert_type_vars(ty);
self.normalize_associated_types_in(ty)
}
+ fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty {
+ self.make_ty(type_ref, &self.body.types)
+ }
+
fn err_ty(&self) -> Ty {
self.result.standard_types.unknown.clone()
}
fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime {
- let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
- let lt = ctx.lower_lifetime(lifetime_ref);
+ let lt = self.with_ty_lowering(TypesMap::EMPTY, |ctx| ctx.lower_lifetime(lifetime_ref));
self.insert_type_vars(lt)
}
@@ -1363,9 +1420,14 @@
Some(path) => path,
None => return (self.err_ty(), None),
};
- let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
+ let ctx = crate::lower::TyLoweringContext::new(
+ self.db,
+ &self.resolver,
+ &self.body.types,
+ self.owner.into(),
+ );
let (resolution, unresolved) = if value_ns {
- match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path) {
+ match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, HygieneId::ROOT) {
Some(ResolveValueResult::ValueNs(value, _)) => match value {
ValueNs::EnumVariantId(var) => {
let substs = ctx.substs_from_path(path, var.into(), true);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index e9825cf..5a25168 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -11,11 +11,12 @@
use hir_def::{
data::adt::VariantData,
hir::{
- Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, Statement,
- UnaryOp,
+ Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId,
+ Statement, UnaryOp,
},
lang_item::LangItem,
- resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
+ path::Path,
+ resolver::ValueNs,
DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId,
};
use hir_expand::name::Name;
@@ -282,11 +283,11 @@
ProjectionElem::Deref => {}
ProjectionElem::Field(Either::Left(f)) => {
match &*f.parent.variant_data(db.upcast()) {
- VariantData::Record(fields) => {
+ VariantData::Record { fields, .. } => {
result.push('_');
result.push_str(fields[f.local_id].name.as_str())
}
- VariantData::Tuple(fields) => {
+ VariantData::Tuple { fields, .. } => {
let index = fields.iter().position(|it| it.0 == f.local_id);
if let Some(index) = index {
format_to!(result, "_{index}");
@@ -324,12 +325,12 @@
ProjectionElem::Field(Either::Left(f)) => {
let variant_data = f.parent.variant_data(db.upcast());
match &*variant_data {
- VariantData::Record(fields) => format_to!(
+ VariantData::Record { fields, .. } => format_to!(
result,
".{}",
fields[f.local_id].name.display(db.upcast(), edition)
),
- VariantData::Tuple(fields) => format_to!(
+ VariantData::Tuple { fields, .. } => format_to!(
result,
".{}",
fields.iter().position(|it| it.0 == f.local_id).unwrap_or_default()
@@ -382,8 +383,10 @@
}
let variant_data = f.parent.variant_data(db.upcast());
let field = match &*variant_data {
- VariantData::Record(fields) => fields[f.local_id].name.as_str().to_owned(),
- VariantData::Tuple(fields) => fields
+ VariantData::Record { fields, .. } => {
+ fields[f.local_id].name.as_str().to_owned()
+ }
+ VariantData::Tuple { fields, .. } => fields
.iter()
.position(|it| it.0 == f.local_id)
.unwrap_or_default()
@@ -508,18 +511,39 @@
apply_adjusts_to_place(&mut self.current_capture_span_stack, r, adjustments)
}
+ /// Pushes the span into `current_capture_span_stack`, *without clearing it first*.
+ fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option<HirPlace> {
+ if path.type_anchor().is_some() {
+ return None;
+ }
+ let hygiene = self.body.expr_or_pat_path_hygiene(id);
+ let result = self
+ .resolver
+ .resolve_path_in_value_ns_fully(self.db.upcast(), path, hygiene)
+ .and_then(|result| match result {
+ ValueNs::LocalBinding(binding) => {
+ let mir_span = match id {
+ ExprOrPatId::ExprId(id) => MirSpan::ExprId(id),
+ ExprOrPatId::PatId(id) => MirSpan::PatId(id),
+ };
+ self.current_capture_span_stack.push(mir_span);
+ Some(HirPlace { local: binding, projections: Vec::new() })
+ }
+ _ => None,
+ });
+ result
+ }
+
/// Changes `current_capture_span_stack` to contain the stack of spans for this expr.
fn place_of_expr_without_adjust(&mut self, tgt_expr: ExprId) -> Option<HirPlace> {
self.current_capture_span_stack.clear();
match &self.body[tgt_expr] {
Expr::Path(p) => {
- let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
- if let Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(b), _)) =
- resolver.resolve_path_in_value_ns(self.db.upcast(), p)
- {
- self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr));
- return Some(HirPlace { local: b, projections: vec![] });
- }
+ let resolver_guard =
+ self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
+ let result = self.path_place(p, tgt_expr.into());
+ self.resolver.reset_to_guard(resolver_guard);
+ return result;
}
Expr::Field { expr, name: _ } => {
let mut place = self.place_of_expr(*expr)?;
@@ -590,6 +614,16 @@
}
}
+ fn mutate_path_pat(&mut self, path: &Path, id: PatId) {
+ if let Some(place) = self.path_place(path, id.into()) {
+ self.add_capture(
+ place,
+ CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }),
+ );
+ self.current_capture_span_stack.pop(); // Remove the pattern span.
+ }
+ }
+
fn mutate_expr(&mut self, expr: ExprId, place: Option<HirPlace>) {
if let Some(place) = place {
self.add_capture(
@@ -715,14 +749,14 @@
Statement::Expr { expr, has_semi: _ } => {
self.consume_expr(*expr);
}
- Statement::Item => (),
+ Statement::Item(_) => (),
}
}
if let Some(tail) = tail {
self.consume_expr(*tail);
}
}
- Expr::Call { callee, args, is_assignee_expr: _ } => {
+ Expr::Call { callee, args } => {
self.consume_expr(*callee);
self.consume_exprs(args.iter().copied());
}
@@ -838,7 +872,7 @@
self.consume_expr(expr);
}
}
- Expr::Index { base, index, is_assignee_expr: _ } => {
+ Expr::Index { base, index } => {
self.select_from_expr(*base);
self.consume_expr(*index);
}
@@ -862,10 +896,30 @@
}));
self.current_captures = cc;
}
- Expr::Array(Array::ElementList { elements: exprs, is_assignee_expr: _ })
- | Expr::Tuple { exprs, is_assignee_expr: _ } => {
+ Expr::Array(Array::ElementList { elements: exprs }) | Expr::Tuple { exprs } => {
self.consume_exprs(exprs.iter().copied())
}
+ &Expr::Assignment { target, value } => {
+ self.walk_expr(value);
+ let resolver_guard =
+ self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
+ match self.place_of_expr(value) {
+ Some(rhs_place) => {
+ self.inside_assignment = true;
+ self.consume_with_pat(rhs_place, target);
+ self.inside_assignment = false;
+ }
+ None => self.body.walk_pats(target, &mut |pat| match &self.body[pat] {
+ Pat::Path(path) => self.mutate_path_pat(path, pat),
+ &Pat::Expr(expr) => {
+ let place = self.place_of_expr(expr);
+ self.mutate_expr(expr, place);
+ }
+ _ => {}
+ }),
+ }
+ self.resolver.reset_to_guard(resolver_guard);
+ }
Expr::Missing
| Expr::Continue { .. }
@@ -903,6 +957,7 @@
| Pat::Missing
| Pat::Wild
| Pat::Tuple { .. }
+ | Pat::Expr(_)
| Pat::Or(_) => (),
Pat::TupleStruct { .. } | Pat::Record { .. } => {
if let Some(variant) = self.result.variant_resolution_for_pat(p) {
@@ -1122,11 +1177,15 @@
}
}
}
- Pat::Range { .. }
- | Pat::Slice { .. }
- | Pat::ConstBlock(_)
- | Pat::Path(_)
- | Pat::Lit(_) => self.consume_place(place),
+ Pat::Range { .. } | Pat::Slice { .. } | Pat::ConstBlock(_) | Pat::Lit(_) => {
+ self.consume_place(place)
+ }
+ Pat::Path(path) => {
+ if self.inside_assignment {
+ self.mutate_path_pat(path, tgt_pat);
+ }
+ self.consume_place(place);
+ }
&Pat::Bind { id, subpat: _ } => {
let mode = self.result.binding_modes[tgt_pat];
let capture_kind = match mode {
@@ -1180,6 +1239,15 @@
self.current_capture_span_stack.pop();
}
Pat::Box { .. } => (), // not supported
+ &Pat::Expr(expr) => {
+ self.consume_place(place);
+ let pat_capture_span_stack = mem::take(&mut self.current_capture_span_stack);
+ let old_inside_assignment = mem::replace(&mut self.inside_assignment, false);
+ let lhs_place = self.place_of_expr(expr);
+ self.mutate_expr(expr, lhs_place);
+ self.inside_assignment = old_inside_assignment;
+ self.current_capture_span_stack = pat_capture_span_stack;
+ }
}
}
self.current_capture_span_stack
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 657e4d7..32b4ea2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -9,8 +9,8 @@
use either::Either;
use hir_def::{
hir::{
- ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, LabelId,
- Literal, Pat, PatId, Statement, UnaryOp,
+ ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, ExprOrPatId,
+ LabelId, Literal, Pat, PatId, Statement, UnaryOp,
},
lang_item::{LangItem, LangItemTarget},
path::{GenericArg, GenericArgs, Path},
@@ -188,6 +188,9 @@
| Pat::ConstBlock(_)
| Pat::Record { .. }
| Pat::Missing => true,
+ Pat::Expr(_) => unreachable!(
+ "we don't call pat_guaranteed_to_constitute_read_for_never() with assignments"
+ ),
}
}
@@ -195,10 +198,14 @@
match &self.body[expr] {
// Lang item paths cannot currently be local variables or statics.
Expr::Path(Path::LangItem(_, _)) => false,
- Expr::Path(Path::Normal { type_anchor: Some(_), .. }) => false,
+ Expr::Path(Path::Normal(path)) => path.type_anchor().is_none(),
Expr::Path(path) => self
.resolver
- .resolve_path_in_value_ns_fully(self.db.upcast(), path)
+ .resolve_path_in_value_ns_fully(
+ self.db.upcast(),
+ path,
+ self.body.expr_path_hygiene(expr),
+ )
.map_or(true, |res| matches!(res, ValueNs::LocalBinding(_) | ValueNs::StaticId(_))),
Expr::Underscore => true,
Expr::UnaryOp { op: UnaryOp::Deref, .. } => true,
@@ -223,6 +230,7 @@
| Expr::Const(..)
| Expr::UnaryOp { .. }
| Expr::BinaryOp { .. }
+ | Expr::Assignment { .. }
| Expr::Yield { .. }
| Expr::Cast { .. }
| Expr::Async { .. }
@@ -374,7 +382,7 @@
// collect explicitly written argument types
for arg_type in arg_types.iter() {
let arg_ty = match arg_type {
- Some(type_ref) => self.make_ty(type_ref),
+ Some(type_ref) => self.make_body_ty(*type_ref),
None => self.table.new_type_var(),
};
sig_tys.push(arg_ty);
@@ -382,7 +390,7 @@
// add return type
let ret_ty = match ret_type {
- Some(type_ref) => self.make_ty(type_ref),
+ Some(type_ref) => self.make_body_ty(*type_ref),
None => self.table.new_type_var(),
};
if let ClosureKind::Async = closure_kind {
@@ -609,23 +617,7 @@
coerce.complete(self)
}
}
- Expr::Path(p) => {
- let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
- let ty = match self.infer_path(p, tgt_expr.into()) {
- Some(ty) => ty,
- None => {
- if matches!(p, Path::Normal { mod_path, .. } if mod_path.is_ident() || mod_path.is_self())
- {
- self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent {
- expr: tgt_expr,
- });
- }
- self.err_ty()
- }
- };
- self.resolver.reset_to_guard(g);
- ty
- }
+ Expr::Path(p) => self.infer_expr_path(p, tgt_expr.into(), tgt_expr),
&Expr::Continue { label } => {
if find_continuable(&mut self.breakables, label).is_none() {
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
@@ -794,7 +786,7 @@
self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
}
Expr::Cast { expr, type_ref } => {
- let cast_ty = self.make_ty(type_ref);
+ let cast_ty = self.make_body_ty(*type_ref);
let expr_ty = self.infer_expr(
*expr,
&Expectation::Castable(cast_ty.clone()),
@@ -892,36 +884,6 @@
}
}
Expr::BinaryOp { lhs, rhs, op } => match op {
- Some(BinaryOp::Assignment { op: None }) => {
- let lhs = *lhs;
- let is_ordinary = match &self.body[lhs] {
- Expr::Array(_)
- | Expr::RecordLit { .. }
- | Expr::Tuple { .. }
- | Expr::Underscore => false,
- Expr::Call { callee, .. } => !matches!(&self.body[*callee], Expr::Path(_)),
- _ => true,
- };
-
- // In ordinary (non-destructuring) assignments, the type of
- // `lhs` must be inferred first so that the ADT fields
- // instantiations in RHS can be coerced to it. Note that this
- // cannot happen in destructuring assignments because of how
- // they are desugared.
- if is_ordinary {
- // LHS of assignment doesn't constitute reads.
- let lhs_ty = self.infer_expr(lhs, &Expectation::none(), ExprIsRead::No);
- self.infer_expr_coerce(
- *rhs,
- &Expectation::has_type(lhs_ty),
- ExprIsRead::No,
- );
- } else {
- let rhs_ty = self.infer_expr(*rhs, &Expectation::none(), ExprIsRead::Yes);
- self.infer_assignee_expr(lhs, &rhs_ty);
- }
- self.result.standard_types.unit.clone()
- }
Some(BinaryOp::LogicOp(_)) => {
let bool_ty = self.result.standard_types.bool_.clone();
self.infer_expr_coerce(
@@ -942,6 +904,35 @@
Some(op) => self.infer_overloadable_binop(*lhs, *op, *rhs, tgt_expr),
_ => self.err_ty(),
},
+ &Expr::Assignment { target, value } => {
+ // In ordinary (non-destructuring) assignments, the type of
+ // `lhs` must be inferred first so that the ADT fields
+ // instantiations in RHS can be coerced to it. Note that this
+ // cannot happen in destructuring assignments because of how
+ // they are desugared.
+ let lhs_ty = match &self.body[target] {
+ // LHS of assignment doesn't constitute reads.
+ &Pat::Expr(expr) => {
+ Some(self.infer_expr(expr, &Expectation::none(), ExprIsRead::No))
+ }
+ Pat::Path(path) => Some(self.infer_expr_path(path, target.into(), tgt_expr)),
+ _ => None,
+ };
+
+ if let Some(lhs_ty) = lhs_ty {
+ self.write_pat_ty(target, lhs_ty.clone());
+ self.infer_expr_coerce(value, &Expectation::has_type(lhs_ty), ExprIsRead::No);
+ } else {
+ let rhs_ty = self.infer_expr(value, &Expectation::none(), ExprIsRead::Yes);
+ let resolver_guard =
+ self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
+ self.inside_assignment = true;
+ self.infer_top_pat(target, &rhs_ty);
+ self.inside_assignment = false;
+ self.resolver.reset_to_guard(resolver_guard);
+ }
+ self.result.standard_types.unit.clone()
+ }
Expr::Range { lhs, rhs, range_type } => {
let lhs_ty =
lhs.map(|e| self.infer_expr_inner(e, &Expectation::none(), ExprIsRead::Yes));
@@ -981,7 +972,7 @@
(RangeOp::Inclusive, _, None) => self.err_ty(),
}
}
- Expr::Index { base, index, is_assignee_expr } => {
+ Expr::Index { base, index } => {
let base_ty = self.infer_expr_inner(*base, &Expectation::none(), ExprIsRead::Yes);
let index_ty = self.infer_expr(*index, &Expectation::none(), ExprIsRead::Yes);
@@ -1017,23 +1008,11 @@
self.write_method_resolution(tgt_expr, func, subst);
}
let assoc = self.resolve_ops_index_output();
- let res = self.resolve_associated_type_with_params(
+ self.resolve_associated_type_with_params(
self_ty.clone(),
assoc,
&[index_ty.clone().cast(Interner)],
- );
-
- if *is_assignee_expr {
- if let Some(index_trait) = self.resolve_lang_trait(LangItem::IndexMut) {
- let trait_ref = TyBuilder::trait_ref(self.db, index_trait)
- .push(self_ty)
- .fill(|_| index_ty.clone().cast(Interner))
- .build();
- self.push_obligation(trait_ref.cast(Interner));
- }
- }
-
- res
+ )
} else {
self.err_ty()
}
@@ -1151,9 +1130,7 @@
},
},
Expr::Underscore => {
- // Underscore expressions may only appear in assignee expressions,
- // which are handled by `infer_assignee_expr()`.
- // Any other underscore expression is an error, we render a specialized diagnostic
+ // Underscore expression is an error, we render a specialized diagnostic
// to let the user know what type is expected though.
let expected = expected.to_option(&mut self.table).unwrap_or_else(|| self.err_ty());
self.push_diagnostic(InferenceDiagnostic::TypedHole {
@@ -1232,6 +1209,22 @@
ty
}
+ fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatId, scope_id: ExprId) -> Ty {
+ let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, scope_id);
+ let ty = match self.infer_path(path, id) {
+ Some(ty) => ty,
+ None => {
+ if path.mod_path().is_some_and(|mod_path| mod_path.is_ident() || mod_path.is_self())
+ {
+ self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent { id });
+ }
+ self.err_ty()
+ }
+ };
+ self.resolver.reset_to_guard(g);
+ ty
+ }
+
fn infer_async_block(
&mut self,
tgt_expr: ExprId,
@@ -1482,107 +1475,6 @@
}
}
- pub(super) fn infer_assignee_expr(&mut self, lhs: ExprId, rhs_ty: &Ty) -> Ty {
- let is_rest_expr = |expr| {
- matches!(
- &self.body[expr],
- Expr::Range { lhs: None, rhs: None, range_type: RangeOp::Exclusive },
- )
- };
-
- let rhs_ty = self.resolve_ty_shallow(rhs_ty);
-
- let ty = match &self.body[lhs] {
- Expr::Tuple { exprs, .. } => {
- // We don't consider multiple ellipses. This is analogous to
- // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
- let ellipsis = exprs.iter().position(|e| is_rest_expr(*e)).map(|it| it as u32);
- let exprs: Vec<_> = exprs.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
-
- self.infer_tuple_pat_like(&rhs_ty, (), ellipsis, &exprs)
- }
- Expr::Call { callee, args, .. } => {
- // Tuple structs
- let path = match &self.body[*callee] {
- Expr::Path(path) => Some(path),
- _ => None,
- };
-
- // We don't consider multiple ellipses. This is analogous to
- // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
- let ellipsis = args.iter().position(|e| is_rest_expr(*e)).map(|it| it as u32);
- let args: Vec<_> = args.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
-
- self.infer_tuple_struct_pat_like(path, &rhs_ty, (), lhs, ellipsis, &args)
- }
- Expr::Array(Array::ElementList { elements, .. }) => {
- let elem_ty = match rhs_ty.kind(Interner) {
- TyKind::Array(st, _) => st.clone(),
- _ => self.err_ty(),
- };
-
- // There's no need to handle `..` as it cannot be bound.
- let sub_exprs = elements.iter().filter(|e| !is_rest_expr(**e));
-
- for e in sub_exprs {
- self.infer_assignee_expr(*e, &elem_ty);
- }
-
- match rhs_ty.kind(Interner) {
- TyKind::Array(_, _) => rhs_ty.clone(),
- // Even when `rhs_ty` is not an array type, this assignee
- // expression is inferred to be an array (of unknown element
- // type and length). This should not be just an error type,
- // because we are to compute the unifiability of this type and
- // `rhs_ty` in the end of this function to issue type mismatches.
- _ => TyKind::Array(
- self.err_ty(),
- crate::consteval::usize_const(self.db, None, self.resolver.krate()),
- )
- .intern(Interner),
- }
- }
- Expr::RecordLit { path, fields, .. } => {
- let subs = fields.iter().map(|f| (f.name.clone(), f.expr));
-
- self.infer_record_pat_like(path.as_deref(), &rhs_ty, (), lhs, subs)
- }
- Expr::Underscore => rhs_ty.clone(),
- _ => {
- // `lhs` is a place expression, a unit struct, or an enum variant.
- // LHS of assignment doesn't constitute reads.
- let lhs_ty = self.infer_expr_inner(lhs, &Expectation::none(), ExprIsRead::No);
-
- // This is the only branch where this function may coerce any type.
- // We are returning early to avoid the unifiability check below.
- let lhs_ty = self.insert_type_vars_shallow(lhs_ty);
- let ty = match self.coerce(None, &rhs_ty, &lhs_ty, CoerceNever::Yes) {
- Ok(ty) => ty,
- Err(_) => {
- self.result.type_mismatches.insert(
- lhs.into(),
- TypeMismatch { expected: rhs_ty.clone(), actual: lhs_ty.clone() },
- );
- // `rhs_ty` is returned so no further type mismatches are
- // reported because of this mismatch.
- rhs_ty
- }
- };
- self.write_expr_ty(lhs, ty.clone());
- return ty;
- }
- };
-
- let ty = self.insert_type_vars_shallow(ty);
- if !self.unify(&ty, &rhs_ty) {
- self.result
- .type_mismatches
- .insert(lhs.into(), TypeMismatch { expected: rhs_ty.clone(), actual: ty.clone() });
- }
- self.write_expr_ty(lhs, ty.clone());
- ty
- }
-
fn infer_overloadable_binop(
&mut self,
lhs: ExprId,
@@ -1706,7 +1598,7 @@
Statement::Let { pat, type_ref, initializer, else_branch } => {
let decl_ty = type_ref
.as_ref()
- .map(|tr| this.make_ty(tr))
+ .map(|&tr| this.make_body_ty(tr))
.unwrap_or_else(|| this.table.new_type_var());
let ty = if let Some(expr) = initializer {
@@ -1764,7 +1656,7 @@
);
}
}
- Statement::Item => (),
+ Statement::Item(_) => (),
}
}
@@ -2249,7 +2141,8 @@
kind_id,
args.next().unwrap(), // `peek()` is `Some(_)`, so guaranteed no panic
self,
- |this, type_ref| this.make_ty(type_ref),
+ &self.body.types,
+ |this, type_ref| this.make_body_ty(type_ref),
|this, c, ty| {
const_or_path_to_chalk(
this.db,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
index 6a0daee..d74a383 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
@@ -4,7 +4,8 @@
use chalk_ir::{cast::Cast, Mutability};
use hir_def::{
hir::{
- Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp,
+ Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, Pat, PatId, Statement,
+ UnaryOp,
},
lang_item::LangItem,
};
@@ -88,7 +89,7 @@
Statement::Expr { expr, has_semi: _ } => {
self.infer_mut_expr(*expr, Mutability::Not);
}
- Statement::Item => (),
+ Statement::Item(_) => (),
}
}
if let Some(tail) = tail {
@@ -96,7 +97,7 @@
}
}
Expr::MethodCall { receiver: it, method_name: _, args, generic_args: _ }
- | Expr::Call { callee: it, args, is_assignee_expr: _ } => {
+ | Expr::Call { callee: it, args } => {
self.infer_mut_not_expr_iter(args.iter().copied().chain(Some(*it)));
}
Expr::Match { expr, arms } => {
@@ -120,10 +121,10 @@
Expr::Become { expr } => {
self.infer_mut_expr(*expr, Mutability::Not);
}
- Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => {
+ Expr::RecordLit { path: _, fields, spread } => {
self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread))
}
- &Expr::Index { base, index, is_assignee_expr } => {
+ &Expr::Index { base, index } => {
if mutability == Mutability::Mut {
if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) {
if let Some(index_trait) = self
@@ -148,11 +149,8 @@
target,
}) = base_adjustments
{
- // For assignee exprs `IndexMut` obligations are already applied
- if !is_assignee_expr {
- if let TyKind::Ref(_, _, ty) = target.kind(Interner) {
- base_ty = Some(ty.clone());
- }
+ if let TyKind::Ref(_, _, ty) = target.kind(Interner) {
+ base_ty = Some(ty.clone());
}
*mutability = Mutability::Mut;
}
@@ -233,6 +231,14 @@
self.infer_mut_expr(*lhs, Mutability::Mut);
self.infer_mut_expr(*rhs, Mutability::Not);
}
+ &Expr::Assignment { target, value } => {
+ self.body.walk_pats(target, &mut |pat| match self.body[pat] {
+ Pat::Expr(expr) => self.infer_mut_expr(expr, Mutability::Mut),
+ Pat::ConstBlock(block) => self.infer_mut_expr(block, Mutability::Not),
+ _ => {}
+ });
+ self.infer_mut_expr(value, Mutability::Not);
+ }
Expr::Array(Array::Repeat { initializer: lhs, repeat: rhs })
| Expr::BinaryOp { lhs, rhs, op: _ }
| Expr::Range { lhs: Some(lhs), rhs: Some(rhs), range_type: _ } => {
@@ -242,8 +248,7 @@
Expr::Closure { body, .. } => {
self.infer_mut_expr(*body, Mutability::Not);
}
- Expr::Tuple { exprs, is_assignee_expr: _ }
- | Expr::Array(Array::ElementList { elements: exprs, is_assignee_expr: _ }) => {
+ Expr::Tuple { exprs } | Expr::Array(Array::ElementList { elements: exprs }) => {
self.infer_mut_not_expr_iter(exprs.iter().copied());
}
// These don't need any action, as they don't have sub expressions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index fee6755..50e7611 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -4,7 +4,7 @@
use hir_def::{
body::Body,
- hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId},
+ hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId},
path::Path,
};
use hir_expand::name::Name;
@@ -12,63 +12,28 @@
use crate::{
consteval::{try_const_usize, usize_const},
- infer::{expr::ExprIsRead, BindingMode, Expectation, InferenceContext, TypeMismatch},
+ infer::{
+ coerce::CoerceNever, expr::ExprIsRead, BindingMode, Expectation, InferenceContext,
+ TypeMismatch,
+ },
lower::lower_to_chalk_mutability,
primitive::UintTy,
static_lifetime, InferenceDiagnostic, Interner, Mutability, Scalar, Substitution, Ty,
TyBuilder, TyExt, TyKind,
};
-/// Used to generalize patterns and assignee expressions.
-pub(super) trait PatLike: Into<ExprOrPatId> + Copy {
- type BindingMode: Copy;
-
- fn infer(
- this: &mut InferenceContext<'_>,
- id: Self,
- expected_ty: &Ty,
- default_bm: Self::BindingMode,
- ) -> Ty;
-}
-
-impl PatLike for ExprId {
- type BindingMode = ();
-
- fn infer(
- this: &mut InferenceContext<'_>,
- id: Self,
- expected_ty: &Ty,
- (): Self::BindingMode,
- ) -> Ty {
- this.infer_assignee_expr(id, expected_ty)
- }
-}
-
-impl PatLike for PatId {
- type BindingMode = BindingMode;
-
- fn infer(
- this: &mut InferenceContext<'_>,
- id: Self,
- expected_ty: &Ty,
- default_bm: Self::BindingMode,
- ) -> Ty {
- this.infer_pat(id, expected_ty, default_bm)
- }
-}
-
impl InferenceContext<'_> {
/// Infers type for tuple struct pattern or its corresponding assignee expression.
///
/// Ellipses found in the original pattern or expression must be filtered out.
- pub(super) fn infer_tuple_struct_pat_like<T: PatLike>(
+ pub(super) fn infer_tuple_struct_pat_like(
&mut self,
path: Option<&Path>,
expected: &Ty,
- default_bm: T::BindingMode,
- id: T,
+ default_bm: BindingMode,
+ id: PatId,
ellipsis: Option<u32>,
- subs: &[T],
+ subs: &[PatId],
) -> Ty {
let (ty, def) = self.resolve_variant(path, true);
let var_data = def.map(|it| it.variant_data(self.db.upcast()));
@@ -127,13 +92,13 @@
}
};
- T::infer(self, subpat, &expected_ty, default_bm);
+ self.infer_pat(subpat, &expected_ty, default_bm);
}
}
None => {
let err_ty = self.err_ty();
for &inner in subs {
- T::infer(self, inner, &err_ty, default_bm);
+ self.infer_pat(inner, &err_ty, default_bm);
}
}
}
@@ -142,13 +107,13 @@
}
/// Infers type for record pattern or its corresponding assignee expression.
- pub(super) fn infer_record_pat_like<T: PatLike>(
+ pub(super) fn infer_record_pat_like(
&mut self,
path: Option<&Path>,
expected: &Ty,
- default_bm: T::BindingMode,
- id: T,
- subs: impl ExactSizeIterator<Item = (Name, T)>,
+ default_bm: BindingMode,
+ id: PatId,
+ subs: impl ExactSizeIterator<Item = (Name, PatId)>,
) -> Ty {
let (ty, def) = self.resolve_variant(path, false);
if let Some(variant) = def {
@@ -197,13 +162,13 @@
}
};
- T::infer(self, inner, &expected_ty, default_bm);
+ self.infer_pat(inner, &expected_ty, default_bm);
}
}
None => {
let err_ty = self.err_ty();
for (_, inner) in subs {
- T::infer(self, inner, &err_ty, default_bm);
+ self.infer_pat(inner, &err_ty, default_bm);
}
}
}
@@ -214,12 +179,12 @@
/// Infers type for tuple pattern or its corresponding assignee expression.
///
/// Ellipses found in the original pattern or expression must be filtered out.
- pub(super) fn infer_tuple_pat_like<T: PatLike>(
+ pub(super) fn infer_tuple_pat_like(
&mut self,
expected: &Ty,
- default_bm: T::BindingMode,
+ default_bm: BindingMode,
ellipsis: Option<u32>,
- subs: &[T],
+ subs: &[PatId],
) -> Ty {
let expected = self.resolve_ty_shallow(expected);
let expectations = match expected.as_tuple() {
@@ -244,18 +209,20 @@
// Process pre
for (ty, pat) in inner_tys.iter_mut().zip(pre) {
- *ty = T::infer(self, *pat, ty, default_bm);
+ *ty = self.infer_pat(*pat, ty, default_bm);
}
// Process post
for (ty, pat) in inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post) {
- *ty = T::infer(self, *pat, ty, default_bm);
+ *ty = self.infer_pat(*pat, ty, default_bm);
}
TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
.intern(Interner)
}
+ /// The resolver needs to be updated to the surrounding expression when inside assignment
+ /// (because there, `Pat::Path` can refer to a variable).
pub(super) fn infer_top_pat(&mut self, pat: PatId, expected: &Ty) {
self.infer_pat(pat, expected, BindingMode::default());
}
@@ -263,7 +230,14 @@
fn infer_pat(&mut self, pat: PatId, expected: &Ty, mut default_bm: BindingMode) -> Ty {
let mut expected = self.resolve_ty_shallow(expected);
- if self.is_non_ref_pat(self.body, pat) {
+ if matches!(&self.body[pat], Pat::Ref { .. }) || self.inside_assignment {
+ cov_mark::hit!(match_ergonomics_ref);
+ // When you encounter a `&pat` pattern, reset to Move.
+ // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
+ // Destructuring assignments also reset the binding mode and
+ // don't do match ergonomics.
+ default_bm = BindingMode::Move;
+ } else if self.is_non_ref_pat(self.body, pat) {
let mut pat_adjustments = Vec::new();
while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
pat_adjustments.push(expected.clone());
@@ -279,11 +253,6 @@
pat_adjustments.shrink_to_fit();
self.result.pat_adjustments.insert(pat, pat_adjustments);
}
- } else if let Pat::Ref { .. } = &self.body[pat] {
- cov_mark::hit!(match_ergonomics_ref);
- // When you encounter a `&pat` pattern, reset to Move.
- // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
- default_bm = BindingMode::Move;
}
// Lose mutability.
@@ -320,8 +289,34 @@
self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat, subs)
}
Pat::Path(path) => {
- // FIXME update resolver for the surrounding expression
- self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty())
+ let ty = self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty());
+ let ty_inserted_vars = self.insert_type_vars_shallow(ty.clone());
+ match self.table.coerce(&expected, &ty_inserted_vars, CoerceNever::Yes) {
+ Ok((adjustments, coerced_ty)) => {
+ if !adjustments.is_empty() {
+ self.result
+ .pat_adjustments
+ .entry(pat)
+ .or_default()
+ .extend(adjustments.into_iter().map(|adjust| adjust.target));
+ }
+ self.write_pat_ty(pat, coerced_ty);
+ return self.pat_ty_after_adjustment(pat);
+ }
+ Err(_) => {
+ self.result.type_mismatches.insert(
+ pat.into(),
+ TypeMismatch {
+ expected: expected.clone(),
+ actual: ty_inserted_vars.clone(),
+ },
+ );
+ self.write_pat_ty(pat, ty);
+ // We return `expected` to prevent cascading errors. I guess an alternative is to
+ // not emit type mismatches for error types and emit an error type here.
+ return expected;
+ }
+ }
}
Pat::Bind { id, subpat } => {
return self.infer_bind_pat(pat, *id, default_bm, *subpat, &expected);
@@ -361,7 +356,40 @@
None => self.err_ty(),
},
Pat::ConstBlock(expr) => {
- self.infer_expr(*expr, &Expectation::has_type(expected.clone()), ExprIsRead::Yes)
+ let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false);
+ let result = self.infer_expr(
+ *expr,
+ &Expectation::has_type(expected.clone()),
+ ExprIsRead::Yes,
+ );
+ self.inside_assignment = old_inside_assign;
+ result
+ }
+ Pat::Expr(expr) => {
+ let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false);
+ // LHS of assignment doesn't constitute reads.
+ let result = self.infer_expr_coerce(
+ *expr,
+ &Expectation::has_type(expected.clone()),
+ ExprIsRead::No,
+ );
+ // We are returning early to avoid the unifiability check below.
+ let lhs_ty = self.insert_type_vars_shallow(result);
+ let ty = match self.coerce(None, &expected, &lhs_ty, CoerceNever::Yes) {
+ Ok(ty) => ty,
+ Err(_) => {
+ self.result.type_mismatches.insert(
+ pat.into(),
+ TypeMismatch { expected: expected.clone(), actual: lhs_ty.clone() },
+ );
+ // `rhs_ty` is returned so no further type mismatches are
+ // reported because of this mismatch.
+ expected
+ }
+ };
+ self.write_pat_ty(pat, ty.clone());
+ self.inside_assignment = old_inside_assign;
+ return ty;
}
Pat::Missing => self.err_ty(),
};
@@ -517,9 +545,12 @@
body[*expr],
Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
),
- Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => {
- false
- }
+ Pat::Wild
+ | Pat::Bind { .. }
+ | Pat::Ref { .. }
+ | Pat::Box { .. }
+ | Pat::Missing
+ | Pat::Expr(_) => false,
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index e4841c7..442daa9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -94,8 +94,7 @@
return Some(ValuePathResolution::NonGeneric(ty));
};
- let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
- let substs = ctx.substs_from_path(path, value_def, true);
+ let substs = self.with_body_ty_lowering(|ctx| ctx.substs_from_path(path, value_def, true));
let substs = substs.as_slice(Interner);
if let ValueNs::EnumVariantId(_) = value {
@@ -152,8 +151,12 @@
let last = path.segments().last()?;
// Don't use `self.make_ty()` here as we need `orig_ns`.
- let ctx =
- crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
+ let ctx = crate::lower::TyLoweringContext::new(
+ self.db,
+ &self.resolver,
+ &self.body.types,
+ self.owner.into(),
+ );
let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
let ty = self.table.insert_type_vars(ty);
let ty = self.table.normalize_associated_types_in(ty);
@@ -164,9 +167,10 @@
let ty = self.table.normalize_associated_types_in(ty);
self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
} else {
+ let hygiene = self.body.expr_or_pat_path_hygiene(id);
// FIXME: report error, unresolved first path segment
let value_or_partial =
- self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?;
+ self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, hygiene)?;
match value_or_partial {
ResolveValueResult::ValueNs(it, _) => (it, None),
@@ -218,7 +222,7 @@
let _d;
let (resolved_segment, remaining_segments) = match path {
- Path::Normal { .. } => {
+ Path::Normal { .. } | Path::BarePath(_) => {
assert!(remaining_index < path.segments().len());
(
path.segments().get(remaining_index - 1).unwrap(),
@@ -242,17 +246,10 @@
(TypeNs::TraitId(trait_), true) => {
let segment =
remaining_segments.last().expect("there should be at least one segment here");
- let ctx = crate::lower::TyLoweringContext::new(
- self.db,
- &self.resolver,
- self.owner.into(),
- );
- let trait_ref = ctx.lower_trait_ref_from_resolved_path(
- trait_,
- resolved_segment,
- self.table.new_type_var(),
- );
-
+ let self_ty = self.table.new_type_var();
+ let trait_ref = self.with_body_ty_lowering(|ctx| {
+ ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty)
+ });
self.resolve_trait_assoc_item(trait_ref, segment, id)
}
(def, _) => {
@@ -262,17 +259,14 @@
// as Iterator>::Item::default`)
let remaining_segments_for_ty =
remaining_segments.take(remaining_segments.len() - 1);
- let ctx = crate::lower::TyLoweringContext::new(
- self.db,
- &self.resolver,
- self.owner.into(),
- );
- let (ty, _) = ctx.lower_partly_resolved_path(
- def,
- resolved_segment,
- remaining_segments_for_ty,
- true,
- );
+ let (ty, _) = self.with_body_ty_lowering(|ctx| {
+ ctx.lower_partly_resolved_path(
+ def,
+ resolved_segment,
+ remaining_segments_for_ty,
+ true,
+ )
+ });
if ty.is_unknown() {
return None;
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index 8083144..9f4cc98 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -6,7 +6,7 @@
use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
use hir_def::{
layout::{
- Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutS,
+ Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData,
Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange,
},
LocalFieldId, StructId,
@@ -66,7 +66,7 @@
}
}
-pub type Layout = LayoutS<RustcFieldIdx, RustcEnumVariantIdx>;
+pub type Layout = LayoutData<RustcFieldIdx, RustcEnumVariantIdx>;
pub type TagEncoding = hir_def::layout::TagEncoding<RustcEnumVariantIdx>;
pub type Variants = hir_def::layout::Variants<RustcFieldIdx, RustcEnumVariantIdx>;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index c7ed684..e3a92e5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -34,6 +34,7 @@
resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
type_ref::{
ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
+ TypeRefId, TypesMap, TypesSourceMap,
},
AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId,
@@ -41,7 +42,6 @@
TypeOwnerId, UnionId, VariantId,
};
use hir_expand::{name::Name, ExpandResult};
-use intern::Interned;
use la_arena::{Arena, ArenaMap};
use rustc_hash::FxHashSet;
use rustc_pattern_analysis::Captures;
@@ -122,6 +122,11 @@
pub db: &'a dyn HirDatabase,
resolver: &'a Resolver,
generics: OnceCell<Option<Generics>>,
+ types_map: &'a TypesMap,
+ /// If this is set, that means we're in a context of a freshly expanded macro, and that means
+ /// we should not use `TypeRefId` in diagnostics because the caller won't have the `TypesMap`,
+ /// instead we need to put `TypeSource` from the source map.
+ types_source_map: Option<&'a TypesSourceMap>,
in_binders: DebruijnIndex,
// FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases
// where expected
@@ -138,13 +143,20 @@
}
impl<'a> TyLoweringContext<'a> {
- pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver, owner: TypeOwnerId) -> Self {
- Self::new_maybe_unowned(db, resolver, Some(owner))
+ pub fn new(
+ db: &'a dyn HirDatabase,
+ resolver: &'a Resolver,
+ types_map: &'a TypesMap,
+ owner: TypeOwnerId,
+ ) -> Self {
+ Self::new_maybe_unowned(db, resolver, types_map, None, Some(owner))
}
pub fn new_maybe_unowned(
db: &'a dyn HirDatabase,
resolver: &'a Resolver,
+ types_map: &'a TypesMap,
+ types_source_map: Option<&'a TypesSourceMap>,
owner: Option<TypeOwnerId>,
) -> Self {
let impl_trait_mode = ImplTraitLoweringState::Disallowed;
@@ -154,6 +166,8 @@
db,
resolver,
generics: OnceCell::new(),
+ types_map,
+ types_source_map,
owner,
in_binders,
impl_trait_mode,
@@ -201,6 +215,16 @@
pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
Self { type_param_mode, ..self }
}
+
+ pub fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self {
+ self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode);
+ self
+ }
+
+ pub fn type_param_mode(&mut self, type_param_mode: ParamLoweringMode) -> &mut Self {
+ self.type_param_mode = type_param_mode;
+ self
+ }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -230,7 +254,7 @@
}
impl<'a> TyLoweringContext<'a> {
- pub fn lower_ty(&self, type_ref: &TypeRef) -> Ty {
+ pub fn lower_ty(&self, type_ref: TypeRefId) -> Ty {
self.lower_ty_ext(type_ref).0
}
@@ -254,12 +278,13 @@
.as_ref()
}
- pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
+ pub fn lower_ty_ext(&self, type_ref_id: TypeRefId) -> (Ty, Option<TypeNs>) {
let mut res = None;
+ let type_ref = &self.types_map[type_ref_id];
let ty = match type_ref {
TypeRef::Never => TyKind::Never.intern(Interner),
TypeRef::Tuple(inner) => {
- let inner_tys = inner.iter().map(|tr| self.lower_ty(tr));
+ let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr));
TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
.intern(Interner)
}
@@ -268,38 +293,43 @@
res = res_;
ty
}
- TypeRef::RawPtr(inner, mutability) => {
+ &TypeRef::RawPtr(inner, mutability) => {
let inner_ty = self.lower_ty(inner);
- TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(Interner)
+ TyKind::Raw(lower_to_chalk_mutability(mutability), inner_ty).intern(Interner)
}
- TypeRef::Array(inner, len) => {
- let inner_ty = self.lower_ty(inner);
- let const_len = self.lower_const(len, TyBuilder::usize());
+ TypeRef::Array(array) => {
+ let inner_ty = self.lower_ty(array.ty);
+ let const_len = self.lower_const(&array.len, TyBuilder::usize());
TyKind::Array(inner_ty, const_len).intern(Interner)
}
- TypeRef::Slice(inner) => {
+ &TypeRef::Slice(inner) => {
let inner_ty = self.lower_ty(inner);
TyKind::Slice(inner_ty).intern(Interner)
}
- TypeRef::Reference(inner, lifetime, mutability) => {
- let inner_ty = self.lower_ty(inner);
+ TypeRef::Reference(ref_) => {
+ let inner_ty = self.lower_ty(ref_.ty);
// FIXME: It should infer the eldided lifetimes instead of stubbing with static
- let lifetime =
- lifetime.as_ref().map_or_else(error_lifetime, |lr| self.lower_lifetime(lr));
- TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty)
+ let lifetime = ref_
+ .lifetime
+ .as_ref()
+ .map_or_else(error_lifetime, |lr| self.lower_lifetime(lr));
+ TyKind::Ref(lower_to_chalk_mutability(ref_.mutability), lifetime, inner_ty)
.intern(Interner)
}
TypeRef::Placeholder => TyKind::Error.intern(Interner),
- &TypeRef::Fn(ref params, variadic, is_unsafe, ref abi) => {
+ TypeRef::Fn(fn_) => {
let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
- Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr)))
+ Substitution::from_iter(
+ Interner,
+ fn_.params().iter().map(|&(_, tr)| ctx.lower_ty(tr)),
+ )
});
TyKind::Function(FnPointer {
num_binders: 0, // FIXME lower `for<'a> fn()` correctly
sig: FnSig {
- abi: abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
- safety: if is_unsafe { Safety::Unsafe } else { Safety::Safe },
- variadic,
+ abi: fn_.abi().as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
+ safety: if fn_.is_unsafe() { Safety::Unsafe } else { Safety::Safe },
+ variadic: fn_.is_varargs(),
},
substitution: FnSubst(substs),
})
@@ -351,8 +381,8 @@
ImplTraitLoweringState::Param(counter) => {
let idx = counter.get();
// Count the number of `impl Trait` things that appear within our bounds.
- // Since t hose have been emitted as implicit type args already.
- counter.set(idx + count_impl_traits(type_ref) as u16);
+ // Since those have been emitted as implicit type args already.
+ counter.set(idx + self.count_impl_traits(type_ref_id) as u16);
let kind = self
.generics()
.expect("param impl trait lowering must be in a generic def")
@@ -376,7 +406,7 @@
let idx = counter.get();
// Count the number of `impl Trait` things that appear within our bounds.
// Since t hose have been emitted as implicit type args already.
- counter.set(idx + count_impl_traits(type_ref) as u16);
+ counter.set(idx + self.count_impl_traits(type_ref_id) as u16);
let kind = self
.generics()
.expect("variable impl trait lowering must be in a generic def")
@@ -432,12 +462,40 @@
match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, resolver)
{
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
- let ctx = expander.ctx(self.db.upcast());
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+
+ let ctx = expander.ctx(
+ self.db.upcast(),
+ &mut types_map,
+ &mut types_source_map,
+ );
// FIXME: Report syntax errors in expansion here
let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
drop(expander);
- let ty = self.lower_ty(&type_ref);
+
+ // FIXME: That may be better served by mutating `self` then restoring, but this requires
+ // making it `&mut self`.
+ let inner_ctx = TyLoweringContext {
+ db: self.db,
+ resolver: self.resolver,
+ generics: self.generics.clone(),
+ types_map: &types_map,
+ types_source_map: Some(&types_source_map),
+ in_binders: self.in_binders,
+ owner: self.owner,
+ type_param_mode: self.type_param_mode,
+ impl_trait_mode: self.impl_trait_mode.take(),
+ expander: RefCell::new(self.expander.take()),
+ unsized_types: RefCell::new(self.unsized_types.take()),
+ };
+
+ let ty = inner_ctx.lower_ty(type_ref);
+
+ self.impl_trait_mode.swap(&inner_ctx.impl_trait_mode);
+ *self.expander.borrow_mut() = inner_ctx.expander.into_inner();
+ *self.unsized_types.borrow_mut() = inner_ctx.unsized_types.into_inner();
self.expander.borrow_mut().as_mut().unwrap().exit(mark);
Some(ty)
@@ -463,7 +521,8 @@
/// This is only for `generic_predicates_for_param`, where we can't just
/// lower the self types of the predicates since that could lead to cycles.
/// So we just check here if the `type_ref` resolves to a generic param, and which.
- fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option<TypeOrConstParamId> {
+ fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> {
+ let type_ref = &self.types_map[type_ref];
let path = match type_ref {
TypeRef::Path(path) => path,
_ => return None,
@@ -663,7 +722,7 @@
if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
// trait object type without dyn
let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None);
- let ty = self.lower_dyn_trait(&[Interned::new(bound)]);
+ let ty = self.lower_dyn_trait(&[bound]);
return (ty, None);
}
@@ -864,7 +923,7 @@
assert!(matches!(id, GenericParamId::TypeParamId(_)));
had_explicit_args = true;
if let GenericArg::Type(ty) = &args[0] {
- substs.push(self.lower_ty(ty).cast(Interner));
+ substs.push(self.lower_ty(*ty).cast(Interner));
}
}
} else {
@@ -901,6 +960,7 @@
id,
arg,
&mut (),
+ self.types_map,
|_, type_ref| self.lower_ty(type_ref),
|_, const_ref, ty| self.lower_const(const_ref, ty),
|_, lifetime_ref| self.lower_lifetime(lifetime_ref),
@@ -998,7 +1058,7 @@
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound } => {
let self_ty = match target {
- WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
+ WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(*type_ref),
&WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
let param_id = hir_def::TypeOrConstParamId { parent: def, local_id };
match self.type_param_mode {
@@ -1029,12 +1089,12 @@
pub(crate) fn lower_type_bound(
&'a self,
- bound: &'a Interned<TypeBound>,
+ bound: &'a TypeBound,
self_ty: Ty,
ignore_bindings: bool,
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
let mut trait_ref = None;
- let clause = match bound.as_ref() {
+ let clause = match bound {
TypeBound::Path(path, TraitBoundModifier::None) => {
trait_ref = self.lower_trait_ref_from_path(path, self_ty);
trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
@@ -1067,7 +1127,7 @@
lifetime,
})))
}
- TypeBound::Error => None,
+ TypeBound::Use(_) | TypeBound::Error => None,
};
clause.into_iter().chain(
trait_ref
@@ -1079,14 +1139,15 @@
fn assoc_type_bindings_from_type_bound(
&'a self,
- bound: &'a Interned<TypeBound>,
+ bound: &'a TypeBound,
trait_ref: TraitRef,
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
- let last_segment = match bound.as_ref() {
+ let last_segment = match bound {
TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => {
path.segments().last()
}
TypeBound::Path(_, TraitBoundModifier::Maybe)
+ | TypeBound::Use(_)
| TypeBound::Error
| TypeBound::Lifetime(_) => None,
};
@@ -1110,7 +1171,7 @@
// this point (`super_trait_ref.substitution`).
let substitution = self.substs_from_path_segment(
// FIXME: This is hack. We shouldn't really build `PathSegment` directly.
- PathSegment { name: &binding.name, args_and_bindings: binding.args.as_deref() },
+ PathSegment { name: &binding.name, args_and_bindings: binding.args.as_ref() },
Some(associated_ty.into()),
false, // this is not relevant
Some(super_trait_ref.self_type_parameter(Interner)),
@@ -1130,8 +1191,8 @@
let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
);
- if let Some(type_ref) = &binding.type_ref {
- match (type_ref, &self.impl_trait_mode) {
+ if let Some(type_ref) = binding.type_ref {
+ match (&self.types_map[type_ref], &self.impl_trait_mode) {
(TypeRef::ImplTrait(_), ImplTraitLoweringState::Disallowed) => (),
(
_,
@@ -1178,6 +1239,8 @@
let mut ext = TyLoweringContext::new_maybe_unowned(
self.db,
self.resolver,
+ self.types_map,
+ self.types_source_map,
self.owner,
)
.with_type_param_mode(self.type_param_mode);
@@ -1215,7 +1278,7 @@
})
}
- fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
+ fn lower_dyn_trait(&self, bounds: &[TypeBound]) -> Ty {
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
// INVARIANT: The principal trait bound, if present, must come first. Others may be in any
// order but should be in the same order for the same set but possibly different order of
@@ -1313,7 +1376,7 @@
}
}
- fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>], krate: CrateId) -> ImplTrait {
+ fn lower_impl_trait(&self, bounds: &[TypeBound], krate: CrateId) -> ImplTrait {
cov_mark::hit!(lower_rpit);
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
@@ -1365,6 +1428,17 @@
None => error_lifetime(),
}
}
+
+ // FIXME: This does not handle macros!
+ fn count_impl_traits(&self, type_ref: TypeRefId) -> usize {
+ let mut count = 0;
+ TypeRef::walk(type_ref, self.types_map, &mut |type_ref| {
+ if matches!(type_ref, TypeRef::ImplTrait(_)) {
+ count += 1;
+ }
+ });
+ count
+ }
}
/// Build the signature of a callable item (function, struct or enum variant).
@@ -1385,17 +1459,6 @@
named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id))
}
-// FIXME: This does not handle macros!
-fn count_impl_traits(type_ref: &TypeRef) -> usize {
- let mut count = 0;
- type_ref.walk(&mut |type_ref| {
- if matches!(type_ref, TypeRef::ImplTrait(_)) {
- count += 1;
- }
- });
- count
-}
-
fn named_associated_type_shorthand_candidates<R>(
db: &dyn HirDatabase,
// If the type parameter is defined in an impl and we're in a method, there
@@ -1499,10 +1562,10 @@
};
let generics = generics(db.upcast(), def);
let mut res = ArenaMap::default();
- let ctx = TyLoweringContext::new(db, &resolver, def.into())
+ let ctx = TyLoweringContext::new(db, &resolver, var_data.types_map(), def.into())
.with_type_param_mode(ParamLoweringMode::Variable);
for (field_id, field_data) in var_data.fields().iter() {
- res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)));
+ res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref)));
}
Arc::new(res)
}
@@ -1522,38 +1585,38 @@
assoc_name: Option<Name>,
) -> GenericPredicates {
let resolver = def.resolver(db.upcast());
- let ctx = if let GenericDefId::FunctionId(_) = def {
- TyLoweringContext::new(db, &resolver, def.into())
+ let mut ctx = if let GenericDefId::FunctionId(_) = def {
+ TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Variable)
.with_type_param_mode(ParamLoweringMode::Variable)
} else {
- TyLoweringContext::new(db, &resolver, def.into())
+ TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_type_param_mode(ParamLoweringMode::Variable)
};
let generics = generics(db.upcast(), def);
// we have to filter out all other predicates *first*, before attempting to lower them
- let predicate = |(pred, &def): &(&_, _)| match pred {
+ let predicate = |pred: &_, def: &_, ctx: &TyLoweringContext<'_>| match pred {
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound, .. } => {
let invalid_target = match target {
WherePredicateTypeTarget::TypeRef(type_ref) => {
- ctx.lower_ty_only_param(type_ref) != Some(param_id)
+ ctx.lower_ty_only_param(*type_ref) != Some(param_id)
}
&WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
- let target_id = TypeOrConstParamId { parent: def, local_id };
+ let target_id = TypeOrConstParamId { parent: *def, local_id };
target_id != param_id
}
};
if invalid_target {
// If this is filtered out without lowering, `?Sized` is not gathered into `ctx.unsized_types`
- if let TypeBound::Path(_, TraitBoundModifier::Maybe) = &**bound {
- ctx.lower_where_predicate(pred, &def, true).for_each(drop);
+ if let TypeBound::Path(_, TraitBoundModifier::Maybe) = bound {
+ ctx.lower_where_predicate(pred, def, true).for_each(drop);
}
return false;
}
- match &**bound {
+ match bound {
TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => {
// Only lower the bound if the trait could possibly define the associated
// type we're looking for.
@@ -1571,18 +1634,20 @@
})
})
}
- TypeBound::Lifetime(_) | TypeBound::Error => false,
+ TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
}
}
WherePredicate::Lifetime { .. } => false,
};
- let mut predicates: Vec<_> = resolver
- .where_predicates_in_scope()
- .filter(predicate)
- .flat_map(|(pred, def)| {
- ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
- })
- .collect();
+ let mut predicates = Vec::new();
+ for (params, def) in resolver.all_generic_params() {
+ ctx.types_map = ¶ms.types_map;
+ predicates.extend(
+ params.where_predicates().filter(|pred| predicate(pred, def, &ctx)).flat_map(|pred| {
+ ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
+ }),
+ );
+ }
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
if !subst.is_empty(Interner) {
@@ -1629,23 +1694,27 @@
def: GenericDefId,
) -> Arc<TraitEnvironment> {
let resolver = def.resolver(db.upcast());
- let ctx = if let GenericDefId::FunctionId(_) = def {
- TyLoweringContext::new(db, &resolver, def.into())
+ let mut ctx = if let GenericDefId::FunctionId(_) = def {
+ TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Param)
.with_type_param_mode(ParamLoweringMode::Placeholder)
} else {
- TyLoweringContext::new(db, &resolver, def.into())
+ TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_type_param_mode(ParamLoweringMode::Placeholder)
};
let mut traits_in_scope = Vec::new();
let mut clauses = Vec::new();
- for (pred, def) in resolver.where_predicates_in_scope() {
- for pred in ctx.lower_where_predicate(pred, def, false) {
- if let WhereClause::Implemented(tr) = &pred.skip_binders() {
- traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
+ for (params, def) in resolver.all_generic_params() {
+ ctx.types_map = ¶ms.types_map;
+ for pred in params.where_predicates() {
+ for pred in ctx.lower_where_predicate(pred, def, false) {
+ if let WhereClause::Implemented(tr) = pred.skip_binders() {
+ traits_in_scope
+ .push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
+ }
+ let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
+ clauses.push(program_clause.into_from_env_clause(Interner));
}
- let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
- clauses.push(program_clause.into_from_env_clause(Interner));
}
}
@@ -1724,18 +1793,20 @@
}
_ => (ImplTraitLoweringMode::Disallowed, ParamLoweringMode::Variable),
};
- let ctx = TyLoweringContext::new(db, &resolver, def.into())
+ let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_impl_trait_mode(impl_trait_lowering)
.with_type_param_mode(param_lowering);
let generics = generics(db.upcast(), def);
- let mut predicates = resolver
- .where_predicates_in_scope()
- .filter(|(pred, def)| filter(pred, def))
- .flat_map(|(pred, def)| {
- ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
- })
- .collect::<Vec<_>>();
+ let mut predicates = Vec::new();
+ for (params, def) in resolver.all_generic_params() {
+ ctx.types_map = ¶ms.types_map;
+ predicates.extend(params.where_predicates().filter(|pred| filter(pred, def)).flat_map(
+ |pred| {
+ ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
+ },
+ ));
+ }
if generics.len() > 0 {
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
@@ -1811,18 +1882,19 @@
let resolver = def.resolver(db.upcast());
let parent_start_idx = generic_params.len_self();
- let ctx = TyLoweringContext::new(db, &resolver, def.into())
+ let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
.with_type_param_mode(ParamLoweringMode::Variable);
- GenericDefaults(Some(Arc::from_iter(generic_params.iter().enumerate().map(
- |(idx, (id, p))| {
+ GenericDefaults(Some(Arc::from_iter(generic_params.iter_with_types_map().enumerate().map(
+ |(idx, ((id, p), types_map))| {
+ ctx.types_map = types_map;
match p {
GenericParamDataRef::TypeParamData(p) => {
let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| {
// Each default can only refer to previous parameters.
// Type variable default referring to parameter coming
// after it is forbidden (FIXME: report diagnostic)
- fallback_bound_vars(ctx.lower_ty(ty), idx, parent_start_idx)
+ fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx)
});
crate::make_binders(db, &generic_params, ty.cast(Interner))
}
@@ -1834,7 +1906,7 @@
let mut val = p.default.as_ref().map_or_else(
|| unknown_const_as_generic(db.const_param_ty(id)),
|c| {
- let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
+ let c = ctx.lower_const(c, ctx.lower_ty(p.ty));
c.cast(Interner)
},
);
@@ -1874,14 +1946,14 @@
fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
let data = db.function_data(def);
let resolver = def.resolver(db.upcast());
- let ctx_params = TyLoweringContext::new(db, &resolver, def.into())
+ let ctx_params = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Variable)
.with_type_param_mode(ParamLoweringMode::Variable);
- let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr));
- let ctx_ret = TyLoweringContext::new(db, &resolver, def.into())
+ let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
+ let ctx_ret = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable);
- let ret = ctx_ret.lower_ty(&data.ret_type);
+ let ret = ctx_ret.lower_ty(data.ret_type);
let generics = generics(db.upcast(), def.into());
let sig = CallableSig::from_params_and_return(
params,
@@ -1910,28 +1982,33 @@
let data = db.const_data(def);
let generics = generics(db.upcast(), def.into());
let resolver = def.resolver(db.upcast());
- let ctx = TyLoweringContext::new(db, &resolver, def.into())
+ let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_type_param_mode(ParamLoweringMode::Variable);
- make_binders(db, &generics, ctx.lower_ty(&data.type_ref))
+ make_binders(db, &generics, ctx.lower_ty(data.type_ref))
}
/// Build the declared type of a static.
fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
let data = db.static_data(def);
let resolver = def.resolver(db.upcast());
- let ctx = TyLoweringContext::new(db, &resolver, def.into());
+ let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into());
- Binders::empty(Interner, ctx.lower_ty(&data.type_ref))
+ Binders::empty(Interner, ctx.lower_ty(data.type_ref))
}
fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
let struct_data = db.struct_data(def);
let fields = struct_data.variant_data.fields();
let resolver = def.resolver(db.upcast());
- let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into())
- .with_type_param_mode(ParamLoweringMode::Variable);
- let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref));
+ let ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ struct_data.variant_data.types_map(),
+ AdtId::from(def).into(),
+ )
+ .with_type_param_mode(ParamLoweringMode::Variable);
+ let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref));
let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
Binders::new(
binders,
@@ -1961,9 +2038,14 @@
let var_data = db.enum_variant_data(def);
let fields = var_data.variant_data.fields();
let resolver = def.resolver(db.upcast());
- let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into())
- .with_type_param_mode(ParamLoweringMode::Variable);
- let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref));
+ let ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ var_data.variant_data.types_map(),
+ DefWithBodyId::VariantId(def).into(),
+ )
+ .with_type_param_mode(ParamLoweringMode::Variable);
+ let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref));
let (ret, binders) =
type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders();
Binders::new(
@@ -2004,15 +2086,17 @@
fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
let generics = generics(db.upcast(), t.into());
let resolver = t.resolver(db.upcast());
- let ctx = TyLoweringContext::new(db, &resolver, t.into())
+ let type_alias_data = db.type_alias_data(t);
+ let ctx = TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, t.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable);
- let type_alias_data = db.type_alias_data(t);
let inner = if type_alias_data.is_extern {
TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)
} else {
- let type_ref = &type_alias_data.type_ref;
- ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error))
+ type_alias_data
+ .type_ref
+ .map(|type_ref| ctx.lower_ty(type_ref))
+ .unwrap_or_else(|| TyKind::Error.intern(Interner))
};
make_binders(db, &generics, inner)
}
@@ -2085,9 +2169,9 @@
let impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast());
let generics = generics(db.upcast(), impl_id.into());
- let ctx = TyLoweringContext::new(db, &resolver, impl_id.into())
+ let ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
.with_type_param_mode(ParamLoweringMode::Variable);
- make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty))
+ make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty))
}
// returns None if def is a type arg
@@ -2095,13 +2179,13 @@
let parent_data = db.generic_params(def.parent());
let data = &parent_data[def.local_id()];
let resolver = def.parent().resolver(db.upcast());
- let ctx = TyLoweringContext::new(db, &resolver, def.parent().into());
+ let ctx = TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into());
match data {
TypeOrConstParamData::TypeParamData(_) => {
never!();
Ty::new(Interner, TyKind::Error)
}
- TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(&d.ty),
+ TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
}
}
@@ -2117,7 +2201,7 @@
pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
let impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast());
- let ctx = TyLoweringContext::new(db, &resolver, impl_id.into())
+ let ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
.with_type_param_mode(ParamLoweringMode::Variable);
let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
let target_trait = impl_data.target_trait.as_ref()?;
@@ -2131,10 +2215,10 @@
// FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
let data = db.function_data(def);
let resolver = def.resolver(db.upcast());
- let ctx_ret = TyLoweringContext::new(db, &resolver, def.into())
+ let ctx_ret = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable);
- let _ret = ctx_ret.lower_ty(&data.ret_type);
+ let _ret = ctx_ret.lower_ty(data.ret_type);
let generics = generics(db.upcast(), def.into());
let return_type_impl_traits = ImplTraits {
impl_traits: match ctx_ret.impl_trait_mode {
@@ -2155,10 +2239,10 @@
) -> Option<Arc<Binders<ImplTraits>>> {
let data = db.type_alias_data(def);
let resolver = def.resolver(db.upcast());
- let ctx = TyLoweringContext::new(db, &resolver, def.into())
+ let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable);
- if let Some(type_ref) = &data.type_ref {
+ if let Some(type_ref) = data.type_ref {
let _ty = ctx.lower_ty(type_ref);
}
let type_alias_impl_traits = ImplTraits {
@@ -2190,7 +2274,8 @@
kind_id: GenericParamId,
arg: &'a GenericArg,
this: &mut T,
- for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
+ types_map: &TypesMap,
+ for_type: impl FnOnce(&mut T, TypeRefId) -> Ty + 'a,
for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a,
for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a,
) -> crate::GenericArg {
@@ -2203,7 +2288,7 @@
GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
};
match (arg, kind) {
- (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner),
+ (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, *type_ref).cast(Interner),
(GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner),
(GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => {
for_lifetime(this, lifetime_ref).cast(Interner)
@@ -2214,7 +2299,7 @@
// We want to recover simple idents, which parser detects them
// as types. Maybe here is not the best place to do it, but
// it works.
- if let TypeRef::Path(p) = t {
+ if let TypeRef::Path(p) = &types_map[*t] {
if let Some(p) = p.mod_path() {
if p.kind == PathKind::Plain {
if let [n] = p.segments() {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
index 8e815aa..59c583a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -879,7 +879,8 @@
///
/// **Needs clarification**: Are there weird additional semantics here related to the runtime
/// nature of this operation?
- //ThreadLocalRef(DefId),
+ // ThreadLocalRef(DefId),
+ ThreadLocalRef(std::convert::Infallible),
/// Creates a pointer with the indicated mutability to the place.
///
@@ -888,7 +889,8 @@
///
/// Like with references, the semantics of this operation are heavily dependent on the aliasing
/// model.
- //AddressOf(Mutability, Place),
+ // AddressOf(Mutability, Place),
+ AddressOf(std::convert::Infallible),
/// Yields the length of the place, as a `usize`.
///
@@ -906,19 +908,21 @@
Cast(CastKind, Operand, Ty),
// FIXME link to `pointer::offset` when it hits stable.
- // /// * `Offset` has the same semantics as `pointer::offset`, except that the second
- // /// parameter may be a `usize` as well.
- // /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
- // /// raw pointers, or function pointers and return a `bool`. The types of the operands must be
- // /// matching, up to the usual caveat of the lifetimes in function pointers.
- // /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
- // /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is
- // /// truncated as needed.
- // /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
- // /// types and return a value of that type.
- // /// * The remaining operations accept signed integers, unsigned integers, or floats with
- // /// matching types and return a value of that type.
+ /// * `Offset` has the same semantics as `pointer::offset`, except that the second
+ /// parameter may be a `usize` as well.
+ /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
+ /// raw pointers, or function pointers and return a `bool`. The types of the operands must be
+ /// matching, up to the usual caveat of the lifetimes in function pointers.
+ /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
+ /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is
+ /// truncated as needed.
+ /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
+ /// types and return a value of that type.
+ /// * The remaining operations accept signed integers, unsigned integers, or floats with
+ /// matching types and return a value of that type.
//BinaryOp(BinOp, Box<(Operand, Operand)>),
+ BinaryOp(std::convert::Infallible),
+
/// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
///
/// When overflow checking is disabled and we are generating run-time code, the error condition
@@ -937,6 +941,7 @@
/// Computes a value as described by the operation.
//NullaryOp(NullOp, Ty),
+ NullaryOp(std::convert::Infallible),
/// Exactly like `BinaryOp`, but less operands.
///
@@ -1095,6 +1100,10 @@
for_operand(op, &mut f, &mut self.projection_store);
}
}
+ Rvalue::ThreadLocalRef(n)
+ | Rvalue::AddressOf(n)
+ | Rvalue::BinaryOp(n)
+ | Rvalue::NullaryOp(n) => match *n {},
}
}
StatementKind::FakeRead(p) | StatementKind::Deinit(p) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
index 9830fa1..9c86d3b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
@@ -167,6 +167,10 @@
for_operand(op, statement.span);
}
}
+ Rvalue::ThreadLocalRef(n)
+ | Rvalue::AddressOf(n)
+ | Rvalue::BinaryOp(n)
+ | Rvalue::NullaryOp(n) => match *n {},
},
StatementKind::FakeRead(_)
| StatementKind::Deinit(_)
@@ -253,6 +257,10 @@
for_operand(op, statement.span);
}
}
+ Rvalue::ThreadLocalRef(n)
+ | Rvalue::AddressOf(n)
+ | Rvalue::BinaryOp(n)
+ | Rvalue::NullaryOp(n) => match *n {},
},
StatementKind::FakeRead(_)
| StatementKind::Deinit(_)
@@ -548,6 +556,10 @@
}
}
Rvalue::ShallowInitBox(_, _) | Rvalue::ShallowInitBoxWithAlloc(_) => (),
+ Rvalue::ThreadLocalRef(n)
+ | Rvalue::AddressOf(n)
+ | Rvalue::BinaryOp(n)
+ | Rvalue::NullaryOp(n) => match *n {},
}
if let Rvalue::Ref(
BorrowKind::Mut {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index 0d42617..e73b9dc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -6,6 +6,7 @@
use chalk_ir::{cast::Cast, Mutability};
use either::Either;
use hir_def::{
+ body::HygieneId,
builtin_type::BuiltinType,
data::adt::{StructFlags, VariantData},
lang_item::LangItem,
@@ -1628,6 +1629,10 @@
}
CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"),
},
+ Rvalue::ThreadLocalRef(n)
+ | Rvalue::AddressOf(n)
+ | Rvalue::BinaryOp(n)
+ | Rvalue::NullaryOp(n) => match *n {},
})
}
@@ -2703,17 +2708,15 @@
TyKind::Function(_) => {
self.exec_fn_pointer(func_data, destination, &args[1..], locals, target_bb, span)
}
- TyKind::Closure(closure, subst) => {
- return self.exec_closure(
- *closure,
- func_data,
- &Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()),
- destination,
- &args[1..],
- locals,
- span,
- );
- }
+ TyKind::Closure(closure, subst) => self.exec_closure(
+ *closure,
+ func_data,
+ &Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()),
+ destination,
+ &args[1..],
+ locals,
+ span,
+ ),
_ => {
// try to execute the manual impl of `FnTrait` for structs (nightly feature used in std)
let arg0 = func;
@@ -2846,7 +2849,8 @@
}
let layout = self.layout_adt(id.0, subst.clone())?;
match data.variant_data.as_ref() {
- VariantData::Record(fields) | VariantData::Tuple(fields) => {
+ VariantData::Record { fields, .. }
+ | VariantData::Tuple { fields, .. } => {
let field_types = self.db.field_types(s.into());
for (field, _) in fields.iter() {
let offset = layout
@@ -2951,6 +2955,7 @@
let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully(
db.upcast(),
&hir_def::path::Path::from_known_path_with_no_generic(path![std::fmt::format]),
+ HygieneId::ROOT,
) else {
not_supported!("std::fmt::format not found");
};
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 16994cd..c4e0640 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -5,7 +5,7 @@
use base_db::ra_salsa::Cycle;
use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind};
use hir_def::{
- body::Body,
+ body::{Body, HygieneId},
data::adt::{StructKind, VariantData},
hir::{
ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal,
@@ -13,7 +13,8 @@
},
lang_item::{LangItem, LangItemTarget},
path::Path,
- resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs},
+ resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
+ type_ref::TypesMap,
AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
Lookup, TraitId, TupleId, TypeOrConstParamId,
};
@@ -28,7 +29,7 @@
use crate::{
consteval::ConstEvalError,
db::{HirDatabase, InternedClosure},
- display::HirDisplay,
+ display::{hir_display_with_types_map, HirDisplay},
error_lifetime,
generics::generics,
infer::{cast::CastTy, unify::InferenceTable, CaptureKind, CapturedItem, TypeMismatch},
@@ -76,6 +77,7 @@
db: &'a dyn HirDatabase,
body: &'a Body,
infer: &'a InferenceResult,
+ resolver: Resolver,
drop_scopes: Vec<DropScope>,
}
@@ -246,8 +248,15 @@
}
impl MirLowerError {
- fn unresolved_path(db: &dyn HirDatabase, p: &Path, edition: Edition) -> Self {
- Self::UnresolvedName(p.display(db, edition).to_string())
+ fn unresolved_path(
+ db: &dyn HirDatabase,
+ p: &Path,
+ edition: Edition,
+ types_map: &TypesMap,
+ ) -> Self {
+ Self::UnresolvedName(
+ hir_display_with_types_map(p, types_map).display(db, edition).to_string(),
+ )
}
}
@@ -278,6 +287,7 @@
owner,
closures: vec![],
};
+ let resolver = owner.resolver(db.upcast());
MirLowerCtx {
result: mir,
@@ -285,6 +295,7 @@
infer,
body,
owner,
+ resolver,
current_loop_blocks: None,
labeled_loop_blocks: Default::default(),
discr_temp: None,
@@ -410,43 +421,54 @@
Err(MirLowerError::IncompleteExpr)
}
Expr::Path(p) => {
- let pr =
- if let Some((assoc, subst)) = self.infer.assoc_resolutions_for_expr(expr_id) {
- match assoc {
- hir_def::AssocItemId::ConstId(c) => {
- self.lower_const(
- c.into(),
- current,
- place,
- subst,
- expr_id.into(),
- self.expr_ty_without_adjust(expr_id),
- )?;
- return Ok(Some(current));
- }
- hir_def::AssocItemId::FunctionId(_) => {
- // FnDefs are zero sized, no action is needed.
- return Ok(Some(current));
- }
- hir_def::AssocItemId::TypeAliasId(_) => {
- // FIXME: If it is unreachable, use proper error instead of `not_supported`.
- not_supported!("associated functions and types")
- }
+ let pr = if let Some((assoc, subst)) =
+ self.infer.assoc_resolutions_for_expr(expr_id)
+ {
+ match assoc {
+ hir_def::AssocItemId::ConstId(c) => {
+ self.lower_const(
+ c.into(),
+ current,
+ place,
+ subst,
+ expr_id.into(),
+ self.expr_ty_without_adjust(expr_id),
+ )?;
+ return Ok(Some(current));
}
- } else if let Some(variant) = self.infer.variant_resolution_for_expr(expr_id) {
- match variant {
- VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e),
- VariantId::StructId(s) => ValueNs::StructId(s),
- VariantId::UnionId(_) => implementation_error!("Union variant as path"),
+ hir_def::AssocItemId::FunctionId(_) => {
+ // FnDefs are zero sized, no action is needed.
+ return Ok(Some(current));
}
- } else {
- let unresolved_name =
- || MirLowerError::unresolved_path(self.db, p, self.edition());
- let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id);
- resolver
- .resolve_path_in_value_ns_fully(self.db.upcast(), p)
- .ok_or_else(unresolved_name)?
- };
+ hir_def::AssocItemId::TypeAliasId(_) => {
+ // FIXME: If it is unreachable, use proper error instead of `not_supported`.
+ not_supported!("associated functions and types")
+ }
+ }
+ } else if let Some(variant) = self.infer.variant_resolution_for_expr(expr_id) {
+ match variant {
+ VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e),
+ VariantId::StructId(s) => ValueNs::StructId(s),
+ VariantId::UnionId(_) => implementation_error!("Union variant as path"),
+ }
+ } else {
+ let resolver_guard =
+ self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
+ let hygiene = self.body.expr_path_hygiene(expr_id);
+ let result = self
+ .resolver
+ .resolve_path_in_value_ns_fully(self.db.upcast(), p, hygiene)
+ .ok_or_else(|| {
+ MirLowerError::unresolved_path(
+ self.db,
+ p,
+ self.edition(),
+ &self.body.types,
+ )
+ })?;
+ self.resolver.reset_to_guard(resolver_guard);
+ result
+ };
match pr {
ValueNs::LocalBinding(_) | ValueNs::StaticId(_) => {
let Some((temp, current)) =
@@ -553,8 +575,11 @@
return Ok(None);
};
self.push_fake_read(current, cond_place, expr_id.into());
+ let resolver_guard =
+ self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
let (then_target, else_target) =
self.pattern_match(current, None, cond_place, *pat)?;
+ self.resolver.reset_to_guard(resolver_guard);
self.write_bytes_to_place(
then_target,
place,
@@ -688,6 +713,8 @@
};
self.push_fake_read(current, cond_place, expr_id.into());
let mut end = None;
+ let resolver_guard =
+ self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
for MatchArm { pat, guard, expr } in arms.iter() {
let (then, mut otherwise) =
self.pattern_match(current, None, cond_place, *pat)?;
@@ -721,6 +748,7 @@
}
}
}
+ self.resolver.reset_to_guard(resolver_guard);
if self.is_unterminated(current) {
self.set_terminator(current, TerminatorKind::Unreachable, expr_id.into());
}
@@ -795,7 +823,7 @@
}
Expr::Become { .. } => not_supported!("tail-calls"),
Expr::Yield { .. } => not_supported!("yield"),
- Expr::RecordLit { fields, path, spread, ellipsis: _, is_assignee_expr: _ } => {
+ Expr::RecordLit { fields, path, spread } => {
let spread_place = match spread {
&Some(it) => {
let Some((p, c)) = self.lower_expr_as_place(current, it, true)? else {
@@ -809,7 +837,9 @@
let variant_id =
self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path {
Some(p) => MirLowerError::UnresolvedName(
- p.display(self.db, self.edition()).to_string(),
+ hir_display_with_types_map(&**p, &self.body.types)
+ .display(self.db, self.edition())
+ .to_string(),
),
None => MirLowerError::RecordLiteralWithoutPath,
})?;
@@ -1010,35 +1040,28 @@
);
}
}
- if let hir_def::hir::BinaryOp::Assignment { op } = op {
- if let Some(op) = op {
- // last adjustment is `&mut` which we don't want it.
- let adjusts = self
- .infer
- .expr_adjustments
- .get(lhs)
- .and_then(|it| it.split_last())
- .map(|it| it.1)
- .ok_or(MirLowerError::TypeError(
- "adjustment of binary op was missing",
- ))?;
- let Some((lhs_place, current)) =
- self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)?
- else {
- return Ok(None);
- };
- let Some((rhs_op, current)) =
- self.lower_expr_to_some_operand(*rhs, current)?
- else {
- return Ok(None);
- };
- let r_value =
- Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place), rhs_op);
- self.push_assignment(current, lhs_place, r_value, expr_id.into());
- return Ok(Some(current));
- } else {
- return self.lower_assignment(current, *lhs, *rhs, expr_id.into());
- }
+ if let hir_def::hir::BinaryOp::Assignment { op: Some(op) } = op {
+ // last adjustment is `&mut` which we don't want it.
+ let adjusts = self
+ .infer
+ .expr_adjustments
+ .get(lhs)
+ .and_then(|it| it.split_last())
+ .map(|it| it.1)
+ .ok_or(MirLowerError::TypeError("adjustment of binary op was missing"))?;
+ let Some((lhs_place, current)) =
+ self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)?
+ else {
+ return Ok(None);
+ };
+ let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)?
+ else {
+ return Ok(None);
+ };
+ let r_value =
+ Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place), rhs_op);
+ self.push_assignment(current, lhs_place, r_value, expr_id.into());
+ return Ok(Some(current));
}
let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)?
else {
@@ -1097,6 +1120,18 @@
);
Ok(Some(current))
}
+ &Expr::Assignment { target, value } => {
+ let Some((value, mut current)) = self.lower_expr_as_place(current, value, true)?
+ else {
+ return Ok(None);
+ };
+ self.push_fake_read(current, value, expr_id.into());
+ let resolver_guard =
+ self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
+ current = self.pattern_match_assignment(current, value, target)?;
+ self.resolver.reset_to_guard(resolver_guard);
+ Ok(Some(current))
+ }
&Expr::Range { lhs, rhs, range_type: _ } => {
let ty = self.expr_ty_without_adjust(expr_id);
let Some((adt, subst)) = ty.as_adt() else {
@@ -1213,7 +1248,7 @@
);
Ok(Some(current))
}
- Expr::Tuple { exprs, is_assignee_expr: _ } => {
+ Expr::Tuple { exprs } => {
let Some(values) = exprs
.iter()
.map(|it| {
@@ -1291,73 +1326,6 @@
}
}
- fn lower_destructing_assignment(
- &mut self,
- mut current: BasicBlockId,
- lhs: ExprId,
- rhs: Place,
- span: MirSpan,
- ) -> Result<Option<BasicBlockId>> {
- match &self.body.exprs[lhs] {
- Expr::Tuple { exprs, is_assignee_expr: _ } => {
- for (i, expr) in exprs.iter().enumerate() {
- let rhs = rhs.project(
- ProjectionElem::Field(Either::Right(TupleFieldId {
- tuple: TupleId(!0), // Dummy this as its unused
- index: i as u32,
- })),
- &mut self.result.projection_store,
- );
- let Some(c) = self.lower_destructing_assignment(current, *expr, rhs, span)?
- else {
- return Ok(None);
- };
- current = c;
- }
- Ok(Some(current))
- }
- Expr::Underscore => Ok(Some(current)),
- _ => {
- let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)?
- else {
- return Ok(None);
- };
- self.push_assignment(current, lhs_place, Operand::Copy(rhs).into(), span);
- Ok(Some(current))
- }
- }
- }
-
- fn lower_assignment(
- &mut self,
- current: BasicBlockId,
- lhs: ExprId,
- rhs: ExprId,
- span: MirSpan,
- ) -> Result<Option<BasicBlockId>> {
- let Some((rhs_op, current)) = self.lower_expr_to_some_operand(rhs, current)? else {
- return Ok(None);
- };
- if matches!(&self.body.exprs[lhs], Expr::Underscore) {
- self.push_fake_read_for_operand(current, rhs_op, span);
- return Ok(Some(current));
- }
- if matches!(
- &self.body.exprs[lhs],
- Expr::Tuple { .. } | Expr::RecordLit { .. } | Expr::Call { .. }
- ) {
- let temp = self.temp(self.expr_ty_after_adjustments(rhs), current, rhs.into())?;
- let temp = Place::from(temp);
- self.push_assignment(current, temp, rhs_op.into(), span);
- return self.lower_destructing_assignment(current, lhs, temp, span);
- }
- let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)? else {
- return Ok(None);
- };
- self.push_assignment(current, lhs_place, rhs_op.into(), span);
- Ok(Some(current))
- }
-
fn placeholder_subst(&mut self) -> Substitution {
match self.owner.as_generic_def_id(self.db.upcast()) {
Some(it) => TyBuilder::placeholder_subst(self.db, it),
@@ -1406,10 +1374,10 @@
};
let edition = self.edition();
let unresolved_name =
- || MirLowerError::unresolved_path(self.db, c.as_ref(), edition);
- let resolver = self.owner.resolver(self.db.upcast());
- let pr = resolver
- .resolve_path_in_value_ns(self.db.upcast(), c.as_ref())
+ || MirLowerError::unresolved_path(self.db, c, edition, &self.body.types);
+ let pr = self
+ .resolver
+ .resolve_path_in_value_ns(self.db.upcast(), c, HygieneId::ROOT)
.ok_or_else(unresolved_name)?;
match pr {
ResolveValueResult::ValueNs(v, _) => {
@@ -1632,12 +1600,6 @@
self.push_statement(block, StatementKind::FakeRead(p).with_span(span));
}
- fn push_fake_read_for_operand(&mut self, block: BasicBlockId, operand: Operand, span: MirSpan) {
- if let Operand::Move(p) | Operand::Copy(p) = operand {
- self.push_fake_read(block, p, span);
- }
- }
-
fn push_assignment(
&mut self,
block: BasicBlockId,
@@ -1791,8 +1753,16 @@
};
current = c;
self.push_fake_read(current, init_place, span);
+ // Using the initializer for the resolver scope is good enough for us, as it cannot create new declarations
+ // and has all declarations of the `let`.
+ let resolver_guard = self.resolver.update_to_inner_scope(
+ self.db.upcast(),
+ self.owner,
+ *expr_id,
+ );
(current, else_block) =
self.pattern_match(current, None, init_place, *pat)?;
+ self.resolver.reset_to_guard(resolver_guard);
match (else_block, else_branch) {
(None, _) => (),
(Some(else_block), None) => {
@@ -1828,7 +1798,7 @@
self.push_fake_read(c, p, expr.into());
current = scope2.pop_and_drop(self, c, expr.into());
}
- hir_def::hir::Statement::Item => (),
+ hir_def::hir::Statement::Item(_) => (),
}
}
if let Some(tail) = tail {
@@ -2066,11 +2036,13 @@
let Some(sig) = ClosureSubst(substs).sig_ty().callable_sig(db) else {
implementation_error!("closure has not callable sig");
};
+ let resolver_guard = ctx.resolver.update_to_inner_scope(db.upcast(), owner, expr);
let current = ctx.lower_params_and_bindings(
args.iter().zip(sig.params().iter()).map(|(it, y)| (*it, y.clone())),
None,
|_| true,
)?;
+ ctx.resolver.reset_to_guard(resolver_guard);
if let Some(current) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? {
let current = ctx.pop_drop_scope_assert_finished(current, root.into())?;
ctx.set_terminator(current, TerminatorKind::Return, (*root).into());
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
index 424ee11..420f2aa 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
@@ -135,8 +135,13 @@
};
match &self.body.exprs[expr_id] {
Expr::Path(p) => {
- let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id);
- let Some(pr) = resolver.resolve_path_in_value_ns_fully(self.db.upcast(), p) else {
+ let resolver_guard =
+ self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
+ let hygiene = self.body.expr_path_hygiene(expr_id);
+ let resolved =
+ self.resolver.resolve_path_in_value_ns_fully(self.db.upcast(), p, hygiene);
+ self.resolver.reset_to_guard(resolver_guard);
+ let Some(pr) = resolved else {
return try_rvalue(self);
};
match pr {
@@ -216,7 +221,7 @@
self.push_field_projection(&mut r, expr_id)?;
Ok(Some((r, current)))
}
- Expr::Index { base, index, is_assignee_expr: _ } => {
+ Expr::Index { base, index } => {
let base_ty = self.expr_ty_after_adjustments(*base);
let index_ty = self.expr_ty_after_adjustments(*index);
if index_ty != TyBuilder::usize()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
index b1c0d1f..2ffea34 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -1,6 +1,6 @@
//! MIR lowering for patterns
-use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId};
+use hir_def::{hir::LiteralOrConst, AssocItemId};
use crate::{
mir::{
@@ -46,6 +46,8 @@
Check,
/// Assume that this pattern matches, fill bindings
Bind,
+ /// Assume that this pattern matches, assign to existing variables.
+ Assign,
}
impl MirLowerCtx<'_> {
@@ -82,6 +84,17 @@
Ok((current, current_else))
}
+ pub(super) fn pattern_match_assignment(
+ &mut self,
+ current: BasicBlockId,
+ value: Place,
+ pattern: PatId,
+ ) -> Result<BasicBlockId> {
+ let (current, _) =
+ self.pattern_match_inner(current, None, value, pattern, MatchingMode::Assign)?;
+ Ok(current)
+ }
+
pub(super) fn match_self_param(
&mut self,
id: BindingId,
@@ -155,14 +168,8 @@
*pat,
MatchingMode::Check,
)?;
- if mode == MatchingMode::Bind {
- (next, _) = self.pattern_match_inner(
- next,
- None,
- cond_place,
- *pat,
- MatchingMode::Bind,
- )?;
+ if mode != MatchingMode::Check {
+ (next, _) = self.pattern_match_inner(next, None, cond_place, *pat, mode)?;
}
self.set_goto(next, then_target, pattern.into());
match next_else {
@@ -176,11 +183,11 @@
}
}
if !finished {
- if mode == MatchingMode::Bind {
- self.set_terminator(current, TerminatorKind::Unreachable, pattern.into());
- } else {
+ if mode == MatchingMode::Check {
let ce = *current_else.get_or_insert_with(|| self.new_basic_block());
self.set_goto(current, ce, pattern.into());
+ } else {
+ self.set_terminator(current, TerminatorKind::Unreachable, pattern.into());
}
}
(then_target, current_else)
@@ -300,7 +307,7 @@
self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
}
if let &Some(slice) = slice {
- if mode == MatchingMode::Bind {
+ if mode != MatchingMode::Check {
if let Pat::Bind { id, subpat: _ } = self.body[slice] {
let next_place = cond_place.project(
ProjectionElem::Subslice {
@@ -342,17 +349,36 @@
mode,
)?,
None => {
- // The path is not a variant, so it is a const
+ let unresolved_name = || {
+ MirLowerError::unresolved_path(self.db, p, self.edition(), &self.body.types)
+ };
+ let hygiene = self.body.pat_path_hygiene(pattern);
+ let pr = self
+ .resolver
+ .resolve_path_in_value_ns(self.db.upcast(), p, hygiene)
+ .ok_or_else(unresolved_name)?;
+
+ if let (
+ MatchingMode::Assign,
+ ResolveValueResult::ValueNs(ValueNs::LocalBinding(binding), _),
+ ) = (mode, &pr)
+ {
+ let local = self.binding_local(*binding)?;
+ self.push_match_assignment(
+ current,
+ local,
+ BindingMode::Move,
+ cond_place,
+ pattern.into(),
+ );
+ return Ok((current, current_else));
+ }
+
+ // The path is not a variant or a local, so it is a const
if mode != MatchingMode::Check {
// A const don't bind anything. Only needs check.
return Ok((current, current_else));
}
- let unresolved_name =
- || MirLowerError::unresolved_path(self.db, p, self.edition());
- let resolver = self.owner.resolver(self.db.upcast());
- let pr = resolver
- .resolve_path_in_value_ns(self.db.upcast(), p)
- .ok_or_else(unresolved_name)?;
let (c, subst) = 'b: {
if let Some(x) = self.infer.assoc_resolutions_for_pat(pattern) {
if let AssocItemId::ConstId(c) = x.0 {
@@ -415,7 +441,7 @@
(current, current_else) =
self.pattern_match_inner(current, current_else, cond_place, *subpat, mode)?
}
- if mode == MatchingMode::Bind {
+ if mode != MatchingMode::Check {
let mode = self.infer.binding_modes[pattern];
self.pattern_match_binding(
*id,
@@ -448,6 +474,23 @@
cond_place.project(ProjectionElem::Deref, &mut self.result.projection_store);
self.pattern_match_inner(current, current_else, cond_place, *pat, mode)?
}
+ &Pat::Expr(expr) => {
+ stdx::always!(
+ mode == MatchingMode::Assign,
+ "Pat::Expr can only come in destructuring assignments"
+ );
+ let Some((lhs_place, current)) = self.lower_expr_as_place(current, expr, false)?
+ else {
+ return Ok((current, current_else));
+ };
+ self.push_assignment(
+ current,
+ lhs_place,
+ Operand::Copy(cond_place).into(),
+ expr.into(),
+ );
+ (current, current_else)
+ }
Pat::Box { .. } => not_supported!("box pattern"),
Pat::ConstBlock(_) => not_supported!("const block pattern"),
})
@@ -464,6 +507,18 @@
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let target_place = self.binding_local(id)?;
self.push_storage_live(id, current)?;
+ self.push_match_assignment(current, target_place, mode, cond_place, span);
+ Ok((current, current_else))
+ }
+
+ fn push_match_assignment(
+ &mut self,
+ current: BasicBlockId,
+ target_place: LocalId,
+ mode: BindingMode,
+ cond_place: Place,
+ span: MirSpan,
+ ) {
self.push_assignment(
current,
target_place.into(),
@@ -476,7 +531,6 @@
},
span,
);
- Ok((current, current_else))
}
fn pattern_match_const(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
index 4c6bc37..92132fa 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
@@ -258,6 +258,10 @@
| Rvalue::UnaryOp(_, _)
| Rvalue::Discriminant(_)
| Rvalue::CopyForDeref(_) => (),
+ Rvalue::ThreadLocalRef(n)
+ | Rvalue::AddressOf(n)
+ | Rvalue::BinaryOp(n)
+ | Rvalue::NullaryOp(n) => match *n {},
},
StatementKind::Deinit(_)
| StatementKind::FakeRead(_)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
index df56071..06765a1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
@@ -459,6 +459,10 @@
self.place(p);
w!(self, ")");
}
+ Rvalue::ThreadLocalRef(n)
+ | Rvalue::AddressOf(n)
+ | Rvalue::BinaryOp(n)
+ | Rvalue::NullaryOp(n) => match *n {},
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index a8170b6..5f0f341 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -3418,11 +3418,11 @@
fn main() {
let x;
[x,] = &[1,];
- //^^^^expected &'? [i32; 1], got [{unknown}; _]
+ //^^^^expected &'? [i32; 1], got [{unknown}]
let x;
[(x,),] = &[(1,),];
- //^^^^^^^expected &'? [(i32,); 1], got [{unknown}; _]
+ //^^^^^^^expected &'? [(i32,); 1], got [{unknown}]
let x;
((x,),) = &((1,),);
@@ -3720,3 +3720,85 @@
"#]],
);
}
+
+#[test]
+fn macro_semitransparent_hygiene() {
+ check_types(
+ r#"
+macro_rules! m {
+ () => { let bar: i32; };
+}
+fn foo() {
+ let bar: bool;
+ m!();
+ bar;
+ // ^^^ bool
+}
+ "#,
+ );
+}
+
+#[test]
+fn macro_expansion_can_refer_variables_defined_before_macro_definition() {
+ check_types(
+ r#"
+fn foo() {
+ let v: i32 = 0;
+ macro_rules! m {
+ () => { v };
+ }
+ let v: bool = true;
+ m!();
+ // ^^^^ i32
+}
+ "#,
+ );
+}
+
+#[test]
+fn macro_rules_shadowing_works_with_hygiene() {
+ check_types(
+ r#"
+fn foo() {
+ let v: bool;
+ macro_rules! m { () => { v } }
+ m!();
+ // ^^^^ bool
+
+ let v: char;
+ macro_rules! m { () => { v } }
+ m!();
+ // ^^^^ char
+
+ {
+ let v: u8;
+ macro_rules! m { () => { v } }
+ m!();
+ // ^^^^ u8
+
+ let v: i8;
+ macro_rules! m { () => { v } }
+ m!();
+ // ^^^^ i8
+
+ let v: i16;
+ macro_rules! m { () => { v } }
+ m!();
+ // ^^^^ i16
+
+ {
+ let v: u32;
+ macro_rules! m { () => { v } }
+ m!();
+ // ^^^^ u32
+
+ let v: u64;
+ macro_rules! m { () => { v } }
+ m!();
+ // ^^^^ u64
+ }
+ }
+}
+ "#,
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index 620bba2..0a436ff 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -123,7 +123,7 @@
seen: FxHashSet<WhereClause>,
}
-impl<'a> ClauseElaborator<'a> {
+impl ClauseElaborator<'_> {
fn extend_deduped(&mut self, clauses: impl IntoIterator<Item = WhereClause>) {
self.stack.extend(clauses.into_iter().filter(|c| self.seen.insert(c.clone())))
}
@@ -163,10 +163,12 @@
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound } => {
let is_trait = match target {
- WherePredicateTypeTarget::TypeRef(type_ref) => match &**type_ref {
- TypeRef::Path(p) => p.is_self_type(),
- _ => false,
- },
+ WherePredicateTypeTarget::TypeRef(type_ref) => {
+ match &generic_params.types_map[*type_ref] {
+ TypeRef::Path(p) => p.is_self_type(),
+ _ => false,
+ }
+ }
WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
Some(*local_id) == trait_self
}
diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs
index cb5f5b0..22760c4 100644
--- a/src/tools/rust-analyzer/crates/hir/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/db.rs
@@ -4,35 +4,43 @@
//!
//! But we need this for at least LRU caching at the query level.
pub use hir_def::db::{
- AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BodyQuery, BodyWithSourceMapQuery,
- ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery, CrateLangItemsQuery,
- CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase, DefDatabaseStorage,
- EnumDataQuery, EnumVariantDataWithDiagnosticsQuery, ExprScopesQuery, ExternCrateDeclDataQuery,
- FieldVisibilitiesQuery, FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery,
- FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, ImplDataWithDiagnosticsQuery,
- ImportMapQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery, InternDatabase,
- InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery, InternExternCrateQuery,
- InternFunctionQuery, InternImplQuery, InternInTypeConstQuery, InternMacro2Query,
- InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery, InternStructQuery,
- InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery,
- InternUseQuery, LangItemQuery, Macro2DataQuery, MacroRulesDataQuery, ProcMacroDataQuery,
- StaticDataQuery, StructDataWithDiagnosticsQuery, TraitAliasDataQuery,
- TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataWithDiagnosticsQuery,
+ AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BlockItemTreeWithSourceMapQuery, BodyQuery,
+ BodyWithSourceMapQuery, ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery,
+ CrateLangItemsQuery, CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase,
+ DefDatabaseStorage, EnumDataQuery, EnumVariantDataWithDiagnosticsQuery,
+ ExpandProcAttrMacrosQuery, ExprScopesQuery, ExternCrateDeclDataQuery, FieldVisibilitiesQuery,
+ FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, FileItemTreeWithSourceMapQuery,
+ FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery,
+ GenericParamsWithSourceMapQuery, ImplDataWithDiagnosticsQuery, ImportMapQuery,
+ IncludeMacroInvocQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery,
+ InternDatabase, InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery,
+ InternExternCrateQuery, InternFunctionQuery, InternImplQuery, InternInTypeConstQuery,
+ InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery,
+ InternStructQuery, InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery,
+ InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery, MacroDefQuery,
+ MacroRulesDataQuery, NotableTraitsInDepsQuery, ProcMacroDataQuery, StaticDataQuery,
+ StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataWithDiagnosticsQuery,
+ TypeAliasDataQuery, UnionDataWithDiagnosticsQuery,
};
pub use hir_expand::db::{
AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage,
ExpandProcMacroQuery, InternMacroCallQuery, InternSyntaxContextQuery, MacroArgQuery,
- ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacrosQuery, RealSpanMapQuery,
+ ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacroSpanQuery, ProcMacrosQuery,
+ RealSpanMapQuery,
};
pub use hir_ty::db::{
AdtDatumQuery, AdtVarianceQuery, AssociatedTyDataQuery, AssociatedTyValueQuery, BorrowckQuery,
CallableItemSignatureQuery, ConstEvalDiscriminantQuery, ConstEvalQuery, ConstEvalStaticQuery,
- ConstParamTyQuery, FieldTypesQuery, FnDefDatumQuery, FnDefVarianceQuery, GenericDefaultsQuery,
- GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, HirDatabaseStorage,
- ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery,
+ ConstParamTyQuery, DynCompatibilityOfTraitQuery, FieldTypesQuery, FnDefDatumQuery,
+ FnDefVarianceQuery, GenericDefaultsQuery, GenericPredicatesForParamQuery,
+ GenericPredicatesQuery, GenericPredicatesWithoutParentQuery, HirDatabase, HirDatabaseStorage,
+ ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery, InferQuery,
InherentImplsInBlockQuery, InherentImplsInCrateQuery, InternCallableDefQuery,
InternClosureQuery, InternCoroutineQuery, InternImplTraitIdQuery, InternLifetimeParamIdQuery,
- InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, MirBodyQuery, ProgramClausesForChalkEnvQuery,
- ReturnTypeImplTraitsQuery, TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery,
- TraitImplsInBlockQuery, TraitImplsInCrateQuery, TraitImplsInDepsQuery, TyQuery, ValueTyQuery,
+ InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, LayoutOfTyQuery, LookupImplMethodQuery,
+ MirBodyForClosureQuery, MirBodyQuery, MonomorphizedMirBodyForClosureQuery,
+ MonomorphizedMirBodyQuery, ProgramClausesForChalkEnvQuery, ReturnTypeImplTraitsQuery,
+ TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery, TraitImplsInBlockQuery,
+ TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery,
+ TypeAliasImplTraitsQuery, ValueTyQuery,
};
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 0b3cdb2..8297acd 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -165,6 +165,7 @@
pub precise_location: Option<TextRange>,
pub message: String,
pub error: bool,
+ pub kind: &'static str,
}
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -246,7 +247,7 @@
#[derive(Debug)]
pub struct UnresolvedIdent {
- pub expr: InFile<AstPtr<ast::Expr>>,
+ pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
}
#[derive(Debug)]
@@ -257,7 +258,7 @@
#[derive(Debug)]
pub struct MissingUnsafe {
- pub expr: InFile<AstPtr<ast::Expr>>,
+ pub expr: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
/// If true, the diagnostics is an `unsafe_op_in_unsafe_fn` lint instead of a hard error.
pub only_lint: bool,
}
@@ -398,56 +399,46 @@
.map(|idx| variant_data.fields()[idx].name.clone())
.collect();
- match record {
- Either::Left(record_expr) => match source_map.expr_syntax(record_expr) {
- Ok(source_ptr) => {
- let root = source_ptr.file_syntax(db.upcast());
- if let ast::Expr::RecordExpr(record_expr) =
- source_ptr.value.to_node(&root)
- {
- if record_expr.record_expr_field_list().is_some() {
- let field_list_parent_path =
- record_expr.path().map(|path| AstPtr::new(&path));
- return Some(
- MissingFields {
- file: source_ptr.file_id,
- field_list_parent: AstPtr::new(&Either::Left(
- record_expr,
- )),
- field_list_parent_path,
- missed_fields,
- }
- .into(),
- );
+ let record = match record {
+ Either::Left(record_expr) => {
+ source_map.expr_syntax(record_expr).ok()?.map(AstPtr::wrap_left)
+ }
+ Either::Right(record_pat) => source_map.pat_syntax(record_pat).ok()?,
+ };
+ let file = record.file_id;
+ let root = record.file_syntax(db.upcast());
+ match record.value.to_node(&root) {
+ Either::Left(ast::Expr::RecordExpr(record_expr)) => {
+ if record_expr.record_expr_field_list().is_some() {
+ let field_list_parent_path =
+ record_expr.path().map(|path| AstPtr::new(&path));
+ return Some(
+ MissingFields {
+ file,
+ field_list_parent: AstPtr::new(&Either::Left(record_expr)),
+ field_list_parent_path,
+ missed_fields,
}
- }
+ .into(),
+ );
}
- Err(SyntheticSyntax) => (),
- },
- Either::Right(record_pat) => match source_map.pat_syntax(record_pat) {
- Ok(source_ptr) => {
- if let Some(ptr) = source_ptr.value.cast::<ast::RecordPat>() {
- let root = source_ptr.file_syntax(db.upcast());
- let record_pat = ptr.to_node(&root);
- if record_pat.record_pat_field_list().is_some() {
- let field_list_parent_path =
- record_pat.path().map(|path| AstPtr::new(&path));
- return Some(
- MissingFields {
- file: source_ptr.file_id,
- field_list_parent: AstPtr::new(&Either::Right(
- record_pat,
- )),
- field_list_parent_path,
- missed_fields,
- }
- .into(),
- );
+ }
+ Either::Right(ast::Pat::RecordPat(record_pat)) => {
+ if record_pat.record_pat_field_list().is_some() {
+ let field_list_parent_path =
+ record_pat.path().map(|path| AstPtr::new(&path));
+ return Some(
+ MissingFields {
+ file,
+ field_list_parent: AstPtr::new(&Either::Right(record_pat)),
+ field_list_parent_path,
+ missed_fields,
}
- }
+ .into(),
+ );
}
- Err(SyntheticSyntax) => (),
- },
+ }
+ _ => {}
}
}
BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => {
@@ -541,15 +532,17 @@
let pat_syntax = |pat| {
source_map.pat_syntax(pat).inspect_err(|_| tracing::error!("synthetic syntax")).ok()
};
+ let expr_or_pat_syntax = |id| match id {
+ ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(|it| it.map(AstPtr::wrap_left)),
+ ExprOrPatId::PatId(pat) => pat_syntax(pat),
+ };
Some(match d {
&InferenceDiagnostic::NoSuchField { field: expr, private, variant } => {
let expr_or_pat = match expr {
ExprOrPatId::ExprId(expr) => {
source_map.field_syntax(expr).map(AstPtr::wrap_left)
}
- ExprOrPatId::PatId(pat) => {
- source_map.pat_field_syntax(pat).map(AstPtr::wrap_right)
- }
+ ExprOrPatId::PatId(pat) => source_map.pat_field_syntax(pat),
};
NoSuchField { field: expr_or_pat, private, variant }.into()
}
@@ -562,10 +555,7 @@
PrivateField { expr, field }.into()
}
&InferenceDiagnostic::PrivateAssocItem { id, item } => {
- let expr_or_pat = match id {
- ExprOrPatId::ExprId(expr) => expr_syntax(expr)?.map(AstPtr::wrap_left),
- ExprOrPatId::PatId(pat) => pat_syntax(pat)?.map(AstPtr::wrap_right),
- };
+ let expr_or_pat = expr_or_pat_syntax(id)?;
let item = item.into();
PrivateAssocItem { expr_or_pat, item }.into()
}
@@ -609,15 +599,12 @@
.into()
}
&InferenceDiagnostic::UnresolvedAssocItem { id } => {
- let expr_or_pat = match id {
- ExprOrPatId::ExprId(expr) => expr_syntax(expr)?.map(AstPtr::wrap_left),
- ExprOrPatId::PatId(pat) => pat_syntax(pat)?.map(AstPtr::wrap_right),
- };
+ let expr_or_pat = expr_or_pat_syntax(id)?;
UnresolvedAssocItem { expr_or_pat }.into()
}
- &InferenceDiagnostic::UnresolvedIdent { expr } => {
- let expr = expr_syntax(expr)?;
- UnresolvedIdent { expr }.into()
+ &InferenceDiagnostic::UnresolvedIdent { id } => {
+ let expr_or_pat = expr_or_pat_syntax(id)?;
+ UnresolvedIdent { expr_or_pat }.into()
}
&InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => {
let expr = expr_syntax(expr)?;
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index c2b2fbe..9275f45 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -12,12 +12,11 @@
};
use hir_ty::{
display::{
- write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
- HirFormatter, SizedByDefault,
+ hir_display_with_types_map, write_bounds_like_dyn_trait_with_prefix, write_visibility,
+ HirDisplay, HirDisplayError, HirDisplayWithTypesMap, HirFormatter, SizedByDefault,
},
AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause,
};
-use intern::Interned;
use itertools::Itertools;
use crate::{
@@ -113,7 +112,7 @@
f.write_str(&pat_str)?;
f.write_str(": ")?;
- type_ref.hir_fmt(f)?;
+ type_ref.hir_fmt(f, &data.types_map)?;
}
if data.is_varargs() {
@@ -129,28 +128,30 @@
// Use ugly pattern match to strip the Future trait.
// Better way?
let ret_type = if !data.is_async() {
- &data.ret_type
+ Some(data.ret_type)
} else {
- match &*data.ret_type {
- TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() {
- TypeBound::Path(path, _) => {
- path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
+ match &data.types_map[data.ret_type] {
+ TypeRef::ImplTrait(bounds) => match &bounds[0] {
+ TypeBound::Path(path, _) => Some(
+ *path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
[0]
.type_ref
.as_ref()
- .unwrap()
- }
- _ => &TypeRef::Error,
+ .unwrap(),
+ ),
+ _ => None,
},
- _ => &TypeRef::Error,
+ _ => None,
}
};
- match ret_type {
- TypeRef::Tuple(tup) if tup.is_empty() => {}
- ty => {
- f.write_str(" -> ")?;
- ty.hir_fmt(f)?;
+ if let Some(ret_type) = ret_type {
+ match &data.types_map[ret_type] {
+ TypeRef::Tuple(tup) if tup.is_empty() => {}
+ _ => {
+ f.write_str(" -> ")?;
+ ret_type.hir_fmt(f, &data.types_map)?;
+ }
}
}
@@ -192,23 +193,23 @@
impl HirDisplay for SelfParam {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
let data = f.db.function_data(self.func);
- let param = data.params.first().unwrap();
- match &**param {
+ let param = *data.params.first().unwrap();
+ match &data.types_map[param] {
TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
- TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner, TypeRef::Path(p) if p.is_self_type()) =>
+ TypeRef::Reference(ref_) if matches!(&data.types_map[ref_.ty], TypeRef::Path(p) if p.is_self_type()) =>
{
f.write_char('&')?;
- if let Some(lifetime) = lifetime {
+ if let Some(lifetime) = &ref_.lifetime {
write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
}
- if let hir_def::type_ref::Mutability::Mut = mut_ {
+ if let hir_def::type_ref::Mutability::Mut = ref_.mutability {
f.write_str("mut ")?;
}
f.write_str("self")
}
- ty => {
+ _ => {
f.write_str("self: ")?;
- ty.hir_fmt(f)
+ param.hir_fmt(f, &data.types_map)
}
}
}
@@ -393,7 +394,7 @@
let data = self.variant_data(f.db);
match &*data {
VariantData::Unit => {}
- VariantData::Tuple(fields) => {
+ VariantData::Tuple { fields, types_map } => {
f.write_char('(')?;
let mut first = true;
for (_, field) in fields.iter() {
@@ -403,11 +404,11 @@
f.write_str(", ")?;
}
// Enum variant fields must be pub.
- field.type_ref.hir_fmt(f)?;
+ field.type_ref.hir_fmt(f, types_map)?;
}
f.write_char(')')?;
}
- VariantData::Record(_) => {
+ VariantData::Record { .. } => {
if let Some(limit) = f.entity_limit {
write_fields(&self.fields(f.db), false, limit, true, f)?;
}
@@ -579,13 +580,13 @@
write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
if let Some(default) = &ty.default {
f.write_str(" = ")?;
- default.hir_fmt(f)?;
+ default.hir_fmt(f, ¶ms.types_map)?;
}
}
TypeOrConstParamData::ConstParamData(c) => {
delim(f)?;
write!(f, "const {}: ", name.display(f.db.upcast(), f.edition()))?;
- c.ty.hir_fmt(f)?;
+ c.ty.hir_fmt(f, ¶ms.types_map)?;
if let Some(default) = &c.default {
f.write_str(" = ")?;
@@ -615,7 +616,7 @@
Ok(true)
}
-fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool {
+fn has_disaplayable_predicates(params: &GenericParams) -> bool {
params.where_predicates().any(|pred| {
!matches!(
pred,
@@ -626,21 +627,20 @@
}
fn write_where_predicates(
- params: &Interned<GenericParams>,
+ params: &GenericParams,
f: &mut HirFormatter<'_>,
) -> Result<(), HirDisplayError> {
use WherePredicate::*;
// unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
- let is_unnamed_type_target =
- |params: &Interned<GenericParams>, target: &WherePredicateTypeTarget| {
- matches!(target,
- WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none()
- )
- };
+ let is_unnamed_type_target = |params: &GenericParams, target: &WherePredicateTypeTarget| {
+ matches!(target,
+ WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none()
+ )
+ };
let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
- WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
+ WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f, ¶ms.types_map),
WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
Some(name) => write!(f, "{}", name.display(f.db.upcast(), f.edition())),
None => f.write_str("{unnamed}"),
@@ -668,7 +668,7 @@
TypeBound { target, bound } => {
write_target(target, f)?;
f.write_str(": ")?;
- bound.hir_fmt(f)?;
+ bound.hir_fmt(f, ¶ms.types_map)?;
}
Lifetime { target, bound } => {
let target = target.name.display(f.db.upcast(), f.edition());
@@ -681,14 +681,16 @@
write!(f, "for<{lifetimes}> ")?;
write_target(target, f)?;
f.write_str(": ")?;
- bound.hir_fmt(f)?;
+ bound.hir_fmt(f, ¶ms.types_map)?;
}
}
while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) {
f.write_str(" + ")?;
match nxt {
- TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?,
+ TypeBound { bound, .. } | ForLifetime { bound, .. } => {
+ bound.hir_fmt(f, ¶ms.types_map)?
+ }
Lifetime { bound, .. } => {
write!(f, "{}", bound.name.display(f.db.upcast(), f.edition()))?
}
@@ -716,7 +718,7 @@
Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?,
None => f.write_str("_: ")?,
}
- data.type_ref.hir_fmt(f)?;
+ data.type_ref.hir_fmt(f, &data.types_map)?;
Ok(())
}
}
@@ -730,7 +732,7 @@
f.write_str("mut ")?;
}
write!(f, "{}: ", data.name.display(f.db.upcast(), f.edition()))?;
- data.type_ref.hir_fmt(f)?;
+ data.type_ref.hir_fmt(f, &data.types_map)?;
Ok(())
}
}
@@ -813,11 +815,14 @@
write_generic_params(def_id, f)?;
if !data.bounds.is_empty() {
f.write_str(": ")?;
- f.write_joined(data.bounds.iter(), " + ")?;
+ f.write_joined(
+ data.bounds.iter().map(|bound| hir_display_with_types_map(bound, &data.types_map)),
+ " + ",
+ )?;
}
- if let Some(ty) = &data.type_ref {
+ if let Some(ty) = data.type_ref {
f.write_str(" = ")?;
- ty.hir_fmt(f)?;
+ ty.hir_fmt(f, &data.types_map)?;
}
write_where_clause(def_id, f)?;
Ok(())
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 30e023e..88eb3b1 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -58,7 +58,8 @@
TypeOrConstParamId, TypeParamId, UnionId,
};
use hir_expand::{
- attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult,
+ attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, RenderedExpandError,
+ ValueResult,
};
use hir_ty::{
all_super_traits, autoderef, check_orphan_rules,
@@ -838,7 +839,7 @@
let file_id = loc.kind.file_id();
let node =
InFile::new(file_id, db.ast_id_map(file_id).get_erased(loc.kind.erased_ast_id()));
- let (message, error) = err.render_to_string(db.upcast());
+ let RenderedExpandError { message, error, kind } = err.render_to_string(db.upcast());
let precise_location = if err.span().anchor.file_id == file_id {
Some(
err.span().range
@@ -850,7 +851,7 @@
} else {
None
};
- acc.push(MacroError { node, precise_location, message, error }.into());
+ acc.push(MacroError { node, precise_location, message, error, kind }.into());
}
if !parse_errors.is_empty() {
@@ -916,13 +917,14 @@
DefDiagnosticKind::MacroError { ast, path, err } => {
let item = ast.to_ptr(db.upcast());
- let (message, error) = err.render_to_string(db.upcast());
+ let RenderedExpandError { message, error, kind } = err.render_to_string(db.upcast());
acc.push(
MacroError {
node: InFile::new(ast.file_id, item.syntax_node_ptr()),
precise_location: None,
message: format!("{}: {message}", path.display(db.upcast(), edition)),
error,
+ kind,
}
.into(),
)
@@ -1811,7 +1813,8 @@
InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into()
}
BodyDiagnostic::MacroError { node, err } => {
- let (message, error) = err.render_to_string(db.upcast());
+ let RenderedExpandError { message, error, kind } =
+ err.render_to_string(db.upcast());
let precise_location = if err.span().anchor.file_id == node.file_id {
Some(
@@ -1829,6 +1832,7 @@
precise_location,
message,
error,
+ kind,
}
.into()
}
@@ -1885,7 +1889,7 @@
let (unafe_exprs, only_lint) = hir_ty::diagnostics::missing_unsafe(db, self.into());
for expr in unafe_exprs {
- match source_map.expr_syntax(expr) {
+ match source_map.expr_or_pat_syntax(expr) {
Ok(expr) => acc.push(MissingUnsafe { expr, only_lint }.into()),
Err(SyntheticSyntax) => {
// FIXME: Here and elsewhere in this file, the `expr` was
@@ -2420,8 +2424,8 @@
func_data
.params
.first()
- .map(|param| match &**param {
- TypeRef::Reference(.., mutability) => match mutability {
+ .map(|¶m| match &func_data.types_map[param] {
+ TypeRef::Reference(ref_) => match ref_.mutability {
hir_def::type_ref::Mutability::Shared => Access::Shared,
hir_def::type_ref::Mutability::Mut => Access::Exclusive,
},
@@ -2747,10 +2751,6 @@
Module { id: self.id.module(db.upcast()) }
}
- pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
- db.type_alias_data(self.id).type_ref.as_deref().cloned()
- }
-
pub fn ty(self, db: &dyn HirDatabase) -> Type {
Type::from_def(db, self.id)
}
@@ -3481,7 +3481,7 @@
LocalSource {
local: self,
source: src.map(|ast| match ast.to_node(&root) {
- ast::Pat::IdentPat(it) => Either::Left(it),
+ Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it),
_ => unreachable!("local with non ident-pattern"),
}),
}
@@ -3510,7 +3510,7 @@
LocalSource {
local: self,
source: src.map(|ast| match ast.to_node(&root) {
- ast::Pat::IdentPat(it) => Either::Left(it),
+ Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it),
_ => unreachable!("local with non ident-pattern"),
}),
}
@@ -4235,10 +4235,7 @@
}
mir::MirSpan::PatId(pat) => {
if let Ok(pat) = source_map.pat_syntax(pat) {
- result.push(CaptureUsageSource {
- is_ref,
- source: pat.map(AstPtr::wrap_right),
- });
+ result.push(CaptureUsageSource { is_ref, source: pat });
}
}
mir::MirSpan::BindingId(binding) => result.extend(
@@ -4246,10 +4243,7 @@
.patterns_for_binding(binding)
.iter()
.filter_map(|&pat| source_map.pat_syntax(pat).ok())
- .map(|pat| CaptureUsageSource {
- is_ref,
- source: pat.map(AstPtr::wrap_right),
- }),
+ .map(|pat| CaptureUsageSource { is_ref, source: pat }),
),
mir::MirSpan::SelfParam | mir::MirSpan::Unknown => {
unreachable!("invalid capture usage span")
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 3eac33c..feb9a34 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -11,13 +11,13 @@
use either::Either;
use hir_def::{
- hir::Expr,
+ hir::{Expr, ExprOrPatId},
lower::LowerCtx,
nameres::{MacroSubNs, ModuleOrigin},
path::ModPath,
resolver::{self, HasResolver, Resolver, TypeNs},
- type_ref::Mutability,
- AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId,
+ type_ref::{Mutability, TypesMap, TypesSourceMap},
+ AsMacroCall, DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId,
};
use hir_expand::{
attrs::collect_attrs,
@@ -45,7 +45,7 @@
use crate::{
db::HirDatabase,
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
- source_analyzer::{resolve_hir_path, SourceAnalyzer},
+ source_analyzer::{name_hygiene, resolve_hir_path, SourceAnalyzer},
Access, Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
ConstParam, Crate, DeriveHelper, Enum, Field, Function, HasSource, HirFileId, Impl, InFile,
InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name,
@@ -154,7 +154,7 @@
}
}
-impl<'db, DB: HirDatabase> Semantics<'db, DB> {
+impl<DB: HirDatabase> Semantics<'_, DB> {
pub fn new(db: &DB) -> Semantics<'_, DB> {
let impl_ = SemanticsImpl::new(db);
Semantics { db, imp: impl_ }
@@ -203,6 +203,14 @@
self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast))
}
+ pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> {
+ self.imp.resolve_range_pat(range_pat).map(Struct::from)
+ }
+
+ pub fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<Struct> {
+ self.imp.resolve_range_expr(range_expr).map(Struct::from)
+ }
+
pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
self.imp.resolve_await_to_poll(await_expr).map(Function::from)
}
@@ -928,16 +936,7 @@
}
}
- let (file_id, tokens) = stack.first()?;
- // make sure we pick the token in the expanded include if we encountered an include,
- // otherwise we'll get the wrong semantics
- let sa =
- tokens.first()?.0.parent().and_then(|parent| {
- self.analyze_impl(InFile::new(*file_id, &parent), None, false)
- })?;
-
let mut m_cache = self.macro_call_cache.borrow_mut();
- let def_map = sa.resolver.def_map();
// Filters out all tokens that contain the given range (usually the macro call), any such
// token is redundant as the corresponding macro call has already been processed
@@ -946,6 +945,10 @@
};
while let Some((expansion, ref mut tokens)) = stack.pop() {
+ // Reverse the tokens so we prefer first tokens (to accommodate for popping from the
+ // back)
+ // alternatively we could pop from the front but that would shift the content on every pop
+ tokens.reverse();
while let Some((token, ctx)) = tokens.pop() {
let was_not_remapped = (|| {
// First expand into attribute invocations
@@ -1016,8 +1019,16 @@
) {
call.as_macro_file()
} else {
- // FIXME: This is wrong, the SourceAnalyzer might be invalid here
- sa.expand(self.db, mcall.as_ref())?
+ token
+ .parent()
+ .and_then(|parent| {
+ self.analyze_impl(
+ InFile::new(expansion, &parent),
+ None,
+ false,
+ )
+ })?
+ .expand(self.db, mcall.as_ref())?
};
m_cache.insert(mcall, it);
it
@@ -1087,9 +1098,16 @@
attr.path().and_then(|it| it.as_single_name_ref())?.as_name();
// Not an attribute, nor a derive, so it's either an intert attribute or a derive helper
// Try to resolve to a derive helper and downmap
+ let resolver = &token
+ .parent()
+ .and_then(|parent| {
+ self.analyze_impl(InFile::new(expansion, &parent), None, false)
+ })?
+ .resolver;
let id = self.db.ast_id_map(expansion).ast_id(&adt);
- let helpers =
- def_map.derive_helpers_in_scope(InFile::new(expansion, id))?;
+ let helpers = resolver
+ .def_map()
+ .derive_helpers_in_scope(InFile::new(expansion, id))?;
if !helpers.is_empty() {
let text_range = attr.syntax().text_range();
@@ -1251,19 +1269,28 @@
pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
let analyze = self.analyze(ty.syntax())?;
- let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id);
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let ctx =
+ LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map);
+ let type_ref = crate::TypeRef::from_ast(&ctx, ty.clone());
let ty = hir_ty::TyLoweringContext::new_maybe_unowned(
self.db,
&analyze.resolver,
+ &types_map,
+ None,
analyze.resolver.type_owner(),
)
- .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone()));
+ .lower_ty(type_ref);
Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
}
pub fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
let analyze = self.analyze(path.syntax())?;
- let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id);
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let ctx =
+ LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map);
let hir_path = Path::from_src(&ctx, path.clone())?;
match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? {
TypeNs::TraitId(id) => Some(Trait { id }),
@@ -1363,6 +1390,14 @@
self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
}
+ fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> {
+ self.analyze(range_pat.syntax())?.resolve_range_pat(self.db, range_pat)
+ }
+
+ fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<StructId> {
+ self.analyze(range_expr.syntax())?.resolve_range_expr(self.db, range_expr)
+ }
+
fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> {
self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
}
@@ -1761,7 +1796,9 @@
}
if let Some(parent) = ast::Expr::cast(parent.clone()) {
- if let Some(expr_id) = source_map.node_expr(InFile { file_id, value: &parent }) {
+ if let Some(ExprOrPatId::ExprId(expr_id)) =
+ source_map.node_expr(InFile { file_id, value: &parent })
+ {
if let Expr::Unsafe { .. } = body[expr_id] {
break true;
}
@@ -1934,10 +1971,19 @@
/// Resolve a path as-if it was written at the given scope. This is
/// necessary a heuristic, as it doesn't take hygiene into account.
- pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> {
- let ctx = LowerCtx::new(self.db.upcast(), self.file_id);
- let path = Path::from_src(&ctx, path.clone())?;
- resolve_hir_path(self.db, &self.resolver, &path)
+ pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> {
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let ctx =
+ LowerCtx::new(self.db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
+ let path = Path::from_src(&ctx, ast_path.clone())?;
+ resolve_hir_path(
+ self.db,
+ &self.resolver,
+ &path,
+ name_hygiene(self.db, InFile::new(self.file_id, ast_path.syntax())),
+ &types_map,
+ )
}
/// Iterates over associated types that may be specified after the given path (using
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index 389778b..5357e82 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -328,7 +328,7 @@
.position(|it| it == *src.value)?;
let container = self.find_pat_or_label_container(src.syntax_ref())?;
let (_, source_map) = self.db.body_with_source_map(container);
- let expr = source_map.node_expr(src.with_value(&ast::Expr::AsmExpr(asm)))?;
+ let expr = source_map.node_expr(src.with_value(&ast::Expr::AsmExpr(asm)))?.as_expr()?;
Some(InlineAsmOperand { owner: container, expr, index })
}
@@ -372,7 +372,8 @@
let break_or_continue = ast::Expr::cast(src.value.syntax().parent()?)?;
let container = self.find_pat_or_label_container(src.syntax_ref())?;
let (body, source_map) = self.db.body_with_source_map(container);
- let break_or_continue = source_map.node_expr(src.with_value(&break_or_continue))?;
+ let break_or_continue =
+ source_map.node_expr(src.with_value(&break_or_continue))?.as_expr()?;
let (Expr::Break { label, .. } | Expr::Continue { label }) = body[break_or_continue] else {
return None;
};
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 3da67ae..8d6e228 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -7,21 +7,26 @@
//! purely for "IDE needs".
use std::iter::{self, once};
+use crate::{
+ db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
+ BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static,
+ Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, Variant,
+};
use either::Either;
use hir_def::{
body::{
scope::{ExprScopes, ScopeId},
- Body, BodySourceMap,
+ Body, BodySourceMap, HygieneId,
},
- hir::{BindingId, ExprId, Pat, PatId},
+ hir::{BindingId, ExprId, ExprOrPatId, Pat, PatId},
lang_item::LangItem,
lower::LowerCtx,
nameres::MacroSubNs,
path::{ModPath, Path, PathKind},
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
- type_ref::Mutability,
+ type_ref::{Mutability, TypesMap, TypesSourceMap},
AsMacroCall, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, ItemContainerId,
- LocalFieldId, Lookup, ModuleDefId, TraitId, VariantId,
+ LocalFieldId, Lookup, ModuleDefId, StructId, TraitId, VariantId,
};
use hir_expand::{
mod_path::path,
@@ -40,18 +45,13 @@
use intern::sym;
use itertools::Itertools;
use smallvec::SmallVec;
+use syntax::ast::{RangeItem, RangeOp};
use syntax::{
ast::{self, AstNode},
SyntaxKind, SyntaxNode, TextRange, TextSize,
};
use triomphe::Arc;
-use crate::{
- db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
- BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static,
- Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, Variant,
-};
-
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
/// original source files. It should not be used inside the HIR itself.
#[derive(Debug)]
@@ -120,7 +120,7 @@
self.def.as_ref().map(|(_, body, _)| &**body)
}
- fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
+ fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprOrPatId> {
let src = match expr {
ast::Expr::MacroExpr(expr) => {
self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?.into()
@@ -174,7 +174,9 @@
db: &dyn HirDatabase,
expr: &ast::Expr,
) -> Option<&[Adjustment]> {
- let expr_id = self.expr_id(db, expr)?;
+ // It is safe to omit destructuring assignments here because they have no adjustments (neither
+ // expressions nor patterns).
+ let expr_id = self.expr_id(db, expr)?.as_expr()?;
let infer = self.infer.as_ref()?;
infer.expr_adjustments.get(&expr_id).map(|v| &**v)
}
@@ -186,9 +188,9 @@
) -> Option<(Type, Option<Type>)> {
let expr_id = self.expr_id(db, expr)?;
let infer = self.infer.as_ref()?;
- let coerced = infer
- .expr_adjustments
- .get(&expr_id)
+ let coerced = expr_id
+ .as_expr()
+ .and_then(|expr_id| infer.expr_adjustments.get(&expr_id))
.and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
let ty = infer[expr_id].clone();
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
@@ -268,7 +270,7 @@
db: &dyn HirDatabase,
call: &ast::MethodCallExpr,
) -> Option<Callable> {
- let expr_id = self.expr_id(db, &call.clone().into())?;
+ let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?;
let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
let ty = db.value_ty(func.into())?.substitute(Interner, &substs);
let ty = Type::new_with_resolver(db, &self.resolver, ty);
@@ -282,7 +284,7 @@
db: &dyn HirDatabase,
call: &ast::MethodCallExpr,
) -> Option<Function> {
- let expr_id = self.expr_id(db, &call.clone().into())?;
+ let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?;
let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs).into())
@@ -293,7 +295,7 @@
db: &dyn HirDatabase,
call: &ast::MethodCallExpr,
) -> Option<Either<Function, Field>> {
- let expr_id = self.expr_id(db, &call.clone().into())?;
+ let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?;
let inference_result = self.infer.as_ref()?;
match inference_result.method_resolution(expr_id) {
Some((f_in_trait, substs)) => Some(Either::Left(
@@ -322,7 +324,7 @@
field: &ast::FieldExpr,
) -> Option<Either<Field, TupleField>> {
let &(def, ..) = self.def.as_ref()?;
- let expr_id = self.expr_id(db, &field.clone().into())?;
+ let expr_id = self.expr_id(db, &field.clone().into())?.as_expr()?;
self.infer.as_ref()?.field_resolution(expr_id).map(|it| {
it.map_either(Into::into, |f| TupleField { owner: def, tuple: f.tuple, index: f.index })
})
@@ -334,7 +336,7 @@
field: &ast::FieldExpr,
) -> Option<Either<Either<Field, TupleField>, Function>> {
let &(def, ..) = self.def.as_ref()?;
- let expr_id = self.expr_id(db, &field.clone().into())?;
+ let expr_id = self.expr_id(db, &field.clone().into())?.as_expr()?;
let inference_result = self.infer.as_ref()?;
match inference_result.field_resolution(expr_id) {
Some(field) => Some(Either::Left(field.map_either(Into::into, |f| TupleField {
@@ -348,6 +350,45 @@
}
}
+ pub(crate) fn resolve_range_pat(
+ &self,
+ db: &dyn HirDatabase,
+ range_pat: &ast::RangePat,
+ ) -> Option<StructId> {
+ let path: ModPath = match (range_pat.op_kind()?, range_pat.start(), range_pat.end()) {
+ (RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo],
+ (RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom],
+ (RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range],
+ (RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive],
+ (RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive],
+
+ (RangeOp::Exclusive, None, None) => return None,
+ (RangeOp::Inclusive, None, None) => return None,
+ (RangeOp::Inclusive, Some(_), None) => return None,
+ };
+ self.resolver.resolve_known_struct(db.upcast(), &path)
+ }
+
+ pub(crate) fn resolve_range_expr(
+ &self,
+ db: &dyn HirDatabase,
+ range_expr: &ast::RangeExpr,
+ ) -> Option<StructId> {
+ let path: ModPath = match (range_expr.op_kind()?, range_expr.start(), range_expr.end()) {
+ (RangeOp::Exclusive, None, None) => path![core::ops::RangeFull],
+ (RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo],
+ (RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom],
+ (RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range],
+ (RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive],
+ (RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive],
+
+ // [E0586] inclusive ranges must be bounded at the end
+ (RangeOp::Inclusive, None, None) => return None,
+ (RangeOp::Inclusive, Some(_), None) => return None,
+ };
+ self.resolver.resolve_known_struct(db.upcast(), &path)
+ }
+
pub(crate) fn resolve_await_to_poll(
&self,
db: &dyn HirDatabase,
@@ -403,7 +444,7 @@
self.infer
.as_ref()
.and_then(|infer| {
- let expr = self.expr_id(db, &prefix_expr.clone().into())?;
+ let expr = self.expr_id(db, &prefix_expr.clone().into())?.as_expr()?;
let (func, _) = infer.method_resolution(expr)?;
let (deref_mut_trait, deref_mut) = self.lang_trait_fn(
db,
@@ -449,7 +490,7 @@
.infer
.as_ref()
.and_then(|infer| {
- let expr = self.expr_id(db, &index_expr.clone().into())?;
+ let expr = self.expr_id(db, &index_expr.clone().into())?.as_expr()?;
let (func, _) = infer.method_resolution(expr)?;
let (index_mut_trait, index_mut_fn) = self.lang_trait_fn(
db,
@@ -521,7 +562,8 @@
let expr = ast::Expr::from(record_expr);
let expr_id = self.body_source_map()?.node_expr(InFile::new(self.file_id, &expr))?;
- let local_name = field.field_name()?.as_name();
+ let ast_name = field.field_name()?;
+ let local_name = ast_name.as_name();
let local = if field.name_ref().is_some() {
None
} else {
@@ -530,15 +572,19 @@
PathKind::Plain,
once(local_name.clone()),
));
- match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
+ match self.resolver.resolve_path_in_value_ns_fully(
+ db.upcast(),
+ &path,
+ name_hygiene(db, InFile::new(self.file_id, ast_name.syntax())),
+ ) {
Some(ValueNs::LocalBinding(binding_id)) => {
Some(Local { binding_id, parent: self.resolver.body_owner()? })
}
_ => None,
}
};
- let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?;
- let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
+ let (_, subst) = self.infer.as_ref()?.type_of_expr_or_pat(expr_id)?.as_adt()?;
+ let variant = self.infer.as_ref()?.variant_resolution_for_expr_or_pat(expr_id)?;
let variant_data = variant.variant_data(db.upcast());
let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
let field_ty =
@@ -568,7 +614,10 @@
db: &dyn HirDatabase,
macro_call: InFile<&ast::MacroCall>,
) -> Option<Macro> {
- let ctx = LowerCtx::new(db.upcast(), macro_call.file_id);
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let ctx =
+ LowerCtx::new(db.upcast(), macro_call.file_id, &mut types_map, &mut types_source_map);
let path = macro_call.value.path().and_then(|ast| Path::from_src(&ctx, ast))?;
self.resolver
.resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang))
@@ -586,7 +635,7 @@
Pat::Path(path) => path,
_ => return None,
};
- let res = resolve_hir_path(db, &self.resolver, path)?;
+ let res = resolve_hir_path(db, &self.resolver, path, HygieneId::ROOT, TypesMap::EMPTY)?;
match res {
PathResolution::Def(def) => Some(def),
_ => None,
@@ -606,10 +655,10 @@
let infer = self.infer.as_deref()?;
if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
let expr_id = self.expr_id(db, &path_expr.into())?;
- if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr(expr_id) {
+ if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr_or_pat(expr_id) {
let assoc = match assoc {
AssocItemId::FunctionId(f_in_trait) => {
- match infer.type_of_expr.get(expr_id) {
+ match infer.type_of_expr_or_pat(expr_id) {
None => assoc,
Some(func_ty) => {
if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
@@ -634,7 +683,7 @@
return Some(PathResolution::Def(AssocItem::from(assoc).into()));
}
if let Some(VariantId::EnumVariantId(variant)) =
- infer.variant_resolution_for_expr(expr_id)
+ infer.variant_resolution_for_expr_or_pat(expr_id)
{
return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
}
@@ -658,7 +707,7 @@
} else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) {
let expr_id = self.expr_id(db, &rec_lit.into())?;
if let Some(VariantId::EnumVariantId(variant)) =
- infer.variant_resolution_for_expr(expr_id)
+ infer.variant_resolution_for_expr_or_pat(expr_id)
{
return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
}
@@ -680,14 +729,16 @@
return resolved;
}
- let ctx = LowerCtx::new(db.upcast(), self.file_id);
+ let (mut types_map, mut types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let ctx = LowerCtx::new(db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
let hir_path = Path::from_src(&ctx, path.clone())?;
// Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
// trying to resolve foo::bar.
if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
if use_tree.coloncolon_token().is_some() {
- return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
+ return resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map);
}
}
@@ -704,7 +755,7 @@
// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
// trying to resolve foo::bar.
if path.parent_path().is_some() {
- return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) {
+ return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map) {
None if meta_path.is_some() => {
path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
@@ -775,9 +826,16 @@
};
}
if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
- resolve_hir_path_qualifier(db, &self.resolver, &hir_path)
+ resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map)
} else {
- resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns)
+ resolve_hir_path_(
+ db,
+ &self.resolver,
+ &hir_path,
+ prefer_value_ns,
+ name_hygiene(db, InFile::new(self.file_id, path.syntax())),
+ &types_map,
+ )
}
}
@@ -790,10 +848,16 @@
let infer = self.infer.as_ref()?;
let expr_id = self.expr_id(db, &literal.clone().into())?;
- let substs = infer.type_of_expr[expr_id].as_adt()?.1;
+ let substs = infer[expr_id].as_adt()?.1;
- let (variant, missing_fields, _exhaustive) =
- record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
+ let (variant, missing_fields, _exhaustive) = match expr_id {
+ ExprOrPatId::ExprId(expr_id) => {
+ record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?
+ }
+ ExprOrPatId::PatId(pat_id) => {
+ record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?
+ }
+ };
let res = self.missing_fields(db, substs, variant, missing_fields);
Some(res)
}
@@ -856,7 +920,7 @@
) -> Option<VariantId> {
let infer = self.infer.as_ref()?;
let expr_id = self.expr_id(db, &record_lit.into())?;
- infer.variant_resolution_for_expr(expr_id)
+ infer.variant_resolution_for_expr_or_pat(expr_id)
}
pub(crate) fn is_unsafe_macro_call_expr(
@@ -867,14 +931,24 @@
if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) {
if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) {
let mut is_unsafe = false;
- unsafe_expressions(
- db,
- infer,
- *def,
- body,
- expanded_expr,
- &mut |UnsafeExpr { inside_unsafe_block, .. }| is_unsafe |= !inside_unsafe_block,
- );
+ let mut walk_expr = |expr_id| {
+ unsafe_expressions(
+ db,
+ infer,
+ *def,
+ body,
+ expr_id,
+ &mut |UnsafeExpr { inside_unsafe_block, .. }| {
+ is_unsafe |= !inside_unsafe_block
+ },
+ )
+ };
+ match expanded_expr {
+ ExprOrPatId::ExprId(expanded_expr) => walk_expr(expanded_expr),
+ ExprOrPatId::PatId(expanded_pat) => {
+ body.walk_exprs_in_pat(expanded_pat, &mut walk_expr)
+ }
+ }
return is_unsafe;
}
}
@@ -887,7 +961,7 @@
format_args: InFile<&ast::FormatArgsExpr>,
offset: TextSize,
) -> Option<(TextRange, Option<PathResolution>)> {
- let implicits = self.body_source_map()?.implicit_format_args(format_args)?;
+ let (hygiene, implicits) = self.body_source_map()?.implicit_format_args(format_args)?;
implicits.iter().find(|(range, _)| range.contains_inclusive(offset)).map(|(range, name)| {
(
*range,
@@ -899,6 +973,7 @@
PathKind::Plain,
Some(name.clone()),
)),
+ hygiene,
),
)
})
@@ -925,22 +1000,22 @@
db: &'a dyn HirDatabase,
format_args: InFile<&ast::FormatArgsExpr>,
) -> Option<impl Iterator<Item = (TextRange, Option<PathResolution>)> + 'a> {
- Some(self.body_source_map()?.implicit_format_args(format_args)?.iter().map(
- move |(range, name)| {
- (
- *range,
- resolve_hir_value_path(
- db,
- &self.resolver,
- self.resolver.body_owner(),
- &Path::from_known_path_with_no_generic(ModPath::from_segments(
- PathKind::Plain,
- Some(name.clone()),
- )),
- ),
- )
- },
- ))
+ let (hygiene, names) = self.body_source_map()?.implicit_format_args(format_args)?;
+ Some(names.iter().map(move |(range, name)| {
+ (
+ *range,
+ resolve_hir_value_path(
+ db,
+ &self.resolver,
+ self.resolver.body_owner(),
+ &Path::from_known_path_with_no_generic(ModPath::from_segments(
+ PathKind::Plain,
+ Some(name.clone()),
+ )),
+ hygiene,
+ ),
+ )
+ }))
}
pub(crate) fn as_asm_parts(
@@ -991,7 +1066,7 @@
}
fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
- self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, expr)?)
+ self.infer.as_ref()?.type_of_expr_or_pat(self.expr_id(db, expr)?)
}
}
@@ -1004,7 +1079,7 @@
node.ancestors_with_macros(db.upcast())
.take_while(|it| !ast::Item::can_cast(it.kind()) || ast::MacroCall::can_cast(it.kind()))
.filter_map(|it| it.map(ast::Expr::cast).transpose())
- .filter_map(|it| source_map.node_expr(it.as_ref()))
+ .filter_map(|it| source_map.node_expr(it.as_ref())?.as_expr())
.find_map(|it| scopes.scope_for(it))
}
@@ -1086,8 +1161,10 @@
db: &dyn HirDatabase,
resolver: &Resolver,
path: &Path,
+ hygiene: HygieneId,
+ types_map: &TypesMap,
) -> Option<PathResolution> {
- resolve_hir_path_(db, resolver, path, false)
+ resolve_hir_path_(db, resolver, path, false, hygiene, types_map)
}
#[inline]
@@ -1107,13 +1184,20 @@
resolver: &Resolver,
path: &Path,
prefer_value_ns: bool,
+ hygiene: HygieneId,
+ types_map: &TypesMap,
) -> Option<PathResolution> {
let types = || {
let (ty, unresolved) = match path.type_anchor() {
Some(type_ref) => {
- let (_, res) =
- TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner())
- .lower_ty_ext(type_ref);
+ let (_, res) = TyLoweringContext::new_maybe_unowned(
+ db,
+ resolver,
+ types_map,
+ None,
+ resolver.type_owner(),
+ )
+ .lower_ty_ext(type_ref);
res.map(|ty_ns| (ty_ns, path.segments().first()))
}
None => {
@@ -1172,7 +1256,7 @@
};
let body_owner = resolver.body_owner();
- let values = || resolve_hir_value_path(db, resolver, body_owner, path);
+ let values = || resolve_hir_value_path(db, resolver, body_owner, path, hygiene);
let items = || {
resolver
@@ -1197,8 +1281,9 @@
resolver: &Resolver,
body_owner: Option<DefWithBodyId>,
path: &Path,
+ hygiene: HygieneId,
) -> Option<PathResolution> {
- resolver.resolve_path_in_value_ns_fully(db.upcast(), path).and_then(|val| {
+ resolver.resolve_path_in_value_ns_fully(db.upcast(), path, hygiene).and_then(|val| {
let res = match val {
ValueNs::LocalBinding(binding_id) => {
let var = Local { parent: body_owner?, binding_id };
@@ -1233,13 +1318,19 @@
db: &dyn HirDatabase,
resolver: &Resolver,
path: &Path,
+ types_map: &TypesMap,
) -> Option<PathResolution> {
(|| {
let (ty, unresolved) = match path.type_anchor() {
Some(type_ref) => {
- let (_, res) =
- TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner())
- .lower_ty_ext(type_ref);
+ let (_, res) = TyLoweringContext::new_maybe_unowned(
+ db,
+ resolver,
+ types_map,
+ None,
+ resolver.type_owner(),
+ )
+ .lower_ty_ext(type_ref);
res.map(|ty_ns| (ty_ns, path.segments().first()))
}
None => {
@@ -1303,3 +1394,13 @@
.map(|it| PathResolution::Def(it.into()))
})
}
+
+pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> HygieneId {
+ let Some(macro_file) = name.file_id.macro_file() else {
+ return HygieneId::ROOT;
+ };
+ let span_map = db.expansion_span_map(macro_file);
+ let ctx = span_map.span_at(name.value.text_range().start()).ctx;
+ let ctx = db.lookup_intern_syntax_context(ctx);
+ HygieneId::new(ctx.opaque_and_semitransparent)
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index cabb7e3..f8416f8 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -8,7 +8,10 @@
TraitId,
};
use hir_expand::HirFileId;
-use hir_ty::{db::HirDatabase, display::HirDisplay};
+use hir_ty::{
+ db::HirDatabase,
+ display::{hir_display_with_types_map, HirDisplay},
+};
use span::Edition;
use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr};
@@ -214,8 +217,11 @@
fn collect_from_impl(&mut self, impl_id: ImplId) {
let impl_data = self.db.impl_data(impl_id);
- let impl_name =
- Some(SmolStr::new(impl_data.self_ty.display(self.db, self.edition).to_string()));
+ let impl_name = Some(
+ hir_display_with_types_map(impl_data.self_ty, &impl_data.types_map)
+ .display(self.db, self.edition)
+ .to_smolstr(),
+ );
self.with_container_name(impl_name, |s| {
for &assoc_item_id in impl_data.items.iter() {
s.push_assoc_item(assoc_item_id)
diff --git a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
index 2a14fbe..ba21586 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
@@ -23,7 +23,6 @@
# local deps
stdx.workspace = true
syntax.workspace = true
-text-edit.workspace = true
ide-db.workspace = true
hir.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
index c035c59..605fd14 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
@@ -1,5 +1,6 @@
use either::Either;
use hir::ModuleDef;
+use ide_db::text_edit::TextRange;
use ide_db::{
assists::{AssistId, AssistKind},
defs::Definition,
@@ -19,7 +20,6 @@
},
AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T,
};
-use text_edit::TextRange;
use crate::{
assist_context::{AssistContext, Assists},
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
index b229b75..22a1efd 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
@@ -1,4 +1,5 @@
use hir::{sym, HasVisibility};
+use ide_db::text_edit::TextRange;
use ide_db::{
assists::{AssistId, AssistKind},
defs::Definition,
@@ -8,7 +9,6 @@
};
use itertools::Itertools;
use syntax::{ast, ted, AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr};
-use text_edit::TextRange;
use crate::{
assist_context::{AssistContext, Assists, SourceChangeBuilder},
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
index 9ecfb83..3f0d5cf 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
@@ -1,3 +1,4 @@
+use ide_db::text_edit::TextRange;
use ide_db::{
assists::{AssistId, AssistKind},
defs::Definition,
@@ -8,7 +9,6 @@
ast::{self, make, AstNode, FieldExpr, HasName, IdentPat},
ted,
};
-use text_edit::TextRange;
use crate::{
assist_context::{AssistContext, Assists, SourceChangeBuilder},
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
index 0e9c463..94274f6 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -41,7 +41,7 @@
macro_calls.into_iter().filter_map(compute_dbg_replacement).collect::<Vec<_>>();
acc.add(
- AssistId("remove_dbg", AssistKind::Refactor),
+ AssistId("remove_dbg", AssistKind::QuickFix),
"Remove dbg!()",
replacements.iter().map(|&(range, _)| range).reduce(|acc, range| acc.cover(range))?,
|builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
index c6f99d6..0570b44 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
@@ -1,6 +1,7 @@
use std::collections::hash_map::Entry;
use hir::{FileRange, HirFileIdExt, InFile, InRealFile, Module, ModuleSource};
+use ide_db::text_edit::TextRange;
use ide_db::{
defs::Definition,
search::{FileReference, ReferenceCategory, SearchScope},
@@ -10,7 +11,6 @@
ast::{self, Rename},
AstNode,
};
-use text_edit::TextRange;
use crate::{AssistContext, AssistId, AssistKind, Assists};
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
index 8a6c293..26fd887 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
@@ -1,4 +1,5 @@
use hir::{FileRange, Semantics};
+use ide_db::text_edit::TextRange;
use ide_db::{
defs::Definition,
search::{SearchScope, UsageSearchResult},
@@ -11,7 +12,6 @@
},
match_ast, ted, AstNode,
};
-use text_edit::TextRange;
use crate::{AssistContext, AssistId, AssistKind, Assists};
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
index db789cf..648bf35 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
@@ -34,6 +34,9 @@
pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
let pipe_token = ctx.find_token_syntax_at_offset(T![|])?;
let or_pat = ast::OrPat::cast(pipe_token.parent()?)?.clone_for_update();
+ if or_pat.leading_pipe().is_some_and(|it| it == pipe_token) {
+ return None;
+ }
let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?;
let match_arm_body = match_arm.expr()?;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index 2262081..8aaf5d6 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -301,6 +301,7 @@
inline_call::inline_into_callers,
inline_const_as_literal::inline_const_as_literal,
inline_local_variable::inline_local_variable,
+ inline_macro::inline_macro,
inline_type_alias::inline_type_alias,
inline_type_alias::inline_type_alias_uses,
into_to_qualified_from::into_to_qualified_from,
@@ -326,6 +327,7 @@
raw_string::add_hash,
raw_string::make_usual_string,
raw_string::remove_hash,
+ remove_dbg::remove_dbg,
remove_mut::remove_mut,
remove_unused_imports::remove_unused_imports,
remove_unused_param::remove_unused_param,
@@ -381,9 +383,6 @@
generate_getter_or_setter::generate_setter,
generate_delegate_methods::generate_delegate_methods,
generate_deref::generate_deref,
- //
- remove_dbg::remove_dbg,
- inline_macro::inline_macro,
// Are you sure you want to add new assist here, and not to the
// sorted list above?
]
diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
index 614465b..1bef82a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
@@ -25,7 +25,6 @@
ide-db.workspace = true
stdx.workspace = true
syntax.workspace = true
-text-edit.workspace = true
# completions crate should depend only on the top-level `hir` package. if you need
# something from some `hir-xxx` subpackage, reexport the API via `hir`.
hir.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 672e179..c38a8ef 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -32,6 +32,7 @@
//! ```
use hir::{db::ExpandDatabase, HasAttrs, MacroFileId, Name};
+use ide_db::text_edit::TextEdit;
use ide_db::{
documentation::HasDocs, path_transform::PathTransform,
syntax_helpers::prettify_macro_expansion, traits::get_missing_assoc_items, SymbolKind,
@@ -40,7 +41,6 @@
ast::{self, edit_in_place::AttrsOwnerEdit, make, HasGenericArgs, HasTypeBounds},
format_smolstr, ted, AstNode, SmolStr, SyntaxElement, SyntaxKind, TextRange, ToSmolStr, T,
};
-use text_edit::TextEdit;
use crate::{
context::PathCompletionCtx, CompletionContext, CompletionItem, CompletionItemKind,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
index 05e2892..f12f011 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
@@ -7,7 +7,6 @@
base_db::{SourceRootDatabase, VfsPath},
FxHashSet, RootDatabase, SymbolKind,
};
-use stdx::IsNoneOr;
use syntax::{ast, AstNode, SyntaxKind, ToSmolStr};
use crate::{context::CompletionContext, CompletionItem, Completions};
@@ -66,7 +65,7 @@
.iter()
.filter(|&submodule_candidate_file| submodule_candidate_file != module_definition_file)
.filter(|&submodule_candidate_file| {
- IsNoneOr::is_none_or(module_declaration_file, |it| it != submodule_candidate_file)
+ module_declaration_file.is_none_or(|it| it != submodule_candidate_file)
})
.filter_map(|submodule_file| {
let submodule_path = source_root.path_for_file(&submodule_file)?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index d3579fd..495f82d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -3,6 +3,7 @@
mod format_like;
use hir::ItemInNs;
+use ide_db::text_edit::TextEdit;
use ide_db::{
documentation::{Documentation, HasDocs},
imports::insert_use::ImportScope,
@@ -15,7 +16,6 @@
SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR},
TextRange, TextSize,
};
-use text_edit::TextEdit;
use crate::{
completions::postfix::format_like::add_format_like_completions,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 0e1302f..efbee39 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -20,7 +20,6 @@
SyntaxKind::{self, *},
SyntaxToken, TextRange, TextSize, T,
};
-use text_edit::Indel;
use crate::{
context::analysis::{expand_and_analyze, AnalysisResult},
@@ -684,8 +683,7 @@
// actual completion.
let file_with_fake_ident = {
let parse = db.parse(file_id);
- let edit = Indel::insert(offset, COMPLETION_MARKER.to_owned());
- parse.reparse(&edit, file_id.edition()).tree()
+ parse.reparse(TextRange::empty(offset), COMPLETION_MARKER, file_id.edition()).tree()
};
// always pick the token to the immediate left of the cursor, as that is what we are actually
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index 8c97ebd..52f6bed 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -3,6 +3,7 @@
use std::{fmt, mem};
use hir::Mutability;
+use ide_db::text_edit::TextEdit;
use ide_db::{
documentation::Documentation, imports::import_assets::LocatedImport, RootDatabase, SnippetCap,
SymbolKind,
@@ -11,7 +12,6 @@
use smallvec::SmallVec;
use stdx::{impl_from, never};
use syntax::{format_smolstr, Edition, SmolStr, TextRange, TextSize};
-use text_edit::TextEdit;
use crate::{
context::{CompletionContext, PathCompletionCtx},
@@ -426,7 +426,7 @@
self.lookup.as_str()
}
- pub fn ref_match(&self) -> Option<(String, text_edit::Indel, CompletionRelevance)> {
+ pub fn ref_match(&self) -> Option<(String, ide_db::text_edit::Indel, CompletionRelevance)> {
// Relevance of the ref match should be the same as the original
// match, but with exact type match set because self.ref_match
// is only set if there is an exact type match.
@@ -436,7 +436,10 @@
self.ref_match.map(|(mutability, offset)| {
(
format!("&{}{}", mutability.as_keyword_for_ref(), self.label),
- text_edit::Indel::insert(offset, format!("&{}", mutability.as_keyword_for_ref())),
+ ide_db::text_edit::Indel::insert(
+ offset,
+ format!("&{}", mutability.as_keyword_for_ref()),
+ ),
relevance,
)
})
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index a78976d..dfee01b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -10,16 +10,17 @@
#[cfg(test)]
mod tests;
+use ide_db::text_edit::TextEdit;
use ide_db::{
helpers::mod_path_to_ast,
imports::{
import_assets::NameToImport,
insert_use::{self, ImportScope},
},
- items_locator, FilePosition, RootDatabase,
+ items_locator,
+ syntax_helpers::tree_diff::diff,
+ FilePosition, RootDatabase,
};
-use syntax::algo;
-use text_edit::TextEdit;
use crate::{
completions::Completions,
@@ -297,6 +298,6 @@
}
});
- algo::diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
+ diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
Some(vec![import_insert.finish()])
}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 4dd1711..ec3c2fe 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -11,6 +11,7 @@
pub(crate) mod variant;
use hir::{sym, AsAssocItem, HasAttrs, HirDisplay, ModuleDef, ScopeDef, Type};
+use ide_db::text_edit::TextEdit;
use ide_db::{
documentation::{Documentation, HasDocs},
helpers::item_name,
@@ -18,7 +19,6 @@
RootDatabase, SnippetCap, SymbolKind,
};
use syntax::{ast, format_smolstr, AstNode, Edition, SmolStr, SyntaxKind, TextRange, ToSmolStr};
-use text_edit::TextEdit;
use crate::{
context::{DotAccess, DotAccessKind, PathCompletionCtx, PathKind, PatternContext},
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
index 1bbe097..4567935 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
@@ -663,6 +663,7 @@
ba dbg
ba opt_level
ba test
+ ba true
"#]],
);
check(
@@ -674,6 +675,7 @@
ba dbg
ba opt_level
ba test
+ ba true
"#]],
);
}
diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
index c078188..17f0e69 100644
--- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
@@ -35,7 +35,6 @@
profile.workspace = true
stdx.workspace = true
syntax.workspace = true
-text-edit.workspace = true
span.workspace = true
# ide should depend only on the top-level `hir` package. if you need
# something from some `hir-xxx` subpackage, reexport the API via `hir`.
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
index 7474d7b..35e3a8d 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
@@ -100,16 +100,19 @@
hir::db::ConstEvalQuery
hir::db::ConstEvalStaticQuery
hir::db::ConstParamTyQuery
+ hir::db::DynCompatibilityOfTraitQuery
hir::db::FieldTypesQuery
hir::db::FnDefDatumQuery
hir::db::FnDefVarianceQuery
hir::db::GenericDefaultsQuery
hir::db::GenericPredicatesForParamQuery
hir::db::GenericPredicatesQuery
+ hir::db::GenericPredicatesWithoutParentQuery
hir::db::ImplDatumQuery
hir::db::ImplSelfTyQuery
hir::db::ImplTraitQuery
hir::db::IncoherentInherentImplCratesQuery
+ hir::db::InferQuery
hir::db::InherentImplsInBlockQuery
hir::db::InherentImplsInCrateQuery
hir::db::InternCallableDefQuery
@@ -119,7 +122,12 @@
hir::db::InternLifetimeParamIdQuery
hir::db::InternTypeOrConstParamIdQuery
hir::db::LayoutOfAdtQuery
+ hir::db::LayoutOfTyQuery
+ hir::db::LookupImplMethodQuery
+ hir::db::MirBodyForClosureQuery
hir::db::MirBodyQuery
+ hir::db::MonomorphizedMirBodyForClosureQuery
+ hir::db::MonomorphizedMirBodyQuery
hir::db::ProgramClausesForChalkEnvQuery
hir::db::ReturnTypeImplTraitsQuery
hir::db::TargetDataLayoutQuery
@@ -128,13 +136,16 @@
hir::db::TraitImplsInBlockQuery
hir::db::TraitImplsInCrateQuery
hir::db::TraitImplsInDepsQuery
+ hir::db::TraitSolveQuery
hir::db::TyQuery
+ hir::db::TypeAliasImplTraitsQuery
hir::db::ValueTyQuery
// DefDatabase
hir::db::AttrsQuery
hir::db::BlockDefMapQuery
hir::db::BlockItemTreeQuery
+ hir::db::BlockItemTreeWithSourceMapQuery
hir::db::BodyQuery
hir::db::BodyWithSourceMapQuery
hir::db::ConstDataQuery
@@ -145,17 +156,21 @@
hir::db::CrateSupportsNoStdQuery
hir::db::EnumDataQuery
hir::db::EnumVariantDataWithDiagnosticsQuery
+ hir::db::ExpandProcAttrMacrosQuery
hir::db::ExprScopesQuery
hir::db::ExternCrateDeclDataQuery
hir::db::FieldVisibilitiesQuery
hir::db::FieldsAttrsQuery
hir::db::FieldsAttrsSourceMapQuery
hir::db::FileItemTreeQuery
+ hir::db::FileItemTreeWithSourceMapQuery
hir::db::FunctionDataQuery
hir::db::FunctionVisibilityQuery
hir::db::GenericParamsQuery
+ hir::db::GenericParamsWithSourceMapQuery
hir::db::ImplDataWithDiagnosticsQuery
hir::db::ImportMapQuery
+ hir::db::IncludeMacroInvocQuery
hir::db::InternAnonymousConstQuery
hir::db::InternBlockQuery
hir::db::InternConstQuery
@@ -177,7 +192,9 @@
hir::db::InternUseQuery
hir::db::LangItemQuery
hir::db::Macro2DataQuery
+ hir::db::MacroDefQuery
hir::db::MacroRulesDataQuery
+ hir::db::NotableTraitsInDepsQuery
hir::db::ProcMacroDataQuery
hir::db::StaticDataQuery
hir::db::StructDataWithDiagnosticsQuery
@@ -212,6 +229,7 @@
hir::db::MacroArgQuery
hir::db::ParseMacroExpansionErrorQuery
hir::db::ParseMacroExpansionQuery
+ hir::db::ProcMacroSpanQuery
hir::db::ProcMacrosQuery
hir::db::RealSpanMapQuery
@@ -220,7 +238,9 @@
// SourceDatabase
base_db::ParseQuery
+ base_db::ParseErrorsQuery
base_db::CrateGraphQuery
+ base_db::CrateWorkspaceDataQuery
// SourceDatabaseExt
base_db::FileTextQuery
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index 099f26e..fdac4dd 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -5,14 +5,17 @@
// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
+use crate::documentation::{Documentation, HasDocs};
+use crate::famous_defs::FamousDefs;
+use crate::RootDatabase;
use arrayvec::ArrayVec;
use either::Either;
use hir::{
Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field,
Function, GenericParam, HasVisibility, HirDisplay, Impl, InlineAsmOperand, Label, Local, Macro,
- Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait,
- TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility,
+ Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, Struct, ToolModule,
+ Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility,
};
use span::Edition;
use stdx::{format_to, impl_from};
@@ -21,10 +24,6 @@
match_ast, SyntaxKind, SyntaxNode, SyntaxToken,
};
-use crate::documentation::{Documentation, HasDocs};
-use crate::famous_defs::FamousDefs;
-use crate::RootDatabase;
-
// FIXME: a more precise name would probably be `Symbol`?
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub enum Definition {
@@ -179,7 +178,19 @@
Definition::Static(it) => it.docs(db),
Definition::Trait(it) => it.docs(db),
Definition::TraitAlias(it) => it.docs(db),
- Definition::TypeAlias(it) => it.docs(db),
+ Definition::TypeAlias(it) => {
+ it.docs(db).or_else(|| {
+ // docs are missing, try to fall back to the docs of the aliased item.
+ let adt = it.ty(db).as_adt()?;
+ let docs = adt.docs(db)?;
+ let docs = format!(
+ "*This is the documentation for* `{}`\n\n{}",
+ adt.display(db, edition),
+ docs.as_str()
+ );
+ Some(Documentation::new(docs))
+ })
+ }
Definition::BuiltinType(it) => {
famous_defs.and_then(|fd| {
// std exposes prim_{} modules with docstrings on the root to document the builtins
@@ -319,6 +330,8 @@
.map(IdentClass::NameClass)
.or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass))
},
+ ast::RangePat(range_pat) => OperatorClass::classify_range_pat(sema, &range_pat).map(IdentClass::Operator),
+ ast::RangeExpr(range_expr) => OperatorClass::classify_range_expr(sema, &range_expr).map(IdentClass::Operator),
ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator),
ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator),
ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator),
@@ -372,6 +385,9 @@
| OperatorClass::Index(func)
| OperatorClass::Try(func),
) => res.push(Definition::Function(func)),
+ IdentClass::Operator(OperatorClass::Range(struct0)) => {
+ res.push(Definition::Adt(Adt::Struct(struct0)))
+ }
}
res
}
@@ -546,6 +562,7 @@
#[derive(Debug)]
pub enum OperatorClass {
+ Range(Struct),
Await(Function),
Prefix(Function),
Index(Function),
@@ -554,6 +571,20 @@
}
impl OperatorClass {
+ pub fn classify_range_pat(
+ sema: &Semantics<'_, RootDatabase>,
+ range_pat: &ast::RangePat,
+ ) -> Option<OperatorClass> {
+ sema.resolve_range_pat(range_pat).map(OperatorClass::Range)
+ }
+
+ pub fn classify_range_expr(
+ sema: &Semantics<'_, RootDatabase>,
+ range_expr: &ast::RangeExpr,
+ ) -> Option<OperatorClass> {
+ sema.resolve_range_expr(range_expr).map(OperatorClass::Range)
+ }
+
pub fn classify_await(
sema: &Semantics<'_, RootDatabase>,
await_expr: &ast::AwaitExpr,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
index 5e443ba..b52a325 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
@@ -5,11 +5,11 @@
resolve_doc_path_on, sym, AttrId, AttrSourceMap, AttrsWithOwner, HasAttrs, InFile,
};
use itertools::Itertools;
+use span::{TextRange, TextSize};
use syntax::{
ast::{self, IsString},
AstToken,
};
-use text_edit::{TextRange, TextSize};
/// Holds documentation
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
index aed093f..81260c3 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
@@ -19,6 +19,7 @@
pub mod search;
pub mod source_change;
pub mod symbol_index;
+pub mod text_edit;
pub mod traits;
pub mod ty_filter;
pub mod use_trivial_constructor;
@@ -36,6 +37,7 @@
pub mod syntax_helpers {
pub mod format_string;
pub mod format_string_exprs;
+ pub mod tree_diff;
pub use hir::prettify_macro_expansion;
pub mod node_ext;
pub mod suggest_name;
@@ -293,3 +295,35 @@
}
}
}
+
+pub struct Ranker<'a> {
+ pub kind: parser::SyntaxKind,
+ pub text: &'a str,
+ pub ident_kind: bool,
+}
+
+impl<'a> Ranker<'a> {
+ pub const MAX_RANK: usize = 0b1110;
+
+ pub fn from_token(token: &'a syntax::SyntaxToken) -> Self {
+ let kind = token.kind();
+ Ranker { kind, text: token.text(), ident_kind: kind.is_any_identifier() }
+ }
+
+ /// A utility function that ranks a token again a given kind and text, returning a number that
+ /// represents how close the token is to the given kind and text.
+ pub fn rank_token(&self, tok: &syntax::SyntaxToken) -> usize {
+ let tok_kind = tok.kind();
+
+ let exact_same_kind = tok_kind == self.kind;
+ let both_idents = exact_same_kind || (tok_kind.is_any_identifier() && self.ident_kind);
+ let same_text = tok.text() == self.text;
+ // anything that mapped into a token tree has likely no semantic information
+ let no_tt_parent =
+ tok.parent().map_or(false, |it| it.kind() != parser::SyntaxKind::TOKEN_TREE);
+ (both_idents as usize)
+ | ((exact_same_kind as usize) << 1)
+ | ((same_text as usize) << 2)
+ | ((no_tt_parent as usize) << 3)
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index f1404ed9..1d1679c 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -22,6 +22,7 @@
//! Our current behavior is ¯\_(ツ)_/¯.
use std::fmt;
+use crate::text_edit::{TextEdit, TextEditBuilder};
use base_db::AnchoredPathBuf;
use either::Either;
use hir::{FieldSource, FileRange, HirFileIdExt, InFile, ModuleSource, Semantics};
@@ -32,7 +33,6 @@
utils::is_raw_identifier,
AstNode, SyntaxKind, TextRange, T,
};
-use text_edit::{TextEdit, TextEditBuilder};
use crate::{
defs::Definition,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
index 73073e9..27ff91d 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
@@ -5,7 +5,8 @@
use std::{collections::hash_map::Entry, iter, mem};
-use crate::{assists::Command, SnippetCap};
+use crate::text_edit::{TextEdit, TextEditBuilder};
+use crate::{assists::Command, syntax_helpers::tree_diff::diff, SnippetCap};
use base_db::AnchoredPathBuf;
use itertools::Itertools;
use nohash_hasher::IntMap;
@@ -13,11 +14,9 @@
use span::FileId;
use stdx::never;
use syntax::{
- algo,
syntax_editor::{SyntaxAnnotation, SyntaxEditor},
AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize,
};
-use text_edit::{TextEdit, TextEditBuilder};
#[derive(Default, Debug, Clone)]
pub struct SourceChange {
@@ -315,7 +314,7 @@
}
let mut edit = TextEdit::builder();
- algo::diff(edit_result.old_root(), edit_result.new_root()).into_text_edit(&mut edit);
+ diff(edit_result.old_root(), edit_result.new_root()).into_text_edit(&mut edit);
let edit = edit.finish();
let snippet_edit =
@@ -334,7 +333,7 @@
});
if let Some(tm) = self.mutated_tree.take() {
- algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit);
+ diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit);
}
let edit = mem::take(&mut self.edit).finish();
@@ -373,7 +372,7 @@
self.edit.replace(range, replace_with.into())
}
pub fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
- algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
+ diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
}
pub fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) {
let file_system_edit = FileSystemEdit::CreateFile { dst, initial_contents: content.into() };
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs
new file mode 100644
index 0000000..02e24c4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs
@@ -0,0 +1,559 @@
+//! Basic tree diffing functionality.
+use rustc_hash::FxHashMap;
+use syntax::{NodeOrToken, SyntaxElement, SyntaxNode};
+
+use crate::{text_edit::TextEditBuilder, FxIndexMap};
+
+#[derive(Debug, Hash, PartialEq, Eq)]
+enum TreeDiffInsertPos {
+ After(SyntaxElement),
+ AsFirstChild(SyntaxElement),
+}
+
+#[derive(Debug)]
+pub struct TreeDiff {
+ replacements: FxHashMap<SyntaxElement, SyntaxElement>,
+ deletions: Vec<SyntaxElement>,
+ // the vec as well as the indexmap are both here to preserve order
+ insertions: FxIndexMap<TreeDiffInsertPos, Vec<SyntaxElement>>,
+}
+
+impl TreeDiff {
+ pub fn into_text_edit(&self, builder: &mut TextEditBuilder) {
+ let _p = tracing::info_span!("into_text_edit").entered();
+
+ for (anchor, to) in &self.insertions {
+ let offset = match anchor {
+ TreeDiffInsertPos::After(it) => it.text_range().end(),
+ TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(),
+ };
+ to.iter().for_each(|to| builder.insert(offset, to.to_string()));
+ }
+ for (from, to) in &self.replacements {
+ builder.replace(from.text_range(), to.to_string());
+ }
+ for text_range in self.deletions.iter().map(SyntaxElement::text_range) {
+ builder.delete(text_range);
+ }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.replacements.is_empty() && self.deletions.is_empty() && self.insertions.is_empty()
+ }
+}
+
+/// Finds a (potentially minimal) diff, which, applied to `from`, will result in `to`.
+///
+/// Specifically, returns a structure that consists of a replacements, insertions and deletions
+/// such that applying this map on `from` will result in `to`.
+///
+/// This function tries to find a fine-grained diff.
+pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
+ let _p = tracing::info_span!("diff").entered();
+
+ let mut diff = TreeDiff {
+ replacements: FxHashMap::default(),
+ insertions: FxIndexMap::default(),
+ deletions: Vec::new(),
+ };
+ let (from, to) = (from.clone().into(), to.clone().into());
+
+ if !syntax_element_eq(&from, &to) {
+ go(&mut diff, from, to);
+ }
+ return diff;
+
+ fn syntax_element_eq(lhs: &SyntaxElement, rhs: &SyntaxElement) -> bool {
+ lhs.kind() == rhs.kind()
+ && lhs.text_range().len() == rhs.text_range().len()
+ && match (&lhs, &rhs) {
+ (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => {
+ lhs == rhs || lhs.text() == rhs.text()
+ }
+ (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(),
+ _ => false,
+ }
+ }
+
+ // FIXME: this is horribly inefficient. I bet there's a cool algorithm to diff trees properly.
+ fn go(diff: &mut TreeDiff, lhs: SyntaxElement, rhs: SyntaxElement) {
+ let (lhs, rhs) = match lhs.as_node().zip(rhs.as_node()) {
+ Some((lhs, rhs)) => (lhs, rhs),
+ _ => {
+ cov_mark::hit!(diff_node_token_replace);
+ diff.replacements.insert(lhs, rhs);
+ return;
+ }
+ };
+
+ let mut look_ahead_scratch = Vec::default();
+
+ let mut rhs_children = rhs.children_with_tokens();
+ let mut lhs_children = lhs.children_with_tokens();
+ let mut last_lhs = None;
+ loop {
+ let lhs_child = lhs_children.next();
+ match (lhs_child.clone(), rhs_children.next()) {
+ (None, None) => break,
+ (None, Some(element)) => {
+ let insert_pos = match last_lhs.clone() {
+ Some(prev) => {
+ cov_mark::hit!(diff_insert);
+ TreeDiffInsertPos::After(prev)
+ }
+ // first iteration, insert into out parent as the first child
+ None => {
+ cov_mark::hit!(diff_insert_as_first_child);
+ TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
+ }
+ };
+ diff.insertions.entry(insert_pos).or_default().push(element);
+ }
+ (Some(element), None) => {
+ cov_mark::hit!(diff_delete);
+ diff.deletions.push(element);
+ }
+ (Some(ref lhs_ele), Some(ref rhs_ele)) if syntax_element_eq(lhs_ele, rhs_ele) => {}
+ (Some(lhs_ele), Some(rhs_ele)) => {
+ // nodes differ, look for lhs_ele in rhs, if its found we can mark everything up
+ // until that element as insertions. This is important to keep the diff minimal
+ // in regards to insertions that have been actually done, this is important for
+ // use insertions as we do not want to replace the entire module node.
+ look_ahead_scratch.push(rhs_ele.clone());
+ let mut rhs_children_clone = rhs_children.clone();
+ let mut insert = false;
+ for rhs_child in &mut rhs_children_clone {
+ if syntax_element_eq(&lhs_ele, &rhs_child) {
+ cov_mark::hit!(diff_insertions);
+ insert = true;
+ break;
+ }
+ look_ahead_scratch.push(rhs_child);
+ }
+ let drain = look_ahead_scratch.drain(..);
+ if insert {
+ let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) {
+ TreeDiffInsertPos::After(prev)
+ } else {
+ cov_mark::hit!(insert_first_child);
+ TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
+ };
+
+ diff.insertions.entry(insert_pos).or_default().extend(drain);
+ rhs_children = rhs_children_clone;
+ } else {
+ go(diff, lhs_ele, rhs_ele);
+ }
+ }
+ }
+ last_lhs = lhs_child.or(last_lhs);
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use expect_test::{expect, Expect};
+ use itertools::Itertools;
+ use parser::{Edition, SyntaxKind};
+ use syntax::{AstNode, SourceFile, SyntaxElement};
+
+ use crate::text_edit::TextEdit;
+
+ #[test]
+ fn replace_node_token() {
+ cov_mark::check!(diff_node_token_replace);
+ check_diff(
+ r#"use node;"#,
+ r#"ident"#,
+ expect![[r#"
+ insertions:
+
+
+
+ replacements:
+
+ Line 0: Token(USE_KW@0..3 "use") -> ident
+
+ deletions:
+
+ Line 1: " "
+ Line 1: node
+ Line 1: ;
+ "#]],
+ );
+ }
+
+ #[test]
+ fn replace_parent() {
+ cov_mark::check!(diff_insert_as_first_child);
+ check_diff(
+ r#""#,
+ r#"use foo::bar;"#,
+ expect![[r#"
+ insertions:
+
+ Line 0: AsFirstChild(Node(SOURCE_FILE@0..0))
+ -> use foo::bar;
+
+ replacements:
+
+
+
+ deletions:
+
+
+ "#]],
+ );
+ }
+
+ #[test]
+ fn insert_last() {
+ cov_mark::check!(diff_insert);
+ check_diff(
+ r#"
+use foo;
+use bar;"#,
+ r#"
+use foo;
+use bar;
+use baz;"#,
+ expect![[r#"
+ insertions:
+
+ Line 2: After(Node(USE@10..18))
+ -> "\n"
+ -> use baz;
+
+ replacements:
+
+
+
+ deletions:
+
+
+ "#]],
+ );
+ }
+
+ #[test]
+ fn insert_middle() {
+ check_diff(
+ r#"
+use foo;
+use baz;"#,
+ r#"
+use foo;
+use bar;
+use baz;"#,
+ expect![[r#"
+ insertions:
+
+ Line 2: After(Token(WHITESPACE@9..10 "\n"))
+ -> use bar;
+ -> "\n"
+
+ replacements:
+
+
+
+ deletions:
+
+
+ "#]],
+ )
+ }
+
+ #[test]
+ fn insert_first() {
+ check_diff(
+ r#"
+use bar;
+use baz;"#,
+ r#"
+use foo;
+use bar;
+use baz;"#,
+ expect![[r#"
+ insertions:
+
+ Line 0: After(Token(WHITESPACE@0..1 "\n"))
+ -> use foo;
+ -> "\n"
+
+ replacements:
+
+
+
+ deletions:
+
+
+ "#]],
+ )
+ }
+
+ #[test]
+ fn first_child_insertion() {
+ cov_mark::check!(insert_first_child);
+ check_diff(
+ r#"fn main() {
+ stdi
+ }"#,
+ r#"use foo::bar;
+
+ fn main() {
+ stdi
+ }"#,
+ expect![[r#"
+ insertions:
+
+ Line 0: AsFirstChild(Node(SOURCE_FILE@0..30))
+ -> use foo::bar;
+ -> "\n\n "
+
+ replacements:
+
+
+
+ deletions:
+
+
+ "#]],
+ );
+ }
+
+ #[test]
+ fn delete_last() {
+ cov_mark::check!(diff_delete);
+ check_diff(
+ r#"use foo;
+ use bar;"#,
+ r#"use foo;"#,
+ expect![[r#"
+ insertions:
+
+
+
+ replacements:
+
+
+
+ deletions:
+
+ Line 1: "\n "
+ Line 2: use bar;
+ "#]],
+ );
+ }
+
+ #[test]
+ fn delete_middle() {
+ cov_mark::check!(diff_insertions);
+ check_diff(
+ r#"
+use expect_test::{expect, Expect};
+use text_edit::TextEdit;
+
+use crate::AstNode;
+"#,
+ r#"
+use expect_test::{expect, Expect};
+
+use crate::AstNode;
+"#,
+ expect![[r#"
+ insertions:
+
+ Line 1: After(Node(USE@1..35))
+ -> "\n\n"
+ -> use crate::AstNode;
+
+ replacements:
+
+
+
+ deletions:
+
+ Line 2: use text_edit::TextEdit;
+ Line 3: "\n\n"
+ Line 4: use crate::AstNode;
+ Line 5: "\n"
+ "#]],
+ )
+ }
+
+ #[test]
+ fn delete_first() {
+ check_diff(
+ r#"
+use text_edit::TextEdit;
+
+use crate::AstNode;
+"#,
+ r#"
+use crate::AstNode;
+"#,
+ expect![[r#"
+ insertions:
+
+
+
+ replacements:
+
+ Line 2: Token(IDENT@5..14 "text_edit") -> crate
+ Line 2: Token(IDENT@16..24 "TextEdit") -> AstNode
+ Line 2: Token(WHITESPACE@25..27 "\n\n") -> "\n"
+
+ deletions:
+
+ Line 3: use crate::AstNode;
+ Line 4: "\n"
+ "#]],
+ )
+ }
+
+ #[test]
+ fn merge_use() {
+ check_diff(
+ r#"
+use std::{
+ fmt,
+ hash::BuildHasherDefault,
+ ops::{self, RangeInclusive},
+};
+"#,
+ r#"
+use std::fmt;
+use std::hash::BuildHasherDefault;
+use std::ops::{self, RangeInclusive};
+"#,
+ expect![[r#"
+ insertions:
+
+ Line 2: After(Node(PATH_SEGMENT@5..8))
+ -> ::
+ -> fmt
+ Line 6: After(Token(WHITESPACE@86..87 "\n"))
+ -> use std::hash::BuildHasherDefault;
+ -> "\n"
+ -> use std::ops::{self, RangeInclusive};
+ -> "\n"
+
+ replacements:
+
+ Line 2: Token(IDENT@5..8 "std") -> std
+
+ deletions:
+
+ Line 2: ::
+ Line 2: {
+ fmt,
+ hash::BuildHasherDefault,
+ ops::{self, RangeInclusive},
+ }
+ "#]],
+ )
+ }
+
+ #[test]
+ fn early_return_assist() {
+ check_diff(
+ r#"
+fn main() {
+ if let Ok(x) = Err(92) {
+ foo(x);
+ }
+}
+ "#,
+ r#"
+fn main() {
+ let x = match Err(92) {
+ Ok(it) => it,
+ _ => return,
+ };
+ foo(x);
+}
+ "#,
+ expect![[r#"
+ insertions:
+
+ Line 3: After(Node(BLOCK_EXPR@40..63))
+ -> " "
+ -> match Err(92) {
+ Ok(it) => it,
+ _ => return,
+ }
+ -> ;
+ Line 3: After(Node(IF_EXPR@17..63))
+ -> "\n "
+ -> foo(x);
+
+ replacements:
+
+ Line 3: Token(IF_KW@17..19 "if") -> let
+ Line 3: Token(LET_KW@20..23 "let") -> x
+ Line 3: Node(BLOCK_EXPR@40..63) -> =
+
+ deletions:
+
+ Line 3: " "
+ Line 3: Ok(x)
+ Line 3: " "
+ Line 3: =
+ Line 3: " "
+ Line 3: Err(92)
+ "#]],
+ )
+ }
+
+ fn check_diff(from: &str, to: &str, expected_diff: Expect) {
+ let from_node = SourceFile::parse(from, Edition::CURRENT).tree().syntax().clone();
+ let to_node = SourceFile::parse(to, Edition::CURRENT).tree().syntax().clone();
+ let diff = super::diff(&from_node, &to_node);
+
+ let line_number =
+ |syn: &SyntaxElement| from[..syn.text_range().start().into()].lines().count();
+
+ let fmt_syntax = |syn: &SyntaxElement| match syn.kind() {
+ SyntaxKind::WHITESPACE => format!("{:?}", syn.to_string()),
+ _ => format!("{syn}"),
+ };
+
+ let insertions =
+ diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> {
+ f(&format!(
+ "Line {}: {:?}\n-> {}",
+ line_number(match k {
+ super::TreeDiffInsertPos::After(syn) => syn,
+ super::TreeDiffInsertPos::AsFirstChild(syn) => syn,
+ }),
+ k,
+ v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v)))
+ ))
+ });
+
+ let replacements = diff
+ .replacements
+ .iter()
+ .sorted_by_key(|(syntax, _)| syntax.text_range().start())
+ .format_with("\n", |(k, v), f| {
+ f(&format!("Line {}: {k:?} -> {}", line_number(k), fmt_syntax(v)))
+ });
+
+ let deletions = diff
+ .deletions
+ .iter()
+ .format_with("\n", |v, f| f(&format!("Line {}: {}", line_number(v), fmt_syntax(v))));
+
+ let actual = format!(
+ "insertions:\n\n{insertions}\n\nreplacements:\n\n{replacements}\n\ndeletions:\n\n{deletions}\n"
+ );
+ expected_diff.assert_eq(&actual);
+
+ let mut from = from.to_owned();
+ let mut text_edit = TextEdit::builder();
+ diff.into_text_edit(&mut text_edit);
+ text_edit.finish().apply(&mut from);
+ assert_eq!(&*from, to, "diff did not turn `from` to `to`");
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs
similarity index 98%
rename from src/tools/rust-analyzer/crates/text-edit/src/lib.rs
rename to src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs
index 3efe085..0c675f0 100644
--- a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs
@@ -5,8 +5,8 @@
//! rust-analyzer.
use itertools::Itertools;
+pub use span::{TextRange, TextSize};
use std::cmp::max;
-pub use text_size::{TextRange, TextSize};
/// `InsertDelete` -- a single "atomic" change to text
///
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
index bf54f4a..281a08e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
@@ -22,7 +22,6 @@
# local deps
stdx.workspace = true
syntax.workspace = true
-text-edit.workspace = true
cfg.workspace = true
hir.workspace = true
ide-db.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs
index c7071d1..876c2cc 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs
@@ -1,9 +1,9 @@
//! Suggests shortening `Foo { field: field }` to `Foo { field }` in both
//! expressions and patterns.
+use ide_db::text_edit::TextEdit;
use ide_db::{source_change::SourceChange, EditionedFileId, FileRange};
use syntax::{ast, match_ast, AstNode, SyntaxNode};
-use text_edit::TextEdit;
use crate::{fix, Diagnostic, DiagnosticCode};
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
index 1f8f805..4c0c685 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -195,4 +195,20 @@
"#,
);
}
+
+ #[test]
+ fn cfg_true_false() {
+ check(
+ r#"
+ #[cfg(false)] fn inactive() {}
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: false is disabled
+
+ #[cfg(true)] fn active() {}
+
+ #[cfg(any(not(true)), false)] fn inactive2() {}
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: true is enabled
+
+"#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index ccb33fe..dca889d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -2,6 +2,7 @@
//! example.
use hir::{ImportPathConfig, PathResolution, Semantics};
+use ide_db::text_edit::TextEdit;
use ide_db::{
helpers::mod_path_to_ast,
imports::insert_use::{insert_use, ImportScope},
@@ -14,7 +15,6 @@
ast::{self, make},
Edition, SyntaxKind, SyntaxNode,
};
-use text_edit::TextEdit;
use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsConfig, Severity};
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
index 6a97669..e177b72 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -3,14 +3,19 @@
// Diagnostic: macro-error
//
// This diagnostic is shown for macro expansion errors.
+
+// Diagnostic: proc-macros-disabled
+//
+// This diagnostic is shown for proc macros where proc macros have been disabled.
+
+// Diagnostic: proc-macro-disabled
+//
+// This diagnostic is shown for proc macros that has been specifically disabled via `rust-analyzer.procMacro.ignored`.
pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic {
// Use more accurate position if available.
let display_range = ctx.resolve_precise_location(&d.node, d.precise_location);
Diagnostic::new(
- DiagnosticCode::Ra(
- "macro-error",
- if d.error { Severity::Error } else { Severity::WeakWarning },
- ),
+ DiagnosticCode::Ra(d.kind, if d.error { Severity::Error } else { Severity::WeakWarning }),
d.message.clone(),
display_range,
)
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 86c237f..fd1044e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -5,15 +5,14 @@
};
use ide_db::{
assists::Assist, famous_defs::FamousDefs, imports::import_assets::item_for_path_search,
- source_change::SourceChange, use_trivial_constructor::use_trivial_constructor, FxHashMap,
+ source_change::SourceChange, syntax_helpers::tree_diff::diff, text_edit::TextEdit,
+ use_trivial_constructor::use_trivial_constructor, FxHashMap,
};
use stdx::format_to;
use syntax::{
- algo,
ast::{self, make},
AstNode, Edition, SyntaxNode, SyntaxNodePtr, ToSmolStr,
};
-use text_edit::TextEdit;
use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
@@ -77,7 +76,7 @@
// FIXME: this also currently discards a lot of whitespace in the input... we really need a formatter here
builder.replace(old_range.range, new_syntax.to_string());
} else {
- algo::diff(old_syntax, new_syntax).into_text_edit(&mut builder);
+ diff(old_syntax, new_syntax).into_text_edit(&mut builder);
}
builder.finish()
};
@@ -308,22 +307,27 @@
fn regular(a: S) {
let s;
S { s, .. } = a;
+ _ = s;
}
fn nested(a: S2) {
let s;
S2 { s: S { s, .. }, .. } = a;
+ _ = s;
}
fn in_tuple(a: (S,)) {
let s;
(S { s, .. },) = a;
+ _ = s;
}
fn in_array(a: [S;1]) {
let s;
[S { s, .. },] = a;
+ _ = s;
}
fn in_tuple_struct(a: T) {
let s;
T(S { s, .. }) = a;
+ _ = s;
}
",
);
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 44be53b..a630d3c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -1,9 +1,9 @@
use hir::db::ExpandDatabase;
use hir::HirFileIdExt;
+use ide_db::text_edit::TextEdit;
use ide_db::{assists::Assist, source_change::SourceChange};
use syntax::{ast, SyntaxNode};
use syntax::{match_ast, AstNode};
-use text_edit::TextEdit;
use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
@@ -32,7 +32,8 @@
}
let root = ctx.sema.db.parse_or_expand(d.expr.file_id);
- let expr = d.expr.value.to_node(&root);
+ let node = d.expr.value.to_node(&root);
+ let expr = node.syntax().ancestors().find_map(ast::Expr::cast)?;
let node_to_add_unsafe_block = pick_best_node_to_add_unsafe_block(&expr)?;
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 6fa0e7a..1397979 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -1,6 +1,7 @@
+use hir::db::ExpandDatabase;
use ide_db::source_change::SourceChange;
-use syntax::{AstNode, SyntaxKind, SyntaxNode, SyntaxToken, T};
-use text_edit::TextEdit;
+use ide_db::text_edit::TextEdit;
+use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, T};
use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
@@ -8,18 +9,27 @@
//
// This diagnostic is triggered on mutating an immutable variable.
pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option<Diagnostic> {
- if d.span.file_id.macro_file().is_some() {
- // FIXME: Our infra can't handle allow from within macro expansions rn
- return None;
- }
+ let root = ctx.sema.db.parse_or_expand(d.span.file_id);
+ let node = d.span.value.to_node(&root);
+ let mut span = d.span;
+ if let Some(parent) = node.parent() {
+ if ast::BinExpr::can_cast(parent.kind()) {
+ // In case of an assignment, the diagnostic is provided on the variable name.
+ // We want to expand it to include the whole assignment, but only when this
+ // is an ordinary assignment, not a destructuring assignment. So, the direct
+ // parent is an assignment expression.
+ span = d.span.with_value(SyntaxNodePtr::new(&parent));
+ }
+ };
+
let fixes = (|| {
if d.local.is_ref(ctx.sema.db) {
// There is no simple way to add `mut` to `ref x` and `ref mut x`
return None;
}
- let file_id = d.span.file_id.file_id()?;
+ let file_id = span.file_id.file_id()?;
let mut edit_builder = TextEdit::builder();
- let use_range = d.span.value.text_range();
+ let use_range = span.value.text_range();
for source in d.local.sources(ctx.sema.db) {
let Some(ast) = source.name() else { continue };
// FIXME: macros
@@ -33,6 +43,7 @@
use_range,
)])
})();
+
Some(
Diagnostic::new_with_syntax_node_ptr(
ctx,
@@ -42,7 +53,7 @@
"cannot mutate immutable variable `{}`",
d.local.name(ctx.sema.db).display(ctx.sema.db, ctx.edition)
),
- d.span,
+ span,
)
.with_fixes(fixes),
)
@@ -53,10 +64,6 @@
// This diagnostic is triggered when a mutable variable isn't actually mutated.
pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Option<Diagnostic> {
let ast = d.local.primary_source(ctx.sema.db).syntax_ptr();
- if ast.file_id.macro_file().is_some() {
- // FIXME: Our infra can't handle allow from within macro expansions rn
- return None;
- }
let fixes = (|| {
let file_id = ast.file_id.file_id()?;
let mut edit_builder = TextEdit::builder();
@@ -937,7 +944,6 @@
#[test]
fn closure() {
- // FIXME: Diagnostic spans are inconsistent inside and outside closure
check_diagnostics(
r#"
//- minicore: copy, fn
@@ -950,11 +956,11 @@
fn f() {
let x = 5;
let closure1 = || { x = 2; };
- //^ 💡 error: cannot mutate immutable variable `x`
+ //^^^^^ 💡 error: cannot mutate immutable variable `x`
let _ = closure1();
//^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
let closure2 = || { x = x; };
- //^ 💡 error: cannot mutate immutable variable `x`
+ //^^^^^ 💡 error: cannot mutate immutable variable `x`
let closure3 = || {
let x = 2;
x = 5;
@@ -996,7 +1002,7 @@
|| {
let x = 2;
|| { || { x = 5; } }
- //^ 💡 error: cannot mutate immutable variable `x`
+ //^^^^^ 💡 error: cannot mutate immutable variable `x`
}
}
};
@@ -1283,4 +1289,19 @@
"#,
);
}
+
+ #[test]
+ fn destructuring_assignment_needs_mut() {
+ check_diagnostics(
+ r#"
+//- minicore: fn
+
+fn main() {
+ let mut var = 1;
+ let mut func = || (var,) = (2,);
+ func();
+}
+ "#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index dfadef1..e5d8719 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -1,11 +1,11 @@
use either::Either;
use hir::{db::ExpandDatabase, HasSource, HirDisplay, HirFileIdExt, Semantics, VariantId};
+use ide_db::text_edit::TextEdit;
use ide_db::{source_change::SourceChange, EditionedFileId, RootDatabase};
use syntax::{
ast::{self, edit::IndentLevel, make},
AstNode,
};
-use text_edit::TextEdit;
use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
index 62bc1f3..c8e3cff 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
@@ -1,7 +1,7 @@
use hir::{db::ExpandDatabase, diagnostics::RemoveTrailingReturn, FileRange};
+use ide_db::text_edit::TextEdit;
use ide_db::{assists::Assist, source_change::SourceChange};
use syntax::{ast, AstNode};
-use text_edit::TextEdit;
use crate::{adjusted_display_range, fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
index 448df1c..a46c486 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
@@ -1,4 +1,5 @@
use hir::{db::ExpandDatabase, diagnostics::RemoveUnnecessaryElse, HirFileIdExt};
+use ide_db::text_edit::TextEdit;
use ide_db::{assists::Assist, source_change::SourceChange};
use itertools::Itertools;
use syntax::{
@@ -8,7 +9,6 @@
},
AstNode, SyntaxToken, TextRange,
};
-use text_edit::TextEdit;
use crate::{
adjusted_display_range, fix, Diagnostic, DiagnosticCode, DiagnosticsContext, Severity,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index 1864720..f481365 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -1,10 +1,10 @@
use hir::{db::ExpandDatabase, HirFileIdExt, InFile};
use ide_db::source_change::SourceChange;
+use ide_db::text_edit::TextEdit;
use syntax::{
ast::{self, HasArgList},
AstNode, TextRange,
};
-use text_edit::TextEdit;
use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index 3de51ca..1363a8f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -1,11 +1,11 @@
use hir::{db::ExpandDatabase, HasSource, HirDisplay};
+use ide_db::text_edit::TextRange;
use ide_db::{
assists::{Assist, AssistId, AssistKind},
label::Label,
source_change::SourceChangeBuilder,
};
use syntax::ToSmolStr;
-use text_edit::TextRange;
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 90f88d6..93fe937 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -1,5 +1,6 @@
use either::Either;
use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type};
+use ide_db::text_edit::TextEdit;
use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
use syntax::{
ast::{
@@ -9,7 +10,6 @@
},
AstNode, AstPtr, TextSize,
};
-use text_edit::TextEdit;
use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index 6994a7e..3ad84f7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -3,13 +3,13 @@
term_search::{term_search, TermSearchConfig, TermSearchCtx},
ClosureStyle, HirDisplay, ImportPathConfig,
};
+use ide_db::text_edit::TextEdit;
use ide_db::{
assists::{Assist, AssistId, AssistKind, GroupLabel},
label::Label,
source_change::SourceChange,
};
use itertools::Itertools;
-use text_edit::TextEdit;
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
index 6af36fb..d16bfb8 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
@@ -107,4 +107,34 @@
"#,
);
}
+
+ #[test]
+ fn macro_expansion_can_refer_label_defined_before_macro_definition() {
+ check_diagnostics(
+ r#"
+fn foo() {
+ 'bar: loop {
+ macro_rules! m {
+ () => { break 'bar };
+ }
+ m!();
+ }
+}
+"#,
+ );
+ check_diagnostics(
+ r#"
+fn foo() {
+ 'bar: loop {
+ macro_rules! m {
+ () => { break 'bar };
+ }
+ 'bar: loop {
+ m!();
+ }
+ }
+}
+"#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index e0822fc..13591df 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -3,6 +3,7 @@
use std::iter;
use hir::{db::DefDatabase, DefMap, InFile, ModuleSource};
+use ide_db::text_edit::TextEdit;
use ide_db::{
base_db::{FileLoader, SourceDatabase, SourceRootDatabase},
source_change::SourceChange,
@@ -13,7 +14,6 @@
ast::{self, edit::IndentLevel, HasModuleItem, HasName},
AstNode, TextRange,
};
-use text_edit::TextEdit;
use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, Severity};
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 76d624c..656bedf 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -1,6 +1,7 @@
use std::iter;
use hir::{db::ExpandDatabase, Adt, FileRange, HasSource, HirDisplay, InFile, Struct, Union};
+use ide_db::text_edit::TextEdit;
use ide_db::{
assists::{Assist, AssistId, AssistKind},
helpers::is_editable_crate,
@@ -16,7 +17,6 @@
ast::{edit::AstNodeEdit, Type},
SyntaxNode,
};
-use text_edit::TextEdit;
use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext};
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
index 9a81682..68f14a9 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
@@ -11,7 +11,7 @@
ctx,
DiagnosticCode::RustcHardError("E0425"),
"no such value in this scope",
- d.expr.map(Into::into),
+ d.expr_or_pat.map(Into::into),
)
.experimental()
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
index 5b59612..0d1c977 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
@@ -82,4 +82,29 @@
"#,
);
}
+
+ #[test]
+ fn no_unresolved_panic_inside_mod_inside_fn() {
+ check_diagnostics(
+ r#"
+//- /core.rs library crate:core
+#[macro_export]
+macro_rules! panic {
+ () => {};
+}
+
+//- /lib.rs crate:foo deps:core
+#[macro_use]
+extern crate core;
+
+fn foo() {
+ mod init {
+ pub fn init() {
+ panic!();
+ }
+ }
+}
+ "#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index c0d038a..81cb452 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -1,4 +1,5 @@
use hir::{db::ExpandDatabase, AssocItem, FileRange, HirDisplay, InFile};
+use ide_db::text_edit::TextEdit;
use ide_db::{
assists::{Assist, AssistId, AssistKind},
label::Label,
@@ -8,7 +9,6 @@
ast::{self, make, HasArgList},
format_smolstr, AstNode, SmolStr, TextRange, ToSmolStr,
};
-use text_edit::TextEdit;
use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext};
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
index 84007b1..67ece56 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -1,4 +1,5 @@
use hir::Name;
+use ide_db::text_edit::TextEdit;
use ide_db::{
assists::{Assist, AssistId, AssistKind},
label::Label,
@@ -6,7 +7,6 @@
FileRange, RootDatabase,
};
use syntax::{Edition, TextRange};
-use text_edit::TextEdit;
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
index 2d380ae..e5c2eca 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
@@ -1,8 +1,8 @@
use hir::InFile;
+use ide_db::text_edit::TextEdit;
use ide_db::{source_change::SourceChange, EditionedFileId, FileRange};
use itertools::Itertools;
use syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr};
-use text_edit::TextEdit;
use crate::{fix, Diagnostic, DiagnosticCode};
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
index fad62fa..2561467 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
@@ -24,7 +24,6 @@
parser.workspace = true
stdx.workspace = true
syntax.workspace = true
-text-edit.workspace = true
[dev-dependencies]
expect-test = "1.4.0"
@@ -34,4 +33,4 @@
test-fixture.workspace = true
[lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
index 54236ea..eaca95d 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
@@ -84,10 +84,10 @@
use crate::{errors::bail, matching::MatchFailureReason};
use hir::{FileRange, Semantics};
+use ide_db::text_edit::TextEdit;
use ide_db::{base_db::SourceDatabase, EditionedFileId, FileId, FxHashMap, RootDatabase};
use resolving::ResolvedRule;
use syntax::{ast, AstNode, SyntaxNode, TextRange};
-use text_edit::TextEdit;
// A structured search replace rule. Create by calling `parse` on a str.
#[derive(Debug)]
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs
index e752ee3..ea40d5b 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs
@@ -190,7 +190,7 @@
let mut res = FxHashMap::default();
for t in &self.tokens {
if let PatternElement::Placeholder(placeholder) = t {
- res.insert(SmolStr::new(placeholder.stand_in_name.clone()), placeholder.clone());
+ res.insert(SmolStr::new(&placeholder.stand_in_name), placeholder.clone());
}
}
res
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
index 6575660..11c1615 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
@@ -1,5 +1,6 @@
//! Code for applying replacement templates for matches that have previously been found.
+use ide_db::text_edit::TextEdit;
use ide_db::{FxHashMap, FxHashSet};
use itertools::Itertools;
use parser::Edition;
@@ -7,7 +8,6 @@
ast::{self, AstNode, AstToken},
SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize,
};
-use text_edit::TextEdit;
use crate::{fragments, resolving::ResolvedRule, Match, SsrMatches};
diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml
index d976d60..7c66b36 100644
--- a/src/tools/rust-analyzer/crates/ide/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml
@@ -39,7 +39,6 @@
stdx.workspace = true
syntax.workspace = true
span.workspace = true
-text-edit.workspace = true
# ide should depend only on the top-level `hir` package. if you need
# something from some `hir-xxx` subpackage, reexport the API via `hir`.
hir.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
index 1b82c00..e5b4ed1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
@@ -510,6 +510,7 @@
expect![[]],
);
}
+
#[test]
fn test_call_hierarchy_in_macros_incoming_different_files() {
check_hierarchy(
@@ -591,9 +592,9 @@
"#,
expect!["callee Function FileId(0) 22..37 30..36"],
expect![[r#"
- callee Function FileId(0) 38..52 44..50 : FileId(0):44..50
caller Function FileId(0) 38..52 : FileId(0):44..50
- caller Function FileId(1) 130..136 130..136 : FileId(0):44..50"#]],
+ caller Function FileId(1) 130..136 130..136 : FileId(0):44..50
+ callee Function FileId(0) 38..52 44..50 : FileId(0):44..50"#]],
expect![[]],
);
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
index 9245818..055080a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
@@ -187,6 +187,24 @@
};
Some(node)
},
+ ast::LetStmt(it) => {
+ let pat = it.pat()?;
+
+ let mut label = String::new();
+ collapse_ws(pat.syntax(), &mut label);
+
+ let node = StructureNode {
+ parent: None,
+ label,
+ navigation_range: pat.syntax().text_range(),
+ node_range: it.syntax().text_range(),
+ kind: StructureNodeKind::SymbolKind(SymbolKind::Local),
+ detail: it.ty().map(|ty| ty.to_string()),
+ deprecated: false,
+ };
+
+ Some(node)
+ },
ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)),
_ => None,
}
@@ -308,6 +326,17 @@
// endregion
fn g() {}
}
+
+fn let_statements() {
+ let x = 42;
+ let mut y = x;
+ let Foo {
+ ..
+ } = Foo { x };
+ if let None = Some(x) {}
+ _ = ();
+ let _ = g();
+}
"#,
expect![[r#"
[
@@ -633,6 +662,71 @@
),
deprecated: false,
},
+ StructureNode {
+ parent: None,
+ label: "let_statements",
+ navigation_range: 641..655,
+ node_range: 638..798,
+ kind: SymbolKind(
+ Function,
+ ),
+ detail: Some(
+ "fn()",
+ ),
+ deprecated: false,
+ },
+ StructureNode {
+ parent: Some(
+ 26,
+ ),
+ label: "x",
+ navigation_range: 668..669,
+ node_range: 664..675,
+ kind: SymbolKind(
+ Local,
+ ),
+ detail: None,
+ deprecated: false,
+ },
+ StructureNode {
+ parent: Some(
+ 26,
+ ),
+ label: "mut y",
+ navigation_range: 684..689,
+ node_range: 680..694,
+ kind: SymbolKind(
+ Local,
+ ),
+ detail: None,
+ deprecated: false,
+ },
+ StructureNode {
+ parent: Some(
+ 26,
+ ),
+ label: "Foo { .. }",
+ navigation_range: 703..725,
+ node_range: 699..738,
+ kind: SymbolKind(
+ Local,
+ ),
+ detail: None,
+ deprecated: false,
+ },
+ StructureNode {
+ parent: Some(
+ 26,
+ ),
+ label: "_",
+ navigation_range: 788..789,
+ node_range: 784..796,
+ kind: SymbolKind(
+ Local,
+ ),
+ detail: None,
+ deprecated: false,
+ },
]
"#]],
);
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index 4cbcb6e..363f852 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -13,7 +13,6 @@
RootDatabase, SymbolKind,
};
use itertools::Itertools;
-
use span::{Edition, FileId};
use syntax::{
ast::{self, HasLoopBody},
@@ -99,6 +98,7 @@
return Some(vec![x]);
}
}
+
Some(
IdentClass::classify_node(sema, &parent)?
.definitions()
@@ -418,10 +418,10 @@
#[cfg(test)]
mod tests {
+ use crate::fixture;
use ide_db::FileRange;
use itertools::Itertools;
-
- use crate::fixture;
+ use syntax::SmolStr;
#[track_caller]
fn check(ra_fixture: &str) {
@@ -450,6 +450,170 @@
assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")
}
+ fn check_name(expected_name: &str, ra_fixture: &str) {
+ let (analysis, position, _) = fixture::annotations(ra_fixture);
+ let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
+ assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len());
+ let Some(target) = navs.into_iter().next() else {
+ panic!("expected single navigation target but encountered none");
+ };
+ assert_eq!(target.name, SmolStr::new_inline(expected_name));
+ }
+
+ #[test]
+ fn goto_def_pat_range_to_inclusive() {
+ check_name(
+ "RangeToInclusive",
+ r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+ match ch {
+ ..$0='z' => true,
+ _ => false
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_def_pat_range_to() {
+ check_name(
+ "RangeTo",
+ r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+ match ch {
+ .$0.'z' => true,
+ _ => false
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_def_pat_range() {
+ check_name(
+ "Range",
+ r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+ match ch {
+ 'a'.$0.'z' => true,
+ _ => false
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_def_pat_range_inclusive() {
+ check_name(
+ "RangeInclusive",
+ r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+ match ch {
+ 'a'..$0='z' => true,
+ _ => false
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_def_pat_range_from() {
+ check_name(
+ "RangeFrom",
+ r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+ match ch {
+ 'a'..$0 => true,
+ _ => false
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_def_expr_range() {
+ check_name(
+ "Range",
+ r#"
+//- minicore: range
+let x = 0.$0.1;
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_def_expr_range_from() {
+ check_name(
+ "RangeFrom",
+ r#"
+//- minicore: range
+fn f(arr: &[i32]) -> &[i32] {
+ &arr[0.$0.]
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_def_expr_range_inclusive() {
+ check_name(
+ "RangeInclusive",
+ r#"
+//- minicore: range
+let x = 0.$0.=1;
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_def_expr_range_full() {
+ check_name(
+ "RangeFull",
+ r#"
+//- minicore: range
+fn f(arr: &[i32]) -> &[i32] {
+ &arr[.$0.]
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_def_expr_range_to() {
+ check_name(
+ "RangeTo",
+ r#"
+//- minicore: range
+fn f(arr: &[i32]) -> &[i32] {
+ &arr[.$0.10]
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_def_expr_range_to_inclusive() {
+ check_name(
+ "RangeToInclusive",
+ r#"
+//- minicore: range
+fn f(arr: &[i32]) -> &[i32] {
+ &arr[.$0.=10]
+}
+"#,
+ );
+ }
+
#[test]
fn goto_def_in_included_file() {
check(
@@ -2838,4 +3002,24 @@
"#,
);
}
+
+ #[test]
+ fn macro_label_hygiene() {
+ check(
+ r#"
+macro_rules! m {
+ ($x:stmt) => {
+ 'bar: loop { $x }
+ };
+}
+
+fn foo() {
+ 'bar: loop {
+ // ^^^^
+ m!(continue 'bar$0);
+ }
+}
+"#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 124db29..6cac4f1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -11,7 +11,7 @@
defs::{Definition, IdentClass, NameRefClass, OperatorClass},
famous_defs::FamousDefs,
helpers::pick_best_token,
- FileRange, FxIndexSet, RootDatabase,
+ FileRange, FxIndexSet, Ranker, RootDatabase,
};
use itertools::{multizip, Itertools};
use span::Edition;
@@ -182,27 +182,13 @@
// equivalency is more important
let mut descended = sema.descend_into_macros(original_token.clone());
- let kind = original_token.kind();
- let text = original_token.text();
- let ident_kind = kind.is_any_identifier();
+ let ranker = Ranker::from_token(&original_token);
- descended.sort_by_cached_key(|tok| {
- let tok_kind = tok.kind();
-
- let exact_same_kind = tok_kind == kind;
- let both_idents = exact_same_kind || (tok_kind.is_any_identifier() && ident_kind);
- let same_text = tok.text() == text;
- // anything that mapped into a token tree has likely no semantic information
- let no_tt_parent = tok.parent().map_or(false, |it| it.kind() != TOKEN_TREE);
- !((both_idents as usize)
- | ((exact_same_kind as usize) << 1)
- | ((same_text as usize) << 2)
- | ((no_tt_parent as usize) << 3))
- });
+ descended.sort_by_cached_key(|tok| !ranker.rank_token(tok));
let mut res = vec![];
for token in descended {
- let is_same_kind = token.kind() == kind;
+ let is_same_kind = token.kind() == ranker.kind;
let lint_hover = (|| {
// FIXME: Definition should include known lints and the like instead of having this special case here
let attr = token.parent_ancestors().find_map(ast::Attr::cast)?;
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index 01fa316..a31b14d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -1042,7 +1042,7 @@
}
DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait) => {
let name = hir::Trait::from(super_trait).name(db);
- format_to!(buf, "has a object unsafe supertrait `{}`", name.as_str());
+ format_to!(buf, "has a dyn incompatible supertrait `{}`", name.as_str());
}
}
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 81397b07..3e40263 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -289,19 +289,6 @@
*abc*
```rust
- test::module
- ```
-
- ```rust
- fn abc()
- ```
-
- ---
-
- Inner
- ---
-
- ```rust
test
```
@@ -312,6 +299,19 @@
---
Outer
+ ---
+
+ ```rust
+ test::module
+ ```
+
+ ```rust
+ fn abc()
+ ```
+
+ ---
+
+ Inner
"#]],
);
}
@@ -9018,3 +9018,156 @@
"#]],
);
}
+
+#[test]
+fn type_alias_without_docs() {
+ // Simple.
+ check(
+ r#"
+/// Docs for B
+struct B;
+
+type A$0 = B;
+"#,
+ expect![[r#"
+ *A*
+
+ ```rust
+ test
+ ```
+
+ ```rust
+ // size = 0, align = 1
+ type A = B
+ ```
+
+ ---
+
+ *This is the documentation for* `struct B`
+
+ Docs for B
+ "#]],
+ );
+
+ // Nested.
+ check(
+ r#"
+/// Docs for C
+struct C;
+
+type B = C;
+
+type A$0 = B;
+"#,
+ expect![[r#"
+ *A*
+
+ ```rust
+ test
+ ```
+
+ ```rust
+ // size = 0, align = 1
+ type A = B
+ ```
+
+ ---
+
+ *This is the documentation for* `struct C`
+
+ Docs for C
+ "#]],
+ );
+
+ // Showing the docs for aliased struct instead of intermediate type.
+ check(
+ r#"
+/// Docs for C
+struct C;
+
+/// Docs for B
+type B = C;
+
+type A$0 = B;
+"#,
+ expect![[r#"
+ *A*
+
+ ```rust
+ test
+ ```
+
+ ```rust
+ // size = 0, align = 1
+ type A = B
+ ```
+
+ ---
+
+ *This is the documentation for* `struct C`
+
+ Docs for C
+ "#]],
+ );
+
+ // No docs found.
+ check(
+ r#"
+struct C;
+
+type B = C;
+
+type A$0 = B;
+"#,
+ expect![[r#"
+ *A*
+
+ ```rust
+ test
+ ```
+
+ ```rust
+ // size = 0, align = 1
+ type A = B
+ ```
+ "#]],
+ );
+
+ // Multiple nested crate.
+ check(
+ r#"
+//- /lib.rs crate:c
+/// Docs for C
+pub struct C;
+
+//- /lib.rs crate:b deps:c
+pub use c::C;
+pub type B = C;
+
+//- /lib.rs crate:a deps:b
+pub use b::B;
+pub type A = B;
+
+//- /main.rs crate:main deps:a
+use a::A$0;
+"#,
+ expect![[r#"
+ *A*
+
+ ```rust
+ a
+ ```
+
+ ```rust
+ // size = 0, align = 1
+ pub type A = B
+ ```
+
+ ---
+
+ *This is the documentation for* `pub struct C`
+
+ Docs for C
+ "#]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 97e7123..c58ca0f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -8,6 +8,7 @@
sym, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef,
ModuleDefId, Semantics,
};
+use ide_db::text_edit::TextEdit;
use ide_db::{famous_defs::FamousDefs, FileRange, RootDatabase};
use itertools::Itertools;
use smallvec::{smallvec, SmallVec};
@@ -17,7 +18,6 @@
ast::{self, AstNode, HasGenericParams},
format_smolstr, match_ast, SmolStr, SyntaxNode, TextRange, TextSize, WalkEvent,
};
-use text_edit::TextEdit;
use crate::{navigation_target::TryToNav, FileId};
@@ -410,19 +410,6 @@
}
}
- fn opening_paren_before(kind: InlayKind, range: TextRange) -> InlayHint {
- InlayHint {
- range,
- kind,
- label: InlayHintLabel::from("("),
- text_edit: None,
- position: InlayHintPosition::Before,
- pad_left: false,
- pad_right: false,
- resolve_parent: None,
- }
- }
-
pub fn needs_resolve(&self) -> Option<TextRange> {
self.resolve_parent.filter(|_| self.text_edit.is_some() || self.label.needs_resolve())
}
@@ -475,6 +462,18 @@
}
}
+ pub fn append_part(&mut self, part: InlayHintLabelPart) {
+ if part.linked_location.is_none() && part.tooltip.is_none() {
+ if let Some(InlayHintLabelPart { text, linked_location: None, tooltip: None }) =
+ self.parts.last_mut()
+ {
+ text.push_str(&part.text);
+ return;
+ }
+ }
+ self.parts.push(part);
+ }
+
pub fn needs_resolve(&self) -> bool {
self.parts.iter().any(|part| part.linked_location.is_some() || part.tooltip.is_some())
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
index c37c469..4d7d6e2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
@@ -3,12 +3,15 @@
//! let _: u32 = /* <never-to-any> */ loop {};
//! let _: &u32 = /* &* */ &mut 0;
//! ```
+use std::ops::Not;
+
use either::Either;
use hir::{
Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety,
};
use ide_db::famous_defs::FamousDefs;
+use ide_db::text_edit::TextEditBuilder;
use span::EditionedFileId;
use stdx::never;
use syntax::{
@@ -17,8 +20,8 @@
};
use crate::{
- AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintPosition,
- InlayHintsConfig, InlayKind, InlayTooltip,
+ AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintLabelPart,
+ InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip,
};
pub(super) fn hints(
@@ -51,32 +54,47 @@
let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr {
- if let [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), source: _, target }] =
- &*adjustments
- {
- // Don't show unnecessary reborrows for these, they will just repeat the inner ones again
- if source == target {
- return None;
- }
+ // Don't show unnecessary reborrows for these, they will just repeat the inner ones again
+ if matches!(
+ &*adjustments,
+ [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), target, .. }]
+ if source == target
+ ) {
+ return None;
}
}
let (postfix, needs_outer_parens, needs_inner_parens) =
mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode);
- if needs_outer_parens {
- acc.push(InlayHint::opening_paren_before(
- InlayKind::Adjustment,
- expr.syntax().text_range(),
- ));
+ let range = expr.syntax().text_range();
+ let mut pre = InlayHint {
+ range,
+ position: InlayHintPosition::Before,
+ pad_left: false,
+ pad_right: false,
+ kind: InlayKind::Adjustment,
+ label: InlayHintLabel::default(),
+ text_edit: None,
+ resolve_parent: Some(range),
+ };
+ let mut post = InlayHint {
+ range,
+ position: InlayHintPosition::After,
+ pad_left: false,
+ pad_right: false,
+ kind: InlayKind::Adjustment,
+ label: InlayHintLabel::default(),
+ text_edit: None,
+ resolve_parent: Some(range),
+ };
+
+ if needs_outer_parens || (postfix && needs_inner_parens) {
+ pre.label.append_str("(");
}
if postfix && needs_inner_parens {
- acc.push(InlayHint::opening_paren_before(
- InlayKind::Adjustment,
- expr.syntax().text_range(),
- ));
- acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
+ post.label.append_str(")");
}
let mut iter = if postfix {
@@ -86,6 +104,7 @@
};
let iter: &mut dyn Iterator<Item = _> = iter.as_mut().either(|it| it as _, |it| it as _);
+ let mut allow_edit = !postfix;
for Adjustment { source, target, kind } in iter {
if source == target {
cov_mark::hit!(same_type_adjustment);
@@ -95,6 +114,7 @@
// FIXME: Add some nicer tooltips to each of these
let (text, coercion) = match kind {
Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
+ allow_edit = false;
("<never-to-any>", "never to any")
}
Adjust::Deref(None) => ("*", "dereference"),
@@ -115,6 +135,7 @@
// some of these could be represented via `as` casts, but that's not too nice and
// handling everything as a prefix expr makes the `(` and `)` insertion easier
Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
+ allow_edit = false;
match cast {
PointerCast::ReifyFnPointer => {
("<fn-item-to-fn-pointer>", "fn item to fn pointer")
@@ -138,36 +159,58 @@
}
_ => continue,
};
- let label = InlayHintLabel::simple(
- if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
- Some(InlayTooltip::Markdown(format!(
+ let label = InlayHintLabelPart {
+ text: if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
+ linked_location: None,
+ tooltip: Some(InlayTooltip::Markdown(format!(
"`{}` → `{}` ({coercion} coercion)",
source.display(sema.db, file_id.edition()),
target.display(sema.db, file_id.edition()),
))),
- None,
- );
- acc.push(InlayHint {
- range: expr.syntax().text_range(),
- pad_left: false,
- pad_right: false,
- position: if postfix { InlayHintPosition::After } else { InlayHintPosition::Before },
- kind: InlayKind::Adjustment,
- label,
- text_edit: None,
- resolve_parent: Some(expr.syntax().text_range()),
- });
+ };
+ if postfix { &mut post } else { &mut pre }.label.append_part(label);
}
if !postfix && needs_inner_parens {
- acc.push(InlayHint::opening_paren_before(
- InlayKind::Adjustment,
- expr.syntax().text_range(),
- ));
- acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
+ pre.label.append_str("(");
}
- if needs_outer_parens {
- acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
+ if needs_outer_parens || (!postfix && needs_inner_parens) {
+ post.label.append_str(")");
}
+
+ let mut pre = pre.label.parts.is_empty().not().then_some(pre);
+ let mut post = post.label.parts.is_empty().not().then_some(post);
+ if pre.is_none() && post.is_none() {
+ return None;
+ }
+ if allow_edit {
+ let edit = {
+ let mut b = TextEditBuilder::default();
+ if let Some(pre) = &pre {
+ b.insert(
+ pre.range.start(),
+ pre.label.parts.iter().map(|part| &*part.text).collect::<String>(),
+ );
+ }
+ if let Some(post) = &post {
+ b.insert(
+ post.range.end(),
+ post.label.parts.iter().map(|part| &*part.text).collect::<String>(),
+ );
+ }
+ b.finish()
+ };
+ match (&mut pre, &mut post) {
+ (Some(pre), Some(post)) => {
+ pre.text_edit = Some(edit.clone());
+ post.text_edit = Some(edit);
+ }
+ (Some(pre), None) => pre.text_edit = Some(edit),
+ (None, Some(post)) => post.text_edit = Some(edit),
+ (None, None) => (),
+ }
+ }
+ acc.extend(pre);
+ acc.extend(post);
Some(())
}
@@ -293,25 +336,19 @@
let _: u32 = loop {};
//^^^^^^^<never-to-any>
let _: &u32 = &mut 0;
- //^^^^^^&
- //^^^^^^*
+ //^^^^^^&*
let _: &mut u32 = &mut 0;
- //^^^^^^&mut $
- //^^^^^^*
+ //^^^^^^&mut *
let _: *const u32 = &mut 0;
- //^^^^^^&raw const $
- //^^^^^^*
+ //^^^^^^&raw const *
let _: *mut u32 = &mut 0;
- //^^^^^^&raw mut $
- //^^^^^^*
+ //^^^^^^&raw mut *
let _: fn() = main;
//^^^^<fn-item-to-fn-pointer>
let _: unsafe fn() = main;
- //^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
- //^^^^<fn-item-to-fn-pointer>
+ //^^^^<safe-fn-pointer-to-unsafe-fn-pointer><fn-item-to-fn-pointer>
let _: unsafe fn() = main as fn();
- //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
- //^^^^^^^^^^^^(
+ //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>(
//^^^^^^^^^^^^)
//^^^^<fn-item-to-fn-pointer>
let _: fn() = || {};
@@ -319,72 +356,51 @@
let _: unsafe fn() = || {};
//^^^^^<closure-to-unsafe-fn-pointer>
let _: *const u32 = &mut 0u32 as *mut u32;
- //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
- //^^^^^^^^^^^^^^^^^^^^^(
+ //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>(
//^^^^^^^^^^^^^^^^^^^^^)
- //^^^^^^^^^&raw mut $
- //^^^^^^^^^*
+ //^^^^^^^^^&raw mut *
let _: &mut [_] = &mut [0; 0];
- //^^^^^^^^^^^<unsize>
- //^^^^^^^^^^^&mut $
- //^^^^^^^^^^^*
+ //^^^^^^^^^^^<unsize>&mut *
Struct.consume();
Struct.by_ref();
- //^^^^^^(
- //^^^^^^&
+ //^^^^^^(&
//^^^^^^)
Struct.by_ref_mut();
- //^^^^^^(
- //^^^^^^&mut $
+ //^^^^^^(&mut $
//^^^^^^)
(&Struct).consume();
//^^^^^^^*
(&Struct).by_ref();
- //^^^^^^^&
- //^^^^^^^*
+ //^^^^^^^&*
(&mut Struct).consume();
//^^^^^^^^^^^*
(&mut Struct).by_ref();
- //^^^^^^^^^^^&
- //^^^^^^^^^^^*
+ //^^^^^^^^^^^&*
(&mut Struct).by_ref_mut();
- //^^^^^^^^^^^&mut $
- //^^^^^^^^^^^*
+ //^^^^^^^^^^^&mut *
// Check that block-like expressions don't duplicate hints
let _: &mut [u32] = (&mut []);
- //^^^^^^^<unsize>
- //^^^^^^^&mut $
- //^^^^^^^*
+ //^^^^^^^<unsize>&mut *
let _: &mut [u32] = { &mut [] };
- //^^^^^^^<unsize>
- //^^^^^^^&mut $
- //^^^^^^^*
+ //^^^^^^^<unsize>&mut *
let _: &mut [u32] = unsafe { &mut [] };
- //^^^^^^^<unsize>
- //^^^^^^^&mut $
- //^^^^^^^*
+ //^^^^^^^<unsize>&mut *
let _: &mut [u32] = if true {
&mut []
- //^^^^^^^<unsize>
- //^^^^^^^&mut $
- //^^^^^^^*
+ //^^^^^^^<unsize>&mut *
} else {
loop {}
//^^^^^^^<never-to-any>
};
let _: &mut [u32] = match () { () => &mut [] };
- //^^^^^^^<unsize>
- //^^^^^^^&mut $
- //^^^^^^^*
+ //^^^^^^^<unsize>&mut *
let _: &mut dyn Fn() = &mut || ();
- //^^^^^^^^^^<unsize>
- //^^^^^^^^^^&mut $
- //^^^^^^^^^^*
+ //^^^^^^^^^^<unsize>&mut *
() == ();
// ^^&
// ^^&
@@ -393,16 +409,13 @@
// ^^^^&
let closure: dyn Fn = || ();
closure();
- //^^^^^^^(
- //^^^^^^^&
+ //^^^^^^^(&
//^^^^^^^)
Struct[0];
- //^^^^^^(
- //^^^^^^&
+ //^^^^^^(&
//^^^^^^)
&mut Struct[0];
- //^^^^^^(
- //^^^^^^&mut $
+ //^^^^^^(&mut $
//^^^^^^)
}
@@ -442,72 +455,46 @@
(&Struct).consume();
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
+ //^^^^^^^).*
(&Struct).by_ref();
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
- //^^^^^^^.&
+ //^^^^^^^).*.&
(&mut Struct).consume();
//^^^^^^^^^^^(
- //^^^^^^^^^^^)
- //^^^^^^^^^^^.*
+ //^^^^^^^^^^^).*
(&mut Struct).by_ref();
//^^^^^^^^^^^(
- //^^^^^^^^^^^)
- //^^^^^^^^^^^.*
- //^^^^^^^^^^^.&
+ //^^^^^^^^^^^).*.&
(&mut Struct).by_ref_mut();
//^^^^^^^^^^^(
- //^^^^^^^^^^^)
- //^^^^^^^^^^^.*
- //^^^^^^^^^^^.&mut
+ //^^^^^^^^^^^).*.&mut
// Check that block-like expressions don't duplicate hints
let _: &mut [u32] = (&mut []);
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
- //^^^^^^^.&mut
- //^^^^^^^.<unsize>
+ //^^^^^^^).*.&mut.<unsize>
let _: &mut [u32] = { &mut [] };
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
- //^^^^^^^.&mut
- //^^^^^^^.<unsize>
+ //^^^^^^^).*.&mut.<unsize>
let _: &mut [u32] = unsafe { &mut [] };
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
- //^^^^^^^.&mut
- //^^^^^^^.<unsize>
+ //^^^^^^^).*.&mut.<unsize>
let _: &mut [u32] = if true {
&mut []
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
- //^^^^^^^.&mut
- //^^^^^^^.<unsize>
+ //^^^^^^^).*.&mut.<unsize>
} else {
loop {}
//^^^^^^^.<never-to-any>
};
let _: &mut [u32] = match () { () => &mut [] };
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
- //^^^^^^^.&mut
- //^^^^^^^.<unsize>
+ //^^^^^^^).*.&mut.<unsize>
let _: &mut dyn Fn() = &mut || ();
//^^^^^^^^^^(
- //^^^^^^^^^^)
- //^^^^^^^^^^.*
- //^^^^^^^^^^.&mut
- //^^^^^^^^^^.<unsize>
+ //^^^^^^^^^^).*.&mut.<unsize>
() == ();
// ^^.&
// ^^.&
@@ -619,9 +606,7 @@
r#"
unsafe fn enabled() {
f(&&());
- //^^^^&
- //^^^^*
- //^^^^*
+ //^^^^&**
}
fn disabled() {
@@ -633,9 +618,7 @@
unsafe {
f(&&());
- //^^^^&
- //^^^^*
- //^^^^*
+ //^^^^&**
}
}
@@ -644,9 +627,7 @@
unsafe {
f(&&());
- //^^^^&
- //^^^^*
- //^^^^*
+ //^^^^&**
}
};
@@ -655,18 +636,14 @@
unsafe {
f(&&());
- //^^^^&
- //^^^^*
- //^^^^*
+ //^^^^&**
}
};
enum E {
Disable = { f(&&()); 0 },
Enable = unsafe { f(&&()); 1 },
- //^^^^&
- //^^^^*
- //^^^^*
+ //^^^^&**
}
const fn f(_: &()) {}
@@ -692,8 +669,7 @@
_ = Struct.by_ref();
_ = unsafe { Struct.by_ref() };
- //^^^^^^(
- //^^^^^^&
+ //^^^^^^(&
//^^^^^^)
}
"#,
@@ -726,10 +702,7 @@
fn hello(it: &&[impl T]) {
it.len();
- //^^(
- //^^&
- //^^*
- //^^*
+ //^^(&**
//^^)
}
"#,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
index d1c0677..cfe8657 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
@@ -2,13 +2,16 @@
//! ```no_run
//! let /* & */ (/* ref */ x,) = &(0,);
//! ```
+use std::mem;
+
use hir::Mutability;
use ide_db::famous_defs::FamousDefs;
+use ide_db::text_edit::TextEditBuilder;
use span::EditionedFileId;
use syntax::ast::{self, AstNode};
-use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind};
+use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
@@ -21,16 +24,7 @@
return None;
}
- let outer_paren_pat = pat
- .syntax()
- .ancestors()
- .skip(1)
- .map_while(ast::Pat::cast)
- .map_while(|pat| match pat {
- ast::Pat::ParenPat(pat) => Some(pat),
- _ => None,
- })
- .last();
+ let outer_paren_pat = pat.syntax().ancestors().skip(1).map_while(ast::ParenPat::cast).last();
let range = outer_paren_pat.as_ref().map_or_else(
|| match pat {
// for ident patterns that @ bind a name, render the un-ref patterns in front of the inner pattern
@@ -42,7 +36,18 @@
},
|it| it.syntax().text_range(),
);
+ let mut hint = InlayHint {
+ range,
+ kind: InlayKind::BindingMode,
+ label: InlayHintLabel::default(),
+ text_edit: None,
+ position: InlayHintPosition::Before,
+ pad_left: false,
+ pad_right: false,
+ resolve_parent: Some(pat.syntax().text_range()),
+ };
let pattern_adjustments = sema.pattern_adjustments(pat);
+ let mut was_mut_last = false;
pattern_adjustments.iter().for_each(|ty| {
let reference = ty.is_reference();
let mut_reference = ty.is_mutable_reference();
@@ -51,41 +56,36 @@
(true, false) => "&",
_ => return,
};
- acc.push(InlayHint {
- range,
- kind: InlayKind::BindingMode,
- label: r.into(),
- text_edit: None,
- position: InlayHintPosition::Before,
- pad_left: false,
- pad_right: mut_reference,
- resolve_parent: Some(pat.syntax().text_range()),
- });
+ if mem::replace(&mut was_mut_last, mut_reference) {
+ hint.label.append_str(" ");
+ }
+ hint.label.append_str(r);
});
+ hint.pad_right = was_mut_last;
+ let acc_base = acc.len();
match pat {
ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => {
let bm = sema.binding_mode_of_pat(pat)?;
let bm = match bm {
- hir::BindingMode::Move => return None,
- hir::BindingMode::Ref(Mutability::Mut) => "ref mut",
- hir::BindingMode::Ref(Mutability::Shared) => "ref",
+ hir::BindingMode::Move => None,
+ hir::BindingMode::Ref(Mutability::Mut) => Some("ref mut"),
+ hir::BindingMode::Ref(Mutability::Shared) => Some("ref"),
};
- acc.push(InlayHint {
- range: pat.syntax().text_range(),
- kind: InlayKind::BindingMode,
- label: bm.into(),
- text_edit: None,
- position: InlayHintPosition::Before,
- pad_left: false,
- pad_right: true,
- resolve_parent: Some(pat.syntax().text_range()),
- });
+ if let Some(bm) = bm {
+ acc.push(InlayHint {
+ range: pat.syntax().text_range(),
+ kind: InlayKind::BindingMode,
+ label: bm.into(),
+ text_edit: None,
+ position: InlayHintPosition::Before,
+ pad_left: false,
+ pad_right: true,
+ resolve_parent: Some(pat.syntax().text_range()),
+ });
+ }
}
ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => {
- acc.push(InlayHint::opening_paren_before(
- InlayKind::BindingMode,
- pat.syntax().text_range(),
- ));
+ hint.label.append_str("(");
acc.push(InlayHint::closing_paren_after(
InlayKind::BindingMode,
pat.syntax().text_range(),
@@ -93,6 +93,24 @@
}
_ => (),
}
+ if !hint.label.parts.is_empty() {
+ acc.push(hint);
+ }
+
+ if let hints @ [_, ..] = &mut acc[acc_base..] {
+ let mut edit = TextEditBuilder::default();
+ for h in &mut *hints {
+ edit.insert(
+ match h.position {
+ InlayHintPosition::Before => h.range.start(),
+ InlayHintPosition::After => h.range.end(),
+ },
+ h.label.parts.iter().map(|p| &*p.text).collect(),
+ );
+ }
+ let edit = edit.finish();
+ hints.iter_mut().for_each(|h| h.text_edit = Some(edit.clone()));
+ }
Some(())
}
@@ -117,6 +135,13 @@
(x,): &mut (u32,)
//^^^^&mut
//^ ref mut
+ (x,): &mut &mut (u32,)
+ //^^^^&mut &mut
+ //^ ref mut
+ (x,): &&(u32,)
+ //^^^^&&
+ //^ ref
+
) {
let (x,) = (0,);
let (x,) = &(0,);
@@ -136,11 +161,10 @@
}
match &(0,) {
(x,) | (x,) => (),
- //^^^^^^^^^^^&
+ //^^^^^^^^^^^)
+ //^^^^^^^^^^^&(
//^ ref
//^ ref
- //^^^^^^^^^^^(
- //^^^^^^^^^^^)
((x,) | (x,)) => (),
//^^^^^^^^^^^^^&
//^ ref
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index 58d8f97..028ed16 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -77,7 +77,7 @@
#[cfg(test)]
mod tests {
use expect_test::{expect, Expect};
- use text_edit::{TextRange, TextSize};
+ use ide_db::text_edit::{TextRange, TextSize};
use crate::{
fixture,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
index f399bd0..906f2ac 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
@@ -2,12 +2,14 @@
//!
//! Tests live in [`bind_pat`][super::bind_pat] module.
use ide_db::famous_defs::FamousDefs;
+use ide_db::text_edit::{TextRange, TextSize};
use span::EditionedFileId;
use stdx::{never, TupleExt};
use syntax::ast::{self, AstNode};
-use text_edit::{TextRange, TextSize};
-use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
+use crate::{
+ InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind,
+};
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
@@ -27,34 +29,27 @@
return None;
}
- let move_kw_range = match closure.move_token() {
- Some(t) => t.text_range(),
+ let (range, label) = match closure.move_token() {
+ Some(t) => (t.text_range(), InlayHintLabel::default()),
None => {
- let range = closure.syntax().first_token()?.prev_token()?.text_range();
- let range = TextRange::new(range.end() - TextSize::from(1), range.end());
- acc.push(InlayHint {
- range,
- kind: InlayKind::ClosureCapture,
- label: InlayHintLabel::from("move"),
- text_edit: None,
- position: InlayHintPosition::After,
- pad_left: false,
- pad_right: false,
- resolve_parent: Some(closure.syntax().text_range()),
- });
- range
+ let prev_token = closure.syntax().first_token()?.prev_token()?.text_range();
+ (
+ TextRange::new(prev_token.end() - TextSize::from(1), prev_token.end()),
+ InlayHintLabel::from("move"),
+ )
}
};
- acc.push(InlayHint {
- range: move_kw_range,
+ let mut hint = InlayHint {
+ range,
kind: InlayKind::ClosureCapture,
- label: InlayHintLabel::from("("),
+ label,
text_edit: None,
position: InlayHintPosition::After,
pad_left: false,
- pad_right: false,
- resolve_parent: None,
- });
+ pad_right: true,
+ resolve_parent: Some(closure.syntax().text_range()),
+ };
+ hint.label.append_str("(");
let last = captures.len() - 1;
for (idx, capture) in captures.into_iter().enumerate() {
let local = capture.local();
@@ -76,48 +71,20 @@
if never!(label.is_empty()) {
continue;
}
- let label = InlayHintLabel::simple(
- label,
- None,
- source.name().and_then(|name| {
+ hint.label.append_part(InlayHintLabelPart {
+ text: label,
+ linked_location: source.name().and_then(|name| {
name.syntax().original_file_range_opt(sema.db).map(TupleExt::head).map(Into::into)
}),
- );
- acc.push(InlayHint {
- range: move_kw_range,
- kind: InlayKind::ClosureCapture,
- label,
- text_edit: None,
- position: InlayHintPosition::After,
- pad_left: false,
- pad_right: false,
- resolve_parent: Some(closure.syntax().text_range()),
+ tooltip: None,
});
if idx != last {
- acc.push(InlayHint {
- range: move_kw_range,
- kind: InlayKind::ClosureCapture,
- label: InlayHintLabel::from(", "),
- text_edit: None,
- position: InlayHintPosition::After,
- pad_left: false,
- pad_right: false,
- resolve_parent: None,
- });
+ hint.label.append_str(", ");
}
}
- acc.push(InlayHint {
- range: move_kw_range,
- kind: InlayKind::ClosureCapture,
- label: InlayHintLabel::from(")"),
- text_edit: None,
- position: InlayHintPosition::After,
- pad_left: false,
- pad_right: true,
- resolve_parent: None,
- });
-
+ hint.label.append_str(")");
+ acc.push(hint);
Some(())
}
@@ -147,51 +114,25 @@
let mut baz = NonCopy;
let qux = &mut NonCopy;
|| {
-// ^ move
-// ^ (
-// ^ &foo
-// ^ , $
-// ^ bar
-// ^ , $
-// ^ baz
-// ^ , $
-// ^ qux
-// ^ )
+// ^ move(&foo, bar, baz, qux)
foo;
bar;
baz;
qux;
};
|| {
-// ^ move
-// ^ (
-// ^ &foo
-// ^ , $
-// ^ &bar
-// ^ , $
-// ^ &baz
-// ^ , $
-// ^ &qux
-// ^ )
+// ^ move(&foo, &bar, &baz, &qux)
&foo;
&bar;
&baz;
&qux;
};
|| {
-// ^ move
-// ^ (
-// ^ &mut baz
-// ^ )
+// ^ move(&mut baz)
&mut baz;
};
|| {
-// ^ move
-// ^ (
-// ^ &mut baz
-// ^ , $
-// ^ &mut *qux
-// ^ )
+// ^ move(&mut baz, &mut *qux)
baz = NonCopy;
*qux = NonCopy;
};
@@ -209,9 +150,7 @@
fn main() {
let foo = u32;
move || {
-// ^^^^ (
-// ^^^^ foo
-// ^^^^ )
+// ^^^^ (foo)
foo;
};
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
index 35b6287..cd77c3e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
@@ -5,6 +5,7 @@
//! }
//! ```
use hir::Semantics;
+use ide_db::text_edit::TextEdit;
use ide_db::{famous_defs::FamousDefs, RootDatabase};
use span::EditionedFileId;
use syntax::ast::{self, AstNode, HasName};
@@ -65,11 +66,11 @@
let eq_ = if eq_token.is_none() { " =" } else { "" };
let label = InlayHintLabel::simple(
match d {
- Ok(x) => {
- if x >= 10 {
- format!("{eq_} {x} ({x:#X})")
+ Ok(val) => {
+ if val >= 10 {
+ format!("{eq_} {val} ({val:#X})")
} else {
- format!("{eq_} {x}")
+ format!("{eq_} {val}")
}
}
Err(_) => format!("{eq_} ?"),
@@ -87,7 +88,7 @@
},
kind: InlayKind::Discriminant,
label,
- text_edit: None,
+ text_edit: d.ok().map(|val| TextEdit::insert(range.start(), format!("{eq_} {val}"))),
position: InlayHintPosition::After,
pad_left: false,
pad_right: false,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
index 8d42247..1560df3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
@@ -4,6 +4,7 @@
//! ```
use either::Either;
use ide_db::famous_defs::FamousDefs;
+use ide_db::text_edit::TextEdit;
use span::EditionedFileId;
use syntax::{
ast::{self, AstNode},
@@ -38,7 +39,7 @@
range: t.text_range(),
kind: InlayKind::Lifetime,
label: "'static".into(),
- text_edit: None,
+ text_edit: Some(TextEdit::insert(t.text_range().start(), "'static ".into())),
position: InlayHintPosition::After,
pad_left: false,
pad_right: true,
diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
index 9d8ba90..5192f91 100644
--- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
@@ -8,7 +8,7 @@
SyntaxToken, TextRange, TextSize, T,
};
-use text_edit::{TextEdit, TextEditBuilder};
+use ide_db::text_edit::{TextEdit, TextEditBuilder};
pub struct JoinLinesConfig {
pub join_else_if: bool,
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index d7163d5..d053c4b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -122,6 +122,7 @@
CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem,
CompletionItemKind, CompletionRelevance, Snippet, SnippetScope,
};
+pub use ide_db::text_edit::{Indel, TextEdit};
pub use ide_db::{
base_db::{Cancelled, CrateGraph, CrateId, FileChange, SourceRoot, SourceRootId},
documentation::Documentation,
@@ -139,7 +140,6 @@
pub use ide_ssr::SsrError;
pub use span::Edition;
pub use syntax::{TextRange, TextSize};
-pub use text_edit::{Indel, TextEdit};
pub type Cancellable<T> = Result<T, Cancelled>;
diff --git a/src/tools/rust-analyzer/crates/ide/src/move_item.rs b/src/tools/rust-analyzer/crates/ide/src/move_item.rs
index ea6cc9d..a232df2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/move_item.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/move_item.rs
@@ -1,10 +1,11 @@
use std::{iter::once, mem};
use hir::Semantics;
+use ide_db::syntax_helpers::tree_diff::diff;
+use ide_db::text_edit::{TextEdit, TextEditBuilder};
use ide_db::{helpers::pick_best_token, FileRange, RootDatabase};
use itertools::Itertools;
-use syntax::{algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange};
-use text_edit::{TextEdit, TextEditBuilder};
+use syntax::{ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange};
#[derive(Copy, Clone, Debug)]
pub enum Direction {
@@ -166,7 +167,7 @@
let mut edit = TextEditBuilder::default();
- algo::diff(first, second).into_text_edit(&mut edit);
+ diff(first, second).into_text_edit(&mut edit);
edit.replace(second.text_range(), first_with_cursor);
edit.finish()
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index e7cb8a2..339315d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -1701,14 +1701,14 @@
}
"#,
expect![[r#"
- func Function FileId(0) 137..146 140..144
-
- FileId(0) 161..165
-
-
func Function FileId(0) 137..146 140..144 module
FileId(0) 181..185
+
+
+ func Function FileId(0) 137..146 140..144
+
+ FileId(0) 161..165
"#]],
)
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index f17c1fa..665fc95 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -15,7 +15,7 @@
use stdx::{always, never};
use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize};
-use text_edit::TextEdit;
+use ide_db::text_edit::TextEdit;
use crate::{FilePosition, RangeInfo, SourceChange};
@@ -449,9 +449,9 @@
mod tests {
use expect_test::{expect, Expect};
use ide_db::source_change::SourceChange;
+ use ide_db::text_edit::TextEdit;
use stdx::trim_indent;
use test_utils::assert_eq_text;
- use text_edit::TextEdit;
use crate::fixture;
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
index 961b2a4..0747d1b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
@@ -16,7 +16,7 @@
use std::ops::ControlFlow;
use hir::{InRealFile, Name, Semantics};
-use ide_db::{FxHashMap, RootDatabase, SymbolKind};
+use ide_db::{FxHashMap, Ranker, RootDatabase, SymbolKind};
use span::EditionedFileId;
use syntax::{
ast::{self, IsString},
@@ -397,13 +397,12 @@
Some(AttrOrDerive::Derive(_)) => inside_attribute,
None => false,
};
+
let descended_element = if in_macro {
// Attempt to descend tokens into macro-calls.
let res = match element {
NodeOrToken::Token(token) if token.kind() != COMMENT => {
- let kind = token.kind();
- let text = token.text();
- let ident_kind = kind.is_any_identifier();
+ let ranker = Ranker::from_token(&token);
let mut t = None;
let mut r = 0;
@@ -412,21 +411,9 @@
|tok, _ctx| {
// FIXME: Consider checking ctx transparency for being opaque?
let tok = tok.value;
- let tok_kind = tok.kind();
+ let my_rank = ranker.rank_token(&tok);
- let exact_same_kind = tok_kind == kind;
- let both_idents =
- exact_same_kind || (tok_kind.is_any_identifier() && ident_kind);
- let same_text = tok.text() == text;
- // anything that mapped into a token tree has likely no semantic information
- let no_tt_parent =
- tok.parent().map_or(false, |it| it.kind() != TOKEN_TREE);
- let my_rank = (both_idents as usize)
- | ((exact_same_kind as usize) << 1)
- | ((same_text as usize) << 2)
- | ((no_tt_parent as usize) << 3);
-
- if my_rank > 0b1110 {
+ if my_rank >= Ranker::MAX_RANK {
// a rank of 0b1110 means that we have found a maximally interesting
// token so stop early.
t = Some(tok);
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html
index d07ba74..361dcd1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html
@@ -50,4 +50,4 @@
<span class="brace">}</span>
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="module attribute crate_root library">proc_macros</span><span class="operator attribute">::</span><span class="attribute attribute library">issue_18089</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">fn</span> <span class="function declaration">template</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre>
\ No newline at end of file
+<span class="keyword">fn</span> <span class="macro declaration">template</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index a09e1e8..9bb5de9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -23,7 +23,7 @@
AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, T,
};
-use text_edit::{Indel, TextEdit};
+use ide_db::text_edit::TextEdit;
use crate::SourceChange;
@@ -126,7 +126,7 @@
return None;
}
// FIXME: Edition
- let file = file.reparse(&Indel::delete(range), span::Edition::CURRENT_FIXME);
+ let file = file.reparse(range, "", span::Edition::CURRENT_FIXME);
if let Some(edit) = bracket_expr(&file.tree(), offset, opening_bracket, closing_bracket) {
return Some(edit);
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
index 6e56bd6..773e352 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
@@ -12,7 +12,7 @@
SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset,
};
-use text_edit::TextEdit;
+use ide_db::text_edit::TextEdit;
// Feature: On Enter
//
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
index ecfabca..9231123 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
@@ -144,10 +144,31 @@
LIFETIME_IDENT => lifetime(p),
T![for] => types::for_type(p, false),
// test precise_capturing
- // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T> {}
+ // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}
T![use] if p.nth_at(1, T![<]) => {
p.bump_any();
- generic_param_list(p)
+ let m = p.start();
+ delimited(
+ p,
+ T![<],
+ T![>],
+ T![,],
+ || "expected identifier or lifetime".into(),
+ TokenSet::new(&[T![Self], IDENT, LIFETIME_IDENT]),
+ |p| {
+ if p.at(T![Self]) {
+ let m = p.start();
+ p.bump(T![Self]);
+ m.complete(p, NAME_REF);
+ } else if p.at(LIFETIME_IDENT) {
+ lifetime(p);
+ } else {
+ name_ref(p);
+ }
+ true
+ },
+ );
+ m.complete(p, USE_BOUND_GENERIC_ARGS);
}
T![?] if p.nth_at(1, T![for]) => {
// test question_for_type_trait_bound
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
index 882c243..ed01fca 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
@@ -21,7 +21,8 @@
expressions::LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[T![-], T![const]]));
pub(crate) fn pattern(p: &mut Parser<'_>) {
- pattern_r(p, PAT_RECOVERY_SET);
+ let m = p.start();
+ pattern_r(p, m, false, PAT_RECOVERY_SET);
}
/// Parses a pattern list separated by pipes `|`.
@@ -36,13 +37,11 @@
/// Parses a pattern list separated by pipes `|`
/// using the given `recovery_set`.
pub(super) fn pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
- p.eat(T![|]);
- pattern_r(p, recovery_set);
+ let m = p.start();
+ let has_leading_pipe = p.eat(T![|]);
+ pattern_r(p, m, has_leading_pipe, recovery_set);
}
-/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
-/// given `recovery_set`.
-
// test or_pattern
// fn main() {
// match () {
@@ -52,11 +51,12 @@
// [_ | _,] => (),
// }
// }
-fn pattern_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
- let m = p.start();
+/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
+/// given `recovery_set`.
+fn pattern_r(p: &mut Parser<'_>, m: Marker, has_leading_pipe: bool, recovery_set: TokenSet) {
pattern_single_r(p, recovery_set);
- if !p.at(T![|]) {
+ if !p.at(T![|]) && !has_leading_pipe {
m.abandon(p);
return;
}
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
index 5322463..3c0eb1b 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -39,7 +39,9 @@
conv.offset = shebang_len;
};
- for token in rustc_lexer::tokenize(&text[conv.offset..]) {
+ // Re-create the tokenizer from scratch every token because `GuardedStrPrefix` is one token in the lexer
+ // but we want to split it to two in edition <2024.
+ while let Some(token) = rustc_lexer::tokenize(&text[conv.offset..]).next() {
let token_text = &text[conv.offset..][..token.len as usize];
conv.extend_token(&token.kind, token_text);
@@ -158,7 +160,7 @@
}
}
- fn extend_token(&mut self, kind: &rustc_lexer::TokenKind, token_text: &str) {
+ fn extend_token(&mut self, kind: &rustc_lexer::TokenKind, mut token_text: &str) {
// A note on an intended tradeoff:
// We drop some useful information here (see patterns with double dots `..`)
// Storing that info in `SyntaxKind` is not possible due to its layout requirements of
@@ -189,10 +191,15 @@
rustc_lexer::TokenKind::RawIdent => IDENT,
rustc_lexer::TokenKind::GuardedStrPrefix if self.edition.at_least_2024() => {
+ // FIXME: rustc does something better for recovery.
err = "Invalid string literal (reserved syntax)";
ERROR
}
- rustc_lexer::TokenKind::GuardedStrPrefix => POUND,
+ rustc_lexer::TokenKind::GuardedStrPrefix => {
+ // The token is `#"` or `##`, split it into two.
+ token_text = &token_text[1..];
+ POUND
+ }
rustc_lexer::TokenKind::Literal { kind, .. } => {
self.extend_literal(token_text.len(), kind);
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index 8da338c..2173024 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -312,6 +312,8 @@
UNDERSCORE_EXPR,
UNION,
USE,
+ USE_BOUND_GENERIC_ARG,
+ USE_BOUND_GENERIC_ARGS,
USE_TREE,
USE_TREE_LIST,
VARIANT,
diff --git a/src/tools/rust-analyzer/crates/parser/src/tests.rs b/src/tools/rust-analyzer/crates/parser/src/tests.rs
index e7bccb6..4b19ddc 100644
--- a/src/tools/rust-analyzer/crates/parser/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/tests.rs
@@ -15,11 +15,20 @@
#[path = "../test_data/generated/runner.rs"]
mod runner;
+fn infer_edition(file_path: &Path) -> Edition {
+ let file_content = std::fs::read_to_string(file_path).unwrap();
+ if let Some(edition) = file_content.strip_prefix("//@ edition: ") {
+ edition[..4].parse().expect("invalid edition directive")
+ } else {
+ Edition::CURRENT
+ }
+}
+
#[test]
fn lex_ok() {
for case in TestCase::list("lexer/ok") {
let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
- let actual = lex(&case.text);
+ let actual = lex(&case.text, infer_edition(&case.rs));
expect_file![case.rast].assert_eq(&actual)
}
}
@@ -28,13 +37,13 @@
fn lex_err() {
for case in TestCase::list("lexer/err") {
let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
- let actual = lex(&case.text);
+ let actual = lex(&case.text, infer_edition(&case.rs));
expect_file![case.rast].assert_eq(&actual)
}
}
-fn lex(text: &str) -> String {
- let lexed = LexedStr::new(Edition::CURRENT, text);
+fn lex(text: &str, edition: Edition) -> String {
+ let lexed = LexedStr::new(edition, text);
let mut res = String::new();
for i in 0..lexed.len() {
diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs b/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs
index c56bf0b..7076e03 100644
--- a/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs
@@ -195,6 +195,38 @@
error 0: expected pattern
"#]],
);
+
+ check(
+ TopEntryPoint::Pattern,
+ "| 42 | 43",
+ expect![[r#"
+ OR_PAT
+ PIPE "|"
+ WHITESPACE " "
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "42"
+ WHITESPACE " "
+ PIPE "|"
+ WHITESPACE " "
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "43"
+ "#]],
+ );
+
+ check(
+ TopEntryPoint::Pattern,
+ "| 42",
+ expect![[r#"
+ OR_PAT
+ PIPE "|"
+ WHITESPACE " "
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "42"
+ "#]],
+ );
}
#[test]
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rast
new file mode 100644
index 0000000..1bdd672
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rast
@@ -0,0 +1,4 @@
+COMMENT "//@ edition: 2021"
+WHITESPACE "\n\n"
+POUND "#"
+STRING "\"foo\""
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rs
new file mode 100644
index 0000000..f00f949
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rs
@@ -0,0 +1,3 @@
+//@ edition: 2021
+
+#"foo"
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast
index 8189cf0..9221028 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast
@@ -102,9 +102,9 @@
COMMA ","
WHITESPACE "\n "
MATCH_ARM
- PIPE "|"
- WHITESPACE " "
OR_PAT
+ PIPE "|"
+ WHITESPACE " "
IDENT_PAT
NAME
IDENT "X"
@@ -132,11 +132,12 @@
COMMA ","
WHITESPACE "\n "
MATCH_ARM
- PIPE "|"
- WHITESPACE " "
- IDENT_PAT
- NAME
- IDENT "X"
+ OR_PAT
+ PIPE "|"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "X"
WHITESPACE " "
FAT_ARROW "=>"
WHITESPACE " "
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
index cf52f1e..f9c0a24 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
@@ -50,16 +50,18 @@
WHITESPACE " "
TYPE_BOUND
USE_KW "use"
- GENERIC_PARAM_LIST
+ USE_BOUND_GENERIC_ARGS
L_ANGLE "<"
- LIFETIME_PARAM
- LIFETIME
- LIFETIME_IDENT "'b"
+ LIFETIME
+ LIFETIME_IDENT "'b"
COMMA ","
WHITESPACE " "
- TYPE_PARAM
- NAME
- IDENT "T"
+ NAME_REF
+ IDENT "T"
+ COMMA ","
+ WHITESPACE " "
+ NAME_REF
+ SELF_TYPE_KW "Self"
R_ANGLE ">"
WHITESPACE " "
BLOCK_EXPR
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs
index ec208d5..9ac2305 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs
@@ -1 +1 @@
-fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T> {}
+fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast
index dff72ba..06c30bba 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast
@@ -43,11 +43,12 @@
WHITESPACE " "
SLICE_PAT
L_BRACK "["
- PIPE "|"
- WHITESPACE " "
- IDENT_PAT
- NAME
- IDENT "a"
+ OR_PAT
+ PIPE "|"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "a"
COMMA ","
WHITESPACE " "
REST_PAT
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast
index 1a01e0f..c7cd11f 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast
@@ -91,9 +91,9 @@
WHITESPACE " "
TUPLE_PAT
L_PAREN "("
- PIPE "|"
- WHITESPACE " "
OR_PAT
+ PIPE "|"
+ WHITESPACE " "
IDENT_PAT
NAME
IDENT "a"
@@ -105,11 +105,12 @@
IDENT "a"
COMMA ","
WHITESPACE " "
- PIPE "|"
- WHITESPACE " "
- IDENT_PAT
- NAME
- IDENT "b"
+ OR_PAT
+ PIPE "|"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "b"
R_PAREN ")"
WHITESPACE " "
EQ "="
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast
index 55baf2f..96353f4 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast
@@ -110,11 +110,12 @@
NAME_REF
IDENT "S"
L_PAREN "("
- PIPE "|"
- WHITESPACE " "
- IDENT_PAT
- NAME
- IDENT "a"
+ OR_PAT
+ PIPE "|"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "a"
R_PAREN ")"
WHITESPACE " "
EQ "="
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
index 88256e9..5443a9b 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
@@ -401,7 +401,7 @@
text: Vec<String>,
}
-impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> {
+impl<'a, S: InternableSpan> Writer<'a, '_, S> {
fn write(&mut self, root: &'a tt::Subtree<S>) {
self.enqueue(root);
while let Some((idx, subtree)) = self.work.pop_front() {
@@ -524,7 +524,7 @@
span_data_table: &'span S::Table,
}
-impl<'span, S: InternableSpan> Reader<'span, S> {
+impl<S: InternableSpan> Reader<'_, S> {
pub(crate) fn read(self) -> tt::Subtree<S> {
let mut res: Vec<Option<tt::Subtree<S>>> = vec![None; self.subtree.len()];
let read_span = |id| S::span_for_token_id(self.span_data_table, id);
diff --git a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
index aa73ff8..bc1f0e6 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
@@ -24,14 +24,15 @@
config: RustcCfgConfig<'_>,
) -> Vec<CfgAtom> {
let _p = tracing::info_span!("rustc_cfg::get").entered();
- let mut res: Vec<_> = Vec::with_capacity(6 * 2 + 1);
+ let mut res: Vec<_> = Vec::with_capacity(7 * 2 + 1);
// Some nightly-only cfgs, which are required for stdlib
res.push(CfgAtom::Flag(Symbol::intern("target_thread_local")));
- for ty in ["8", "16", "32", "64", "cas", "ptr"] {
- for key in ["target_has_atomic", "target_has_atomic_load_store"] {
+ for key in ["target_has_atomic", "target_has_atomic_load_store"] {
+ for ty in ["8", "16", "32", "64", "cas", "ptr"] {
res.push(CfgAtom::KeyValue { key: Symbol::intern(key), value: Symbol::intern(ty) });
}
+ res.push(CfgAtom::Flag(Symbol::intern(key)));
}
let rustc_cfgs = get_rust_cfgs(target, extra_env, config);
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index d1ee579..d53639e 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -1062,7 +1062,7 @@
proc_macros,
cargo,
pkg_data,
- build_data,
+ build_data.zip(Some(build_scripts.error().is_some())),
cfg_options.clone(),
file_id,
name,
@@ -1285,7 +1285,7 @@
proc_macros,
rustc_workspace,
&rustc_workspace[pkg],
- build_scripts.get_output(pkg),
+ build_scripts.get_output(pkg).zip(Some(build_scripts.error().is_some())),
cfg_options.clone(),
file_id,
&rustc_workspace[tgt].name,
@@ -1345,7 +1345,7 @@
proc_macros: &mut ProcMacroPaths,
cargo: &CargoWorkspace,
pkg: &PackageData,
- build_data: Option<&BuildScriptOutput>,
+ build_data: Option<(&BuildScriptOutput, bool)>,
cfg_options: CfgOptions,
file_id: FileId,
cargo_name: &str,
@@ -1368,7 +1368,7 @@
for feature in pkg.active_features.iter() {
opts.insert_key_value(sym::feature.clone(), Symbol::intern(feature));
}
- if let Some(cfgs) = build_data.as_ref().map(|it| &it.cfgs) {
+ if let Some(cfgs) = build_data.map(|(it, _)| &it.cfgs) {
opts.extend(cfgs.iter().cloned());
}
opts
@@ -1379,7 +1379,7 @@
inject_cargo_env(&mut env);
inject_rustc_tool_env(&mut env, cargo, cargo_name, kind);
- if let Some(envs) = build_data.map(|it| &it.envs) {
+ if let Some(envs) = build_data.map(|(it, _)| &it.envs) {
for (k, v) in envs {
env.set(k, v.clone());
}
@@ -1396,11 +1396,14 @@
origin,
);
if let TargetKind::Lib { is_proc_macro: true } = kind {
- let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) {
- Some(it) => match it {
- Some(path) => Ok((cargo_name.to_owned(), path.clone())),
- None => Err("proc-macro crate build data is missing dylib path".to_owned()),
- },
+ let proc_macro = match build_data {
+ Some((BuildScriptOutput { proc_macro_dylib_path, .. }, has_errors)) => {
+ match proc_macro_dylib_path {
+ Some(path) => Ok((cargo_name.to_owned(), path.clone())),
+ None if has_errors => Err("failed to build proc-macro".to_owned()),
+ None => Err("proc-macro crate build data is missing dylib path".to_owned()),
+ }
+ }
None => Err("proc-macro crate is missing its build data".to_owned()),
};
proc_macros.insert(crate_id, proc_macro);
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index 3401d7f..880e90c 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -19,6 +19,7 @@
[
"rust_analyzer",
"test",
+ "true",
],
),
potential_cfg_options: None,
@@ -81,6 +82,7 @@
[
"rust_analyzer",
"test",
+ "true",
],
),
potential_cfg_options: None,
@@ -151,6 +153,7 @@
[
"rust_analyzer",
"test",
+ "true",
],
),
potential_cfg_options: None,
@@ -221,6 +224,7 @@
[
"rust_analyzer",
"test",
+ "true",
],
),
potential_cfg_options: None,
@@ -291,6 +295,7 @@
[
"feature=default",
"feature=std",
+ "true",
],
),
potential_cfg_options: Some(
@@ -303,6 +308,7 @@
"feature=rustc-dep-of-std",
"feature=std",
"feature=use_std",
+ "true",
],
),
),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index 3401d7f..880e90c 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -19,6 +19,7 @@
[
"rust_analyzer",
"test",
+ "true",
],
),
potential_cfg_options: None,
@@ -81,6 +82,7 @@
[
"rust_analyzer",
"test",
+ "true",
],
),
potential_cfg_options: None,
@@ -151,6 +153,7 @@
[
"rust_analyzer",
"test",
+ "true",
],
),
potential_cfg_options: None,
@@ -221,6 +224,7 @@
[
"rust_analyzer",
"test",
+ "true",
],
),
potential_cfg_options: None,
@@ -291,6 +295,7 @@
[
"feature=default",
"feature=std",
+ "true",
],
),
potential_cfg_options: Some(
@@ -303,6 +308,7 @@
"feature=rustc-dep-of-std",
"feature=std",
"feature=use_std",
+ "true",
],
),
),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index 491568d..7746acd 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -18,6 +18,7 @@
cfg_options: CfgOptions(
[
"rust_analyzer",
+ "true",
],
),
potential_cfg_options: None,
@@ -79,6 +80,7 @@
cfg_options: CfgOptions(
[
"rust_analyzer",
+ "true",
],
),
potential_cfg_options: None,
@@ -148,6 +150,7 @@
cfg_options: CfgOptions(
[
"rust_analyzer",
+ "true",
],
),
potential_cfg_options: None,
@@ -217,6 +220,7 @@
cfg_options: CfgOptions(
[
"rust_analyzer",
+ "true",
],
),
potential_cfg_options: None,
@@ -287,6 +291,7 @@
[
"feature=default",
"feature=std",
+ "true",
],
),
potential_cfg_options: Some(
@@ -299,6 +304,7 @@
"feature=rustc-dep-of-std",
"feature=std",
"feature=use_std",
+ "true",
],
),
),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
index 8261e5a..90f41a9 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
@@ -17,6 +17,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -56,6 +57,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -86,6 +88,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -116,6 +119,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -146,6 +150,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -193,6 +198,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -223,6 +229,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -318,6 +325,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -348,6 +356,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -378,6 +387,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -410,6 +420,7 @@
"group1_other_cfg=other_config",
"group2_cfg=yet_another_config",
"rust_analyzer",
+ "true",
],
),
potential_cfg_options: None,
@@ -485,6 +496,7 @@
"group2_cfg=fourth_config",
"group2_cfg=yet_another_config",
"rust_analyzer",
+ "true",
"unrelated_cfg",
],
),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index c123df8..a0e14b8 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -17,6 +17,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -56,6 +57,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -86,6 +88,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -116,6 +119,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -146,6 +150,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -193,6 +198,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -223,6 +229,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -318,6 +325,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -348,6 +356,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -378,6 +387,7 @@
[
"debug_assertions",
"miri",
+ "true",
],
),
potential_cfg_options: None,
@@ -407,6 +417,7 @@
cfg_options: CfgOptions(
[
"rust_analyzer",
+ "true",
],
),
potential_cfg_options: None,
diff --git a/src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs b/src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs
index de7a397..6c5ccba 100644
--- a/src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs
+++ b/src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs
@@ -616,7 +616,7 @@
}
}
-impl<'me, Q> Drop for PanicGuard<'me, Q>
+impl<Q> Drop for PanicGuard<'_, Q>
where
Q: QueryFunction,
Q::Value: Eq,
diff --git a/src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs b/src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs
index d0e4b54..ff9cc4e 100644
--- a/src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs
+++ b/src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs
@@ -666,7 +666,7 @@
}
}
-impl<'me, Q, MP> Drop for PanicGuard<'me, Q, MP>
+impl<Q, MP> Drop for PanicGuard<'_, Q, MP>
where
Q: QueryFunction,
MP: MemoizationPolicy<Q>,
diff --git a/src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs b/src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs
index 359662e..42c398d 100644
--- a/src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs
+++ b/src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs
@@ -493,7 +493,7 @@
is_static::<Slot<K>>();
}
-impl<'me, Q> QueryTable<'me, Q>
+impl<Q> QueryTable<'_, Q>
where
Q: Query<Storage = InternedStorage<Q>>,
Q::Key: InternValue,
diff --git a/src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs b/src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs
index 1b32777..bd1ab69 100644
--- a/src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs
@@ -149,7 +149,7 @@
db: &'me D,
}
-impl<'me, D: ?Sized> fmt::Debug for EventDebug<'me, D>
+impl<D: ?Sized> fmt::Debug for EventDebug<'_, D>
where
D: plumbing::DatabaseOps,
{
@@ -242,7 +242,7 @@
db: &'me D,
}
-impl<'me, D: ?Sized> fmt::Debug for EventKindDebug<'me, D>
+impl<D: ?Sized> fmt::Debug for EventKindDebug<'_, D>
where
D: plumbing::DatabaseOps,
{
@@ -729,7 +729,7 @@
db: &'me dyn Database,
}
- impl<'me> std::fmt::Debug for UnexpectedCycleDebug<'me> {
+ impl std::fmt::Debug for UnexpectedCycleDebug<'_> {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.debug_struct("UnexpectedCycle")
.field("all_participants", &self.c.all_participants(self.db))
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
index ecc8333..e872585 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
@@ -85,7 +85,9 @@
flags::RustAnalyzerCmd::UnresolvedReferences(cmd) => cmd.run()?,
flags::RustAnalyzerCmd::Ssr(cmd) => cmd.run()?,
flags::RustAnalyzerCmd::Search(cmd) => cmd.run()?,
- flags::RustAnalyzerCmd::Lsif(cmd) => cmd.run()?,
+ flags::RustAnalyzerCmd::Lsif(cmd) => {
+ cmd.run(&mut std::io::stdout(), Some(project_model::RustLibSource::Discover))?
+ }
flags::RustAnalyzerCmd::Scip(cmd) => cmd.run()?,
flags::RustAnalyzerCmd::RunTests(cmd) => cmd.run()?,
flags::RustAnalyzerCmd::RustcTests(cmd) => cmd.run()?,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
index ca8acf5..33c4f31 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
@@ -12,6 +12,7 @@
use lsp_types::lsif;
use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource};
use rustc_hash::FxHashMap;
+use stdx::format_to;
use vfs::{AbsPathBuf, Vfs};
use crate::{
@@ -21,7 +22,7 @@
version::version,
};
-struct LsifManager<'a> {
+struct LsifManager<'a, 'w> {
count: i32,
token_map: FxHashMap<TokenId, Id>,
range_map: FxHashMap<FileRange, Id>,
@@ -30,6 +31,7 @@
analysis: &'a Analysis,
db: &'a RootDatabase,
vfs: &'a Vfs,
+ out: &'w mut dyn std::io::Write,
}
#[derive(Clone, Copy)]
@@ -41,8 +43,13 @@
}
}
-impl LsifManager<'_> {
- fn new<'a>(analysis: &'a Analysis, db: &'a RootDatabase, vfs: &'a Vfs) -> LsifManager<'a> {
+impl LsifManager<'_, '_> {
+ fn new<'a, 'w>(
+ analysis: &'a Analysis,
+ db: &'a RootDatabase,
+ vfs: &'a Vfs,
+ out: &'w mut dyn std::io::Write,
+ ) -> LsifManager<'a, 'w> {
LsifManager {
count: 0,
token_map: FxHashMap::default(),
@@ -52,6 +59,7 @@
analysis,
db,
vfs,
+ out,
}
}
@@ -70,9 +78,8 @@
self.add(lsif::Element::Edge(edge))
}
- // FIXME: support file in addition to stdout here
- fn emit(&self, data: &str) {
- println!("{data}");
+ fn emit(&mut self, data: &str) {
+ format_to!(self.out, "{data}\n");
}
fn get_token_id(&mut self, id: TokenId) -> Id {
@@ -272,14 +279,14 @@
}
impl flags::Lsif {
- pub fn run(self) -> anyhow::Result<()> {
+ pub fn run(
+ self,
+ out: &mut dyn std::io::Write,
+ sysroot: Option<RustLibSource>,
+ ) -> anyhow::Result<()> {
let now = Instant::now();
- let cargo_config = &CargoConfig {
- sysroot: Some(RustLibSource::Discover),
- all_targets: true,
- set_test: true,
- ..Default::default()
- };
+ let cargo_config =
+ &CargoConfig { sysroot, all_targets: true, set_test: true, ..Default::default() };
let no_progress = &|_| ();
let load_cargo_config = LoadCargoConfig {
load_out_dirs_from_check: true,
@@ -308,7 +315,7 @@
let si = StaticIndex::compute(&analysis, vendored_libs_config);
- let mut lsif = LsifManager::new(&analysis, db, &vfs);
+ let mut lsif = LsifManager::new(&analysis, db, &vfs, out);
lsif.add_vertex(lsif::Vertex::MetaData(lsif::MetaData {
version: String::from("0.5.0"),
project_root: lsp_types::Url::from_file_path(path).unwrap(),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 518b588..f5b0fce 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -727,7 +727,7 @@
Crate(LocalConfigInput),
}
-#[derive(Debug, Clone)]
+#[derive(Clone)]
pub struct Config {
/// Projects that have a Cargo.toml or a rust-project.json in a
/// parent directory, so we can discover them by walking the
@@ -765,6 +765,26 @@
detached_files: Vec<AbsPathBuf>,
}
+impl fmt::Debug for Config {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Config")
+ .field("discovered_projects_from_filesystem", &self.discovered_projects_from_filesystem)
+ .field("discovered_projects_from_command", &self.discovered_projects_from_command)
+ .field("workspace_roots", &self.workspace_roots)
+ .field("caps", &self.caps)
+ .field("root_path", &self.root_path)
+ .field("snippets", &self.snippets)
+ .field("visual_studio_code_version", &self.visual_studio_code_version)
+ .field("client_config", &self.client_config)
+ .field("user_config", &self.user_config)
+ .field("ratoml_file", &self.ratoml_file)
+ .field("source_root_parent_map", &self.source_root_parent_map)
+ .field("validation_errors", &self.validation_errors)
+ .field("detached_files", &self.detached_files)
+ .finish()
+ }
+}
+
// Delegate capability fetching methods
impl std::ops::Deref for Config {
type Target = ClientCapabilities;
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
index 5f2871a..22910ee 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
@@ -173,21 +173,6 @@
let _p = tracing::info_span!("fetch_native_diagnostics").entered();
let _ctx = stdx::panic_context::enter("fetch_native_diagnostics".to_owned());
- let convert_diagnostic =
- |line_index: &crate::line_index::LineIndex, d: ide::Diagnostic| lsp_types::Diagnostic {
- range: lsp::to_proto::range(line_index, d.range.range),
- severity: Some(lsp::to_proto::diagnostic_severity(d.severity)),
- code: Some(lsp_types::NumberOrString::String(d.code.as_str().to_owned())),
- code_description: Some(lsp_types::CodeDescription {
- href: lsp_types::Url::parse(&d.code.url()).unwrap(),
- }),
- source: Some("rust-analyzer".to_owned()),
- message: d.message,
- related_information: None,
- tags: d.unused.then(|| vec![lsp_types::DiagnosticTag::UNNECESSARY]),
- data: None,
- };
-
// the diagnostics produced may point to different files not requested by the concrete request,
// put those into here and filter later
let mut odd_ones = Vec::new();
@@ -203,10 +188,12 @@
NativeDiagnosticsFetchKind::Syntax => {
snapshot.analysis.syntax_diagnostics(config, file_id).ok()?
}
- NativeDiagnosticsFetchKind::Semantic => snapshot
+
+ NativeDiagnosticsFetchKind::Semantic if config.enabled => snapshot
.analysis
.semantic_diagnostics(config, ide::AssistResolveStrategy::None, file_id)
.ok()?,
+ NativeDiagnosticsFetchKind::Semantic => return None,
};
let diagnostics = diagnostics
.into_iter()
@@ -246,3 +233,22 @@
}
diagnostics
}
+
+pub(crate) fn convert_diagnostic(
+ line_index: &crate::line_index::LineIndex,
+ d: ide::Diagnostic,
+) -> lsp_types::Diagnostic {
+ lsp_types::Diagnostic {
+ range: lsp::to_proto::range(line_index, d.range.range),
+ severity: Some(lsp::to_proto::diagnostic_severity(d.severity)),
+ code: Some(lsp_types::NumberOrString::String(d.code.as_str().to_owned())),
+ code_description: Some(lsp_types::CodeDescription {
+ href: lsp_types::Url::parse(&d.code.url()).unwrap(),
+ }),
+ source: Some("rust-analyzer".to_owned()),
+ message: d.message,
+ related_information: None,
+ tags: d.unused.then(|| vec![lsp_types::DiagnosticTag::UNNECESSARY]),
+ data: None,
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs
index ed7bf27..03759b0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs
@@ -5,7 +5,7 @@
};
use ide::Cancelled;
-use lsp_server::ExtractError;
+use lsp_server::{ExtractError, Response, ResponseError};
use serde::{de::DeserializeOwned, Serialize};
use stdx::thread::ThreadIntent;
@@ -117,7 +117,36 @@
}
return self;
}
- self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::Worker, f)
+ self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(
+ ThreadIntent::Worker,
+ f,
+ Self::content_modified_error,
+ )
+ }
+
+ /// Dispatches a non-latency-sensitive request onto the thread pool. When the VFS is marked not
+ /// ready this will return a `default` constructed [`R::Result`].
+ pub(crate) fn on_with<R>(
+ &mut self,
+ f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
+ default: impl FnOnce() -> R::Result,
+ on_cancelled: fn() -> ResponseError,
+ ) -> &mut Self
+ where
+ R: lsp_types::request::Request<
+ Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
+ Result: Serialize,
+ > + 'static,
+ {
+ if !self.global_state.vfs_done {
+ if let Some(lsp_server::Request { id, .. }) =
+ self.req.take_if(|it| it.method == R::METHOD)
+ {
+ self.global_state.respond(lsp_server::Response::new_ok(id, default()));
+ }
+ return self;
+ }
+ self.on_with_thread_intent::<true, false, R>(ThreadIntent::Worker, f, on_cancelled)
}
/// Dispatches a non-latency-sensitive request onto the thread pool. When the VFS is marked not
@@ -136,7 +165,11 @@
}
return self;
}
- self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::Worker, f)
+ self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(
+ ThreadIntent::Worker,
+ f,
+ Self::content_modified_error,
+ )
}
/// Dispatches a latency-sensitive request onto the thread pool. When the VFS is marked not
@@ -159,7 +192,11 @@
}
return self;
}
- self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::LatencySensitive, f)
+ self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(
+ ThreadIntent::LatencySensitive,
+ f,
+ Self::content_modified_error,
+ )
}
/// Formatting requests should never block on waiting a for task thread to open up, editors will wait
@@ -174,7 +211,11 @@
R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
R::Result: Serialize,
{
- self.on_with_thread_intent::<false, false, R>(ThreadIntent::LatencySensitive, f)
+ self.on_with_thread_intent::<false, false, R>(
+ ThreadIntent::LatencySensitive,
+ f,
+ Self::content_modified_error,
+ )
}
pub(crate) fn finish(&mut self) {
@@ -193,6 +234,7 @@
&mut self,
intent: ThreadIntent,
f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
+ on_cancelled: fn() -> ResponseError,
) -> &mut Self
where
R: lsp_types::request::Request + 'static,
@@ -221,11 +263,10 @@
match thread_result_to_response::<R>(req.id.clone(), result) {
Ok(response) => Task::Response(response),
Err(_cancelled) if ALLOW_RETRYING => Task::Retry(req),
- Err(_cancelled) => Task::Response(lsp_server::Response::new_err(
- req.id,
- lsp_server::ErrorCode::ContentModified as i32,
- "content modified".to_owned(),
- )),
+ Err(_cancelled) => {
+ let error = on_cancelled();
+ Task::Response(Response { id: req.id, result: None, error: Some(error) })
+ }
}
});
@@ -256,6 +297,14 @@
}
}
}
+
+ fn content_modified_error() -> ResponseError {
+ ResponseError {
+ code: lsp_server::ErrorCode::ContentModified as i32,
+ message: "content modified".to_owned(),
+ data: None,
+ }
+ }
}
fn thread_result_to_response<R>(
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index a9f8ac3..fa584ab 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -4,6 +4,7 @@
use std::{
fs,
io::Write as _,
+ ops::Not,
process::{self, Stdio},
};
@@ -14,7 +15,7 @@
FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query,
RangeInfo, ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
};
-use ide_db::SymbolKind;
+use ide_db::{FxHashMap, SymbolKind};
use itertools::Itertools;
use lsp_server::ErrorCode;
use lsp_types::{
@@ -36,6 +37,7 @@
use crate::{
config::{Config, RustfmtConfig, WorkspaceSymbolConfig},
+ diagnostics::convert_diagnostic,
global_state::{FetchWorkspaceRequest, GlobalState, GlobalStateSnapshot},
hack_recover_crate_name,
line_index::LineEndings,
@@ -119,7 +121,7 @@
format_to!(buf, "{}", crate::version());
buf.push_str("\nConfiguration: \n");
- format_to!(buf, "{:?}", snap.config);
+ format_to!(buf, "{:#?}", snap.config);
Ok(buf)
}
@@ -473,6 +475,74 @@
Ok(Some(change))
}
+pub(crate) fn handle_document_diagnostics(
+ snap: GlobalStateSnapshot,
+ params: lsp_types::DocumentDiagnosticParams,
+) -> anyhow::Result<lsp_types::DocumentDiagnosticReportResult> {
+ const EMPTY: lsp_types::DocumentDiagnosticReportResult =
+ lsp_types::DocumentDiagnosticReportResult::Report(
+ lsp_types::DocumentDiagnosticReport::Full(
+ lsp_types::RelatedFullDocumentDiagnosticReport {
+ related_documents: None,
+ full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
+ result_id: None,
+ items: vec![],
+ },
+ },
+ ),
+ );
+
+ let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?;
+ let source_root = snap.analysis.source_root_id(file_id)?;
+ if !snap.analysis.is_local_source_root(source_root)? {
+ return Ok(EMPTY);
+ }
+ let config = snap.config.diagnostics(Some(source_root));
+ if !config.enabled {
+ return Ok(EMPTY);
+ }
+ let line_index = snap.file_line_index(file_id)?;
+ let supports_related = snap.config.text_document_diagnostic_related_document_support();
+
+ let mut related_documents = FxHashMap::default();
+ let diagnostics = snap
+ .analysis
+ .full_diagnostics(&config, AssistResolveStrategy::None, file_id)?
+ .into_iter()
+ .filter_map(|d| {
+ let file = d.range.file_id;
+ let diagnostic = convert_diagnostic(&line_index, d);
+ if file == file_id {
+ return Some(diagnostic);
+ }
+ if supports_related {
+ related_documents.entry(file).or_insert_with(Vec::new).push(diagnostic);
+ }
+ None
+ });
+ Ok(lsp_types::DocumentDiagnosticReportResult::Report(
+ lsp_types::DocumentDiagnosticReport::Full(lsp_types::RelatedFullDocumentDiagnosticReport {
+ full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
+ result_id: None,
+ items: diagnostics.collect(),
+ },
+ related_documents: related_documents.is_empty().not().then(|| {
+ related_documents
+ .into_iter()
+ .map(|(id, items)| {
+ (
+ to_proto::url(&snap, id),
+ lsp_types::DocumentDiagnosticReportKind::Full(
+ lsp_types::FullDocumentDiagnosticReport { result_id: None, items },
+ ),
+ )
+ })
+ .collect()
+ }),
+ }),
+ ))
+}
+
pub(crate) fn handle_document_symbol(
snap: GlobalStateSnapshot,
params: lsp_types::DocumentSymbolParams,
@@ -539,18 +609,11 @@
url: &Url,
res: &mut Vec<SymbolInformation>,
) {
- let mut tags = Vec::new();
-
- #[allow(deprecated)]
- if let Some(true) = symbol.deprecated {
- tags.push(SymbolTag::DEPRECATED)
- }
-
#[allow(deprecated)]
res.push(SymbolInformation {
name: symbol.name.clone(),
kind: symbol.kind,
- tags: Some(tags),
+ tags: symbol.tags.clone(),
deprecated: symbol.deprecated,
location: Location::new(url.clone(), symbol.range),
container_name,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
index 3b19284..271a9c0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -155,7 +155,15 @@
"ssr": true,
"workspaceSymbolScopeKindFiltering": true,
})),
- diagnostic_provider: None,
+ diagnostic_provider: Some(lsp_types::DiagnosticServerCapabilities::Options(
+ lsp_types::DiagnosticOptions {
+ identifier: None,
+ inter_file_dependencies: true,
+ // FIXME
+ workspace_diagnostics: false,
+ work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
+ },
+ )),
inline_completion_provider: None,
}
}
@@ -210,9 +218,7 @@
.completion_item
.as_ref()?
.label_details_support
- .as_ref()
- })()
- .is_some()
+ })() == Some(true)
}
fn completion_item(&self) -> Option<CompletionOptionsCompletionItem> {
@@ -382,6 +388,15 @@
.unwrap_or_default()
}
+ pub fn text_document_diagnostic(&self) -> bool {
+ (|| -> _ { self.0.text_document.as_ref()?.diagnostic.as_ref() })().is_some()
+ }
+
+ pub fn text_document_diagnostic_related_document_support(&self) -> bool {
+ (|| -> _ { self.0.text_document.as_ref()?.diagnostic.as_ref()?.related_document_support })()
+ == Some(true)
+ }
+
pub fn code_action_group(&self) -> bool {
self.experimental_bool("codeActionGroup")
}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index 20be38a..9a51df8 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -417,6 +417,8 @@
}
}
+ let supports_diagnostic_pull_model = self.config.text_document_diagnostic();
+
let client_refresh = became_quiescent || state_changed;
if client_refresh {
// Refresh semantic tokens if the client supports it.
@@ -434,11 +436,21 @@
if self.config.inlay_hints_refresh() {
self.send_request::<lsp_types::request::InlayHintRefreshRequest>((), |_, _| ());
}
+
+ if supports_diagnostic_pull_model {
+ self.send_request::<lsp_types::request::WorkspaceDiagnosticRefresh>(
+ (),
+ |_, _| (),
+ );
+ }
}
let project_or_mem_docs_changed =
became_quiescent || state_changed || memdocs_added_or_removed;
- if project_or_mem_docs_changed && self.config.publish_diagnostics(None) {
+ if project_or_mem_docs_changed
+ && !supports_diagnostic_pull_model
+ && self.config.publish_diagnostics(None)
+ {
self.update_diagnostics();
}
if project_or_mem_docs_changed && self.config.test_explorer() {
@@ -1080,6 +1092,23 @@
.on_latency_sensitive::<NO_RETRY, lsp_request::SemanticTokensRangeRequest>(handlers::handle_semantic_tokens_range)
// FIXME: Some of these NO_RETRY could be retries if the file they are interested didn't change.
// All other request handlers
+ .on_with::<lsp_request::DocumentDiagnosticRequest>(handlers::handle_document_diagnostics, || lsp_types::DocumentDiagnosticReportResult::Report(
+ lsp_types::DocumentDiagnosticReport::Full(
+ lsp_types::RelatedFullDocumentDiagnosticReport {
+ related_documents: None,
+ full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
+ result_id: None,
+ items: vec![],
+ },
+ },
+ ),
+ ), || lsp_server::ResponseError {
+ code: lsp_server::ErrorCode::ServerCancelled as i32,
+ message: "server cancelled the request".to_owned(),
+ data: serde_json::to_value(lsp_types::DiagnosticServerCancellationData {
+ retrigger_request: true
+ }).ok(),
+ })
.on::<RETRY, lsp_request::DocumentSymbolRequest>(handlers::handle_document_symbol)
.on::<RETRY, lsp_request::FoldingRangeRequest>(handlers::handle_folding_range)
.on::<NO_RETRY, lsp_request::SignatureHelpRequest>(handlers::handle_signature_help)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs
index 5ab2dc2..02ae418 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs
@@ -58,14 +58,22 @@
let writer = self.writer;
let ra_fmt_layer = tracing_subscriber::fmt::layer()
- .with_timer(
- time::OffsetTime::local_rfc_3339()
- .expect("Could not get local offset, make sure you're on the main thread"),
- )
.with_target(false)
.with_ansi(false)
- .with_writer(writer)
- .with_filter(targets_filter);
+ .with_writer(writer);
+
+ let ra_fmt_layer = match time::OffsetTime::local_rfc_3339() {
+ Ok(timer) => {
+ // If we can get the time offset, format logs with the timezone.
+ ra_fmt_layer.with_timer(timer).boxed()
+ }
+ Err(_) => {
+ // Use system time if we can't get the time offset. This should
+ // never happen on Linux, but can happen on e.g. OpenBSD.
+ ra_fmt_layer.boxed()
+ }
+ }
+ .with_filter(targets_filter);
let chalk_layer = match self.chalk_filter {
Some(chalk_filter) => {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs
index cad9296..d466ace 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs
@@ -120,7 +120,7 @@
string: &'a mut String,
}
-impl<'a> Visit for DataVisitor<'a> {
+impl Visit for DataVisitor<'_> {
fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) {
write!(self.string, "{} = {:?} ", field.name(), value).unwrap();
}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs
new file mode 100644
index 0000000..fba5466
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs
@@ -0,0 +1,131 @@
+use expect_test::expect;
+use test_utils::skip_slow_tests;
+
+use crate::support::Project;
+
+// If you choose to change the test fixture here, please inform the ferrocene/needy maintainers by
+// opening an issue at https://github.com/ferrocene/needy as the tool relies on specific token
+// mapping behavior.
+#[test]
+fn lsif_contains_generated_constant() {
+ if skip_slow_tests() {
+ return;
+ }
+
+ let stdout = Project::with_fixture(
+ r#"
+//- /Cargo.toml
+[package]
+name = "foo"
+version = "0.0.0"
+
+//- /src/lib.rs
+#![allow(unused)]
+
+macro_rules! generate_const_from_identifier(
+ ($id:ident) => (
+ const _: () = { const $id: &str = "encoded_data"; };
+ )
+);
+
+generate_const_from_identifier!(REQ_001);
+mod tests {
+ use super::*;
+ generate_const_from_identifier!(REQ_002);
+}
+"#,
+ )
+ .root("foo")
+ .run_lsif();
+ let n = stdout.find(r#"{"id":2,"#).unwrap();
+ // the first 2 entries contain paths that are not stable
+ let stdout = &stdout[n..];
+ expect![[r#"
+ {"id":2,"type":"vertex","label":"foldingRangeResult","result":[{"startLine":2,"startCharacter":43,"endLine":6,"endCharacter":1},{"startLine":3,"startCharacter":19,"endLine":5,"endCharacter":5},{"startLine":9,"startCharacter":10,"endLine":12,"endCharacter":1}]}
+ {"id":3,"type":"edge","label":"textDocument/foldingRange","inV":2,"outV":1}
+ {"id":4,"type":"vertex","label":"range","start":{"line":0,"character":3},"end":{"line":0,"character":8}}
+ {"id":5,"type":"vertex","label":"resultSet"}
+ {"id":6,"type":"edge","label":"next","inV":5,"outV":4}
+ {"id":7,"type":"vertex","label":"range","start":{"line":2,"character":13},"end":{"line":2,"character":43}}
+ {"id":8,"type":"vertex","label":"resultSet"}
+ {"id":9,"type":"edge","label":"next","inV":8,"outV":7}
+ {"id":10,"type":"vertex","label":"range","start":{"line":8,"character":0},"end":{"line":8,"character":30}}
+ {"id":11,"type":"edge","label":"next","inV":8,"outV":10}
+ {"id":12,"type":"vertex","label":"range","start":{"line":8,"character":32},"end":{"line":8,"character":39}}
+ {"id":13,"type":"vertex","label":"resultSet"}
+ {"id":14,"type":"edge","label":"next","inV":13,"outV":12}
+ {"id":15,"type":"vertex","label":"range","start":{"line":9,"character":4},"end":{"line":9,"character":9}}
+ {"id":16,"type":"vertex","label":"resultSet"}
+ {"id":17,"type":"edge","label":"next","inV":16,"outV":15}
+ {"id":18,"type":"vertex","label":"range","start":{"line":10,"character":8},"end":{"line":10,"character":13}}
+ {"id":19,"type":"vertex","label":"resultSet"}
+ {"id":20,"type":"edge","label":"next","inV":19,"outV":18}
+ {"id":21,"type":"vertex","label":"range","start":{"line":11,"character":4},"end":{"line":11,"character":34}}
+ {"id":22,"type":"edge","label":"next","inV":8,"outV":21}
+ {"id":23,"type":"vertex","label":"range","start":{"line":11,"character":36},"end":{"line":11,"character":43}}
+ {"id":24,"type":"vertex","label":"resultSet"}
+ {"id":25,"type":"edge","label":"next","inV":24,"outV":23}
+ {"id":26,"type":"edge","label":"contains","inVs":[4,7,10,12,15,18,21,23],"outV":1}
+ {"id":27,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\n#[allow]\n```\n\n---\n\nValid forms are:\n\n* \\#\\[allow(lint1, lint2, ..., /\\*opt\\*/ reason = \"...\")\\]"}}}
+ {"id":28,"type":"edge","label":"textDocument/hover","inV":27,"outV":5}
+ {"id":29,"type":"vertex","label":"referenceResult"}
+ {"id":30,"type":"edge","label":"textDocument/references","inV":29,"outV":5}
+ {"id":31,"type":"edge","label":"item","document":1,"property":"references","inVs":[4],"outV":29}
+ {"id":32,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nmacro_rules! generate_const_from_identifier\n```"}}}
+ {"id":33,"type":"edge","label":"textDocument/hover","inV":32,"outV":8}
+ {"id":34,"type":"vertex","label":"packageInformation","name":"foo","manager":"cargo","version":"0.0.0"}
+ {"id":35,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::generate_const_from_identifier","unique":"scheme","kind":"export"}
+ {"id":36,"type":"edge","label":"packageInformation","inV":34,"outV":35}
+ {"id":37,"type":"edge","label":"moniker","inV":35,"outV":8}
+ {"id":38,"type":"vertex","label":"definitionResult"}
+ {"id":39,"type":"edge","label":"item","document":1,"inVs":[7],"outV":38}
+ {"id":40,"type":"edge","label":"textDocument/definition","inV":38,"outV":8}
+ {"id":41,"type":"vertex","label":"referenceResult"}
+ {"id":42,"type":"edge","label":"textDocument/references","inV":41,"outV":8}
+ {"id":43,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[7],"outV":41}
+ {"id":44,"type":"edge","label":"item","document":1,"property":"references","inVs":[10,21],"outV":41}
+ {"id":45,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nconst REQ_001: &str = \"encoded_data\"\n```"}}}
+ {"id":46,"type":"edge","label":"textDocument/hover","inV":45,"outV":13}
+ {"id":47,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::REQ_001","unique":"scheme","kind":"export"}
+ {"id":48,"type":"edge","label":"packageInformation","inV":34,"outV":47}
+ {"id":49,"type":"edge","label":"moniker","inV":47,"outV":13}
+ {"id":50,"type":"vertex","label":"definitionResult"}
+ {"id":51,"type":"edge","label":"item","document":1,"inVs":[12],"outV":50}
+ {"id":52,"type":"edge","label":"textDocument/definition","inV":50,"outV":13}
+ {"id":53,"type":"vertex","label":"referenceResult"}
+ {"id":54,"type":"edge","label":"textDocument/references","inV":53,"outV":13}
+ {"id":55,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[12],"outV":53}
+ {"id":56,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nmod tests\n```"}}}
+ {"id":57,"type":"edge","label":"textDocument/hover","inV":56,"outV":16}
+ {"id":58,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::tests","unique":"scheme","kind":"export"}
+ {"id":59,"type":"edge","label":"packageInformation","inV":34,"outV":58}
+ {"id":60,"type":"edge","label":"moniker","inV":58,"outV":16}
+ {"id":61,"type":"vertex","label":"definitionResult"}
+ {"id":62,"type":"edge","label":"item","document":1,"inVs":[15],"outV":61}
+ {"id":63,"type":"edge","label":"textDocument/definition","inV":61,"outV":16}
+ {"id":64,"type":"vertex","label":"referenceResult"}
+ {"id":65,"type":"edge","label":"textDocument/references","inV":64,"outV":16}
+ {"id":66,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[15],"outV":64}
+ {"id":67,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nextern crate foo\n```"}}}
+ {"id":68,"type":"edge","label":"textDocument/hover","inV":67,"outV":19}
+ {"id":69,"type":"vertex","label":"definitionResult"}
+ {"id":70,"type":"vertex","label":"range","start":{"line":0,"character":0},"end":{"line":13,"character":0}}
+ {"id":71,"type":"edge","label":"contains","inVs":[70],"outV":1}
+ {"id":72,"type":"edge","label":"item","document":1,"inVs":[70],"outV":69}
+ {"id":73,"type":"edge","label":"textDocument/definition","inV":69,"outV":19}
+ {"id":74,"type":"vertex","label":"referenceResult"}
+ {"id":75,"type":"edge","label":"textDocument/references","inV":74,"outV":19}
+ {"id":76,"type":"edge","label":"item","document":1,"property":"references","inVs":[18],"outV":74}
+ {"id":77,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo::tests\n```\n\n```rust\nconst REQ_002: &str = \"encoded_data\"\n```"}}}
+ {"id":78,"type":"edge","label":"textDocument/hover","inV":77,"outV":24}
+ {"id":79,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::tests::REQ_002","unique":"scheme","kind":"export"}
+ {"id":80,"type":"edge","label":"packageInformation","inV":34,"outV":79}
+ {"id":81,"type":"edge","label":"moniker","inV":79,"outV":24}
+ {"id":82,"type":"vertex","label":"definitionResult"}
+ {"id":83,"type":"edge","label":"item","document":1,"inVs":[23],"outV":82}
+ {"id":84,"type":"edge","label":"textDocument/definition","inV":82,"outV":24}
+ {"id":85,"type":"vertex","label":"referenceResult"}
+ {"id":86,"type":"edge","label":"textDocument/references","inV":85,"outV":24}
+ {"id":87,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[23],"outV":85}
+ "#]].assert_eq(stdout);
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index 54cd27f..97c76bf 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -10,6 +10,7 @@
#![allow(clippy::disallowed_types)]
+mod cli;
mod ratoml;
mod support;
mod testdir;
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index 18aface..78572e3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -6,11 +6,13 @@
};
use crossbeam_channel::{after, select, Receiver};
+use itertools::Itertools;
use lsp_server::{Connection, Message, Notification, Request};
use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url};
use parking_lot::{Mutex, MutexGuard};
use paths::{Utf8Path, Utf8PathBuf};
use rust_analyzer::{
+ cli::flags,
config::{Config, ConfigChange, ConfigErrors},
lsp, main_loop,
};
@@ -84,6 +86,46 @@
self
}
+ pub(crate) fn run_lsif(self) -> String {
+ let tmp_dir = self.tmp_dir.unwrap_or_else(|| {
+ if self.root_dir_contains_symlink {
+ TestDir::new_symlink()
+ } else {
+ TestDir::new()
+ }
+ });
+
+ let FixtureWithProjectMeta {
+ fixture,
+ mini_core,
+ proc_macro_names,
+ toolchain,
+ target_data_layout: _,
+ } = FixtureWithProjectMeta::parse(self.fixture);
+ assert!(proc_macro_names.is_empty());
+ assert!(mini_core.is_none());
+ assert!(toolchain.is_none());
+
+ for entry in fixture {
+ let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]);
+ fs::create_dir_all(path.parent().unwrap()).unwrap();
+ fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
+ }
+
+ let tmp_dir_path = AbsPathBuf::assert(tmp_dir.path().to_path_buf());
+ let mut buf = Vec::new();
+ flags::Lsif::run(
+ flags::Lsif {
+ path: tmp_dir_path.join(self.roots.iter().exactly_one().unwrap()).into(),
+ exclude_vendored_libraries: false,
+ },
+ &mut buf,
+ None,
+ )
+ .unwrap();
+ String::from_utf8(buf).unwrap()
+ }
+
pub(crate) fn server(self) -> Server {
static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(());
let tmp_dir = self.tmp_dir.unwrap_or_else(|| {
diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs
index 0ebd72e..1d81d68 100644
--- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs
+++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs
@@ -224,9 +224,10 @@
match self.map.raw_entry().from_hash(hash, |&idx| self.arena[idx] == ptr) {
Some((&idx, &())) => ErasedFileAstId(idx.into_raw().into_u32()),
None => panic!(
- "Can't find {:?} in AstIdMap:\n{:?}",
+ "Can't find {:?} in AstIdMap:\n{:?}\n source text: {}",
item,
self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
+ item
),
}
}
diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
index 76dbd42..04c2153 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
@@ -10,6 +10,7 @@
pub mod panic_context;
pub mod process;
pub mod rand;
+pub mod thin_vec;
pub mod thread;
pub use always_assert::{always, never};
@@ -304,22 +305,6 @@
(0..this.len()).map(|i| &this[i..])
}
-pub trait IsNoneOr {
- type Type;
- #[allow(clippy::wrong_self_convention)]
- fn is_none_or(self, s: impl FnOnce(Self::Type) -> bool) -> bool;
-}
-#[allow(unstable_name_collisions)]
-impl<T> IsNoneOr for Option<T> {
- type Type = T;
- fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool {
- match self {
- Some(v) => f(v),
- None => true,
- }
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs b/src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs
new file mode 100644
index 0000000..700220e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs
@@ -0,0 +1,472 @@
+use std::alloc::{dealloc, handle_alloc_error, Layout};
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
+use std::ops::{Deref, DerefMut};
+use std::ptr::{addr_of_mut, slice_from_raw_parts_mut, NonNull};
+
+/// A type that is functionally equivalent to `(Header, Box<[Item]>)`,
+/// but all data is stored in one heap allocation and the pointer is thin,
+/// so the whole thing's size is like a pointer.
+pub struct ThinVecWithHeader<Header, Item> {
+ /// INVARIANT: Points to a valid heap allocation that contains `ThinVecInner<Header>`,
+ /// followed by (suitably aligned) `len` `Item`s.
+ ptr: NonNull<ThinVecInner<Header>>,
+ _marker: PhantomData<(Header, Box<[Item]>)>,
+}
+
+// SAFETY: We essentially own both the header and the items.
+unsafe impl<Header: Send, Item: Send> Send for ThinVecWithHeader<Header, Item> {}
+unsafe impl<Header: Sync, Item: Sync> Sync for ThinVecWithHeader<Header, Item> {}
+
+#[derive(Clone)]
+struct ThinVecInner<Header> {
+ header: Header,
+ len: usize,
+}
+
+impl<Header, Item> ThinVecWithHeader<Header, Item> {
+ /// # Safety
+ ///
+ /// The iterator must produce `len` elements.
+ #[inline]
+ unsafe fn from_trusted_len_iter(
+ header: Header,
+ len: usize,
+ items: impl Iterator<Item = Item>,
+ ) -> Self {
+ let (ptr, layout, items_offset) = Self::allocate(len);
+
+ struct DeallocGuard(*mut u8, Layout);
+ impl Drop for DeallocGuard {
+ fn drop(&mut self) {
+ // SAFETY: We allocated this above.
+ unsafe {
+ dealloc(self.0, self.1);
+ }
+ }
+ }
+ let _dealloc_guard = DeallocGuard(ptr.as_ptr().cast::<u8>(), layout);
+
+ // INVARIANT: Between `0..1` there are only initialized items.
+ struct ItemsGuard<Item>(*mut Item, *mut Item);
+ impl<Item> Drop for ItemsGuard<Item> {
+ fn drop(&mut self) {
+ // SAFETY: Our invariant.
+ unsafe {
+ slice_from_raw_parts_mut(self.0, self.1.offset_from(self.0) as usize)
+ .drop_in_place();
+ }
+ }
+ }
+
+ // SAFETY: We allocated enough space.
+ let mut items_ptr = unsafe { ptr.as_ptr().byte_add(items_offset).cast::<Item>() };
+ // INVARIANT: There are zero elements in this range.
+ let mut items_guard = ItemsGuard(items_ptr, items_ptr);
+ items.for_each(|item| {
+ // SAFETY: Our precondition guarantee we won't get more than `len` items, and we allocated
+ // enough space for `len` items.
+ unsafe {
+ items_ptr.write(item);
+ items_ptr = items_ptr.add(1);
+ }
+ // INVARIANT: We just initialized this item.
+ items_guard.1 = items_ptr;
+ });
+
+ // SAFETY: We allocated enough space.
+ unsafe {
+ ptr.write(ThinVecInner { header, len });
+ }
+
+ std::mem::forget(items_guard);
+
+ std::mem::forget(_dealloc_guard);
+
+ // INVARIANT: We allocated and initialized all fields correctly.
+ Self { ptr, _marker: PhantomData }
+ }
+
+ #[inline]
+ fn allocate(len: usize) -> (NonNull<ThinVecInner<Header>>, Layout, usize) {
+ let (layout, items_offset) = Self::layout(len);
+ // SAFETY: We always have `len`, so our allocation cannot be zero-sized.
+ let ptr = unsafe { std::alloc::alloc(layout).cast::<ThinVecInner<Header>>() };
+ let Some(ptr) = NonNull::<ThinVecInner<Header>>::new(ptr) else {
+ handle_alloc_error(layout);
+ };
+ (ptr, layout, items_offset)
+ }
+
+ #[inline]
+ #[allow(clippy::should_implement_trait)]
+ pub fn from_iter<I>(header: Header, items: I) -> Self
+ where
+ I: IntoIterator,
+ I::IntoIter: TrustedLen<Item = Item>,
+ {
+ let items = items.into_iter();
+ // SAFETY: `TrustedLen` guarantees the iterator length is exact.
+ unsafe { Self::from_trusted_len_iter(header, items.len(), items) }
+ }
+
+ #[inline]
+ fn items_offset(&self) -> usize {
+ // SAFETY: We `pad_to_align()` in `layout()`, so at most where accessing past the end of the allocation,
+ // which is allowed.
+ unsafe {
+ Layout::new::<ThinVecInner<Header>>().extend(Layout::new::<Item>()).unwrap_unchecked().1
+ }
+ }
+
+ #[inline]
+ fn header_and_len(&self) -> &ThinVecInner<Header> {
+ // SAFETY: By `ptr`'s invariant, it is correctly allocated and initialized.
+ unsafe { &*self.ptr.as_ptr() }
+ }
+
+ #[inline]
+ fn items_ptr(&self) -> *mut [Item] {
+ let len = self.header_and_len().len;
+ // SAFETY: `items_offset()` returns the correct offset of the items, where they are allocated.
+ let ptr = unsafe { self.ptr.as_ptr().byte_add(self.items_offset()).cast::<Item>() };
+ slice_from_raw_parts_mut(ptr, len)
+ }
+
+ #[inline]
+ pub fn header(&self) -> &Header {
+ &self.header_and_len().header
+ }
+
+ #[inline]
+ pub fn header_mut(&mut self) -> &mut Header {
+ // SAFETY: By `ptr`'s invariant, it is correctly allocated and initialized.
+ unsafe { &mut *addr_of_mut!((*self.ptr.as_ptr()).header) }
+ }
+
+ #[inline]
+ pub fn items(&self) -> &[Item] {
+ // SAFETY: `items_ptr()` gives a valid pointer.
+ unsafe { &*self.items_ptr() }
+ }
+
+ #[inline]
+ pub fn items_mut(&mut self) -> &mut [Item] {
+ // SAFETY: `items_ptr()` gives a valid pointer.
+ unsafe { &mut *self.items_ptr() }
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.header_and_len().len
+ }
+
+ #[inline]
+ fn layout(len: usize) -> (Layout, usize) {
+ let (layout, items_offset) = Layout::new::<ThinVecInner<Header>>()
+ .extend(Layout::array::<Item>(len).expect("too big `ThinVec` requested"))
+ .expect("too big `ThinVec` requested");
+ let layout = layout.pad_to_align();
+ (layout, items_offset)
+ }
+}
+
+/// # Safety
+///
+/// The length reported must be exactly the number of items yielded.
+pub unsafe trait TrustedLen: ExactSizeIterator {}
+
+unsafe impl<T> TrustedLen for std::vec::IntoIter<T> {}
+unsafe impl<T> TrustedLen for std::slice::Iter<'_, T> {}
+unsafe impl<'a, T: Clone + 'a, I: TrustedLen<Item = &'a T>> TrustedLen for std::iter::Cloned<I> {}
+unsafe impl<T, I: TrustedLen, F: FnMut(I::Item) -> T> TrustedLen for std::iter::Map<I, F> {}
+unsafe impl<T> TrustedLen for std::vec::Drain<'_, T> {}
+unsafe impl<T, const N: usize> TrustedLen for std::array::IntoIter<T, N> {}
+
+impl<Header: Clone, Item: Clone> Clone for ThinVecWithHeader<Header, Item> {
+ #[inline]
+ fn clone(&self) -> Self {
+ Self::from_iter(self.header().clone(), self.items().iter().cloned())
+ }
+}
+
+impl<Header, Item> Drop for ThinVecWithHeader<Header, Item> {
+ #[inline]
+ fn drop(&mut self) {
+ // This must come before we drop `header`, because after that we cannot make a reference to it in `len()`.
+ let len = self.len();
+
+ // SAFETY: The contents are allocated and initialized.
+ unsafe {
+ addr_of_mut!((*self.ptr.as_ptr()).header).drop_in_place();
+ self.items_ptr().drop_in_place();
+ }
+
+ let (layout, _) = Self::layout(len);
+ // SAFETY: This was allocated in `new()` with the same layout calculation.
+ unsafe {
+ dealloc(self.ptr.as_ptr().cast::<u8>(), layout);
+ }
+ }
+}
+
+impl<Header: fmt::Debug, Item: fmt::Debug> fmt::Debug for ThinVecWithHeader<Header, Item> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ThinVecWithHeader")
+ .field("header", self.header())
+ .field("items", &self.items())
+ .finish()
+ }
+}
+
+impl<Header: PartialEq, Item: PartialEq> PartialEq for ThinVecWithHeader<Header, Item> {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.header() == other.header() && self.items() == other.items()
+ }
+}
+
+impl<Header: Eq, Item: Eq> Eq for ThinVecWithHeader<Header, Item> {}
+
+impl<Header: Hash, Item: Hash> Hash for ThinVecWithHeader<Header, Item> {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.header().hash(state);
+ self.items().hash(state);
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct ThinVec<T>(ThinVecWithHeader<(), T>);
+
+impl<T> ThinVec<T> {
+ #[inline]
+ #[allow(clippy::should_implement_trait)]
+ pub fn from_iter<I>(values: I) -> Self
+ where
+ I: IntoIterator,
+ I::IntoIter: TrustedLen<Item = T>,
+ {
+ Self(ThinVecWithHeader::from_iter((), values))
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.0.len()
+ }
+
+ #[inline]
+ pub fn iter(&self) -> std::slice::Iter<'_, T> {
+ (**self).iter()
+ }
+
+ #[inline]
+ pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
+ (**self).iter_mut()
+ }
+}
+
+impl<T> Deref for ThinVec<T> {
+ type Target = [T];
+
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ self.0.items()
+ }
+}
+
+impl<T> DerefMut for ThinVec<T> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.0.items_mut()
+ }
+}
+
+impl<'a, T> IntoIterator for &'a ThinVec<T> {
+ type IntoIter = std::slice::Iter<'a, T>;
+ type Item = &'a T;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl<'a, T> IntoIterator for &'a mut ThinVec<T> {
+ type IntoIter = std::slice::IterMut<'a, T>;
+ type Item = &'a mut T;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
+impl<T: fmt::Debug> fmt::Debug for ThinVec<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list().entries(&**self).finish()
+ }
+}
+
+/// A [`ThinVec`] that requires no allocation for the empty case.
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct EmptyOptimizedThinVec<T>(Option<ThinVec<T>>);
+
+impl<T> EmptyOptimizedThinVec<T> {
+ #[inline]
+ #[allow(clippy::should_implement_trait)]
+ pub fn from_iter<I>(values: I) -> Self
+ where
+ I: IntoIterator,
+ I::IntoIter: TrustedLen<Item = T>,
+ {
+ let values = values.into_iter();
+ if values.len() == 0 {
+ Self::empty()
+ } else {
+ Self(Some(ThinVec::from_iter(values)))
+ }
+ }
+
+ #[inline]
+ pub fn empty() -> Self {
+ Self(None)
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.0.as_ref().map_or(0, ThinVec::len)
+ }
+
+ #[inline]
+ pub fn iter(&self) -> std::slice::Iter<'_, T> {
+ (**self).iter()
+ }
+
+ #[inline]
+ pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
+ (**self).iter_mut()
+ }
+}
+
+impl<T> Default for EmptyOptimizedThinVec<T> {
+ #[inline]
+ fn default() -> Self {
+ Self::empty()
+ }
+}
+
+impl<T> Deref for EmptyOptimizedThinVec<T> {
+ type Target = [T];
+
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ self.0.as_deref().unwrap_or_default()
+ }
+}
+
+impl<T> DerefMut for EmptyOptimizedThinVec<T> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.0.as_deref_mut().unwrap_or_default()
+ }
+}
+
+impl<'a, T> IntoIterator for &'a EmptyOptimizedThinVec<T> {
+ type IntoIter = std::slice::Iter<'a, T>;
+ type Item = &'a T;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl<'a, T> IntoIterator for &'a mut EmptyOptimizedThinVec<T> {
+ type IntoIter = std::slice::IterMut<'a, T>;
+ type Item = &'a mut T;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
+impl<T: fmt::Debug> fmt::Debug for EmptyOptimizedThinVec<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list().entries(&**self).finish()
+ }
+}
+
+/// Syntax:
+///
+/// ```ignore
+/// thin_vec_with_header_struct! {
+/// pub new(pub(crate)) struct MyCoolStruct, MyCoolStructHeader {
+/// pub(crate) variable_length: [Ty],
+/// pub field1: CopyTy,
+/// pub field2: NonCopyTy; ref,
+/// }
+/// }
+/// ```
+#[doc(hidden)]
+#[macro_export]
+macro_rules! thin_vec_with_header_struct_ {
+ (@maybe_ref (ref) $($t:tt)*) => { &$($t)* };
+ (@maybe_ref () $($t:tt)*) => { $($t)* };
+ (
+ $vis:vis new($new_vis:vis) struct $struct:ident, $header:ident {
+ $items_vis:vis $items:ident : [$items_ty:ty],
+ $( $header_var_vis:vis $header_var:ident : $header_var_ty:ty $(; $ref:ident)?, )+
+ }
+ ) => {
+ #[derive(Debug, Clone, Eq, PartialEq, Hash)]
+ struct $header {
+ $( $header_var : $header_var_ty, )+
+ }
+
+ #[derive(Clone, Eq, PartialEq, Hash)]
+ $vis struct $struct($crate::thin_vec::ThinVecWithHeader<$header, $items_ty>);
+
+ impl $struct {
+ #[inline]
+ #[allow(unused)]
+ $new_vis fn new<I>(
+ $( $header_var: $header_var_ty, )+
+ $items: I,
+ ) -> Self
+ where
+ I: ::std::iter::IntoIterator,
+ I::IntoIter: $crate::thin_vec::TrustedLen<Item = $items_ty>,
+ {
+ Self($crate::thin_vec::ThinVecWithHeader::from_iter(
+ $header { $( $header_var, )+ },
+ $items,
+ ))
+ }
+
+ #[inline]
+ $items_vis fn $items(&self) -> &[$items_ty] {
+ self.0.items()
+ }
+
+ $(
+ #[inline]
+ $header_var_vis fn $header_var(&self) -> $crate::thin_vec_with_header_struct_!(@maybe_ref ($($ref)?) $header_var_ty) {
+ $crate::thin_vec_with_header_struct_!(@maybe_ref ($($ref)?) self.0.header().$header_var)
+ }
+ )+
+ }
+
+ impl ::std::fmt::Debug for $struct {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ f.debug_struct(stringify!($struct))
+ $( .field(stringify!($header_var), &self.$header_var()) )*
+ .field(stringify!($items), &self.$items())
+ .finish()
+ }
+ }
+ };
+}
+pub use crate::thin_vec_with_header_struct_ as thin_vec_with_header_struct;
diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
index fcb9b0e..51eaea5 100644
--- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
@@ -27,7 +27,6 @@
parser.workspace = true
stdx.workspace = true
-text-edit.workspace = true
[dev-dependencies]
rayon.workspace = true
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index 90441c2..02c5964 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -657,7 +657,14 @@
TypeBound =
Lifetime
| ('~' 'const' | 'const')? 'async'? '?'? Type
-| 'use' GenericParamList
+| 'use' UseBoundGenericArgs
+
+UseBoundGenericArgs =
+ '<' (UseBoundGenericArg (',' UseBoundGenericArg)* ','?)? '>'
+
+UseBoundGenericArg =
+ Lifetime
+| NameRef
//************************//
// Patterns //
@@ -729,7 +736,7 @@
Path
OrPat =
- (Pat ('|' Pat)* '|'?)
+ '|'? (Pat ('|' Pat)*)
BoxPat =
'box' Pat
diff --git a/src/tools/rust-analyzer/crates/syntax/src/algo.rs b/src/tools/rust-analyzer/crates/syntax/src/algo.rs
index 8dc6d36..2acb215 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/algo.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/algo.rs
@@ -1,11 +1,6 @@
//! Collection of assorted algorithms for syntax trees.
-use std::hash::BuildHasherDefault;
-
-use indexmap::IndexMap;
use itertools::Itertools;
-use rustc_hash::FxHashMap;
-use text_edit::TextEditBuilder;
use crate::{
AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
@@ -101,559 +96,3 @@
pub fn has_errors(node: &SyntaxNode) -> bool {
node.children().any(|it| it.kind() == SyntaxKind::ERROR)
}
-
-type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>;
-
-#[derive(Debug, Hash, PartialEq, Eq)]
-enum TreeDiffInsertPos {
- After(SyntaxElement),
- AsFirstChild(SyntaxElement),
-}
-
-#[derive(Debug)]
-pub struct TreeDiff {
- replacements: FxHashMap<SyntaxElement, SyntaxElement>,
- deletions: Vec<SyntaxElement>,
- // the vec as well as the indexmap are both here to preserve order
- insertions: FxIndexMap<TreeDiffInsertPos, Vec<SyntaxElement>>,
-}
-
-impl TreeDiff {
- pub fn into_text_edit(&self, builder: &mut TextEditBuilder) {
- let _p = tracing::info_span!("into_text_edit").entered();
-
- for (anchor, to) in &self.insertions {
- let offset = match anchor {
- TreeDiffInsertPos::After(it) => it.text_range().end(),
- TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(),
- };
- to.iter().for_each(|to| builder.insert(offset, to.to_string()));
- }
- for (from, to) in &self.replacements {
- builder.replace(from.text_range(), to.to_string());
- }
- for text_range in self.deletions.iter().map(SyntaxElement::text_range) {
- builder.delete(text_range);
- }
- }
-
- pub fn is_empty(&self) -> bool {
- self.replacements.is_empty() && self.deletions.is_empty() && self.insertions.is_empty()
- }
-}
-
-/// Finds a (potentially minimal) diff, which, applied to `from`, will result in `to`.
-///
-/// Specifically, returns a structure that consists of a replacements, insertions and deletions
-/// such that applying this map on `from` will result in `to`.
-///
-/// This function tries to find a fine-grained diff.
-pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
- let _p = tracing::info_span!("diff").entered();
-
- let mut diff = TreeDiff {
- replacements: FxHashMap::default(),
- insertions: FxIndexMap::default(),
- deletions: Vec::new(),
- };
- let (from, to) = (from.clone().into(), to.clone().into());
-
- if !syntax_element_eq(&from, &to) {
- go(&mut diff, from, to);
- }
- return diff;
-
- fn syntax_element_eq(lhs: &SyntaxElement, rhs: &SyntaxElement) -> bool {
- lhs.kind() == rhs.kind()
- && lhs.text_range().len() == rhs.text_range().len()
- && match (&lhs, &rhs) {
- (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => {
- lhs == rhs || lhs.text() == rhs.text()
- }
- (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(),
- _ => false,
- }
- }
-
- // FIXME: this is horribly inefficient. I bet there's a cool algorithm to diff trees properly.
- fn go(diff: &mut TreeDiff, lhs: SyntaxElement, rhs: SyntaxElement) {
- let (lhs, rhs) = match lhs.as_node().zip(rhs.as_node()) {
- Some((lhs, rhs)) => (lhs, rhs),
- _ => {
- cov_mark::hit!(diff_node_token_replace);
- diff.replacements.insert(lhs, rhs);
- return;
- }
- };
-
- let mut look_ahead_scratch = Vec::default();
-
- let mut rhs_children = rhs.children_with_tokens();
- let mut lhs_children = lhs.children_with_tokens();
- let mut last_lhs = None;
- loop {
- let lhs_child = lhs_children.next();
- match (lhs_child.clone(), rhs_children.next()) {
- (None, None) => break,
- (None, Some(element)) => {
- let insert_pos = match last_lhs.clone() {
- Some(prev) => {
- cov_mark::hit!(diff_insert);
- TreeDiffInsertPos::After(prev)
- }
- // first iteration, insert into out parent as the first child
- None => {
- cov_mark::hit!(diff_insert_as_first_child);
- TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
- }
- };
- diff.insertions.entry(insert_pos).or_default().push(element);
- }
- (Some(element), None) => {
- cov_mark::hit!(diff_delete);
- diff.deletions.push(element);
- }
- (Some(ref lhs_ele), Some(ref rhs_ele)) if syntax_element_eq(lhs_ele, rhs_ele) => {}
- (Some(lhs_ele), Some(rhs_ele)) => {
- // nodes differ, look for lhs_ele in rhs, if its found we can mark everything up
- // until that element as insertions. This is important to keep the diff minimal
- // in regards to insertions that have been actually done, this is important for
- // use insertions as we do not want to replace the entire module node.
- look_ahead_scratch.push(rhs_ele.clone());
- let mut rhs_children_clone = rhs_children.clone();
- let mut insert = false;
- for rhs_child in &mut rhs_children_clone {
- if syntax_element_eq(&lhs_ele, &rhs_child) {
- cov_mark::hit!(diff_insertions);
- insert = true;
- break;
- }
- look_ahead_scratch.push(rhs_child);
- }
- let drain = look_ahead_scratch.drain(..);
- if insert {
- let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) {
- TreeDiffInsertPos::After(prev)
- } else {
- cov_mark::hit!(insert_first_child);
- TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
- };
-
- diff.insertions.entry(insert_pos).or_default().extend(drain);
- rhs_children = rhs_children_clone;
- } else {
- go(diff, lhs_ele, rhs_ele);
- }
- }
- }
- last_lhs = lhs_child.or(last_lhs);
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use expect_test::{expect, Expect};
- use itertools::Itertools;
- use parser::{Edition, SyntaxKind};
- use text_edit::TextEdit;
-
- use crate::{AstNode, SyntaxElement};
-
- #[test]
- fn replace_node_token() {
- cov_mark::check!(diff_node_token_replace);
- check_diff(
- r#"use node;"#,
- r#"ident"#,
- expect![[r#"
- insertions:
-
-
-
- replacements:
-
- Line 0: Token(USE_KW@0..3 "use") -> ident
-
- deletions:
-
- Line 1: " "
- Line 1: node
- Line 1: ;
- "#]],
- );
- }
-
- #[test]
- fn replace_parent() {
- cov_mark::check!(diff_insert_as_first_child);
- check_diff(
- r#""#,
- r#"use foo::bar;"#,
- expect![[r#"
- insertions:
-
- Line 0: AsFirstChild(Node(SOURCE_FILE@0..0))
- -> use foo::bar;
-
- replacements:
-
-
-
- deletions:
-
-
- "#]],
- );
- }
-
- #[test]
- fn insert_last() {
- cov_mark::check!(diff_insert);
- check_diff(
- r#"
-use foo;
-use bar;"#,
- r#"
-use foo;
-use bar;
-use baz;"#,
- expect![[r#"
- insertions:
-
- Line 2: After(Node(USE@10..18))
- -> "\n"
- -> use baz;
-
- replacements:
-
-
-
- deletions:
-
-
- "#]],
- );
- }
-
- #[test]
- fn insert_middle() {
- check_diff(
- r#"
-use foo;
-use baz;"#,
- r#"
-use foo;
-use bar;
-use baz;"#,
- expect![[r#"
- insertions:
-
- Line 2: After(Token(WHITESPACE@9..10 "\n"))
- -> use bar;
- -> "\n"
-
- replacements:
-
-
-
- deletions:
-
-
- "#]],
- )
- }
-
- #[test]
- fn insert_first() {
- check_diff(
- r#"
-use bar;
-use baz;"#,
- r#"
-use foo;
-use bar;
-use baz;"#,
- expect![[r#"
- insertions:
-
- Line 0: After(Token(WHITESPACE@0..1 "\n"))
- -> use foo;
- -> "\n"
-
- replacements:
-
-
-
- deletions:
-
-
- "#]],
- )
- }
-
- #[test]
- fn first_child_insertion() {
- cov_mark::check!(insert_first_child);
- check_diff(
- r#"fn main() {
- stdi
- }"#,
- r#"use foo::bar;
-
- fn main() {
- stdi
- }"#,
- expect![[r#"
- insertions:
-
- Line 0: AsFirstChild(Node(SOURCE_FILE@0..30))
- -> use foo::bar;
- -> "\n\n "
-
- replacements:
-
-
-
- deletions:
-
-
- "#]],
- );
- }
-
- #[test]
- fn delete_last() {
- cov_mark::check!(diff_delete);
- check_diff(
- r#"use foo;
- use bar;"#,
- r#"use foo;"#,
- expect![[r#"
- insertions:
-
-
-
- replacements:
-
-
-
- deletions:
-
- Line 1: "\n "
- Line 2: use bar;
- "#]],
- );
- }
-
- #[test]
- fn delete_middle() {
- cov_mark::check!(diff_insertions);
- check_diff(
- r#"
-use expect_test::{expect, Expect};
-use text_edit::TextEdit;
-
-use crate::AstNode;
-"#,
- r#"
-use expect_test::{expect, Expect};
-
-use crate::AstNode;
-"#,
- expect![[r#"
- insertions:
-
- Line 1: After(Node(USE@1..35))
- -> "\n\n"
- -> use crate::AstNode;
-
- replacements:
-
-
-
- deletions:
-
- Line 2: use text_edit::TextEdit;
- Line 3: "\n\n"
- Line 4: use crate::AstNode;
- Line 5: "\n"
- "#]],
- )
- }
-
- #[test]
- fn delete_first() {
- check_diff(
- r#"
-use text_edit::TextEdit;
-
-use crate::AstNode;
-"#,
- r#"
-use crate::AstNode;
-"#,
- expect![[r#"
- insertions:
-
-
-
- replacements:
-
- Line 2: Token(IDENT@5..14 "text_edit") -> crate
- Line 2: Token(IDENT@16..24 "TextEdit") -> AstNode
- Line 2: Token(WHITESPACE@25..27 "\n\n") -> "\n"
-
- deletions:
-
- Line 3: use crate::AstNode;
- Line 4: "\n"
- "#]],
- )
- }
-
- #[test]
- fn merge_use() {
- check_diff(
- r#"
-use std::{
- fmt,
- hash::BuildHasherDefault,
- ops::{self, RangeInclusive},
-};
-"#,
- r#"
-use std::fmt;
-use std::hash::BuildHasherDefault;
-use std::ops::{self, RangeInclusive};
-"#,
- expect![[r#"
- insertions:
-
- Line 2: After(Node(PATH_SEGMENT@5..8))
- -> ::
- -> fmt
- Line 6: After(Token(WHITESPACE@86..87 "\n"))
- -> use std::hash::BuildHasherDefault;
- -> "\n"
- -> use std::ops::{self, RangeInclusive};
- -> "\n"
-
- replacements:
-
- Line 2: Token(IDENT@5..8 "std") -> std
-
- deletions:
-
- Line 2: ::
- Line 2: {
- fmt,
- hash::BuildHasherDefault,
- ops::{self, RangeInclusive},
- }
- "#]],
- )
- }
-
- #[test]
- fn early_return_assist() {
- check_diff(
- r#"
-fn main() {
- if let Ok(x) = Err(92) {
- foo(x);
- }
-}
- "#,
- r#"
-fn main() {
- let x = match Err(92) {
- Ok(it) => it,
- _ => return,
- };
- foo(x);
-}
- "#,
- expect![[r#"
- insertions:
-
- Line 3: After(Node(BLOCK_EXPR@40..63))
- -> " "
- -> match Err(92) {
- Ok(it) => it,
- _ => return,
- }
- -> ;
- Line 3: After(Node(IF_EXPR@17..63))
- -> "\n "
- -> foo(x);
-
- replacements:
-
- Line 3: Token(IF_KW@17..19 "if") -> let
- Line 3: Token(LET_KW@20..23 "let") -> x
- Line 3: Node(BLOCK_EXPR@40..63) -> =
-
- deletions:
-
- Line 3: " "
- Line 3: Ok(x)
- Line 3: " "
- Line 3: =
- Line 3: " "
- Line 3: Err(92)
- "#]],
- )
- }
-
- fn check_diff(from: &str, to: &str, expected_diff: Expect) {
- let from_node = crate::SourceFile::parse(from, Edition::CURRENT).tree().syntax().clone();
- let to_node = crate::SourceFile::parse(to, Edition::CURRENT).tree().syntax().clone();
- let diff = super::diff(&from_node, &to_node);
-
- let line_number =
- |syn: &SyntaxElement| from[..syn.text_range().start().into()].lines().count();
-
- let fmt_syntax = |syn: &SyntaxElement| match syn.kind() {
- SyntaxKind::WHITESPACE => format!("{:?}", syn.to_string()),
- _ => format!("{syn}"),
- };
-
- let insertions =
- diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> {
- f(&format!(
- "Line {}: {:?}\n-> {}",
- line_number(match k {
- super::TreeDiffInsertPos::After(syn) => syn,
- super::TreeDiffInsertPos::AsFirstChild(syn) => syn,
- }),
- k,
- v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v)))
- ))
- });
-
- let replacements = diff
- .replacements
- .iter()
- .sorted_by_key(|(syntax, _)| syntax.text_range().start())
- .format_with("\n", |(k, v), f| {
- f(&format!("Line {}: {k:?} -> {}", line_number(k), fmt_syntax(v)))
- });
-
- let deletions = diff
- .deletions
- .iter()
- .format_with("\n", |v, f| f(&format!("Line {}: {}", line_number(v), fmt_syntax(v))));
-
- let actual = format!(
- "insertions:\n\n{insertions}\n\nreplacements:\n\n{replacements}\n\ndeletions:\n\n{deletions}\n"
- );
- expected_diff.assert_eq(&actual);
-
- let mut from = from.to_owned();
- let mut text_edit = TextEdit::builder();
- diff.into_text_edit(&mut text_edit);
- text_edit.finish().apply(&mut from);
- assert_eq!(&*from, to, "diff did not turn `from` to `to`");
- }
-}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
index 6ed205e..f3053f5 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
@@ -232,6 +232,10 @@
Some((ix, token, bin_op))
})
}
+
+ pub fn is_range_full(&self) -> bool {
+ support::children::<Expr>(&self.syntax).next().is_none()
+ }
}
impl RangeItem for ast::RangeExpr {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index 4f8bff4..23d2b35 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -1283,6 +1283,8 @@
impl OrPat {
#[inline]
pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
+ #[inline]
+ pub fn pipe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![|]) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -1994,12 +1996,14 @@
}
impl TypeBound {
#[inline]
- pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
- #[inline]
pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
#[inline]
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
#[inline]
+ pub fn use_bound_generic_args(&self) -> Option<UseBoundGenericArgs> {
+ support::child(&self.syntax)
+ }
+ #[inline]
pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
#[inline]
pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
@@ -2077,6 +2081,21 @@
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct UseBoundGenericArgs {
+ pub(crate) syntax: SyntaxNode,
+}
+impl UseBoundGenericArgs {
+ #[inline]
+ pub fn use_bound_generic_args(&self) -> AstChildren<UseBoundGenericArg> {
+ support::children(&self.syntax)
+ }
+ #[inline]
+ pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
+ #[inline]
+ pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UseTree {
pub(crate) syntax: SyntaxNode,
}
@@ -2403,6 +2422,12 @@
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum UseBoundGenericArg {
+ Lifetime(Lifetime),
+ NameRef(NameRef),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AnyHasArgList {
pub(crate) syntax: SyntaxNode,
}
@@ -4435,6 +4460,20 @@
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
+impl AstNode for UseBoundGenericArgs {
+ #[inline]
+ fn can_cast(kind: SyntaxKind) -> bool { kind == USE_BOUND_GENERIC_ARGS }
+ #[inline]
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ #[inline]
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
impl AstNode for UseTree {
#[inline]
fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
@@ -5560,6 +5599,34 @@
}
}
}
+impl From<Lifetime> for UseBoundGenericArg {
+ #[inline]
+ fn from(node: Lifetime) -> UseBoundGenericArg { UseBoundGenericArg::Lifetime(node) }
+}
+impl From<NameRef> for UseBoundGenericArg {
+ #[inline]
+ fn from(node: NameRef) -> UseBoundGenericArg { UseBoundGenericArg::NameRef(node) }
+}
+impl AstNode for UseBoundGenericArg {
+ #[inline]
+ fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, LIFETIME | NAME_REF) }
+ #[inline]
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ LIFETIME => UseBoundGenericArg::Lifetime(Lifetime { syntax }),
+ NAME_REF => UseBoundGenericArg::NameRef(NameRef { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ #[inline]
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ UseBoundGenericArg::Lifetime(it) => &it.syntax,
+ UseBoundGenericArg::NameRef(it) => &it.syntax,
+ }
+ }
+}
impl AnyHasArgList {
#[inline]
pub fn new<T: ast::HasArgList>(node: T) -> AnyHasArgList {
@@ -6570,6 +6637,11 @@
std::fmt::Display::fmt(self.syntax(), f)
}
}
+impl std::fmt::Display for UseBoundGenericArg {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
impl std::fmt::Display for Abi {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
@@ -7275,6 +7347,11 @@
std::fmt::Display::fmt(self.syntax(), f)
}
}
+impl std::fmt::Display for UseBoundGenericArgs {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
impl std::fmt::Display for UseTree {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
index 693bfe3..6ec73e7 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
@@ -795,7 +795,7 @@
/// for<'a> ...
ForType(ast::ForType),
/// use
- Use(ast::GenericParamList),
+ Use(ast::UseBoundGenericArgs),
/// 'a
Lifetime(ast::Lifetime),
}
@@ -806,8 +806,8 @@
TypeBoundKind::PathType(path_type)
} else if let Some(for_type) = support::children(self.syntax()).next() {
TypeBoundKind::ForType(for_type)
- } else if let Some(generic_param_list) = self.generic_param_list() {
- TypeBoundKind::Use(generic_param_list)
+ } else if let Some(args) = self.use_bound_generic_args() {
+ TypeBoundKind::Use(args)
} else if let Some(lifetime) = self.lifetime() {
TypeBoundKind::Lifetime(lifetime)
} else {
@@ -1140,3 +1140,13 @@
Self::new(node)
}
}
+
+impl ast::OrPat {
+ pub fn leading_pipe(&self) -> Option<SyntaxToken> {
+ self.syntax
+ .children_with_tokens()
+ .find(|it| !it.kind().is_trivia())
+ .and_then(NodeOrToken::into_token)
+ .filter(|it| it.kind() == T![|])
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs
index 682dcd7..fd20e60 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs
@@ -5,7 +5,6 @@
use std::str::{self, FromStr};
use parser::Edition;
-use text_edit::Indel;
use crate::{validation, AstNode, SourceFile, TextRange};
@@ -22,7 +21,8 @@
#[derive(Debug, Clone)]
pub struct CheckReparse {
text: String,
- edit: Indel,
+ delete: TextRange,
+ insert: String,
edited_text: String,
}
@@ -43,14 +43,13 @@
TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap());
let edited_text =
format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]);
- let edit = Indel { insert, delete };
- Some(CheckReparse { text, edit, edited_text })
+ Some(CheckReparse { text, insert, delete, edited_text })
}
#[allow(clippy::print_stderr)]
pub fn run(&self) {
let parse = SourceFile::parse(&self.text, Edition::CURRENT);
- let new_parse = parse.reparse(&self.edit, Edition::CURRENT);
+ let new_parse = parse.reparse(self.delete, &self.insert, Edition::CURRENT);
check_file_invariants(&new_parse.tree());
assert_eq!(&new_parse.tree().syntax().text().to_string(), &self.edited_text);
let full_reparse = SourceFile::parse(&self.edited_text, Edition::CURRENT);
diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
index c1554c4..c9e9f46 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
@@ -44,10 +44,9 @@
pub mod ted;
pub mod utils;
-use std::marker::PhantomData;
+use std::{marker::PhantomData, ops::Range};
use stdx::format_to;
-use text_edit::Indel;
use triomphe::Arc;
pub use crate::{
@@ -150,16 +149,22 @@
buf
}
- pub fn reparse(&self, indel: &Indel, edition: Edition) -> Parse<SourceFile> {
- self.incremental_reparse(indel, edition)
- .unwrap_or_else(|| self.full_reparse(indel, edition))
+ pub fn reparse(&self, delete: TextRange, insert: &str, edition: Edition) -> Parse<SourceFile> {
+ self.incremental_reparse(delete, insert, edition)
+ .unwrap_or_else(|| self.full_reparse(delete, insert, edition))
}
- fn incremental_reparse(&self, indel: &Indel, edition: Edition) -> Option<Parse<SourceFile>> {
+ fn incremental_reparse(
+ &self,
+ delete: TextRange,
+ insert: &str,
+ edition: Edition,
+ ) -> Option<Parse<SourceFile>> {
// FIXME: validation errors are not handled here
parsing::incremental_reparse(
self.tree().syntax(),
- indel,
+ delete,
+ insert,
self.errors.as_deref().unwrap_or_default().iter().cloned(),
edition,
)
@@ -170,9 +175,9 @@
})
}
- fn full_reparse(&self, indel: &Indel, edition: Edition) -> Parse<SourceFile> {
+ fn full_reparse(&self, delete: TextRange, insert: &str, edition: Edition) -> Parse<SourceFile> {
let mut text = self.tree().syntax().text().to_string();
- indel.apply(&mut text);
+ text.replace_range(Range::<usize>::from(delete), insert);
SourceFile::parse(&text, edition)
}
}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs b/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs
index a5cc4e9..f2eab18 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs
@@ -6,8 +6,9 @@
//! - otherwise, we search for the nearest `{}` block which contains the edit
//! and try to parse only this block.
+use std::ops::Range;
+
use parser::{Edition, Reparser};
-use text_edit::Indel;
use crate::{
parsing::build_tree,
@@ -19,38 +20,48 @@
pub(crate) fn incremental_reparse(
node: &SyntaxNode,
- edit: &Indel,
+ delete: TextRange,
+ insert: &str,
errors: impl IntoIterator<Item = SyntaxError>,
edition: Edition,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
- if let Some((green, new_errors, old_range)) = reparse_token(node, edit, edition) {
- return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
+ if let Some((green, new_errors, old_range)) = reparse_token(node, delete, insert, edition) {
+ return Some((
+ green,
+ merge_errors(errors, new_errors, old_range, delete, insert),
+ old_range,
+ ));
}
- if let Some((green, new_errors, old_range)) = reparse_block(node, edit, edition) {
- return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
+ if let Some((green, new_errors, old_range)) = reparse_block(node, delete, insert, edition) {
+ return Some((
+ green,
+ merge_errors(errors, new_errors, old_range, delete, insert),
+ old_range,
+ ));
}
None
}
fn reparse_token(
root: &SyntaxNode,
- edit: &Indel,
+ delete: TextRange,
+ insert: &str,
edition: Edition,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
- let prev_token = root.covering_element(edit.delete).as_token()?.clone();
+ let prev_token = root.covering_element(delete).as_token()?.clone();
let prev_token_kind = prev_token.kind();
match prev_token_kind {
WHITESPACE | COMMENT | IDENT | STRING | BYTE_STRING | C_STRING => {
if prev_token_kind == WHITESPACE || prev_token_kind == COMMENT {
// removing a new line may extends previous token
- let deleted_range = edit.delete - prev_token.text_range().start();
+ let deleted_range = delete - prev_token.text_range().start();
if prev_token.text()[deleted_range].contains('\n') {
return None;
}
}
- let mut new_text = get_text_after_edit(prev_token.clone().into(), edit);
+ let mut new_text = get_text_after_edit(prev_token.clone().into(), delete, insert);
let (new_token_kind, new_err) = parser::LexedStr::single_token(edition, &new_text)?;
if new_token_kind != prev_token_kind
@@ -85,11 +96,12 @@
fn reparse_block(
root: &SyntaxNode,
- edit: &Indel,
+ delete: TextRange,
+ insert: &str,
edition: parser::Edition,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
- let (node, reparser) = find_reparsable_node(root, edit.delete)?;
- let text = get_text_after_edit(node.clone().into(), edit);
+ let (node, reparser) = find_reparsable_node(root, delete)?;
+ let text = get_text_after_edit(node.clone().into(), delete, insert);
let lexed = parser::LexedStr::new(edition, text.as_str());
let parser_input = lexed.to_input(edition);
@@ -104,14 +116,14 @@
Some((node.replace_with(green), new_parser_errors, node.text_range()))
}
-fn get_text_after_edit(element: SyntaxElement, edit: &Indel) -> String {
- let edit = Indel::replace(edit.delete - element.text_range().start(), edit.insert.clone());
+fn get_text_after_edit(element: SyntaxElement, mut delete: TextRange, insert: &str) -> String {
+ delete -= element.text_range().start();
let mut text = match element {
NodeOrToken::Token(token) => token.text().to_owned(),
NodeOrToken::Node(node) => node.text().to_string(),
};
- edit.apply(&mut text);
+ text.replace_range(Range::<usize>::from(delete), insert);
text
}
@@ -153,7 +165,8 @@
old_errors: impl IntoIterator<Item = SyntaxError>,
new_errors: Vec<SyntaxError>,
range_before_reparse: TextRange,
- edit: &Indel,
+ delete: TextRange,
+ insert: &str,
) -> Vec<SyntaxError> {
let mut res = Vec::new();
@@ -162,8 +175,8 @@
if old_err_range.end() <= range_before_reparse.start() {
res.push(old_err);
} else if old_err_range.start() >= range_before_reparse.end() {
- let inserted_len = TextSize::of(&edit.insert);
- res.push(old_err.with_range((old_err_range + inserted_len) - edit.delete.len()));
+ let inserted_len = TextSize::of(insert);
+ res.push(old_err.with_range((old_err_range + inserted_len) - delete.len()));
// Note: extra parens are intentional to prevent uint underflow, HWAB (here was a bug)
}
}
@@ -177,6 +190,8 @@
#[cfg(test)]
mod tests {
+ use std::ops::Range;
+
use parser::Edition;
use test_utils::{assert_eq_text, extract_range};
@@ -185,10 +200,9 @@
fn do_check(before: &str, replace_with: &str, reparsed_len: u32) {
let (range, before) = extract_range(before);
- let edit = Indel::replace(range, replace_with.to_owned());
let after = {
let mut after = before.clone();
- edit.apply(&mut after);
+ after.replace_range(Range::<usize>::from(range), replace_with);
after
};
@@ -197,7 +211,8 @@
let before = SourceFile::parse(&before, Edition::CURRENT);
let (green, new_errors, range) = incremental_reparse(
before.tree().syntax(),
- &edit,
+ range,
+ replace_with,
before.errors.as_deref().unwrap_or_default().iter().cloned(),
Edition::CURRENT,
)
diff --git a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml b/src/tools/rust-analyzer/crates/text-edit/Cargo.toml
deleted file mode 100644
index dc6b3d3..0000000
--- a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml
+++ /dev/null
@@ -1,20 +0,0 @@
-[package]
-name = "text-edit"
-version = "0.0.0"
-repository.workspace = true
-description = "Representation of a `TextEdit` for rust-analyzer."
-
-authors.workspace = true
-edition.workspace = true
-license.workspace = true
-rust-version.workspace = true
-
-[lib]
-doctest = false
-
-[dependencies]
-itertools.workspace = true
-text-size.workspace = true
-
-[lints]
-workspace = true
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/tt/src/buffer.rs b/src/tools/rust-analyzer/crates/tt/src/buffer.rs
index 1319739..acb7e2d 100644
--- a/src/tools/rust-analyzer/crates/tt/src/buffer.rs
+++ b/src/tools/rust-analyzer/crates/tt/src/buffer.rs
@@ -134,7 +134,7 @@
Leaf(&'a Leaf<Span>, &'a TokenTree<Span>),
}
-impl<'a, Span: Copy> TokenTreeRef<'a, Span> {
+impl<Span: Copy> TokenTreeRef<'_, Span> {
pub fn span(&self) -> Span {
match self {
TokenTreeRef::Subtree(subtree, _) => subtree.delimiter.open,
diff --git a/src/tools/rust-analyzer/editors/code/.vscodeignore b/src/tools/rust-analyzer/editors/code/.vscodeignore
index 09dc270..1712a14 100644
--- a/src/tools/rust-analyzer/editors/code/.vscodeignore
+++ b/src/tools/rust-analyzer/editors/code/.vscodeignore
@@ -12,3 +12,4 @@
!ra_syntax_tree.tmGrammar.json
!server
!README.md
+!walkthrough-setup-tips.md
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index e55ecef..6eebdf9 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -3224,10 +3224,9 @@
{
"id": "setup",
"title": "Useful Setup Tips",
- "description": "There are a couple of things you might want to configure upfront to your tastes. We'll name a few here but be sure to check out the docs linked below!\n\n**Marking library sources as readonly**\n\nAdding the following to your settings.json will mark all Rust library sources as readonly:\n```json\n\"files.readonlyInclude\": {\n \"**/.cargo/registry/src/**/*.rs\": true,\n \"**/lib/rustlib/src/rust/library/**/*.rs\": true,\n},\n```\n\n**Check on Save**\n\nBy default, rust-analyzer will run `cargo check` on your codebase when you save a file, rendering diagnostics emitted by `cargo check` within your code. This can potentially collide with other `cargo` commands running concurrently, blocking them from running for a certain amount of time. In these cases it is recommended to disable the `rust-analyzer.checkOnSave` configuration and running the `rust-analyzer: Run flycheck` command on-demand instead.",
+ "description": "There are a couple of things you might want to configure upfront to your tastes. We'll name a few here but be sure to check out the docs linked below!\n\n**Marking library sources as readonly**\n\nAdding the snippet on the right to your settings.json will mark all Rust library sources as readonly.\n\n**Check on Save**\n\nBy default, rust-analyzer will run ``cargo check`` on your codebase when you save a file, rendering diagnostics emitted by ``cargo check`` within your code. This can potentially collide with other ``cargo`` commands running concurrently, blocking them from running for a certain amount of time. In these cases it is recommended to disable the ``rust-analyzer.checkOnSave`` configuration and running the ``rust-analyzer: Run flycheck`` command on-demand instead.",
"media": {
- "image": "./icon.png",
- "altText": "rust-analyzer logo"
+ "markdown": "./walkthrough-setup-tips.md"
}
},
{
@@ -3245,7 +3244,7 @@
{
"id": "faq",
"title": "FAQ",
- "description": "What are these code hints that are being inserted into my code?\n\nThese hints are called inlay hints which rust-analyzer support and are enabled by default in VSCode. If you wish to disable them you can do so via the `editor.inlayHints.enabled` setting.",
+ "description": "What are these code hints that are being inserted into my code?\n\nThese hints are called inlay hints which rust-analyzer support and are enabled by default in VSCode. If you wish to disable them you can do so via the ``editor.inlayHints.enabled`` setting.",
"media": {
"image": "icon.png",
"altText": "rust-analyzer logo"
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index 0f2a758..234fe6a 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -446,7 +446,7 @@
return;
}
if (status.message) {
- statusBar.tooltip.appendText(status.message);
+ statusBar.tooltip.appendMarkdown(status.message);
}
if (statusBar.tooltip.value) {
statusBar.tooltip.appendMarkdown("\n\n---\n\n");
diff --git a/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md b/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md
new file mode 100644
index 0000000..fda4ac8
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md
@@ -0,0 +1,10 @@
+# Settings Example
+
+Add the following to settings.json to mark Rust library sources as read-only:
+
+```json
+"files.readonlyInclude": {
+ "**/.cargo/registry/src/**/*.rs": true,
+ "**/lib/rustlib/src/rust/library/**/*.rs": true,
+},
+```
diff --git a/src/tools/rust-analyzer/rust-bors.toml b/src/tools/rust-analyzer/rust-bors.toml
deleted file mode 100644
index c31ba66..0000000
--- a/src/tools/rust-analyzer/rust-bors.toml
+++ /dev/null
@@ -1 +0,0 @@
-timeout = 3600
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index bc32440..ffb312d 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-1de57a5ce952c722f7053aeacfc6c90bc139b678
+a9d17627d241645a54c1134a20f1596127fedb60
diff --git a/src/tools/rust-analyzer/xtask/src/codegen.rs b/src/tools/rust-analyzer/xtask/src/codegen.rs
index 4c7b07c..bc04b94 100644
--- a/src/tools/rust-analyzer/xtask/src/codegen.rs
+++ b/src/tools/rust-analyzer/xtask/src/codegen.rs
@@ -79,7 +79,7 @@
let mut block = dummy_block.clone();
for (line_num, line) in lines.enumerate() {
match line.strip_prefix("//") {
- Some(mut contents) => {
+ Some(mut contents) if !contents.starts_with('/') => {
if let Some('/' | '!') = contents.chars().next() {
contents = &contents[1..];
block.is_doc = true;
@@ -89,7 +89,7 @@
}
block.contents.push(contents.to_owned());
}
- None => {
+ _ => {
if !block.contents.is_empty() {
let block = mem::replace(&mut block, dummy_block.clone());
res.push(block);
diff --git a/src/tools/rust-analyzer/xtask/src/dist.rs b/src/tools/rust-analyzer/xtask/src/dist.rs
index 742cf7f..c6a0be8 100644
--- a/src/tools/rust-analyzer/xtask/src/dist.rs
+++ b/src/tools/rust-analyzer/xtask/src/dist.rs
@@ -101,9 +101,10 @@
cmd!(sh, "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} {features...} --release").run()?;
let dst = Path::new("dist").join(&target.artifact_name);
- gzip(&target.server_path, &dst.with_extension("gz"))?;
if target_name.contains("-windows-") {
zip(&target.server_path, target.symbols_path.as_ref(), &dst.with_extension("zip"))?;
+ } else {
+ gzip(&target.server_path, &dst.with_extension("gz"))?;
}
Ok(())
diff --git a/src/tools/rust-analyzer/xtask/src/release/changelog.rs b/src/tools/rust-analyzer/xtask/src/release/changelog.rs
index 086a4d4..343a9ef 100644
--- a/src/tools/rust-analyzer/xtask/src/release/changelog.rs
+++ b/src/tools/rust-analyzer/xtask/src/release/changelog.rs
@@ -128,9 +128,10 @@
}
fn parse_pr_number(s: &str) -> Option<u32> {
- const BORS_PREFIX: &str = "Merge #";
+ const GITHUB_PREFIX: &str = "Merge pull request #";
const HOMU_PREFIX: &str = "Auto merge of #";
- if let Some(s) = s.strip_prefix(BORS_PREFIX) {
+ if let Some(s) = s.strip_prefix(GITHUB_PREFIX) {
+ let s = if let Some(space) = s.find(' ') { &s[..space] } else { s };
s.parse().ok()
} else if let Some(s) = s.strip_prefix(HOMU_PREFIX) {
if let Some(space) = s.find(' ') {
diff --git a/src/tools/rust-analyzer/xtask/src/tidy.rs b/src/tools/rust-analyzer/xtask/src/tidy.rs
index 0268e24..c3d5313 100644
--- a/src/tools/rust-analyzer/xtask/src/tidy.rs
+++ b/src/tools/rust-analyzer/xtask/src/tidy.rs
@@ -223,7 +223,7 @@
impl TidyDocs {
fn visit(&mut self, path: &Path, text: &str) {
// Tests and diagnostic fixes don't need module level comments.
- if is_exclude_dir(path, &["tests", "test_data", "fixes", "grammar", "ra-salsa"]) {
+ if is_exclude_dir(path, &["tests", "test_data", "fixes", "grammar", "ra-salsa", "stdx"]) {
return;
}
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 060deb1..27ccb20 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
-version = 3
+version = 4
[[package]]
name = "adler2"
@@ -704,6 +704,7 @@
"semver",
"serde_json",
"tempfile",
+ "walkdir",
]
[[package]]
diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs
index 2118af6..f905b92 100644
--- a/src/tools/rustbook/src/main.rs
+++ b/src/tools/rustbook/src/main.rs
@@ -22,6 +22,11 @@
.required(false)
.value_parser(clap::value_parser!(String));
+ let root_arg = arg!(--"rust-root" <ROOT_DIR>
+"Path to the root of the rust source tree")
+ .required(false)
+ .value_parser(clap::value_parser!(PathBuf));
+
let dir_arg = arg!([dir] "Root directory for the book\n\
(Defaults to the current directory when omitted)")
.value_parser(clap::value_parser!(PathBuf));
@@ -37,6 +42,7 @@
.about("Build the book from the markdown files")
.arg(d_arg)
.arg(l_arg)
+ .arg(root_arg)
.arg(&dir_arg),
)
.subcommand(
@@ -96,7 +102,8 @@
}
if book.config.get_preprocessor("spec").is_some() {
- book.with_preprocessor(Spec::new());
+ let rust_root = args.get_one::<PathBuf>("rust-root").cloned();
+ book.with_preprocessor(Spec::new(rust_root)?);
}
book.build()?;
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 7a0f98d..0e156b9 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -2,7 +2,6 @@
run-make/cat-and-grep-sanity-check/Makefile
run-make/extern-fn-reachable/Makefile
run-make/incr-add-rust-src-component/Makefile
-run-make/issue-84395-lto-embed-bitcode/Makefile
run-make/jobserver-error/Makefile
run-make/libs-through-symlinks/Makefile
run-make/split-debuginfo/Makefile
diff --git a/tests/assembly/riscv-soft-abi-with-float-features.rs b/tests/assembly/riscv-soft-abi-with-float-features.rs
index 733137f..6d6001a 100644
--- a/tests/assembly/riscv-soft-abi-with-float-features.rs
+++ b/tests/assembly/riscv-soft-abi-with-float-features.rs
@@ -1,6 +1,9 @@
//@ assembly-output: emit-asm
//@ compile-flags: --target riscv64imac-unknown-none-elf -Ctarget-feature=+f,+d
//@ needs-llvm-components: riscv
+//@ revisions: LLVM-PRE-20 LLVM-POST-20
+//@ [LLVM-PRE-20] ignore-llvm-version: 20 - 99
+//@ [LLVM-POST-20] min-llvm-version: 20
#![feature(no_core, lang_items, f16)]
#![crate_type = "lib"]
@@ -31,9 +34,11 @@
// CHECK-LABEL: read_f32
#[no_mangle]
pub extern "C" fn read_f32(x: &f32) -> f32 {
- // CHECK: flw fa5, 0(a0)
- // CHECK-NEXT: fmv.x.w a0, fa5
- // CHECK-NEXT: ret
+ // LLVM-PRE-20: flw fa5, 0(a0)
+ // LLVM-PRE-20-NEXT: fmv.x.w a0, fa5
+ // LLVM-PRE-20-NEXT: ret
+ // LLVM-POST-20: lw a0, 0(a0)
+ // LLVM-POST-20-NEXT: ret
*x
}
diff --git a/tests/assembly/rust-abi-arg-attr.rs b/tests/assembly/rust-abi-arg-attr.rs
new file mode 100644
index 0000000..2a113ee
--- /dev/null
+++ b/tests/assembly/rust-abi-arg-attr.rs
@@ -0,0 +1,108 @@
+//@ assembly-output: emit-asm
+//@ revisions: riscv64 riscv64-zbb loongarch64
+//@ compile-flags: -C opt-level=3
+//@ [riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu
+//@ [riscv64] needs-llvm-components: riscv
+//@ [riscv64-zbb] compile-flags: --target riscv64gc-unknown-linux-gnu
+//@ [riscv64-zbb] compile-flags: -C target-feature=+zbb
+//@ [riscv64-zbb] needs-llvm-components: riscv
+//@ [loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
+//@ [loongarch64] needs-llvm-components: loongarch
+
+#![feature(no_core, lang_items, intrinsics, rustc_attrs)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+// FIXME: Migrate these code after PR #130693 is landed.
+// vvvvv core
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+impl Copy for i8 {}
+impl Copy for u32 {}
+impl Copy for i32 {}
+
+#[lang = "neg"]
+trait Neg {
+ type Output;
+
+ fn neg(self) -> Self::Output;
+}
+
+impl Neg for i8 {
+ type Output = i8;
+
+ fn neg(self) -> Self::Output {
+ -self
+ }
+}
+
+#[lang = "Ordering"]
+#[repr(i8)]
+enum Ordering {
+ Less = -1,
+ Equal = 0,
+ Greater = 1,
+}
+
+extern "rust-intrinsic" {
+ #[rustc_safe_intrinsic]
+ fn three_way_compare<T: Copy>(lhs: T, rhs: T) -> Ordering;
+}
+
+// ^^^^^ core
+
+// Reimplementation of function `{integer}::max`.
+macro_rules! max {
+ ($a:expr, $b:expr) => {
+ match three_way_compare($a, $b) {
+ Ordering::Less | Ordering::Equal => $b,
+ Ordering::Greater => $a,
+ }
+ };
+}
+
+#[no_mangle]
+// CHECK-LABEL: issue_114508_u32:
+pub fn issue_114508_u32(a: u32, b: u32) -> u32 {
+ // CHECK-NEXT: .cfi_startproc
+
+ // riscv64-NEXT: bltu a1, a0, .[[RET:.+]]
+ // riscv64-NEXT: mv a0, a1
+ // riscv64-NEXT: .[[RET]]:
+
+ // riscv64-zbb-NEXT: maxu a0, a0, a1
+
+ // loongarch64-NEXT: sltu $a2, $a1, $a0
+ // loongarch64-NEXT: masknez $a1, $a1, $a2
+ // loongarch64-NEXT: maskeqz $a0, $a0, $a2
+ // loongarch64-NEXT: or $a0, $a0, $a1
+
+ // CHECK-NEXT: ret
+ max!(a, b)
+}
+
+#[no_mangle]
+// CHECK-LABEL: issue_114508_i32:
+pub fn issue_114508_i32(a: i32, b: i32) -> i32 {
+ // CHECK-NEXT: .cfi_startproc
+
+ // riscv64-NEXT: blt a1, a0, .[[RET:.+]]
+ // riscv64-NEXT: mv a0, a1
+ // riscv64-NEXT: .[[RET]]:
+
+ // riscv64-zbb-NEXT: max a0, a0, a1
+
+ // loongarch64-NEXT: slt $a2, $a1, $a0
+ // loongarch64-NEXT: masknez $a1, $a1, $a2
+ // loongarch64-NEXT: maskeqz $a0, $a0, $a2
+ // loongarch64-NEXT: or $a0, $a0, $a1
+
+ // CHECK-NEXT: ret
+ max!(a, b)
+}
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index f26d06a..1857633 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -522,6 +522,9 @@
//@ revisions: wasm32_unknown_unknown
//@ [wasm32_unknown_unknown] compile-flags: --target wasm32-unknown-unknown
//@ [wasm32_unknown_unknown] needs-llvm-components: webassembly
+//@ revisions: wasm32v1_none
+//@ [wasm32v1_none] compile-flags: --target wasm32v1-none
+//@ [wasm32v1_none] needs-llvm-components: webassembly
//@ revisions: wasm32_wasi
//@ [wasm32_wasi] compile-flags: --target wasm32-wasi
//@ [wasm32_wasi] needs-llvm-components: webassembly
diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs
index 7f9a7e6..a2dcb1c 100644
--- a/tests/codegen/avr/avr-func-addrspace.rs
+++ b/tests/codegen/avr/avr-func-addrspace.rs
@@ -18,8 +18,8 @@
#[lang = "copy"]
pub trait Copy {}
impl<T: ?Sized> Copy for *const T {}
-#[lang = "receiver"]
-pub trait Receiver {}
+#[lang = "legacy_receiver"]
+pub trait LegacyReceiver {}
#[lang = "tuple_trait"]
pub trait Tuple {}
diff --git a/tests/codegen/checked_ilog.rs b/tests/codegen/checked_ilog.rs
index 8f3c071..d7dfc7c 100644
--- a/tests/codegen/checked_ilog.rs
+++ b/tests/codegen/checked_ilog.rs
@@ -5,7 +5,7 @@
// Ensure that when val < base, we do not divide or multiply.
// CHECK-LABEL: @checked_ilog
-// CHECK-SAME: (i16 noundef %val, i16 noundef %base)
+// CHECK-SAME: (i16{{.*}} %val, i16{{.*}} %base)
#[no_mangle]
pub fn checked_ilog(val: u16, base: u16) -> Option<u32> {
// CHECK-NOT: udiv
diff --git a/tests/codegen/checked_math.rs b/tests/codegen/checked_math.rs
index 75df586..63f5c3d 100644
--- a/tests/codegen/checked_math.rs
+++ b/tests/codegen/checked_math.rs
@@ -8,7 +8,7 @@
// Thanks to poison semantics, this doesn't even need branches.
// CHECK-LABEL: @checked_sub_unsigned
-// CHECK-SAME: (i16 noundef %a, i16 noundef %b)
+// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b)
#[no_mangle]
pub fn checked_sub_unsigned(a: u16, b: u16) -> Option<u16> {
// CHECK-DAG: %[[IS_SOME:.+]] = icmp uge i16 %a, %b
@@ -26,7 +26,7 @@
// looking for no-wrap flags, we just need there to not be any masking.
// CHECK-LABEL: @checked_shl_unsigned
-// CHECK-SAME: (i32 noundef %a, i32 noundef %b)
+// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
#[no_mangle]
pub fn checked_shl_unsigned(a: u32, b: u32) -> Option<u32> {
// CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
@@ -41,7 +41,7 @@
}
// CHECK-LABEL: @checked_shr_unsigned
-// CHECK-SAME: (i32 noundef %a, i32 noundef %b)
+// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
#[no_mangle]
pub fn checked_shr_unsigned(a: u32, b: u32) -> Option<u32> {
// CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
@@ -56,7 +56,7 @@
}
// CHECK-LABEL: @checked_shl_signed
-// CHECK-SAME: (i32 noundef %a, i32 noundef %b)
+// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
#[no_mangle]
pub fn checked_shl_signed(a: i32, b: u32) -> Option<i32> {
// CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
@@ -71,7 +71,7 @@
}
// CHECK-LABEL: @checked_shr_signed
-// CHECK-SAME: (i32 noundef %a, i32 noundef %b)
+// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
#[no_mangle]
pub fn checked_shr_signed(a: i32, b: u32) -> Option<i32> {
// CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
@@ -86,7 +86,7 @@
}
// CHECK-LABEL: @checked_add_one_unwrap_unsigned
-// CHECK-SAME: (i32 noundef %x)
+// CHECK-SAME: (i32{{.*}} %x)
#[no_mangle]
pub fn checked_add_one_unwrap_unsigned(x: u32) -> u32 {
// CHECK: %[[IS_MAX:.+]] = icmp eq i32 %x, -1
diff --git a/tests/codegen/comparison-operators-newtype.rs b/tests/codegen/comparison-operators-newtype.rs
index d336c4e..acce0cb 100644
--- a/tests/codegen/comparison-operators-newtype.rs
+++ b/tests/codegen/comparison-operators-newtype.rs
@@ -12,7 +12,7 @@
pub struct Foo(u16);
// CHECK-LABEL: @check_lt
-// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
+// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
#[no_mangle]
pub fn check_lt(a: Foo, b: Foo) -> bool {
// CHECK: %[[R:.+]] = icmp ult i16 %[[A]], %[[B]]
@@ -21,7 +21,7 @@
}
// CHECK-LABEL: @check_le
-// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
+// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
#[no_mangle]
pub fn check_le(a: Foo, b: Foo) -> bool {
// CHECK: %[[R:.+]] = icmp ule i16 %[[A]], %[[B]]
@@ -30,7 +30,7 @@
}
// CHECK-LABEL: @check_gt
-// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
+// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
#[no_mangle]
pub fn check_gt(a: Foo, b: Foo) -> bool {
// CHECK: %[[R:.+]] = icmp ugt i16 %[[A]], %[[B]]
@@ -39,7 +39,7 @@
}
// CHECK-LABEL: @check_ge
-// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
+// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
#[no_mangle]
pub fn check_ge(a: Foo, b: Foo) -> bool {
// CHECK: %[[R:.+]] = icmp uge i16 %[[A]], %[[B]]
diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs
index b14dd30..a171629 100644
--- a/tests/codegen/fewer-names.rs
+++ b/tests/codegen/fewer-names.rs
@@ -6,11 +6,11 @@
#[no_mangle]
pub fn sum(x: u32, y: u32) -> u32 {
- // YES-LABEL: define{{.*}}i32 @sum(i32 noundef %0, i32 noundef %1)
+ // YES-LABEL: define{{.*}}i32 @sum(i32{{.*}} %0, i32{{.*}} %1)
// YES-NEXT: %3 = add i32 %1, %0
// YES-NEXT: ret i32 %3
- // NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y)
+ // NO-LABEL: define{{.*}}i32 @sum(i32{{.*}} %x, i32{{.*}} %y)
// NO-NEXT: start:
// NO-NEXT: %z = add i32 %y, %x
// NO-NEXT: ret i32 %z
diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs
index bf9f405..7fa1d65 100644
--- a/tests/codegen/function-arguments.rs
+++ b/tests/codegen/function-arguments.rs
@@ -32,7 +32,7 @@
x
}
-// CHECK: i8 @maybeuninit_boolean(i8 %x)
+// CHECK: i8 @maybeuninit_boolean(i8{{.*}} %x)
#[no_mangle]
pub fn maybeuninit_boolean(x: MaybeUninit<bool>) -> MaybeUninit<bool> {
x
@@ -44,19 +44,19 @@
x
}
-// CHECK: i8 @maybeuninit_enum_bool(i8 %x)
+// CHECK: i8 @maybeuninit_enum_bool(i8{{.*}} %x)
#[no_mangle]
pub fn maybeuninit_enum_bool(x: MaybeUninit<MyBool>) -> MaybeUninit<MyBool> {
x
}
-// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32 noundef{{( range\(i32 0, 1114112\))?}} %x)
+// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32{{.*}}{{( range\(i32 0, 1114112\))?}} %x)
#[no_mangle]
pub fn char(x: char) -> char {
x
}
-// CHECK: i32 @maybeuninit_char(i32 %x)
+// CHECK: i32 @maybeuninit_char(i32{{.*}} %x)
#[no_mangle]
pub fn maybeuninit_char(x: MaybeUninit<char>) -> MaybeUninit<char> {
x
diff --git a/tests/codegen/intrinsics/three_way_compare.rs b/tests/codegen/intrinsics/three_way_compare.rs
index f3b631a..9a476ab 100644
--- a/tests/codegen/intrinsics/three_way_compare.rs
+++ b/tests/codegen/intrinsics/three_way_compare.rs
@@ -10,8 +10,7 @@
#[no_mangle]
// CHECK-LABEL: @signed_cmp
-// DEBUG-SAME: (i16 %a, i16 %b)
-// OPTIM-SAME: (i16 noundef %a, i16 noundef %b)
+// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b)
pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering {
// DEBUG: %[[GT:.+]] = icmp sgt i16 %a, %b
// DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8
@@ -29,8 +28,7 @@
#[no_mangle]
// CHECK-LABEL: @unsigned_cmp
-// DEBUG-SAME: (i16 %a, i16 %b)
-// OPTIM-SAME: (i16 noundef %a, i16 noundef %b)
+// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b)
pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering {
// DEBUG: %[[GT:.+]] = icmp ugt i16 %a, %b
// DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8
diff --git a/tests/codegen/mir-aggregate-no-alloca.rs b/tests/codegen/mir-aggregate-no-alloca.rs
index 04ffb07..37b024a 100644
--- a/tests/codegen/mir-aggregate-no-alloca.rs
+++ b/tests/codegen/mir-aggregate-no-alloca.rs
@@ -9,7 +9,7 @@
#[repr(transparent)]
pub struct Transparent32(u32);
-// CHECK: i32 @make_transparent(i32 noundef %x)
+// CHECK: i32 @make_transparent(i32{{.*}} %x)
#[no_mangle]
pub fn make_transparent(x: u32) -> Transparent32 {
// CHECK-NOT: alloca
@@ -18,7 +18,7 @@
a
}
-// CHECK: i32 @make_closure(i32 noundef %x)
+// CHECK: i32 @make_closure(i32{{.*}} %x)
#[no_mangle]
pub fn make_closure(x: i32) -> impl Fn(i32) -> i32 {
// CHECK-NOT: alloca
@@ -40,7 +40,7 @@
a
}
-// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32 noundef %x)
+// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32{{.*}} %x)
#[no_mangle]
pub fn make_2_tuple(x: u32) -> (u32, u32) {
// CHECK-NOT: alloca
@@ -59,7 +59,7 @@
std::cell::Cell::new(b)
}
-// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16 noundef %s)
+// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16{{.*}} %s)
#[no_mangle]
pub fn make_cell_of_bool_and_short(b: bool, s: u16) -> std::cell::Cell<(bool, u16)> {
// CHECK-NOT: alloca
@@ -92,7 +92,7 @@
pub struct Struct1(i32);
-// CHECK-LABEL: i32 @make_struct_1(i32 noundef %a)
+// CHECK-LABEL: i32 @make_struct_1(i32{{.*}} %a)
#[no_mangle]
pub fn make_struct_1(a: i32) -> Struct1 {
// CHECK: ret i32 %a
@@ -104,7 +104,7 @@
// bit32-LABEL: void @make_struct_2_asc({{.*}} sret({{[^,]*}}) {{.*}} %s,
// bit64-LABEL: { i64, i16 } @make_struct_2_asc(
-// CHECK-SAME: i16 noundef %a, i64 noundef %b)
+// CHECK-SAME: i16{{.*}} %a, i64 noundef %b)
#[no_mangle]
pub fn make_struct_2_asc(a: i16, b: i64) -> Struct2Asc {
// CHECK-NOT: alloca
@@ -122,7 +122,7 @@
// bit32-LABEL: void @make_struct_2_desc({{.*}} sret({{[^,]*}}) {{.*}} %s,
// bit64-LABEL: { i64, i16 } @make_struct_2_desc(
-// CHECK-SAME: i64 noundef %a, i16 noundef %b)
+// CHECK-SAME: i64 noundef %a, i16{{.*}} %b)
#[no_mangle]
pub fn make_struct_2_desc(a: i64, b: i16) -> Struct2Desc {
// CHECK-NOT: alloca
diff --git a/tests/codegen/range-attribute.rs b/tests/codegen/range-attribute.rs
index 8972fc7..a44ec10 100644
--- a/tests/codegen/range-attribute.rs
+++ b/tests/codegen/range-attribute.rs
@@ -24,7 +24,7 @@
x
}
-// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8 noundef range(i8 0, 3) %x)
+// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8{{.*}} range(i8 0, 3) %x)
#[no_mangle]
pub fn optional_bool(x: Option<bool>) -> Option<bool> {
x
@@ -36,7 +36,7 @@
C,
}
-// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8 noundef range(i8 0, 4) %x)
+// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8{{.*}} range(i8 0, 4) %x)
#[no_mangle]
pub fn enum0_value(x: Enum0) -> Enum0 {
x
diff --git a/tests/codegen/rust-abi-arch-specific-adjustment.rs b/tests/codegen/rust-abi-arch-specific-adjustment.rs
new file mode 100644
index 0000000..9da10f6
--- /dev/null
+++ b/tests/codegen/rust-abi-arch-specific-adjustment.rs
@@ -0,0 +1,111 @@
+//@ compile-flags: -O -C no-prepopulate-passes
+//@ revisions: riscv64 loongarch64
+
+//@[riscv64] only-riscv64
+//@[riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu
+//@[riscv64] needs-llvm-components: riscv
+
+//@[loongarch64] only-loongarch64
+//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
+//@[loongarch64] needs-llvm-components: loongarch
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+// riscv64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x)
+// loongarch64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x)
+pub fn arg_attr_u8(x: u8) -> u8 {
+ x
+}
+
+#[no_mangle]
+// riscv64: define noundef i16 @arg_attr_u16(i16 noundef zeroext %x)
+// loongarch64: define noundef i16 @arg_attr_u16(i16 noundef zeroext %x)
+pub fn arg_attr_u16(x: u16) -> u16 {
+ x
+}
+
+#[no_mangle]
+// riscv64: define noundef i32 @arg_attr_u32(i32 noundef signext %x)
+// loongarch64: define noundef i32 @arg_attr_u32(i32 noundef signext %x)
+pub fn arg_attr_u32(x: u32) -> u32 {
+ x
+}
+
+#[no_mangle]
+// riscv64: define noundef i64 @arg_attr_u64(i64 noundef %x)
+// loongarch64: define noundef i64 @arg_attr_u64(i64 noundef %x)
+pub fn arg_attr_u64(x: u64) -> u64 {
+ x
+}
+
+#[no_mangle]
+// riscv64: define noundef i128 @arg_attr_u128(i128 noundef %x)
+// loongarch64: define noundef i128 @arg_attr_u128(i128 noundef %x)
+pub fn arg_attr_u128(x: u128) -> u128 {
+ x
+}
+
+#[no_mangle]
+// riscv64: define noundef i8 @arg_attr_i8(i8 noundef signext %x)
+// loongarch64: define noundef i8 @arg_attr_i8(i8 noundef signext %x)
+pub fn arg_attr_i8(x: i8) -> i8 {
+ x
+}
+
+#[no_mangle]
+// riscv64: define noundef i16 @arg_attr_i16(i16 noundef signext %x)
+// loongarch64: define noundef i16 @arg_attr_i16(i16 noundef signext %x)
+pub fn arg_attr_i16(x: i16) -> i16 {
+ x
+}
+
+#[no_mangle]
+// riscv64: define noundef i32 @arg_attr_i32(i32 noundef signext %x)
+// loongarch64: define noundef i32 @arg_attr_i32(i32 noundef signext %x)
+pub fn arg_attr_i32(x: i32) -> i32 {
+ x
+}
+
+#[no_mangle]
+// riscv64: define noundef i64 @arg_attr_i64(i64 noundef %x)
+// loongarch64: define noundef i64 @arg_attr_i64(i64 noundef %x)
+pub fn arg_attr_i64(x: i64) -> i64 {
+ x
+}
+
+#[no_mangle]
+// riscv64: define noundef i128 @arg_attr_i128(i128 noundef %x)
+// loongarch64: define noundef i128 @arg_attr_i128(i128 noundef %x)
+pub fn arg_attr_i128(x: i128) -> i128 {
+ x
+}
+
+#[no_mangle]
+// riscv64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x)
+// loongarch64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x)
+pub fn arg_attr_bool(x: bool) -> bool {
+ x
+}
+
+#[no_mangle]
+// ignore-tidy-linelength
+// riscv64: define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x)
+// loongarch64: define noundef{{( range\(i32 0, 1114112\))?}} i32 @arg_attr_char(i32 noundef signext{{( range\(i32 0, 1114112\))?}} %x)
+pub fn arg_attr_char(x: char) -> char {
+ x
+}
+
+#[no_mangle]
+// riscv64: define noundef float @arg_attr_f32(float noundef %x)
+// loongarch64: define noundef float @arg_attr_f32(float noundef %x)
+pub fn arg_attr_f32(x: f32) -> f32 {
+ x
+}
+
+#[no_mangle]
+// riscv64: define noundef double @arg_attr_f64(double noundef %x)
+// loongarch64: define noundef double @arg_attr_f64(double noundef %x)
+pub fn arg_attr_f64(x: f64) -> f64 {
+ x
+}
diff --git a/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs b/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs
index 259967e..71ccdc8 100644
--- a/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs
+++ b/tests/codegen/sanitizer/cfi/emit-type-checks-attr-no-sanitize.rs
@@ -12,7 +12,7 @@
// CHECK: Function Attrs: {{.*}}
// CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
// CHECK: start:
- // CHECK-NEXT: {{%.+}} = call i32 %f(i32 %arg)
+ // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg)
// CHECK-NEXT: ret i32 {{%.+}}
f(arg)
}
diff --git a/tests/codegen/sanitizer/cfi/emit-type-checks.rs b/tests/codegen/sanitizer/cfi/emit-type-checks.rs
index 37edbef..ebc66a0 100644
--- a/tests/codegen/sanitizer/cfi/emit-type-checks.rs
+++ b/tests/codegen/sanitizer/cfi/emit-type-checks.rs
@@ -11,7 +11,7 @@
// CHECK: [[TT:%.+]] = call i1 @llvm.type.test(ptr {{%f|%0}}, metadata !"{{[[:print:]]+}}")
// CHECK-NEXT: br i1 [[TT]], label %type_test.pass, label %type_test.fail
// CHECK: type_test.pass:
- // CHECK-NEXT: {{%.+}} = call i32 %f(i32 %arg)
+ // CHECK-NEXT: {{%.+}} = call i32 %f(i32{{.*}} %arg)
// CHECK: type_test.fail:
// CHECK-NEXT: call void @llvm.trap()
// CHECK-NEXT: unreachable
diff --git a/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
index c1967e5..5ab55a4 100644
--- a/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
+++ b/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
@@ -16,8 +16,8 @@
#[lang = "copy"]
trait Copy {}
impl<T: ?Sized> Copy for &T {}
-#[lang = "receiver"]
-trait Receiver {}
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {}
#[lang = "dispatch_from_dyn"]
trait DispatchFromDyn<T> {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs
index caaa709..43da7c1 100644
--- a/tests/codegen/transmute-scalar.rs
+++ b/tests/codegen/transmute-scalar.rs
@@ -25,7 +25,7 @@
unsafe { std::mem::transmute(b) }
}
-// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8 %byte)
+// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte)
// CHECK: %_0 = trunc i8 %byte to i1
// CHECK-NEXT: ret i1 %_0
#[no_mangle]
diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs
index b3c67a5..2f14682 100644
--- a/tests/codegen/union-abi.rs
+++ b/tests/codegen/union-abi.rs
@@ -131,7 +131,7 @@
pub union UnionBool {
b: bool,
}
-// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8 %b)
+// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8{{.*}} %b)
#[no_mangle]
pub fn test_UnionBool(b: UnionBool) -> bool {
unsafe { b.b }
diff --git a/tests/codegen/var-names.rs b/tests/codegen/var-names.rs
index fd163a5..4ea5b3b 100644
--- a/tests/codegen/var-names.rs
+++ b/tests/codegen/var-names.rs
@@ -2,7 +2,7 @@
#![crate_type = "lib"]
-// CHECK-LABEL: define{{.*}}i32 @test(i32 noundef %a, i32 noundef %b)
+// CHECK-LABEL: define{{.*}}i32 @test(i32{{.*}} %a, i32{{.*}} %b)
#[no_mangle]
pub fn test(a: u32, b: u32) -> u32 {
let c = a + b;
diff --git a/tests/crashes/110630.rs b/tests/crashes/110630.rs
deleted file mode 100644
index f17f6f0..0000000
--- a/tests/crashes/110630.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-//@ known-bug: #110630
-
-#![feature(generic_const_exprs)]
-
-use std::ops::Mul;
-
-pub trait Indices<const N: usize> {
- const NUM_ELEMS: usize = I::NUM_ELEMS * N;
-}
-
-pub trait Concat<J> {
- type Output;
-}
-
-pub struct Tensor<I: Indices<N>, const N: usize>
-where
- [u8; I::NUM_ELEMS]: Sized, {}
-
-impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul<Tensor<J, N>> for Tensor<I, N>
-where
- I: Concat<T>,
- <I as Concat<J>>::Output: Indices<N>,
- [u8; I::NUM_ELEMS]: Sized,
- [u8; J::NUM_ELEMS]: Sized,
- [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized,
-{
- type Output = Tensor<<I as Concat<J>>::Output, N>;
-}
diff --git a/tests/crashes/115808.rs b/tests/crashes/115808.rs
deleted file mode 100644
index 79196ac..0000000
--- a/tests/crashes/115808.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//@ known-bug: #115808
-#![feature(generic_const_exprs)]
-
-use std::ops::Mul;
-
-pub trait Indices<const N: usize> {
- const NUM_ELEMS: usize;
-}
-
-pub trait Concat<J> {
- type Output;
-}
-
-pub struct Tensor<I: Indices<N>, const N: usize>
-where
- [u8; I::NUM_ELEMS]: Sized, {}
-
-impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul<Tensor<J, N>> for Tensor<I, N>
-where
- I: Concat<FN>,
- <I as Concat<J>>::Output: Indices<N>,
- [u8; I::NUM_ELEMS]: Sized,
- [u8; J::NUM_ELEMS]: Sized,
- [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized,
-{
- type Output = Tensor<<I as Concat<J>>::Output, N>;
-}
diff --git a/tests/crashes/118320.rs b/tests/crashes/118320.rs
deleted file mode 100644
index 093c58e..0000000
--- a/tests/crashes/118320.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//@ known-bug: #118320
-//@ edition:2021
-#![feature(const_trait_impl, effects, const_closures)]
-
-#[const_trait]
-trait Bar {
- fn foo(&self);
-}
-
-impl Bar for () {}
-
-const FOO: () = {
- (const || (()).foo())();
-};
diff --git a/tests/crashes/119924-6.rs b/tests/crashes/119924-6.rs
deleted file mode 100644
index f1cc9d2..0000000
--- a/tests/crashes/119924-6.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ known-bug: #119924
-//@ compile-flags: -Znext-solver
-#![feature(const_trait_impl, effects)]
-
-struct S;
-#[const_trait]
-trait Trait<const N: u32> {}
-
-const fn f<T: Trait<{
- struct I<U: ~const Trait<0>>(U); // should've gotten rejected during AST validation
- //~^ ICE no host param id for call in const yet no errors reported
- 0
-}>>() {}
-
-pub fn main() {}
diff --git a/tests/crashes/121052.rs b/tests/crashes/121052.rs
deleted file mode 100644
index 5d16b06..0000000
--- a/tests/crashes/121052.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-//@ known-bug: #121052
-#![feature(generic_const_exprs, with_negative_coherence)]
-
-use std::ops::Mul;
-
-pub trait Indices<const N: usize> {
- const NUM_ELEMS: usize;
-}
-
-impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul for Tensor<I, N>
-where
- I: Concat<J>,
- <I as Concat<J>>::Output: Indices<N>,
- [u8; I::NUM_ELEMS]: Sized,
- [u8; J::NUM_ELEMS]: Sized,
- [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized,
-{
-}
-
-pub trait Concat<J> {}
-
-pub struct Tensor<I: Indices<N>, const N: usize> {}
-
-impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul for Tensor<I, N>
-where
- I: Concat<J>,
- <I as Concat<J>>::Output: Indices<N>,
- [u8; I::NUM_ELEMS]: Sized,
- [u8; J::NUM_ELEMS]: Sized,
- [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized,
-{
-}
diff --git a/tests/crashes/126725.rs b/tests/crashes/126725.rs
deleted file mode 100644
index d7a7d21..0000000
--- a/tests/crashes/126725.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//@ known-bug: rust-lang/rust#126725
-trait Foo {
- fn foo<'a>(&'a self) -> <&'a impl Sized as Bar>::Output;
-}
-
-trait Bar {
- type Output;
-}
-
-struct X(i32);
-
-impl<'a> Bar for &'a X {
- type Output = &'a i32;
-}
-
-impl Foo for X {
- fn foo<'a>(&'a self) -> <&'a Self as Bar>::Output {
- &self.0
- }
-}
diff --git a/tests/crashes/23707.rs b/tests/crashes/23707.rs
deleted file mode 100644
index 4105933..0000000
--- a/tests/crashes/23707.rs
+++ /dev/null
@@ -1,109 +0,0 @@
-//@ known-bug: #23707
-//@ compile-flags: -Copt-level=0 --edition=2021
-//@ only-x86_64
-#![recursion_limit="2048"]
-
-use std::marker::PhantomData;
-use std::fmt;
-use std::fmt::Debug;
-
-pub struct Z( () );
-pub struct S<T> (PhantomData<T>);
-
-
-pub trait Nat {
- fn sing() -> Self;
- fn get(&self) -> usize;
-}
-
-impl Nat for Z {
- fn sing() -> Z { Z( () ) }
- #[inline(always)]
- fn get(&self) -> usize {
- 0
- }
-}
-
-impl<T : Nat> Nat for S<T> {
- fn sing() -> S<T> { S::<T>( PhantomData::<T> ) }
- #[inline(always)]
- fn get(&self) -> usize {
- let prd : T = Nat::sing();
- 1 + prd.get()
- }
-}
-
-pub type N0 = Z;
-pub type N1 = S<N0>;
-pub type N2 = S<N1>;
-pub type N3 = S<N2>;
-pub type N4 = S<N3>;
-pub type N5 = S<N4>;
-
-
-pub struct Node<D : Nat>(usize,PhantomData<D>);
-
-impl<D:Nat> Node<D> {
- pub fn push(&self, c : usize) -> Node<S<D>> {
- let Node(i,_) = *self;
- Node(10*i+c, PhantomData::<S<D>>)
- }
-}
-
-impl<D:Nat> Node<S<D>> {
- pub fn pop(&self) -> (Node<D>,usize) {
- let Node(i,_) = *self;
- (Node(i/10, PhantomData::<D>), i-10*(i/10))
- }
-}
-
-impl<D:Nat> Debug for Node<D> {
- fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
- let s : D = Nat::sing();
- write!(f, "Node<{}>: i= {}",
- s.get(), self.0)
- }
-}
-pub trait Step {
- fn step(&self, usize) -> Self;
-}
-
-impl Step for Node<N0> {
- #[inline(always)]
- fn step(&self, n : usize) -> Node<N0> {
- println!("base case");
- Node(n,PhantomData::<N0>)
- }
-}
-
-impl<D:Nat> Step for Node<S<D>>
- where Node<D> : Step {
- #[inline(always)]
- fn step(&self, n : usize) -> Node<S<D>> {
- println!("rec");
- let (par,c) = self.pop();
- let cnew = c+n;
- par.step(c).push(cnew)
- }
-
-}
-
-fn tst<D:Nat>(ref p : &Node<D>, c : usize) -> usize
- where Node<D> : Step {
- let Node(i,_) = p.step(c);
- i
-}
-
-
-
-fn main() {
- let nd : Node<N3> = Node(555,PhantomData::<N3>);
-
- // overflow...core::marker::Size
- let Node(g,_) = tst(nd,1);
-
- // ok
- //let Node(g,_) = nd.step(1);
-
- println!("{:?}", g);
-}
diff --git a/tests/debuginfo/thread.rs b/tests/debuginfo/thread.rs
index 0415f58..dc8cb08 100644
--- a/tests/debuginfo/thread.rs
+++ b/tests/debuginfo/thread.rs
@@ -12,15 +12,15 @@
// cdb-check:join_handle,d [Type: std::thread::JoinHandle<tuple$<> >]
// cdb-check: [...] __0 [Type: std::thread::JoinInner<tuple$<> >]
//
-// cdb-command:dx t,d
+// cdb-command:dx -r3 t,d
// cdb-check:t,d : [...] [Type: std::thread::Thread *]
-// cdb-check:[...] inner [...][Type: core::pin::Pin<alloc::sync::Arc<std::thread::Inner,alloc::alloc::Global> >]
+// cdb-check: [...] __0 : Other [Type: enum2$<std::thread::Inner>]
+// cdb-check: [...] __0 [Type: core::pin::Pin<alloc::sync::Arc<std::thread::OtherInner,[...]> >]
use std::thread;
#[allow(unused_variables)]
-fn main()
-{
+fn main() {
let join_handle = thread::spawn(|| {
println!("Initialize a thread");
});
diff --git a/tests/run-make/cross-lang-lto-clang/rmake.rs b/tests/run-make/cross-lang-lto-clang/rmake.rs
index 1b15a54..3fed6ea 100644
--- a/tests/run-make/cross-lang-lto-clang/rmake.rs
+++ b/tests/run-make/cross-lang-lto-clang/rmake.rs
@@ -9,6 +9,24 @@
use run_make_support::{clang, env_var, llvm_ar, llvm_objdump, rustc, static_lib_name};
+#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
+static RUST_ALWAYS_INLINED_PATTERN: &'static str = "bl.*<rust_always_inlined>";
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+static RUST_ALWAYS_INLINED_PATTERN: &'static str = "call.*rust_always_inlined";
+#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
+static C_ALWAYS_INLINED_PATTERN: &'static str = "bl.*<c_always_inlined>";
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+static C_ALWAYS_INLINED_PATTERN: &'static str = "call.*c_always_inlined";
+
+#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
+static RUST_NEVER_INLINED_PATTERN: &'static str = "bl.*<rust_never_inlined>";
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+static RUST_NEVER_INLINED_PATTERN: &'static str = "call.*rust_never_inlined";
+#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
+static C_NEVER_INLINED_PATTERN: &'static str = "bl.*<c_never_inlined>";
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+static C_NEVER_INLINED_PATTERN: &'static str = "call.*c_never_inlined";
+
fn main() {
rustc()
.linker_plugin_lto("on")
@@ -31,14 +49,14 @@
.disassemble()
.input("cmain")
.run()
- .assert_stdout_not_contains_regex("call.*rust_always_inlined");
+ .assert_stdout_not_contains_regex(RUST_ALWAYS_INLINED_PATTERN);
// As a sanity check, make sure we do find a call instruction to a
// non-inlined function
llvm_objdump()
.disassemble()
.input("cmain")
.run()
- .assert_stdout_contains_regex("call.*rust_never_inlined");
+ .assert_stdout_contains_regex(RUST_NEVER_INLINED_PATTERN);
clang().input("clib.c").lto("thin").arg("-c").out_exe("clib.o").arg("-O2").run();
llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run();
rustc()
@@ -53,10 +71,10 @@
.disassemble()
.input("rsmain")
.run()
- .assert_stdout_not_contains_regex("call.*c_always_inlined");
+ .assert_stdout_not_contains_regex(C_ALWAYS_INLINED_PATTERN);
llvm_objdump()
.disassemble()
.input("rsmain")
.run()
- .assert_stdout_contains_regex("call.*c_never_inlined");
+ .assert_stdout_contains_regex(C_NEVER_INLINED_PATTERN);
}
diff --git a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
index 9257335..e595dbe 100644
--- a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
+++ b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
@@ -1,21 +1,20 @@
-//! Make sure that cross-language LTO works on riscv targets,
-//! which requires extra `target-abi` metadata to be emitted.
+//! Make sure that cross-language LTO works on riscv targets, which requires extra `target-abi`
+//! metadata to be emitted.
//@ needs-force-clang-based-tests
-//@ needs-llvm-components riscv
+//@ needs-llvm-components: riscv
-//@ needs-force-clang-based-tests
-// FIXME(#126180): This test can only run on `x86_64-gnu-debug`, because that CI job sets
-// RUSTBUILD_FORCE_CLANG_BASED_TESTS and only runs tests which contain "clang" in their
-// name.
-// However, this test does not run at all as its name does not contain "clang".
+// ignore-tidy-linelength
-use std::path::PathBuf;
-use std::process::{Command, Output};
-use std::{env, str};
+use object::elf;
+use object::read::elf as readelf;
+use run_make_support::{bin_name, clang, object, rfs, rustc};
-use run_make_support::{bin_name, clang, llvm_readobj, rustc};
-
-fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float: bool) {
+fn check_target<H: readelf::FileHeader<Endian = object::Endianness>>(
+ target: &str,
+ clang_target: &str,
+ carch: &str,
+ is_double_float: bool,
+) {
eprintln!("Checking target {target}");
// Rust part
rustc()
@@ -39,16 +38,55 @@
// Check that the built binary has correct float abi
let executable = bin_name("riscv-xlto");
- let output = llvm_readobj().input(&executable).file_header().run();
- let stdout = String::from_utf8_lossy(&output.stdout);
- eprintln!("obj:\n{}", stdout);
-
- assert!(!(is_double_float ^ stdout.contains("EF_RISCV_FLOAT_ABI_DOUBLE")));
+ let data = rfs::read(&executable);
+ let header = <H>::parse(&*data).unwrap();
+ let endian = match header.e_ident().data {
+ elf::ELFDATA2LSB => object::Endianness::Little,
+ elf::ELFDATA2MSB => object::Endianness::Big,
+ x => unreachable!("invalid e_ident data: {:#010b}", x),
+ };
+ // Check `(e_flags & EF_RISCV_FLOAT_ABI) == EF_RISCV_FLOAT_ABI_DOUBLE`.
+ //
+ // See
+ // <https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#elf-object-files>.
+ if is_double_float {
+ assert_eq!(
+ header.e_flags(endian) & elf::EF_RISCV_FLOAT_ABI,
+ elf::EF_RISCV_FLOAT_ABI_DOUBLE,
+ "expected {target} to use double ABI, but it did not"
+ );
+ } else {
+ assert_ne!(
+ header.e_flags(endian) & elf::EF_RISCV_FLOAT_ABI,
+ elf::EF_RISCV_FLOAT_ABI_DOUBLE,
+ "did not expected {target} to use double ABI"
+ );
+ }
}
fn main() {
- check_target("riscv64gc-unknown-linux-gnu", "riscv64-linux-gnu", "rv64gc", true);
- check_target("riscv64imac-unknown-none-elf", "riscv64-unknown-elf", "rv64imac", false);
- check_target("riscv32imac-unknown-none-elf", "riscv32-unknown-elf", "rv32imac", false);
- check_target("riscv32gc-unknown-linux-gnu", "riscv32-linux-gnu", "rv32gc", true);
+ check_target::<elf::FileHeader64<object::Endianness>>(
+ "riscv64gc-unknown-linux-gnu",
+ "riscv64-linux-gnu",
+ "rv64gc",
+ true,
+ );
+ check_target::<elf::FileHeader64<object::Endianness>>(
+ "riscv64imac-unknown-none-elf",
+ "riscv64-unknown-elf",
+ "rv64imac",
+ false,
+ );
+ check_target::<elf::FileHeader32<object::Endianness>>(
+ "riscv32imac-unknown-none-elf",
+ "riscv32-unknown-elf",
+ "rv32imac",
+ false,
+ );
+ check_target::<elf::FileHeader32<object::Endianness>>(
+ "riscv32gc-unknown-linux-gnu",
+ "riscv32-linux-gnu",
+ "rv32gc",
+ true,
+ );
}
diff --git a/tests/run-make/issue-84395-lto-embed-bitcode/Makefile b/tests/run-make/issue-84395-lto-embed-bitcode/Makefile
deleted file mode 100644
index aabe907..0000000
--- a/tests/run-make/issue-84395-lto-embed-bitcode/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# needs-force-clang-based-tests
-
-# FIXME(#126180): This test doesn't actually run anywhere, because the only
-# CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests.
-
-# This test makes sure the embed bitcode in elf created with
-# lto-embed-bitcode=optimized is valid llvm BC module.
-
-include ../tools.mk
-
-all:
- $(RUSTC) test.rs --target $(TARGET) -Clink-arg=-fuse-ld=lld -Clinker-plugin-lto -Clinker=$(CLANG) -Clink-arg=-Wl,--plugin-opt=-lto-embed-bitcode=optimized -Zemit-thin-lto=no
- $(LLVM_BIN_DIR)/objcopy --dump-section .llvmbc=$(TMPDIR)/test.bc $(TMPDIR)/test
- $(LLVM_BIN_DIR)/llvm-dis $(TMPDIR)/test.bc
diff --git a/tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs b/tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs
new file mode 100644
index 0000000..450d8a9
--- /dev/null
+++ b/tests/run-make/issue-84395-lto-embed-bitcode/rmake.rs
@@ -0,0 +1,27 @@
+//! Smoke test to make sure the embed bitcode in elf created with
+//! `--plugin-opt=-lto-embed-bitcode=optimized` is valid llvm BC module.
+//!
+//! See <https://github.com/rust-lang/rust/issues/84395> where passing
+//! `-lto-embed-bitcode=optimized` to lld when linking rust code via `linker-plugin-lto` doesn't
+//! produce the expected result.
+//!
+//! See PR <https://github.com/rust-lang/rust/pull/98162> which initially introduced this test.
+
+//@ needs-force-clang-based-tests
+
+use run_make_support::{env_var, llvm_dis, llvm_objcopy, rustc};
+
+fn main() {
+ rustc()
+ .input("test.rs")
+ .arg("-Clink-arg=-fuse-ld=lld")
+ .arg("-Clinker-plugin-lto")
+ .arg(format!("-Clinker={}", env_var("CLANG")))
+ .arg("-Clink-arg=-Wl,--plugin-opt=-lto-embed-bitcode=optimized")
+ .arg("-Zemit-thin-lto=no")
+ .run();
+
+ llvm_objcopy().dump_section(".llvmbc", "test.bc").arg("test").run();
+
+ llvm_dis().arg("test.bc").run();
+}
diff --git a/tests/run-make/linkage-attr-framework/main.rs b/tests/run-make/linkage-attr-framework/main.rs
new file mode 100644
index 0000000..8efabc8
--- /dev/null
+++ b/tests/run-make/linkage-attr-framework/main.rs
@@ -0,0 +1,17 @@
+#![cfg_attr(any(weak, both), feature(link_arg_attribute))]
+
+#[cfg_attr(any(link, both), link(name = "CoreFoundation", kind = "framework"))]
+#[cfg_attr(
+ any(weak, both),
+ link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim"),
+ link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim")
+)]
+extern "C" {
+ fn CFRunLoopGetTypeID() -> core::ffi::c_ulong;
+}
+
+fn main() {
+ unsafe {
+ CFRunLoopGetTypeID();
+ }
+}
diff --git a/tests/run-make/linkage-attr-framework/rmake.rs b/tests/run-make/linkage-attr-framework/rmake.rs
new file mode 100644
index 0000000..4450350
--- /dev/null
+++ b/tests/run-make/linkage-attr-framework/rmake.rs
@@ -0,0 +1,26 @@
+//! Check that linking frameworks on Apple platforms works.
+
+//@ only-apple
+
+use run_make_support::{Rustc, run, rustc};
+
+fn compile(cfg: &str) -> Rustc {
+ let mut rustc = rustc();
+ rustc.cfg(cfg).input("main.rs");
+ rustc
+}
+
+fn main() {
+ for cfg in ["link", "weak", "both"] {
+ compile(cfg).run();
+ run("main");
+ }
+
+ let errs = compile("omit").run_fail();
+ // The linker's exact error output changes between Xcode versions, depends on
+ // linker invocation details, and the linker sometimes outputs more warnings.
+ errs.assert_stderr_contains_regex(r"error: linking with `.*` failed");
+ errs.assert_stderr_contains_regex(r"(Undefined symbols|ld: symbol[^\s]* not found)");
+ errs.assert_stderr_contains_regex(r".?_CFRunLoopGetTypeID.?, referenced from:");
+ errs.assert_stderr_contains("clang: error: linker command failed with exit code 1");
+}
diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
new file mode 100644
index 0000000..cf6e3d8
--- /dev/null
+++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs
@@ -0,0 +1,36 @@
+// `-Z branch protection` is an unstable compiler feature which adds pointer-authentication
+// code (PAC), a useful hashing measure for verifying that pointers have not been modified.
+// This test checks that compilation and execution is successful when this feature is activated,
+// with some of its possible extra arguments (bti, pac-ret, leaf) when doing LTO.
+// See https://github.com/rust-lang/rust/pull/88354
+
+//@ needs-force-clang-based-tests
+//@ only-aarch64
+// Reason: branch protection is not supported on other architectures
+//@ ignore-cross-compile
+// Reason: the compiled binary is executed
+
+use run_make_support::{clang, env_var, llvm_ar, run, rustc, static_lib_name};
+
+fn main() {
+ clang()
+ .arg("-v")
+ .lto("thin")
+ .arg("-mbranch-protection=bti+pac-ret+leaf")
+ .arg("-O2")
+ .arg("-c")
+ .out_exe("test.o")
+ .input("test.c")
+ .run();
+ llvm_ar().obj_to_ar().output_input(static_lib_name("test"), "test.o").run();
+ rustc()
+ .linker_plugin_lto("on")
+ .opt_level("2")
+ .linker(&env_var("CLANG"))
+ .link_arg("-fuse-ld=lld")
+ .arg("-Zbranch-protection=bti,pac-ret,leaf")
+ .input("test.rs")
+ .output("test.bin")
+ .run();
+ run("test.bin");
+}
diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/test.c b/tests/run-make/pointer-auth-link-with-c-lto-clang/test.c
new file mode 100644
index 0000000..9fe07f8
--- /dev/null
+++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/test.c
@@ -0,0 +1 @@
+int foo() { return 0; }
diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/test.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/test.rs
new file mode 100644
index 0000000..1a3be80
--- /dev/null
+++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/test.rs
@@ -0,0 +1,10 @@
+#[link(name = "test")]
+extern "C" {
+ fn foo() -> i32;
+}
+
+fn main() {
+ unsafe {
+ foo();
+ }
+}
diff --git a/tests/run-make/rust-lld-link-script-provide/main.rs b/tests/run-make/rust-lld-link-script-provide/main.rs
new file mode 100644
index 0000000..5c19e7a
--- /dev/null
+++ b/tests/run-make/rust-lld-link-script-provide/main.rs
@@ -0,0 +1,7 @@
+#[no_mangle]
+fn foo() {}
+
+#[no_mangle]
+fn bar() {}
+
+fn main() {}
diff --git a/tests/run-make/rust-lld-link-script-provide/rmake.rs b/tests/run-make/rust-lld-link-script-provide/rmake.rs
new file mode 100644
index 0000000..e78a411
--- /dev/null
+++ b/tests/run-make/rust-lld-link-script-provide/rmake.rs
@@ -0,0 +1,18 @@
+// This test ensures that the “symbol not found” error does not occur
+// when the symbols in the `PROVIDE` of the link script can be eliminated.
+// This is a regression test for #131164.
+
+//@ needs-rust-lld
+//@ only-x86_64-unknown-linux-gnu
+
+use run_make_support::rustc;
+
+fn main() {
+ rustc()
+ .input("main.rs")
+ .arg("-Zlinker-features=+lld")
+ .arg("-Clink-self-contained=+linker")
+ .arg("-Zunstable-options")
+ .link_arg("-Tscript.t")
+ .run();
+}
diff --git a/tests/run-make/rust-lld-link-script-provide/script.t b/tests/run-make/rust-lld-link-script-provide/script.t
new file mode 100644
index 0000000..4c4c6dd
--- /dev/null
+++ b/tests/run-make/rust-lld-link-script-provide/script.t
@@ -0,0 +1 @@
+PROVIDE(foo = bar);
diff --git a/tests/rustdoc-gui/check-stab-in-docblock.goml b/tests/rustdoc-gui/check-stab-in-docblock.goml
index f25c886..916bea6 100644
--- a/tests/rustdoc-gui/check-stab-in-docblock.goml
+++ b/tests/rustdoc-gui/check-stab-in-docblock.goml
@@ -1,5 +1,5 @@
// This test checks that using `.stab` attributes in `.docblock` elements doesn't
-// create scrollable paragraphs.
+// create scrollable paragraphs and is correctly displayed (not making weird blocks).
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
// Needs the text to be display to check for scrollable content.
show-text: true
@@ -31,3 +31,15 @@
".top-doc .docblock p:nth-of-type(3)",
{"scrollHeight": |clientHeight|, "scrollWidth": |clientWidth|},
)
+
+// Ensure that `<code>` elements in code don't make big blocks.
+compare-elements-size-near: (
+ "#reexport\.TheStdReexport > code",
+ ".docblock p span[data-span='1']",
+ {"height": 1},
+)
+compare-elements-size-near: (
+ "#reexport\.TheStdReexport > code",
+ ".docblock p span[data-span='2']",
+ {"height": 1},
+)
diff --git a/tests/rustdoc-gui/docblock-big-code-mobile.goml b/tests/rustdoc-gui/docblock-big-code-mobile.goml
index 6fc6834..71e08e2 100644
--- a/tests/rustdoc-gui/docblock-big-code-mobile.goml
+++ b/tests/rustdoc-gui/docblock-big-code-mobile.goml
@@ -1,13 +1,15 @@
// If we have a long `<code>`, we need to ensure that it'll be fully displayed on mobile, meaning
// that it'll be on two lines.
+
emulate: "iPhone 8" // it has the following size: (375, 667)
go-to: "file://" + |DOC_PATH| + "/test_docs/long_code_block/index.html"
-// We now check that the block is on two lines:
show-text: true // We need to enable text draw to be able to have the "real" size
+
+// We now check that the block is on two lines:
// Little explanations for this test: if the text wasn't displayed on two lines, it would take
-// around 20px (which is the font size).
-assert-property: (".docblock p > code", {"offsetHeight": "44"})
+// around 24px (which is the font size).
+assert-size: (".docblock p > code", {"height": 48})
// Same check, but where the long code block is also a link
go-to: "file://" + |DOC_PATH| + "/test_docs/long_code_block_link/index.html"
-assert-property: (".docblock p > a > code", {"offsetHeight": "44"})
+assert-size: (".docblock p > a > code", {"height": 48})
diff --git a/tests/rustdoc-gui/fields.goml b/tests/rustdoc-gui/fields.goml
index b8139a2..dce9918 100644
--- a/tests/rustdoc-gui/fields.goml
+++ b/tests/rustdoc-gui/fields.goml
@@ -1,13 +1,37 @@
-// This test checks that fields are displayed as expected (one by line).
-go-to: "file://" + |DOC_PATH| + "/test_docs/fields/struct.Struct.html"
-store-position: ("#structfield\.a", {"y": a_y})
-store-position: ("#structfield\.b", {"y": b_y})
-assert: |a_y| < |b_y|
+// This test checks that fields are displayed as expected (one by line) and they are surrounded
+// by margins.
-go-to: "file://" + |DOC_PATH| + "/test_docs/fields/union.Union.html"
-store-position: ("#structfield\.a", {"y": a_y})
-store-position: ("#structfield\.b", {"y": b_y})
-assert: |a_y| < |b_y|
+store-value: (margin, "9.6px")
+define-function: (
+ "check-fields",
+ [path, selector_1, selector_2],
+ block {
+ go-to: "file://" + |DOC_PATH| + "/test_docs/fields/" + |path|
+ store-position: (|selector_1|, {"y": a_y})
+ store-position: (|selector_2|, {"y": b_y})
+ assert: |a_y| < |b_y|
+
+ // Check the margins.
+ assert-css: (".structfield.section-header", {
+ "margin-top": |margin|,
+ "margin-bottom": |margin|,
+ "margin-left": "0px",
+ "margin-right": "0px",
+ }, ALL)
+ }
+)
+
+call-function: ("check-fields", {
+ "path": "struct.Struct.html",
+ "selector_1": "#structfield\.a",
+ "selector_2": "#structfield\.b",
+})
+
+call-function: ("check-fields", {
+ "path": "union.Union.html",
+ "selector_1": "#structfield\.a",
+ "selector_2": "#structfield\.b",
+})
go-to: "file://" + |DOC_PATH| + "/test_docs/fields/enum.Enum.html"
store-position: ("#variant\.A\.field\.a", {"y": a_y})
@@ -16,3 +40,11 @@
store-position: ("#variant\.B\.field\.a", {"y": a_y})
store-position: ("#variant\.B\.field\.b", {"y": b_y})
assert: |a_y| < |b_y|
+
+// Check the margins.
+assert-css: (".sub-variant-field", {
+ "margin-top": |margin|,
+ "margin-bottom": |margin|,
+ "margin-left": "24px",
+ "margin-right": "0px",
+}, ALL)
diff --git a/tests/rustdoc-gui/item-info.goml b/tests/rustdoc-gui/item-info.goml
index c8aa7b3..1636e14 100644
--- a/tests/rustdoc-gui/item-info.goml
+++ b/tests/rustdoc-gui/item-info.goml
@@ -20,7 +20,7 @@
{"x": second_line_x, "y": second_line_y},
)
assert: |first_line_x| != |second_line_x| && |first_line_x| == 516 && |second_line_x| == 272
-assert: |first_line_y| != |second_line_y| && |first_line_y| == 714 && |second_line_y| == 737
+assert: |first_line_y| != |second_line_y| && |first_line_y| == 718 && |second_line_y| == 741
// Now we ensure that they're not rendered on the same line.
set-window-size: (1100, 800)
diff --git a/tests/rustdoc-gui/scrape-examples-layout.goml b/tests/rustdoc-gui/scrape-examples-layout.goml
index 96c78bb..5187ac4 100644
--- a/tests/rustdoc-gui/scrape-examples-layout.goml
+++ b/tests/rustdoc-gui/scrape-examples-layout.goml
@@ -80,8 +80,8 @@
store-value: (offset_y, 4)
// First with desktop
-assert-position: (".scraped-example", {"y": 252})
-assert-position: (".scraped-example .prev", {"y": 252 + |offset_y|})
+assert-position: (".scraped-example", {"y": 256})
+assert-position: (".scraped-example .prev", {"y": 256 + |offset_y|})
// Gradient background should be at the top of the code block.
assert-css: (".scraped-example .example-wrap::before", {"top": "0px"})
@@ -90,8 +90,8 @@
// Then with mobile
set-window-size: (600, 600)
store-size: (".scraped-example .scraped-example-title", {"height": title_height})
-assert-position: (".scraped-example", {"y": 287})
-assert-position: (".scraped-example .prev", {"y": 287 + |offset_y| + |title_height|})
+assert-position: (".scraped-example", {"y": 291})
+assert-position: (".scraped-example .prev", {"y": 291 + |offset_y| + |title_height|})
define-function: (
"check_title_and_code_position",
diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml
index 742453c..1e77bcc 100644
--- a/tests/rustdoc-gui/sidebar-source-code-display.goml
+++ b/tests/rustdoc-gui/sidebar-source-code-display.goml
@@ -141,7 +141,7 @@
wait-for-css: (".src .sidebar > *", {"visibility": "hidden"})
// We scroll to line 117 to change the scroll position.
scroll-to: '//*[@id="117"]'
-store-value: (y_offset, "2570")
+store-value: (y_offset, "2578")
assert-window-property: {"pageYOffset": |y_offset|}
// Expanding the sidebar...
click: "#sidebar-button"
diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml
index f879464..4ad65bb 100644
--- a/tests/rustdoc-gui/source-anchor-scroll.goml
+++ b/tests/rustdoc-gui/source-anchor-scroll.goml
@@ -8,13 +8,13 @@
assert-property: ("html", {"scrollTop": "0"})
click: '//a[text() = "barbar" and @href="#5-7"]'
-assert-property: ("html", {"scrollTop": "200"})
+assert-property: ("html", {"scrollTop": "208"})
click: '//a[text() = "bar" and @href="#28-36"]'
-assert-property: ("html", {"scrollTop": "231"})
+assert-property: ("html", {"scrollTop": "239"})
click: '//a[normalize-space() = "sub_fn" and @href="#2-4"]'
-assert-property: ("html", {"scrollTop": "128"})
+assert-property: ("html", {"scrollTop": "136"})
// We now check that clicking on lines doesn't change the scroll
// Extra information: the "sub_fn" function header is on line 1.
click: '//*[@id="6"]'
-assert-property: ("html", {"scrollTop": "128"})
+assert-property: ("html", {"scrollTop": "136"})
diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml
index 095354c..afb1946 100644
--- a/tests/rustdoc-gui/source-code-page.goml
+++ b/tests/rustdoc-gui/source-code-page.goml
@@ -89,7 +89,7 @@
// do anything (and certainly not add a `#NaN` to the URL!).
go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
// We use this assert-position to know where we will click.
-assert-position: ("//*[@id='1']", {"x": 88, "y": 163})
+assert-position: ("//*[@id='1']", {"x": 88, "y": 171})
// We click on the left of the "1" anchor but still in the "src-line-number" `<pre>`.
click: (163, 77)
assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
@@ -165,7 +165,7 @@
// offsetTop[nav.sub form] = offsetTop[#main-content] - offsetHeight[nav.sub form] - offsetTop[nav.sub form]
assert-position: ("nav.sub form", {"y": 15})
assert-property: ("nav.sub form", {"offsetHeight": 34})
-assert-position: ("h1", {"y": 64})
+assert-position: ("h1", {"y": 68})
// 15 = 64 - 34 - 15
// Now do the same check on moderately-sized, tablet mobile.
@@ -173,7 +173,7 @@
assert-css: ("nav.sub", {"flex-direction": "row"})
assert-position: ("nav.sub form", {"y": 8})
assert-property: ("nav.sub form", {"offsetHeight": 34})
-assert-position: ("h1", {"y": 50})
+assert-position: ("h1", {"y": 54})
// 8 = 50 - 34 - 8
// Check the sidebar directory entries have a marker and spacing (tablet).
diff --git a/tests/rustdoc-gui/struct-fields.goml b/tests/rustdoc-gui/struct-fields.goml
index 3c87a4c..302a1a0 100644
--- a/tests/rustdoc-gui/struct-fields.goml
+++ b/tests/rustdoc-gui/struct-fields.goml
@@ -1,4 +1,5 @@
-// This test ensures that each field is on its own line (In other words, they have display: block).
+// This test ensures that each field is on its own line (In other words, they have
+// `display: block`).
go-to: "file://" + |DOC_PATH| + "/test_docs/struct.StructWithPublicUndocumentedFields.html"
store-property: ("//*[@id='structfield.first']", {"offsetTop": first_top})
diff --git a/tests/rustdoc-js/extern-func.js b/tests/rustdoc-js/extern-func.js
new file mode 100644
index 0000000..a3fe2d8
--- /dev/null
+++ b/tests/rustdoc-js/extern-func.js
@@ -0,0 +1,8 @@
+const EXPECTED = [
+ {
+ 'query': 'c_float -> c_float',
+ 'others': [
+ { 'path': 'extern_func', 'name': 'sqrt' }
+ ],
+ },
+];
diff --git a/tests/rustdoc-js/extern-func.rs b/tests/rustdoc-js/extern-func.rs
new file mode 100644
index 0000000..ab1e3e7
--- /dev/null
+++ b/tests/rustdoc-js/extern-func.rs
@@ -0,0 +1,5 @@
+use std::ffi::c_float;
+
+extern "C" {
+ pub fn sqrt(x: c_float) -> c_float;
+}
diff --git a/tests/rustdoc-json/impls/auto.rs b/tests/rustdoc-json/impls/auto.rs
index e14c935..f37dae4 100644
--- a/tests/rustdoc-json/impls/auto.rs
+++ b/tests/rustdoc-json/impls/auto.rs
@@ -4,8 +4,8 @@
#[lang = "sized"]
trait Sized {}
-#[lang = "receiver"]
-pub trait Receiver {}
+#[lang = "legacy_receiver"]
+pub trait LegacyReceiver {}
pub auto trait Bar {}
diff --git a/tests/rustdoc-ui/doctest/nested-main.rs b/tests/rustdoc-ui/doctest/nested-main.rs
new file mode 100644
index 0000000..e939ba8
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/nested-main.rs
@@ -0,0 +1,24 @@
+//@ check-pass
+//@ compile-flags:--test --test-args=--test-threads=1
+//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+// Regression test for <https://github.com/rust-lang/rust/issues/131893>.
+// It ensures that if a function called `main` is nested, it will not consider
+// it as the `main` function.
+
+/// ```
+/// fn dox() {
+/// fn main() {}
+/// }
+/// ```
+pub fn foo() {}
+
+// This one ensures that having a nested `main` doesn't prevent the
+// actual `main` function to be detected.
+/// ```
+/// fn main() {
+/// fn main() {}
+/// }
+/// ```
+pub fn foo2() {}
diff --git a/tests/rustdoc-ui/doctest/nested-main.stdout b/tests/rustdoc-ui/doctest/nested-main.stdout
new file mode 100644
index 0000000..af9a8f5
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/nested-main.stdout
@@ -0,0 +1,7 @@
+
+running 2 tests
+test $DIR/nested-main.rs - foo (line 10) ... ok
+test $DIR/nested-main.rs - foo2 (line 19) ... ok
+
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/rustdoc/anchors.no_const_anchor.html b/tests/rustdoc/anchors.no_const_anchor.html
index 06673d8..07a7507 100644
--- a/tests/rustdoc/anchors.no_const_anchor.html
+++ b/tests/rustdoc/anchors.no_const_anchor.html
@@ -1 +1 @@
-<section id="associatedconstant.YOLO" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
+<section id="associatedconstant.YOLO" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#16">Source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/anchors.no_const_anchor2.html b/tests/rustdoc/anchors.no_const_anchor2.html
index 73c3d0a..091dac3 100644
--- a/tests/rustdoc/anchors.no_const_anchor2.html
+++ b/tests/rustdoc/anchors.no_const_anchor2.html
@@ -1 +1 @@
-<section id="associatedconstant.X" class="associatedconstant"><a class="src rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
\ No newline at end of file
+<section id="associatedconstant.X" class="associatedconstant"><a class="src rightside" href="../src/foo/anchors.rs.html#42">Source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/anchors.no_method_anchor.html b/tests/rustdoc/anchors.no_method_anchor.html
index e8b61ca..89f9898 100644
--- a/tests/rustdoc/anchors.no_method_anchor.html
+++ b/tests/rustdoc/anchors.no_method_anchor.html
@@ -1 +1 @@
-<section id="method.new" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -> Self</h4></section>
\ No newline at end of file
+<section id="method.new" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#48">Source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>() -> Self</h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/anchors.no_trait_method_anchor.html b/tests/rustdoc/anchors.no_trait_method_anchor.html
index abdb17c..51656a3 100644
--- a/tests/rustdoc/anchors.no_trait_method_anchor.html
+++ b/tests/rustdoc/anchors.no_trait_method_anchor.html
@@ -1 +1 @@
-<section id="method.bar" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section>
\ No newline at end of file
+<section id="method.bar" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#23">Source</a><h4 class="code-header">fn <a href="#method.bar" class="fn">bar</a>()</h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/anchors.no_tymethod_anchor.html b/tests/rustdoc/anchors.no_tymethod_anchor.html
index 23f4277..49ee624 100644
--- a/tests/rustdoc/anchors.no_tymethod_anchor.html
+++ b/tests/rustdoc/anchors.no_tymethod_anchor.html
@@ -1 +1 @@
-<section id="tymethod.foo" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section>
\ No newline at end of file
+<section id="tymethod.foo" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#20">Source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fn">foo</a>()</h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/anchors.no_type_anchor.html b/tests/rustdoc/anchors.no_type_anchor.html
index 62b9295..c5ac3c9 100644
--- a/tests/rustdoc/anchors.no_type_anchor.html
+++ b/tests/rustdoc/anchors.no_type_anchor.html
@@ -1 +1 @@
-<section id="associatedtype.T" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section>
\ No newline at end of file
+<section id="associatedtype.T" class="method"><a class="src rightside" href="../src/foo/anchors.rs.html#13">Source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/anchors.no_type_anchor2.html b/tests/rustdoc/anchors.no_type_anchor2.html
index 9127104..14dd31d 100644
--- a/tests/rustdoc/anchors.no_type_anchor2.html
+++ b/tests/rustdoc/anchors.no_type_anchor2.html
@@ -1 +1 @@
-<section id="associatedtype.Y" class="associatedtype"><a class="src rightside" href="../src/foo/anchors.rs.html#45">source</a><h4 class="code-header">pub type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
+<section id="associatedtype.Y" class="associatedtype"><a class="src rightside" href="../src/foo/anchors.rs.html#45">Source</a><h4 class="code-header">pub type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
\ No newline at end of file
diff --git a/tests/rustdoc/assoc-type-source-link.rs b/tests/rustdoc/assoc-type-source-link.rs
index 34b156b..a955a67 100644
--- a/tests/rustdoc/assoc-type-source-link.rs
+++ b/tests/rustdoc/assoc-type-source-link.rs
@@ -8,7 +8,7 @@
pub struct Bar;
impl Bar {
- //@ has - '//*[@id="implementations-list"]//*[@id="associatedtype.Y"]/a' 'source'
+ //@ has - '//*[@id="implementations-list"]//*[@id="associatedtype.Y"]/a' 'Source'
//@ has - '//*[@id="implementations-list"]//*[@id="associatedtype.Y"]/a/@href' \
// '../src/foo/assoc-type-source-link.rs.html#14'
pub type Y = u8;
@@ -19,7 +19,7 @@
}
impl Foo for Bar {
- //@ has - '//*[@id="trait-implementations-list"]//*[@id="associatedtype.Z"]/a' 'source'
+ //@ has - '//*[@id="trait-implementations-list"]//*[@id="associatedtype.Z"]/a' 'Source'
//@ has - '//*[@id="trait-implementations-list"]//*[@id="associatedtype.Z"]/a/@href' \
// '../src/foo/assoc-type-source-link.rs.html#25'
type Z = u8;
diff --git a/tests/rustdoc/const-display.rs b/tests/rustdoc/const-display.rs
index a71825d..bc4270c 100644
--- a/tests/rustdoc/const-display.rs
+++ b/tests/rustdoc/const-display.rs
@@ -89,10 +89,4 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const2", since = "1.2.0")]
pub const fn stable_impl() -> u32 { 42 }
-
- // Show const-stability even for unstable functions.
- //@ matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.3.0$'
- #[unstable(feature = "foo2", issue = "none")]
- #[rustc_const_stable(feature = "const3", since = "1.3.0")]
- pub const fn const_stable_unstable() -> u32 { 42 }
}
diff --git a/tests/rustdoc/demo-allocator-54478.rs b/tests/rustdoc/demo-allocator-54478.rs
index dd98e80..80acfc0 100644
--- a/tests/rustdoc/demo-allocator-54478.rs
+++ b/tests/rustdoc/demo-allocator-54478.rs
@@ -40,6 +40,7 @@
//! }
//!
//! fn main() {
+//! drop(String::from("An allocation"));
//! assert!(unsafe { HIT });
//! }
//! ```
diff --git a/tests/rustdoc/ensure-src-link.rs b/tests/rustdoc/ensure-src-link.rs
index 4156fdc..f70902b 100644
--- a/tests/rustdoc/ensure-src-link.rs
+++ b/tests/rustdoc/ensure-src-link.rs
@@ -2,5 +2,5 @@
// This test ensures that the [src] link is present on traits items.
-//@ has foo/trait.Iterator.html '//*[@id="method.zip"]//a[@class="src"]' "source"
+//@ has foo/trait.Iterator.html '//*[@id="method.zip"]//a[@class="src"]' "Source"
pub use std::iter::Iterator;
diff --git a/tests/rustdoc/external-macro-src.rs b/tests/rustdoc/external-macro-src.rs
index f723af5..998687d 100644
--- a/tests/rustdoc/external-macro-src.rs
+++ b/tests/rustdoc/external-macro-src.rs
@@ -5,8 +5,8 @@
#[macro_use]
extern crate external_macro_src;
-//@ has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' 'source'
+//@ has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' 'Source'
//@ has foo/struct.Foo.html
-//@ has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' 'source'
+//@ has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' 'Source'
make_foo!();
diff --git a/tests/rustdoc/primitive-tuple-variadic.rs b/tests/rustdoc/primitive-tuple-variadic.rs
index b15e996..d142729 100644
--- a/tests/rustdoc/primitive-tuple-variadic.rs
+++ b/tests/rustdoc/primitive-tuple-variadic.rs
@@ -33,3 +33,22 @@
//@ has - '//section[@id="impl-Baz%3CT%3E-for-(T,)"]/h3' 'impl<T> Baz<T> for (T₁, T₂, …, Tₙ)'
#[doc(fake_variadic)]
impl<T> Baz<T> for (T,) {}
+
+pub trait Qux {}
+
+pub struct NewType<T>(T);
+
+//@ has foo/trait.Qux.html
+//@ has - '//section[@id="impl-Qux-for-NewType%3C(T,)%3E"]/h3' 'impl<T> Qux for NewType<(T₁, T₂, …, Tₙ)>'
+#[doc(fake_variadic)]
+impl<T> Qux for NewType<(T,)> {}
+
+//@ has foo/trait.Qux.html
+//@ has - '//section[@id="impl-Qux-for-NewType%3CNewType%3C(T,)%3E%3E"]/h3' 'impl<T> Qux for NewType<NewType<(T₁, T₂, …, Tₙ)>>'
+#[doc(fake_variadic)]
+impl<T> Qux for NewType<NewType<(T,)>> {}
+
+//@ has foo/trait.Qux.html
+//@ has - '//section[@id="impl-Qux-for-NewType%3Cfn(T)+-%3E+Out%3E"]/h3' 'impl<T, Out> Qux for NewType<fn(T₁, T₂, …, Tₙ) -> Out>'
+#[doc(fake_variadic)]
+impl<T, Out> Qux for NewType<fn(T) -> Out> {}
diff --git a/tests/rustdoc/source-version-separator.rs b/tests/rustdoc/source-version-separator.rs
index 9709bbe..78b9d36 100644
--- a/tests/rustdoc/source-version-separator.rs
+++ b/tests/rustdoc/source-version-separator.rs
@@ -3,23 +3,23 @@
#![feature(staged_api)]
//@ has foo/trait.Bar.html
-//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
+//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · Source'
#[stable(feature = "bar", since = "1.0")]
pub trait Bar {
- //@ has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · source'
+ //@ has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · Source'
#[stable(feature = "foobar", since = "3.0")]
fn foo();
}
-//@ has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · source'
+//@ has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · Source'
//@ has foo/struct.Foo.html
-//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
+//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · Source'
#[stable(feature = "baz", since = "1.0")]
pub struct Foo;
impl Foo {
- //@ has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0.0 · source'
+ //@ has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0.0 · Source'
#[stable(feature = "foobar", since = "3.0")]
pub fn foofoo() {}
}
diff --git a/tests/rustdoc/src-link-external-macro-26606.rs b/tests/rustdoc/src-link-external-macro-26606.rs
index b5662be..0ce829f 100644
--- a/tests/rustdoc/src-link-external-macro-26606.rs
+++ b/tests/rustdoc/src-link-external-macro-26606.rs
@@ -10,5 +10,5 @@
extern crate issue_26606_macro;
//@ has issue_26606/constant.FOO.html
-//@ has - '//a[@href="../src/issue_26606/src-link-external-macro-26606.rs.html#14"]' 'source'
+//@ has - '//a[@href="../src/issue_26606/src-link-external-macro-26606.rs.html#14"]' 'Source'
make_item!(FOO);
diff --git a/tests/rustdoc/src-links-auto-impls.rs b/tests/rustdoc/src-links-auto-impls.rs
index dd07f85..5a777f5 100644
--- a/tests/rustdoc/src-links-auto-impls.rs
+++ b/tests/rustdoc/src-links-auto-impls.rs
@@ -2,11 +2,11 @@
//@ has foo/struct.Unsized.html
//@ has - '//*[@id="impl-Sized-for-Unsized"]/h3[@class="code-header"]' 'impl !Sized for Unsized'
-//@ !has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="src"]' 'source'
+//@ !has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="src"]' 'Source'
//@ has - '//*[@id="impl-Sync-for-Unsized"]/h3[@class="code-header"]' 'impl Sync for Unsized'
-//@ !has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="src"]' 'source'
+//@ !has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="src"]' 'Source'
//@ has - '//*[@id="impl-Any-for-T"]/h3[@class="code-header"]' 'impl<T> Any for T'
-//@ has - '//*[@id="impl-Any-for-T"]//a[@class="src rightside"]' 'source'
+//@ has - '//*[@id="impl-Any-for-T"]//a[@class="src rightside"]' 'Source'
pub struct Unsized {
data: [u8],
}
diff --git a/tests/rustdoc/thread-local-src.rs b/tests/rustdoc/thread-local-src.rs
index b23a9a4..16509e8 100644
--- a/tests/rustdoc/thread-local-src.rs
+++ b/tests/rustdoc/thread-local-src.rs
@@ -1,6 +1,6 @@
#![crate_name = "foo"]
-//@ has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' 'source'
+//@ has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' 'Source'
-//@ has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' 'source'
+//@ has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' 'Source'
thread_local!(pub static FOO: bool = false);
diff --git a/tests/rustdoc/trait-src-link.rs b/tests/rustdoc/trait-src-link.rs
index 7c3afb7..7bf883d 100644
--- a/tests/rustdoc/trait-src-link.rs
+++ b/tests/rustdoc/trait-src-link.rs
@@ -1,26 +1,26 @@
#![crate_name = "quix"]
pub trait Foo {
- //@ has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' 'source'
+ //@ has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' 'Source'
fn required();
- //@ has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source'
+ //@ has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'Source'
fn provided() {}
}
pub struct Bar;
impl Foo for Bar {
- //@ has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' 'source'
+ //@ has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' 'Source'
fn required() {}
- //@ has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source'
+ //@ has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'Source'
}
pub struct Baz;
impl Foo for Baz {
- //@ has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' 'source'
+ //@ has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' 'Source'
fn required() {}
- //@ has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' 'source'
+ //@ has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' 'Source'
fn provided() {}
}
diff --git a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs
index c3df917..6eb698c 100644
--- a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs
+++ b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs
@@ -6,7 +6,7 @@
extern crate rustc_middle;
extern crate rustc_session;
-use rustc_session::lint::{LintPass, LintVec};
+use rustc_session::lint::{LintPass, LintVec, Lint};
use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
declare_lint! {
@@ -21,6 +21,10 @@
fn name(&self) -> &'static str {
"Foo"
}
+
+ fn get_lints(&self) -> Vec<&'static Lint> {
+ vec![TEST_LINT]
+ }
}
macro_rules! custom_lint_pass_macro {
@@ -31,6 +35,10 @@
fn name(&self) -> &'static str {
"Custom"
}
+
+ fn get_lints(&self) -> Vec<&'static Lint> {
+ vec![TEST_LINT]
+ }
}
};
}
diff --git a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr
index ad6e933..824eb35 100644
--- a/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr
+++ b/tests/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr
@@ -12,7 +12,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: implementing `LintPass` by hand
- --> $DIR/lint_pass_impl_without_macro.rs:30:14
+ --> $DIR/lint_pass_impl_without_macro.rs:34:14
|
LL | impl LintPass for Custom {
| ^^^^^^^^
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index ff7af38..03fca17 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -1,10 +1,10 @@
-error: unsupported type attribute for diagnostic derive enum
+error: derive(Diagnostic): unsupported type attribute for diagnostic derive enum
--> $DIR/diagnostic-derive.rs:47:1
|
LL | #[diag(no_crate_example, code = E0123)]
| ^
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:50:5
|
LL | Foo,
@@ -12,7 +12,7 @@
|
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:52:5
|
LL | Bar,
@@ -20,13 +20,13 @@
|
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
-error: `#[nonsense(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[nonsense(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:63:1
|
LL | #[nonsense(no_crate_example, code = E0123)]
| ^
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:63:1
|
LL | #[nonsense(no_crate_example, code = E0123)]
@@ -34,7 +34,7 @@
|
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:70:1
|
LL | #[diag(code = E0123)]
@@ -42,13 +42,13 @@
|
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
-error: diagnostic slug must be the first argument
+error: derive(Diagnostic): diagnostic slug must be the first argument
--> $DIR/diagnostic-derive.rs:80:16
|
LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")]
| ^
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:80:1
|
LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")]
@@ -56,7 +56,7 @@
|
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
-error: unknown argument
+error: derive(Diagnostic): unknown argument
--> $DIR/diagnostic-derive.rs:86:8
|
LL | #[diag(nonsense = "...", code = E0123, slug = "foo")]
@@ -64,7 +64,7 @@
|
= note: only the `code` parameter is valid after the slug
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:86:1
|
LL | #[diag(nonsense = "...", code = E0123, slug = "foo")]
@@ -72,7 +72,7 @@
|
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
-error: unknown argument
+error: derive(Diagnostic): unknown argument
--> $DIR/diagnostic-derive.rs:92:8
|
LL | #[diag(nonsense = 4, code = E0123, slug = "foo")]
@@ -80,7 +80,7 @@
|
= note: only the `code` parameter is valid after the slug
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:92:1
|
LL | #[diag(nonsense = 4, code = E0123, slug = "foo")]
@@ -88,7 +88,7 @@
|
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
-error: unknown argument
+error: derive(Diagnostic): unknown argument
--> $DIR/diagnostic-derive.rs:98:40
|
LL | #[diag(no_crate_example, code = E0123, slug = "foo")]
@@ -96,13 +96,13 @@
|
= note: only the `code` parameter is valid after the slug
-error: `#[suggestion = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion = ...]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:105:5
|
LL | #[suggestion = "bar"]
| ^
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
--> $DIR/diagnostic-derive.rs:112:8
|
LL | #[diag(no_crate_example, code = E0456)]
@@ -114,7 +114,7 @@
LL | #[diag(no_crate_example, code = E0123)]
| ^^^^^^^^^^^^^^^^
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
--> $DIR/diagnostic-derive.rs:112:26
|
LL | #[diag(no_crate_example, code = E0456)]
@@ -126,7 +126,7 @@
LL | #[diag(no_crate_example, code = E0123)]
| ^^^^
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
--> $DIR/diagnostic-derive.rs:118:40
|
LL | #[diag(no_crate_example, code = E0123, code = E0456)]
@@ -138,13 +138,13 @@
LL | #[diag(no_crate_example, code = E0123, code = E0456)]
| ^^^^
-error: diagnostic slug must be the first argument
+error: derive(Diagnostic): diagnostic slug must be the first argument
--> $DIR/diagnostic-derive.rs:123:43
|
LL | #[diag(no_crate_example, no_crate::example, code = E0123)]
| ^
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:128:1
|
LL | struct KindNotProvided {}
@@ -152,7 +152,7 @@
|
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:131:1
|
LL | #[diag(code = E0123)]
@@ -160,25 +160,25 @@
|
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
-error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
--> $DIR/diagnostic-derive.rs:142:5
|
LL | #[primary_span]
| ^
-error: `#[nonsense]` is not a valid attribute
+error: derive(Diagnostic): `#[nonsense]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:150:5
|
LL | #[nonsense]
| ^
-error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
--> $DIR/diagnostic-derive.rs:167:5
|
LL | #[label(no_crate_label)]
| ^
-error: `name` doesn't refer to a field on this type
+error: derive(Diagnostic): `name` doesn't refer to a field on this type
--> $DIR/diagnostic-derive.rs:175:46
|
LL | #[suggestion(no_crate_suggestion, code = "{name}")]
@@ -202,19 +202,19 @@
= note: if you intended to print `}`, you can escape it using `}}`
= note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
--> $DIR/diagnostic-derive.rs:210:5
|
LL | #[label(no_crate_label)]
| ^
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
--> $DIR/diagnostic-derive.rs:229:5
|
LL | #[suggestion(no_crate_suggestion)]
| ^
-error: invalid nested attribute
+error: derive(Diagnostic): invalid nested attribute
--> $DIR/diagnostic-derive.rs:237:18
|
LL | #[suggestion(nonsense = "bar")]
@@ -222,13 +222,13 @@
|
= help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
--> $DIR/diagnostic-derive.rs:237:5
|
LL | #[suggestion(nonsense = "bar")]
| ^
-error: invalid nested attribute
+error: derive(Diagnostic): invalid nested attribute
--> $DIR/diagnostic-derive.rs:246:18
|
LL | #[suggestion(msg = "bar")]
@@ -236,13 +236,13 @@
|
= help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
--> $DIR/diagnostic-derive.rs:246:5
|
LL | #[suggestion(msg = "bar")]
| ^
-error: wrong field type for suggestion
+error: derive(Diagnostic): wrong field type for suggestion
--> $DIR/diagnostic-derive.rs:269:5
|
LL | #[suggestion(no_crate_suggestion, code = "This is suggested code")]
@@ -250,7 +250,7 @@
|
= help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
--> $DIR/diagnostic-derive.rs:285:24
|
LL | suggestion: (Span, Span, Applicability),
@@ -262,7 +262,7 @@
LL | suggestion: (Span, Span, Applicability),
| ^^^^
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
--> $DIR/diagnostic-derive.rs:293:33
|
LL | suggestion: (Applicability, Applicability, Span),
@@ -274,13 +274,13 @@
LL | suggestion: (Applicability, Applicability, Span),
| ^^^^^^^^^^^^^
-error: `#[label = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[label = ...]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:300:5
|
LL | #[label = "bar"]
| ^
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
--> $DIR/diagnostic-derive.rs:451:5
|
LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")]
@@ -292,37 +292,37 @@
LL | suggestion: (Span, Applicability),
| ^^^^^^^^^^^^^
-error: invalid applicability
+error: derive(Diagnostic): invalid applicability
--> $DIR/diagnostic-derive.rs:459:69
|
LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")]
| ^^^^^^^^
-error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()`
+error: derive(Diagnostic): the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()`
--> $DIR/diagnostic-derive.rs:526:5
|
LL | #[help(no_crate_help)]
| ^
-error: a diagnostic slug must be the first argument to the attribute
+error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
--> $DIR/diagnostic-derive.rs:535:32
|
LL | #[label(no_crate_label, foo)]
| ^
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
--> $DIR/diagnostic-derive.rs:543:29
|
LL | #[label(no_crate_label, foo = "...")]
| ^^^
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
--> $DIR/diagnostic-derive.rs:551:29
|
LL | #[label(no_crate_label, foo("..."))]
| ^^^
-error: `#[primary_span]` is not a valid attribute
+error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:563:5
|
LL | #[primary_span]
@@ -330,13 +330,13 @@
|
= help: the `primary_span` field attribute is not valid for lint diagnostics
-error: `#[error(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[error(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:583:1
|
LL | #[error(no_crate_example, code = E0123)]
| ^
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:583:1
|
LL | #[error(no_crate_example, code = E0123)]
@@ -344,13 +344,13 @@
|
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
-error: `#[warn_(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[warn_(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:590:1
|
LL | #[warn_(no_crate_example, code = E0123)]
| ^
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:590:1
|
LL | #[warn_(no_crate_example, code = E0123)]
@@ -358,13 +358,13 @@
|
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
-error: `#[lint(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:597:1
|
LL | #[lint(no_crate_example, code = E0123)]
| ^
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:597:1
|
LL | #[lint(no_crate_example, code = E0123)]
@@ -372,13 +372,13 @@
|
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
-error: `#[lint(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:604:1
|
LL | #[lint(no_crate_example, code = E0123)]
| ^
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:604:1
|
LL | #[lint(no_crate_example, code = E0123)]
@@ -386,7 +386,7 @@
|
= help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]`
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
--> $DIR/diagnostic-derive.rs:613:53
|
LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
@@ -398,7 +398,7 @@
LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
| ^^^^
-error: wrong types for suggestion
+error: derive(Diagnostic): wrong types for suggestion
--> $DIR/diagnostic-derive.rs:622:24
|
LL | suggestion: (Span, usize),
@@ -406,7 +406,7 @@
|
= help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
-error: wrong types for suggestion
+error: derive(Diagnostic): wrong types for suggestion
--> $DIR/diagnostic-derive.rs:630:17
|
LL | suggestion: (Span,),
@@ -414,13 +414,13 @@
|
= help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
--> $DIR/diagnostic-derive.rs:637:5
|
LL | #[suggestion(no_crate_suggestion)]
| ^
-error: `#[multipart_suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:644:1
|
LL | #[multipart_suggestion(no_crate_suggestion)]
@@ -428,7 +428,7 @@
|
= help: consider creating a `Subdiagnostic` instead
-error: `#[multipart_suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:647:1
|
LL | #[multipart_suggestion()]
@@ -436,7 +436,7 @@
|
= help: consider creating a `Subdiagnostic` instead
-error: `#[multipart_suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:651:5
|
LL | #[multipart_suggestion(no_crate_suggestion)]
@@ -444,7 +444,7 @@
|
= help: consider creating a `Subdiagnostic` instead
-error: `#[suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:659:1
|
LL | #[suggestion(no_crate_suggestion, code = "...")]
@@ -452,7 +452,7 @@
|
= help: `#[label]` and `#[suggestion]` can only be applied to fields
-error: `#[label]` is not a valid attribute
+error: derive(Diagnostic): `#[label]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:668:1
|
LL | #[label]
@@ -460,61 +460,61 @@
|
= help: `#[label]` and `#[suggestion]` can only be applied to fields
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:702:5
|
LL | #[subdiagnostic(bad)]
| ^
-error: `#[subdiagnostic = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic = ...]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:710:5
|
LL | #[subdiagnostic = "bad"]
| ^
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:718:5
|
LL | #[subdiagnostic(bad, bad)]
| ^
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:726:5
|
LL | #[subdiagnostic("bad")]
| ^
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:734:5
|
LL | #[subdiagnostic(eager)]
| ^
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:742:5
|
LL | #[subdiagnostic(eager)]
| ^
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:763:5
|
LL | #[subdiagnostic(eager)]
| ^
-error: expected at least one string literal for `code(...)`
+error: derive(Diagnostic): expected at least one string literal for `code(...)`
--> $DIR/diagnostic-derive.rs:794:23
|
LL | #[suggestion(code())]
| ^
-error: `code(...)` must contain only string literals
+error: derive(Diagnostic): `code(...)` must contain only string literals
--> $DIR/diagnostic-derive.rs:802:23
|
LL | #[suggestion(code(foo))]
| ^^^
-error: `#[suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:826:5
|
LL | #[suggestion(no_crate_suggestion, code = "")]
diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr
index df1bad3..4f54239 100644
--- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr
@@ -1,4 +1,4 @@
-error: diagnostic slug and crate name do not match
+error: derive(Diagnostic): diagnostic slug and crate name do not match
--> $DIR/enforce_slug_naming.rs:22:8
|
LL | #[diag(compiletest_example, code = E0123)]
diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
index 96f6ef0..0ae7ba4 100644
--- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
@@ -1,142 +1,142 @@
-error: label without `#[primary_span]` field
+error: derive(Diagnostic): label without `#[primary_span]` field
--> $DIR/subdiagnostic-derive.rs:51:1
|
LL | #[label(no_crate_example)]
| ^
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
--> $DIR/subdiagnostic-derive.rs:58:1
|
LL | #[label]
| ^
-error: `#[foo]` is not a valid attribute
+error: derive(Diagnostic): `#[foo]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:67:1
|
LL | #[foo]
| ^
-error: `#[label = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[label = ...]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:77:1
|
LL | #[label = "..."]
| ^
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
--> $DIR/subdiagnostic-derive.rs:86:9
|
LL | #[label(bug = "...")]
| ^^^
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
--> $DIR/subdiagnostic-derive.rs:86:1
|
LL | #[label(bug = "...")]
| ^
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
--> $DIR/subdiagnostic-derive.rs:106:9
|
LL | #[label(slug = 4)]
| ^^^^
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
--> $DIR/subdiagnostic-derive.rs:106:1
|
LL | #[label(slug = 4)]
| ^
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
--> $DIR/subdiagnostic-derive.rs:116:9
|
LL | #[label(slug("..."))]
| ^^^^
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
--> $DIR/subdiagnostic-derive.rs:116:1
|
LL | #[label(slug("..."))]
| ^
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
--> $DIR/subdiagnostic-derive.rs:136:1
|
LL | #[label()]
| ^
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
--> $DIR/subdiagnostic-derive.rs:145:27
|
LL | #[label(no_crate_example, code = "...")]
| ^^^^
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
--> $DIR/subdiagnostic-derive.rs:154:27
|
LL | #[label(no_crate_example, applicability = "machine-applicable")]
| ^^^^^^^^^^^^^
-error: unsupported type attribute for subdiagnostic enum
+error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum
--> $DIR/subdiagnostic-derive.rs:163:1
|
LL | #[foo]
| ^
-error: `#[bar]` is not a valid attribute
+error: derive(Diagnostic): `#[bar]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:177:5
|
LL | #[bar]
| ^
-error: `#[bar = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:189:5
|
LL | #[bar = "..."]
| ^
-error: `#[bar = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:201:5
|
LL | #[bar = 4]
| ^
-error: `#[bar(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:213:5
|
LL | #[bar("...")]
| ^
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
--> $DIR/subdiagnostic-derive.rs:225:13
|
LL | #[label(code = "...")]
| ^^^^
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
--> $DIR/subdiagnostic-derive.rs:225:5
|
LL | #[label(code = "...")]
| ^
-error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
--> $DIR/subdiagnostic-derive.rs:254:5
|
LL | #[primary_span]
| ^
-error: label without `#[primary_span]` field
+error: derive(Diagnostic): label without `#[primary_span]` field
--> $DIR/subdiagnostic-derive.rs:251:1
|
LL | #[label(no_crate_example)]
| ^
-error: `#[applicability]` is only valid on suggestions
+error: derive(Diagnostic): `#[applicability]` is only valid on suggestions
--> $DIR/subdiagnostic-derive.rs:264:5
|
LL | #[applicability]
| ^
-error: `#[bar]` is not a valid attribute
+error: derive(Diagnostic): `#[bar]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:274:5
|
LL | #[bar]
@@ -144,13 +144,13 @@
|
= help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
-error: `#[bar = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:285:5
|
LL | #[bar = "..."]
| ^
-error: `#[bar(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:296:5
|
LL | #[bar("...")]
@@ -158,13 +158,13 @@
|
= help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
-error: a diagnostic slug must be the first argument to the attribute
+error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
--> $DIR/subdiagnostic-derive.rs:328:44
|
LL | #[label(no_crate_example, no_crate::example)]
| ^
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
--> $DIR/subdiagnostic-derive.rs:341:5
|
LL | #[primary_span]
@@ -176,13 +176,13 @@
LL | #[primary_span]
| ^
-error: subdiagnostic kind not specified
+error: derive(Diagnostic): subdiagnostic kind not specified
--> $DIR/subdiagnostic-derive.rs:347:8
|
LL | struct AG {
| ^^
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
--> $DIR/subdiagnostic-derive.rs:384:46
|
LL | #[suggestion(no_crate_example, code = "...", code = "...")]
@@ -194,7 +194,7 @@
LL | #[suggestion(no_crate_example, code = "...", code = "...")]
| ^^^^
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
--> $DIR/subdiagnostic-derive.rs:402:5
|
LL | #[applicability]
@@ -206,49 +206,49 @@
LL | #[applicability]
| ^
-error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
+error: derive(Diagnostic): the `#[applicability]` attribute can only be applied to fields of type `Applicability`
--> $DIR/subdiagnostic-derive.rs:412:5
|
LL | #[applicability]
| ^
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
--> $DIR/subdiagnostic-derive.rs:425:1
|
LL | #[suggestion(no_crate_example)]
| ^
-error: invalid applicability
+error: derive(Diagnostic): invalid applicability
--> $DIR/subdiagnostic-derive.rs:435:62
|
LL | #[suggestion(no_crate_example, code = "...", applicability = "foo")]
| ^^^^^
-error: suggestion without `#[primary_span]` field
+error: derive(Diagnostic): suggestion without `#[primary_span]` field
--> $DIR/subdiagnostic-derive.rs:453:1
|
LL | #[suggestion(no_crate_example, code = "...")]
| ^
-error: unsupported type attribute for subdiagnostic enum
+error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum
--> $DIR/subdiagnostic-derive.rs:467:1
|
LL | #[label]
| ^
-error: `var` doesn't refer to a field on this type
+error: derive(Diagnostic): `var` doesn't refer to a field on this type
--> $DIR/subdiagnostic-derive.rs:487:39
|
LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
| ^^^^^^^
-error: `var` doesn't refer to a field on this type
+error: derive(Diagnostic): `var` doesn't refer to a field on this type
--> $DIR/subdiagnostic-derive.rs:506:43
|
LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
| ^^^^^^^
-error: `#[suggestion_part]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion_part]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:529:5
|
LL | #[suggestion_part]
@@ -256,7 +256,7 @@
|
= help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
-error: `#[suggestion_part(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion_part(...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:532:5
|
LL | #[suggestion_part(code = "...")]
@@ -264,13 +264,13 @@
|
= help: `#[suggestion_part(...)]` is only valid in multipart suggestions
-error: suggestion without `#[primary_span]` field
+error: derive(Diagnostic): suggestion without `#[primary_span]` field
--> $DIR/subdiagnostic-derive.rs:526:1
|
LL | #[suggestion(no_crate_example, code = "...")]
| ^
-error: invalid nested attribute
+error: derive(Diagnostic): invalid nested attribute
--> $DIR/subdiagnostic-derive.rs:541:42
|
LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
@@ -278,25 +278,25 @@
|
= help: only `no_span`, `style` and `applicability` are valid nested attributes
-error: multipart suggestion without any `#[suggestion_part(...)]` fields
+error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
--> $DIR/subdiagnostic-derive.rs:541:1
|
LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
| ^
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
+error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
--> $DIR/subdiagnostic-derive.rs:551:5
|
LL | #[suggestion_part]
| ^
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
+error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
--> $DIR/subdiagnostic-derive.rs:559:5
|
LL | #[suggestion_part()]
| ^
-error: `#[primary_span]` is not a valid attribute
+error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:568:5
|
LL | #[primary_span]
@@ -304,43 +304,43 @@
|
= help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
-error: multipart suggestion without any `#[suggestion_part(...)]` fields
+error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
--> $DIR/subdiagnostic-derive.rs:565:1
|
LL | #[multipart_suggestion(no_crate_example)]
| ^
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
+error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
--> $DIR/subdiagnostic-derive.rs:576:5
|
LL | #[suggestion_part]
| ^
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
+error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
--> $DIR/subdiagnostic-derive.rs:579:5
|
LL | #[suggestion_part()]
| ^
-error: `code` is the only valid nested attribute
+error: derive(Diagnostic): `code` is the only valid nested attribute
--> $DIR/subdiagnostic-derive.rs:582:23
|
LL | #[suggestion_part(foo = "bar")]
| ^^^
-error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
--> $DIR/subdiagnostic-derive.rs:587:5
|
LL | #[suggestion_part(code = "...")]
| ^
-error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
--> $DIR/subdiagnostic-derive.rs:590:5
|
LL | #[suggestion_part()]
| ^
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
--> $DIR/subdiagnostic-derive.rs:598:37
|
LL | #[suggestion_part(code = "...", code = ",,,")]
@@ -352,37 +352,37 @@
LL | #[suggestion_part(code = "...", code = ",,,")]
| ^^^^
-error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
+error: derive(Diagnostic): `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
--> $DIR/subdiagnostic-derive.rs:627:5
|
LL | #[applicability]
| ^
-error: expected exactly one string literal for `code = ...`
+error: derive(Diagnostic): expected exactly one string literal for `code = ...`
--> $DIR/subdiagnostic-derive.rs:675:34
|
LL | #[suggestion_part(code("foo"))]
| ^
-error: expected exactly one string literal for `code = ...`
+error: derive(Diagnostic): expected exactly one string literal for `code = ...`
--> $DIR/subdiagnostic-derive.rs:686:41
|
LL | #[suggestion_part(code("foo", "bar"))]
| ^
-error: expected exactly one string literal for `code = ...`
+error: derive(Diagnostic): expected exactly one string literal for `code = ...`
--> $DIR/subdiagnostic-derive.rs:697:30
|
LL | #[suggestion_part(code(3))]
| ^
-error: expected exactly one string literal for `code = ...`
+error: derive(Diagnostic): expected exactly one string literal for `code = ...`
--> $DIR/subdiagnostic-derive.rs:708:29
|
LL | #[suggestion_part(code())]
| ^
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
--> $DIR/subdiagnostic-derive.rs:763:1
|
LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")]
@@ -394,7 +394,7 @@
LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")]
| ^
-error: `#[suggestion_hidden(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:772:1
|
LL | #[suggestion_hidden(no_crate_example, code = "")]
@@ -402,7 +402,7 @@
|
= help: Use `#[suggestion(..., style = "hidden")]` instead
-error: `#[suggestion_hidden(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:780:1
|
LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")]
@@ -410,7 +410,7 @@
|
= help: Use `#[suggestion(..., style = "hidden")]` instead
-error: invalid suggestion style
+error: derive(Diagnostic): invalid suggestion style
--> $DIR/subdiagnostic-derive.rs:788:51
|
LL | #[suggestion(no_crate_example, code = "", style = "foo")]
@@ -418,25 +418,25 @@
|
= help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`
-error: expected `= "xxx"`
+error: derive(Diagnostic): expected `= "xxx"`
--> $DIR/subdiagnostic-derive.rs:796:49
|
LL | #[suggestion(no_crate_example, code = "", style = 42)]
| ^
-error: a diagnostic slug must be the first argument to the attribute
+error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
--> $DIR/subdiagnostic-derive.rs:804:48
|
LL | #[suggestion(no_crate_example, code = "", style)]
| ^
-error: expected `= "xxx"`
+error: derive(Diagnostic): expected `= "xxx"`
--> $DIR/subdiagnostic-derive.rs:812:48
|
LL | #[suggestion(no_crate_example, code = "", style("foo"))]
| ^
-error: `#[primary_span]` is not a valid attribute
+error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:825:5
|
LL | #[primary_span]
@@ -445,7 +445,7 @@
= note: there must be exactly one primary span
= help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead
-error: suggestion without `#[primary_span]` field
+error: derive(Diagnostic): suggestion without `#[primary_span]` field
--> $DIR/subdiagnostic-derive.rs:822:1
|
LL | #[suggestion(no_crate_example, code = "")]
diff --git a/tests/ui-fulldeps/try-from-u32/errors.rs b/tests/ui-fulldeps/try-from-u32/errors.rs
new file mode 100644
index 0000000..0470063
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/errors.rs
@@ -0,0 +1,24 @@
+#![feature(rustc_private)]
+//@ edition: 2021
+
+// Checks the error messages produced by `#[derive(TryFromU32)]`.
+
+extern crate rustc_macros;
+
+use rustc_macros::TryFromU32;
+
+#[derive(TryFromU32)]
+struct MyStruct {} //~ type is not an enum
+
+#[derive(TryFromU32)]
+enum NonTrivial {
+ A,
+ B(),
+ C {},
+ D(bool), //~ enum variant cannot have fields
+ E(bool, bool), //~ enum variant cannot have fields
+ F { x: bool }, //~ enum variant cannot have fields
+ G { x: bool, y: bool }, //~ enum variant cannot have fields
+}
+
+fn main() {}
diff --git a/tests/ui-fulldeps/try-from-u32/errors.stderr b/tests/ui-fulldeps/try-from-u32/errors.stderr
new file mode 100644
index 0000000..d205670
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/errors.stderr
@@ -0,0 +1,32 @@
+error: type is not an enum (TryFromU32)
+ --> $DIR/errors.rs:11:1
+ |
+LL | struct MyStruct {}
+ | ^^^^^^
+
+error: enum variant cannot have fields (TryFromU32)
+ --> $DIR/errors.rs:18:7
+ |
+LL | D(bool),
+ | ^^^^
+
+error: enum variant cannot have fields (TryFromU32)
+ --> $DIR/errors.rs:19:7
+ |
+LL | E(bool, bool),
+ | ^^^^
+
+error: enum variant cannot have fields (TryFromU32)
+ --> $DIR/errors.rs:20:9
+ |
+LL | F { x: bool },
+ | ^
+
+error: enum variant cannot have fields (TryFromU32)
+ --> $DIR/errors.rs:21:9
+ |
+LL | G { x: bool, y: bool },
+ | ^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui-fulldeps/try-from-u32/hygiene.rs b/tests/ui-fulldeps/try-from-u32/hygiene.rs
new file mode 100644
index 0000000..e0655a6
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/hygiene.rs
@@ -0,0 +1,32 @@
+#![feature(rustc_private)]
+//@ edition: 2021
+//@ check-pass
+
+// Checks that the derive macro still works even if the surrounding code has
+// shadowed the relevant library types.
+
+extern crate rustc_macros;
+
+mod submod {
+ use rustc_macros::TryFromU32;
+
+ struct Result;
+ trait TryFrom {}
+ #[allow(non_camel_case_types)]
+ struct u32;
+ struct Ok;
+ struct Err;
+ mod core {}
+ mod std {}
+
+ #[derive(TryFromU32)]
+ pub(crate) enum MyEnum {
+ Zero,
+ One,
+ }
+}
+
+fn main() {
+ use submod::MyEnum;
+ let _: Result<MyEnum, u32> = MyEnum::try_from(1u32);
+}
diff --git a/tests/ui-fulldeps/try-from-u32/values.rs b/tests/ui-fulldeps/try-from-u32/values.rs
new file mode 100644
index 0000000..180a8f2
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/values.rs
@@ -0,0 +1,36 @@
+#![feature(assert_matches)]
+#![feature(rustc_private)]
+//@ edition: 2021
+//@ run-pass
+
+// Checks the values accepted by the `TryFrom<u32>` impl produced by `#[derive(TryFromU32)]`.
+
+extern crate rustc_macros;
+
+use core::assert_matches::assert_matches;
+use rustc_macros::TryFromU32;
+
+#[derive(TryFromU32, Debug, PartialEq)]
+#[repr(u32)]
+enum Repr {
+ Zero,
+ One(),
+ Seven = 7,
+}
+
+#[derive(TryFromU32, Debug)]
+enum NoRepr {
+ Zero,
+ One,
+}
+
+fn main() {
+ assert_eq!(Repr::try_from(0u32), Ok(Repr::Zero));
+ assert_eq!(Repr::try_from(1u32), Ok(Repr::One()));
+ assert_eq!(Repr::try_from(2u32), Err(2));
+ assert_eq!(Repr::try_from(7u32), Ok(Repr::Seven));
+
+ assert_matches!(NoRepr::try_from(0u32), Ok(NoRepr::Zero));
+ assert_matches!(NoRepr::try_from(1u32), Ok(NoRepr::One));
+ assert_matches!(NoRepr::try_from(2u32), Err(2));
+}
diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs
index 33d6736..408dbea 100644
--- a/tests/ui/abi/compatibility.rs
+++ b/tests/ui/abi/compatibility.rs
@@ -79,10 +79,10 @@
#[lang = "sized"]
pub trait Sized {}
- #[lang = "receiver"]
- pub trait Receiver {}
- impl<T: ?Sized> Receiver for &T {}
- impl<T: ?Sized> Receiver for &mut T {}
+ #[lang = "legacy_receiver"]
+ pub trait LegacyReceiver {}
+ impl<T: ?Sized> LegacyReceiver for &T {}
+ impl<T: ?Sized> LegacyReceiver for &mut T {}
#[lang = "copy"]
pub trait Copy: Sized {}
diff --git a/tests/ui/associated-type-bounds/implied-from-self-where-clause.rs b/tests/ui/associated-type-bounds/implied-from-self-where-clause.rs
new file mode 100644
index 0000000..38f5569
--- /dev/null
+++ b/tests/ui/associated-type-bounds/implied-from-self-where-clause.rs
@@ -0,0 +1,21 @@
+// Make sure that, like associated type where clauses on traits, we gather item
+// bounds for RPITITs from RTN where clauses.
+
+//@ check-pass
+
+#![feature(return_type_notation)]
+
+trait Foo
+where
+ Self::method(..): Send,
+{
+ fn method() -> impl Sized;
+}
+
+fn is_send(_: impl Send) {}
+
+fn test<T: Foo>() {
+ is_send(T::method());
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/in-trait/unconstrained-impl-region.rs b/tests/ui/async-await/in-trait/unconstrained-impl-region.rs
index 95ba1f3..9382c23 100644
--- a/tests/ui/async-await/in-trait/unconstrained-impl-region.rs
+++ b/tests/ui/async-await/in-trait/unconstrained-impl-region.rs
@@ -14,7 +14,6 @@
//~^ ERROR the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
type Message = &'a ();
async fn on_mount(self, _: impl Inbox<&'a ()>) {}
- //~^ ERROR the trait bound `impl Inbox<&'a ()>: Inbox<&'a ()>` is not satisfied
}
fn main() {}
diff --git a/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr b/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr
index 80dc5fd..ef7e4ef 100644
--- a/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr
+++ b/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr
@@ -1,22 +1,9 @@
-error[E0277]: the trait bound `impl Inbox<&'a ()>: Inbox<&'a ()>` is not satisfied
- --> $DIR/unconstrained-impl-region.rs:16:5
- |
-LL | async fn on_mount(self, _: impl Inbox<&'a ()>) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Inbox<&'a ()>` is not implemented for `impl Inbox<&'a ()>`
- |
-note: required by a bound in `<() as Actor>::on_mount`
- --> $DIR/unconstrained-impl-region.rs:16:37
- |
-LL | async fn on_mount(self, _: impl Inbox<&'a ()>) {}
- | ^^^^^^^^^^^^^ required by this bound in `<() as Actor>::on_mount`
-
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> $DIR/unconstrained-impl-region.rs:13:6
|
LL | impl<'a> Actor for () {
| ^^ unconstrained lifetime parameter
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
-Some errors have detailed explanations: E0207, E0277.
-For more information about an error, try `rustc --explain E0207`.
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/borrowck/issue-64453.rs b/tests/ui/borrowck/issue-64453.rs
index 33d55be..5f1f35d 100644
--- a/tests/ui/borrowck/issue-64453.rs
+++ b/tests/ui/borrowck/issue-64453.rs
@@ -3,7 +3,6 @@
static settings_dir: String = format!("");
//~^ ERROR cannot call non-const fn
-//~| ERROR is not yet stable as a const
fn from_string(_: String) -> Value {
Value
diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr
index e671817..98b05ea 100644
--- a/tests/ui/borrowck/issue-64453.stderr
+++ b/tests/ui/borrowck/issue-64453.stderr
@@ -1,12 +1,3 @@
-error: `Arguments::<'a>::new_const` is not yet stable as a const fn
- --> $DIR/issue-64453.rs:4:31
- |
-LL | static settings_dir: String = format!("");
- | ^^^^^^^^^^^
- |
- = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable
- = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
error[E0015]: cannot call non-const fn `format` in statics
--> $DIR/issue-64453.rs:4:31
|
@@ -18,7 +9,7 @@
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0507]: cannot move out of static item `settings_dir`
- --> $DIR/issue-64453.rs:14:37
+ --> $DIR/issue-64453.rs:13:37
|
LL | let settings_data = from_string(settings_dir);
| ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait
@@ -28,7 +19,7 @@
LL | let settings_data = from_string(settings_dir.clone());
| ++++++++
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
Some errors have detailed explanations: E0015, E0507.
For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/cast/ptr-to-trait-obj-drop-principal.rs b/tests/ui/cast/ptr-to-trait-obj-drop-principal.rs
new file mode 100644
index 0000000..01dd91f
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-drop-principal.rs
@@ -0,0 +1,21 @@
+//! Test that non-coercion casts aren't allowed to drop the principal,
+//! because they cannot modify the pointer metadata.
+//!
+//! We test this in a const context to guard against UB if this is allowed
+//! in the future.
+
+trait Trait {}
+impl Trait for () {}
+
+struct Wrapper<T: ?Sized>(T);
+
+const OBJECT: *const (dyn Trait + Send) = &();
+
+// coercions are allowed
+const _: *const dyn Send = OBJECT as _;
+
+// casts are **not** allowed
+const _: *const Wrapper<dyn Send> = OBJECT as _;
+//~^ ERROR casting `*const (dyn Trait + Send + 'static)` as `*const Wrapper<dyn Send>` is invalid
+
+fn main() {}
diff --git a/tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr b/tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr
new file mode 100644
index 0000000..719e071
--- /dev/null
+++ b/tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr
@@ -0,0 +1,11 @@
+error[E0606]: casting `*const (dyn Trait + Send + 'static)` as `*const Wrapper<dyn Send>` is invalid
+ --> $DIR/ptr-to-trait-obj-drop-principal.rs:18:37
+ |
+LL | const _: *const Wrapper<dyn Send> = OBJECT as _;
+ | ^^^^^^^^^^^
+ |
+ = note: the trait objects may have different vtables
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0606`.
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index c21016e..7589551 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -251,7 +251,7 @@
LL | cfg!(target_feature = "zebra");
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 245 more
+ = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 246 more
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
warning: 27 warnings emitted
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index da790bb..b0ca09a 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -174,7 +174,7 @@
LL | target_feature = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
+ = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pauth-lr`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
index bae8249..b8d7c94 100644
--- a/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
@@ -27,11 +27,13 @@
LL | struct Foo(u8);
|
-error[E0284]: type annotations needed: cannot normalize `foo<N>::{constant#0}`
- --> $DIR/unify-op-with-fn-call.rs:20:25
+error[E0015]: cannot call non-const operator in constants
+ --> $DIR/unify-op-with-fn-call.rs:20:39
|
LL | fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
- | ^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo<N>::{constant#0}`
+ | ^^^^^
+ |
+ = note: calls in constants are limited to constant functions, tuple structs and tuple variants
error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter
--> $DIR/unify-op-with-fn-call.rs:20:17
@@ -63,11 +65,21 @@
LL | fn foo2<const N: usize>(a: Evaluatable2<{ N + N }>) {
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2<N>::{constant#0}`
-error[E0284]: type annotations needed: cannot normalize `foo<N>::{constant#0}`
- --> $DIR/unify-op-with-fn-call.rs:21:11
+error[E0015]: cannot call non-const fn `<Foo as Add>::add` in constants
+ --> $DIR/unify-op-with-fn-call.rs:21:13
|
LL | bar::<{ std::ops::Add::add(N, N) }>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo<N>::{constant#0}`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `<usize as Add>::add` in constants
+ --> $DIR/unify-op-with-fn-call.rs:30:14
+ |
+LL | bar2::<{ std::ops::Add::add(N, N) }>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: calls in constants are limited to constant functions, tuple structs and tuple variants
error[E0284]: type annotations needed: cannot normalize `foo2<N>::{constant#0}`
--> $DIR/unify-op-with-fn-call.rs:30:12
@@ -75,7 +87,7 @@
LL | bar2::<{ std::ops::Add::add(N, N) }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2<N>::{constant#0}`
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
-Some errors have detailed explanations: E0284, E0741.
-For more information about an error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0015, E0284, E0741.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/const-generics/issue-93647.stderr b/tests/ui/const-generics/issue-93647.stderr
index 81f50a1..38fb3d7 100644
--- a/tests/ui/const-generics/issue-93647.stderr
+++ b/tests/ui/const-generics/issue-93647.stderr
@@ -6,10 +6,6 @@
|
= note: closures need an RFC before allowed to be called in constants
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 1 previous error
diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr
index 98bb819..a0ca33e 100644
--- a/tests/ui/const-generics/issues/issue-88119.stderr
+++ b/tests/ui/const-generics/issues/issue-88119.stderr
@@ -11,30 +11,12 @@
|
LL | impl<T: ?Sized + ConstName> const ConstName for &T
| ^^ cannot normalize `<&T as ConstName>::{constant#0}`
- |
-note: required for `&T` to implement `ConstName`
- --> $DIR/issue-88119.rs:19:35
- |
-LL | impl<T: ?Sized + ConstName> const ConstName for &T
- | ^^^^^^^^^ ^^
-LL | where
-LL | [(); name_len::<T>()]:,
- | --------------------- unsatisfied trait bound introduced here
error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}`
--> $DIR/issue-88119.rs:26:49
|
LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
| ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}`
- |
-note: required for `&mut T` to implement `ConstName`
- --> $DIR/issue-88119.rs:26:35
- |
-LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
- | ^^^^^^^^^ ^^^^^^
-LL | where
-LL | [(); name_len::<T>()]:,
- | --------------------- unsatisfied trait bound introduced here
error: aborting due to 3 previous errors
diff --git a/tests/ui/const-generics/issues/issue-90318.stderr b/tests/ui/const-generics/issues/issue-90318.stderr
index a534e8f..9c7cb5c 100644
--- a/tests/ui/const-generics/issues/issue-90318.stderr
+++ b/tests/ui/const-generics/issues/issue-90318.stderr
@@ -29,10 +29,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/any.rs:LL:COL
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: cannot call non-const operator in constants
--> $DIR/issue-90318.rs:22:10
@@ -43,10 +39,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/any.rs:LL:COL
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 4 previous errors
diff --git a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs b/tests/ui/consts/auxiliary/unstable_but_const_stable.rs
deleted file mode 100644
index 88044b0..0000000
--- a/tests/ui/consts/auxiliary/unstable_but_const_stable.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#![feature(staged_api, rustc_attrs, intrinsics)]
-#![stable(since="1.0.0", feature = "stable")]
-
-extern "rust-intrinsic" {
- #[unstable(feature = "unstable", issue = "42")]
- #[rustc_const_stable(feature = "stable", since = "1.0.0")]
- #[rustc_nounwind]
- pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
-}
-
-#[unstable(feature = "unstable", issue = "42")]
-#[rustc_const_stable(feature = "stable", since = "1.0.0")]
-pub const fn some_unstable_fn() {}
diff --git a/tests/ui/consts/auxiliary/unstable_intrinsic.rs b/tests/ui/consts/auxiliary/unstable_intrinsic.rs
new file mode 100644
index 0000000..edef499
--- /dev/null
+++ b/tests/ui/consts/auxiliary/unstable_intrinsic.rs
@@ -0,0 +1,26 @@
+#![feature(staged_api, rustc_attrs, intrinsics)]
+#![stable(since="1.0.0", feature = "stable")]
+
+#[stable(since="1.0.0", feature = "stable")]
+pub mod old_way {
+ extern "rust-intrinsic" {
+ #[unstable(feature = "unstable", issue = "42")]
+ pub fn size_of_val<T>(x: *const T) -> usize;
+
+ #[unstable(feature = "unstable", issue = "42")]
+ #[rustc_const_unstable(feature = "unstable", issue = "42")]
+ pub fn min_align_of_val<T>(x: *const T) -> usize;
+ }
+}
+
+#[stable(since="1.0.0", feature = "stable")]
+pub mod new_way {
+ #[unstable(feature = "unstable", issue = "42")]
+ #[rustc_intrinsic]
+ pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
+
+ #[unstable(feature = "unstable", issue = "42")]
+ #[rustc_const_unstable(feature = "unstable", issue = "42")]
+ #[rustc_intrinsic]
+ pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 }
+}
diff --git a/tests/ui/consts/closure-in-foreign-crate.rs b/tests/ui/consts/closure-in-foreign-crate.rs
index 701cf09..94e40fc 100644
--- a/tests/ui/consts/closure-in-foreign-crate.rs
+++ b/tests/ui/consts/closure-in-foreign-crate.rs
@@ -1,8 +1,8 @@
-//@ aux-build:closure-in-foreign-crate.rs
+// FIXME(effects) aux-build:closure-in-foreign-crate.rs
//@ build-pass
-extern crate closure_in_foreign_crate;
+// FIXME(effects) extern crate closure_in_foreign_crate;
-const _: () = closure_in_foreign_crate::test();
+// FIXME(effects) const _: () = closure_in_foreign_crate::test();
fn main() {}
diff --git a/tests/ui/consts/const-block-const-bound.stderr b/tests/ui/consts/const-block-const-bound.stderr
index 42a42ae..5e24959 100644
--- a/tests/ui/consts/const-block-const-bound.stderr
+++ b/tests/ui/consts/const-block-const-bound.stderr
@@ -1,8 +1,16 @@
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-block-const-bound.rs:8:22
+ --> $DIR/const-block-const-bound.rs:8:15
|
LL | const fn f<T: ~const Destruct>(x: T) {}
- | ^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-block-const-bound.rs:8:15
+ |
+LL | const fn f<T: ~const Destruct>(x: T) {}
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/const-block-const-bound.rs:8:32
@@ -12,6 +20,6 @@
| |
| the destructor for this type cannot be evaluated in constant functions
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
index 4b3cf70..6c93c0e 100644
--- a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
+++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
@@ -3,7 +3,7 @@
we're apparently really bad at it",
issue = "none")]
-#![feature(staged_api)]
+#![feature(staged_api, foo)]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
@@ -11,7 +11,7 @@
fn meh() -> u32 { 42 }
-const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn
+const fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]`
fn a() {
let _: &'static u32 = &foo(); //~ ERROR temporary value dropped while borrowed
diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
index 2e697b2..1de1c78 100644
--- a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
+++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
@@ -1,10 +1,20 @@
-error: `foo` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
--> $DIR/dont_promote_unstable_const_fn.rs:14:25
|
LL | const fn bar() -> u32 { foo() }
| ^^^^^
|
- = help: add `#![feature(foo)]` to the crate attributes to enable
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn bar() -> u32 { foo() }
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo)]
+LL | const fn bar() -> u32 { foo() }
+ |
error[E0716]: temporary value dropped while borrowed
--> $DIR/dont_promote_unstable_const_fn.rs:17:28
diff --git a/tests/ui/consts/const-eval/simd/insert_extract.rs b/tests/ui/consts/const-eval/simd/insert_extract.rs
index f4f2532..57d4b48 100644
--- a/tests/ui/consts/const-eval/simd/insert_extract.rs
+++ b/tests/ui/consts/const-eval/simd/insert_extract.rs
@@ -11,8 +11,11 @@
#[repr(simd)] struct f32x4([f32; 4]);
extern "rust-intrinsic" {
+ #[stable(feature = "foo", since = "1.3.37")]
#[rustc_const_stable(feature = "foo", since = "1.3.37")]
fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
+
+ #[stable(feature = "foo", since = "1.3.37")]
#[rustc_const_stable(feature = "foo", since = "1.3.37")]
fn simd_extract<T, U>(x: T, idx: u32) -> U;
}
diff --git a/tests/ui/consts/const-fn-error.stderr b/tests/ui/consts/const-fn-error.stderr
index e886a0b..42a6f27 100644
--- a/tests/ui/consts/const-fn-error.stderr
+++ b/tests/ui/consts/const-fn-error.stderr
@@ -22,10 +22,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: cannot call non-const fn `<std::ops::Range<usize> as Iterator>::next` in constant functions
--> $DIR/const-fn-error.rs:5:14
@@ -34,10 +30,6 @@
| ^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 3 previous errors
diff --git a/tests/ui/consts/const-for-feature-gate.stderr b/tests/ui/consts/const-for-feature-gate.stderr
index 3344611..6e099a3 100644
--- a/tests/ui/consts/const-for-feature-gate.stderr
+++ b/tests/ui/consts/const-for-feature-gate.stderr
@@ -17,10 +17,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
--> $DIR/const-for-feature-gate.rs:4:14
@@ -29,10 +25,6 @@
| ^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 3 previous errors
diff --git a/tests/ui/consts/const-for.stderr b/tests/ui/consts/const-for.stderr
index 2b817c2..78336dc 100644
--- a/tests/ui/consts/const-for.stderr
+++ b/tests/ui/consts/const-for.stderr
@@ -7,10 +7,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
--> $DIR/const-for.rs:4:14
@@ -19,10 +15,6 @@
| ^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 2 previous errors
diff --git a/tests/ui/consts/const-try-feature-gate.stderr b/tests/ui/consts/const-try-feature-gate.stderr
index 0c4c16f..dc1dabc 100644
--- a/tests/ui/consts/const-try-feature-gate.stderr
+++ b/tests/ui/consts/const-try-feature-gate.stderr
@@ -17,10 +17,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/option.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions
--> $DIR/const-try-feature-gate.rs:4:5
@@ -31,10 +27,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/option.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 3 previous errors
diff --git a/tests/ui/consts/const-try.rs b/tests/ui/consts/const-try.rs
index 9089dd7..758c4dd 100644
--- a/tests/ui/consts/const-try.rs
+++ b/tests/ui/consts/const-try.rs
@@ -1,4 +1,4 @@
-//@ known-bug: #110395
+//@ compile-flags: -Znext-solver
// Demonstrates what's needed to make use of `?` in const contexts.
@@ -14,12 +14,14 @@
struct Error;
impl const FromResidual<Error> for TryMe {
+ //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
fn from_residual(residual: Error) -> Self {
TryMe
}
}
impl const Try for TryMe {
+ //~^ ERROR const `impl` for trait `Try` which is not marked with `#[const_trait]`
type Output = ();
type Residual = Error;
fn from_output(output: Self::Output) -> Self {
@@ -32,6 +34,8 @@
const fn t() -> TryMe {
TryMe?;
+ //~^ ERROR `?` cannot determine the branch of `TryMe` in constant functions
+ //~| ERROR `?` cannot convert from residual of `TryMe` in constant functions
TryMe
}
diff --git a/tests/ui/consts/const-try.stderr b/tests/ui/consts/const-try.stderr
index 8afdd4e..abb1a92 100644
--- a/tests/ui/consts/const-try.stderr
+++ b/tests/ui/consts/const-try.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
--> $DIR/const-try.rs:16:12
|
@@ -13,7 +8,7 @@
= note: adding a non-const method body in the future would be a breaking change
error: const `impl` for trait `Try` which is not marked with `#[const_trait]`
- --> $DIR/const-try.rs:22:12
+ --> $DIR/const-try.rs:23:12
|
LL | impl const Try for TryMe {
| ^^^
@@ -21,5 +16,22 @@
= note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
= note: adding a non-const method body in the future would be a breaking change
-error: aborting due to 3 previous errors
+error[E0015]: `?` cannot determine the branch of `TryMe` in constant functions
+ --> $DIR/const-try.rs:36:5
+ |
+LL | TryMe?;
+ | ^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: `?` cannot convert from residual of `TryMe` in constant functions
+ --> $DIR/const-try.rs:36:5
+ |
+LL | TryMe?;
+ | ^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs
new file mode 100644
index 0000000..050abc6
--- /dev/null
+++ b/tests/ui/consts/const-unstable-intrinsic.rs
@@ -0,0 +1,76 @@
+//! Ensure that unstable intrinsics can actually not be called,
+//! neither within a crate nor cross-crate.
+//@ aux-build:unstable_intrinsic.rs
+#![feature(staged_api, rustc_attrs, intrinsics)]
+#![stable(since="1.0.0", feature = "stable")]
+#![feature(local)]
+
+extern crate unstable_intrinsic;
+
+fn main() {
+ const_main();
+}
+
+const fn const_main() {
+ let x = 42;
+ unsafe {
+ unstable_intrinsic::old_way::size_of_val(&x);
+ //~^ERROR: unstable library feature 'unstable'
+ //~|ERROR: cannot call non-const intrinsic
+ unstable_intrinsic::old_way::min_align_of_val(&x);
+ //~^ERROR: unstable library feature 'unstable'
+ //~|ERROR: not yet stable as a const intrinsic
+ unstable_intrinsic::new_way::size_of_val(&x);
+ //~^ERROR: unstable library feature 'unstable'
+ //~|ERROR: cannot be (indirectly) exposed to stable
+ unstable_intrinsic::new_way::min_align_of_val(&x);
+ //~^ERROR: unstable library feature 'unstable'
+ //~|ERROR: not yet stable as a const intrinsic
+
+ old_way::size_of_val(&x);
+ //~^ERROR: cannot call non-const intrinsic
+ old_way::min_align_of_val(&x);
+ //~^ERROR: cannot use `#[feature(local)]`
+ new_way::size_of_val(&x);
+ //~^ERROR: cannot be (indirectly) exposed to stable
+ new_way::min_align_of_val(&x);
+ //~^ERROR: cannot use `#[feature(local)]`
+ }
+}
+
+#[stable(since="1.0.0", feature = "stable")]
+pub mod old_way {
+ extern "rust-intrinsic" {
+ #[unstable(feature = "local", issue = "42")]
+ pub fn size_of_val<T>(x: *const T) -> usize;
+
+ #[unstable(feature = "local", issue = "42")]
+ #[rustc_const_unstable(feature = "local", issue = "42")]
+ pub fn min_align_of_val<T>(x: *const T) -> usize;
+ }
+}
+
+#[stable(since="1.0.0", feature = "stable")]
+pub mod new_way {
+ #[unstable(feature = "local", issue = "42")]
+ #[rustc_intrinsic]
+ pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
+
+ #[unstable(feature = "local", issue = "42")]
+ #[rustc_const_unstable(feature = "local", issue = "42")]
+ #[rustc_intrinsic]
+ pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize { 42 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
+#[inline]
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
+ // Const stability attributes are not inherited from parent items.
+ extern "rust-intrinsic" {
+ fn copy<T>(src: *const T, dst: *mut T, count: usize);
+ }
+
+ unsafe { copy(src, dst, count) }
+ //~^ ERROR cannot call non-const intrinsic
+}
diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr
new file mode 100644
index 0000000..33a434c
--- /dev/null
+++ b/tests/ui/consts/const-unstable-intrinsic.stderr
@@ -0,0 +1,127 @@
+error[E0658]: use of unstable library feature 'unstable'
+ --> $DIR/const-unstable-intrinsic.rs:17:9
+ |
+LL | unstable_intrinsic::old_way::size_of_val(&x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+ = help: add `#![feature(unstable)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+ --> $DIR/const-unstable-intrinsic.rs:20:9
+ |
+LL | unstable_intrinsic::old_way::min_align_of_val(&x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+ = help: add `#![feature(unstable)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+ --> $DIR/const-unstable-intrinsic.rs:23:9
+ |
+LL | unstable_intrinsic::new_way::size_of_val(&x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+ = help: add `#![feature(unstable)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'unstable'
+ --> $DIR/const-unstable-intrinsic.rs:26:9
+ |
+LL | unstable_intrinsic::new_way::min_align_of_val(&x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
+ = help: add `#![feature(unstable)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: cannot call non-const intrinsic `size_of_val` in constant functions
+ --> $DIR/const-unstable-intrinsic.rs:17:9
+ |
+LL | unstable_intrinsic::old_way::size_of_val(&x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `min_align_of_val` is not yet stable as a const intrinsic
+ --> $DIR/const-unstable-intrinsic.rs:20:9
+ |
+LL | unstable_intrinsic::old_way::min_align_of_val(&x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add `#![feature(unstable)]` to the crate attributes to enable
+
+error: intrinsic `unstable_intrinsic::new_way::size_of_val` cannot be (indirectly) exposed to stable
+ --> $DIR/const-unstable-intrinsic.rs:23:9
+ |
+LL | unstable_intrinsic::new_way::size_of_val(&x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval)
+
+error: `min_align_of_val` is not yet stable as a const intrinsic
+ --> $DIR/const-unstable-intrinsic.rs:26:9
+ |
+LL | unstable_intrinsic::new_way::min_align_of_val(&x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add `#![feature(unstable)]` to the crate attributes to enable
+
+error: cannot call non-const intrinsic `size_of_val` in constant functions
+ --> $DIR/const-unstable-intrinsic.rs:30:9
+ |
+LL | old_way::size_of_val(&x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
+ --> $DIR/const-unstable-intrinsic.rs:32:9
+ |
+LL | old_way::min_align_of_val(&x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn const_main() {
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(local)]
+LL | const fn const_main() {
+ |
+
+error: intrinsic `new_way::size_of_val` cannot be (indirectly) exposed to stable
+ --> $DIR/const-unstable-intrinsic.rs:34:9
+ |
+LL | new_way::size_of_val(&x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval)
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
+ --> $DIR/const-unstable-intrinsic.rs:36:9
+ |
+LL | new_way::min_align_of_val(&x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn const_main() {
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(local)]
+LL | const fn const_main() {
+ |
+
+error: cannot call non-const intrinsic `copy` in constant functions
+ --> $DIR/const-unstable-intrinsic.rs:74:14
+ |
+LL | unsafe { copy(src, dst, count) }
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs
index 7748200..3a54764 100644
--- a/tests/ui/consts/const_cmp_type_id.rs
+++ b/tests/ui/consts/const_cmp_type_id.rs
@@ -1,4 +1,3 @@
-//@ check-pass
//@ compile-flags: -Znext-solver
#![feature(const_type_id, const_trait_impl, effects)]
#![allow(incomplete_features)]
@@ -7,11 +6,13 @@
fn main() {
const {
- // FIXME(effects) this isn't supposed to pass (right now) but it did.
- // revisit binops typeck please.
assert!(TypeId::of::<u8>() == TypeId::of::<u8>());
+ //~^ ERROR cannot call non-const operator in constants
assert!(TypeId::of::<()>() != TypeId::of::<u8>());
+ //~^ ERROR cannot call non-const operator in constants
let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
+ //~^ ERROR cannot call non-const operator in constants
// can't assert `_a` because it is not deterministic
+ // FIXME(effects) make it pass
}
}
diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr
new file mode 100644
index 0000000..12f3536
--- /dev/null
+++ b/tests/ui/consts/const_cmp_type_id.stderr
@@ -0,0 +1,34 @@
+error[E0015]: cannot call non-const operator in constants
+ --> $DIR/const_cmp_type_id.rs:9:17
+ |
+LL | assert!(TypeId::of::<u8>() == TypeId::of::<u8>());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: impl defined here, but it is not `const`
+ --> $SRC_DIR/core/src/any.rs:LL:COL
+ = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const operator in constants
+ --> $DIR/const_cmp_type_id.rs:11:17
+ |
+LL | assert!(TypeId::of::<()>() != TypeId::of::<u8>());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: impl defined here, but it is not `const`
+ --> $SRC_DIR/core/src/any.rs:LL:COL
+ = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const operator in constants
+ --> $DIR/const_cmp_type_id.rs:13:18
+ |
+LL | let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: impl defined here, but it is not `const`
+ --> $SRC_DIR/core/src/any.rs:LL:COL
+ = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+ = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/constifconst-call-in-const-position.stderr b/tests/ui/consts/constifconst-call-in-const-position.stderr
index 7de10f0..6add83d 100644
--- a/tests/ui/consts/constifconst-call-in-const-position.stderr
+++ b/tests/ui/consts/constifconst-call-in-const-position.stderr
@@ -1,26 +1,15 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
-error[E0308]: mismatched types
+error[E0277]: the trait bound `T: const Tr` is not satisfied
--> $DIR/constifconst-call-in-const-position.rs:17:38
|
LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] {
- | ^^^^^^ expected `false`, found `host`
- |
- = note: expected constant `false`
- found constant `host`
+ | ^^^^^^
-error[E0308]: mismatched types
+error[E0277]: the trait bound `T: const Tr` is not satisfied
--> $DIR/constifconst-call-in-const-position.rs:18:9
|
LL | [0; T::a()]
- | ^^^^^^ expected `false`, found `host`
- |
- = note: expected constant `false`
- found constant `host`
+ | ^^^^^^
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/consts/control-flow/loop.stderr b/tests/ui/consts/control-flow/loop.stderr
index 13d5d3e..5e43c70 100644
--- a/tests/ui/consts/control-flow/loop.stderr
+++ b/tests/ui/consts/control-flow/loop.stderr
@@ -35,10 +35,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
--> $DIR/loop.rs:53:14
@@ -47,10 +43,6 @@
| ^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: cannot convert `std::ops::Range<i32>` into an iterator in constants
--> $DIR/loop.rs:59:14
@@ -61,10 +53,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
--> $DIR/loop.rs:59:14
@@ -73,10 +61,6 @@
| ^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 6 previous errors
diff --git a/tests/ui/consts/control-flow/try.stderr b/tests/ui/consts/control-flow/try.stderr
index e08f523..5e2c773 100644
--- a/tests/ui/consts/control-flow/try.stderr
+++ b/tests/ui/consts/control-flow/try.stderr
@@ -17,10 +17,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/option.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: `?` cannot convert from residual of `Option<i32>` in constant functions
--> $DIR/try.rs:6:5
@@ -31,10 +27,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/option.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 3 previous errors
diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs
index 805c03d..62917c0 100644
--- a/tests/ui/consts/copy-intrinsic.rs
+++ b/tests/ui/consts/copy-intrinsic.rs
@@ -5,9 +5,11 @@
use std::mem;
extern "rust-intrinsic" {
+ #[stable(feature = "dummy", since = "1.0.0")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+ #[stable(feature = "dummy", since = "1.0.0")]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}
diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr
index da81391..29a88f6 100644
--- a/tests/ui/consts/copy-intrinsic.stderr
+++ b/tests/ui/consts/copy-intrinsic.stderr
@@ -1,23 +1,23 @@
error[E0080]: evaluation of constant value failed
- --> $DIR/copy-intrinsic.rs:28:5
+ --> $DIR/copy-intrinsic.rs:30:5
|
LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x100[noalloc] which is a dangling pointer (it has no provenance)
error[E0080]: evaluation of constant value failed
- --> $DIR/copy-intrinsic.rs:37:5
+ --> $DIR/copy-intrinsic.rs:39:5
|
LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes
error[E0080]: evaluation of constant value failed
- --> $DIR/copy-intrinsic.rs:44:5
+ --> $DIR/copy-intrinsic.rs:46:5
|
LL | copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy`
error[E0080]: evaluation of constant value failed
- --> $DIR/copy-intrinsic.rs:50:5
+ --> $DIR/copy-intrinsic.rs:52:5
|
LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping`
diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr
index 218c90f..a686bc2 100644
--- a/tests/ui/consts/fn_trait_refs.stderr
+++ b/tests/ui/consts/fn_trait_refs.stderr
@@ -11,96 +11,168 @@
| ^^^^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:13:15
+ --> $DIR/fn_trait_refs.rs:13:8
|
LL | T: ~const Fn<()> + ~const Destruct,
- | ^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:13:31
+ --> $DIR/fn_trait_refs.rs:13:24
|
LL | T: ~const Fn<()> + ~const Destruct,
- | ^^^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:13:15
+ --> $DIR/fn_trait_refs.rs:13:8
|
LL | T: ~const Fn<()> + ~const Destruct,
- | ^^^^^^
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:20:15
+ --> $DIR/fn_trait_refs.rs:13:8
|
-LL | T: ~const FnMut<()> + ~const Destruct,
- | ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:20:34
- |
-LL | T: ~const FnMut<()> + ~const Destruct,
- | ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:20:15
- |
-LL | T: ~const FnMut<()> + ~const Destruct,
- | ^^^^^^^^^
+LL | T: ~const Fn<()> + ~const Destruct,
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:27:15
+ --> $DIR/fn_trait_refs.rs:13:24
+ |
+LL | T: ~const Fn<()> + ~const Destruct,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:20:8
+ |
+LL | T: ~const FnMut<()> + ~const Destruct,
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:20:27
+ |
+LL | T: ~const FnMut<()> + ~const Destruct,
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:20:8
+ |
+LL | T: ~const FnMut<()> + ~const Destruct,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:20:8
+ |
+LL | T: ~const FnMut<()> + ~const Destruct,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:20:27
+ |
+LL | T: ~const FnMut<()> + ~const Destruct,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:27:8
|
LL | T: ~const FnOnce<()>,
- | ^^^^^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:27:15
+ --> $DIR/fn_trait_refs.rs:27:8
|
LL | T: ~const FnOnce<()>,
- | ^^^^^^^^^^
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:34:15
+ --> $DIR/fn_trait_refs.rs:27:8
|
-LL | T: ~const Fn<()> + ~const Destruct,
- | ^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:34:31
- |
-LL | T: ~const Fn<()> + ~const Destruct,
- | ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:34:15
- |
-LL | T: ~const Fn<()> + ~const Destruct,
- | ^^^^^^
+LL | T: ~const FnOnce<()>,
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:48:15
+ --> $DIR/fn_trait_refs.rs:34:8
|
-LL | T: ~const FnMut<()> + ~const Destruct,
- | ^^^^^^^^^
+LL | T: ~const Fn<()> + ~const Destruct,
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:48:34
+ --> $DIR/fn_trait_refs.rs:34:24
|
-LL | T: ~const FnMut<()> + ~const Destruct,
- | ^^^^^^^^
+LL | T: ~const Fn<()> + ~const Destruct,
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/fn_trait_refs.rs:48:15
+ --> $DIR/fn_trait_refs.rs:34:8
+ |
+LL | T: ~const Fn<()> + ~const Destruct,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:34:8
+ |
+LL | T: ~const Fn<()> + ~const Destruct,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:34:24
+ |
+LL | T: ~const Fn<()> + ~const Destruct,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:48:8
|
LL | T: ~const FnMut<()> + ~const Destruct,
- | ^^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:48:27
+ |
+LL | T: ~const FnMut<()> + ~const Destruct,
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:48:8
+ |
+LL | T: ~const FnMut<()> + ~const Destruct,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:48:8
+ |
+LL | T: ~const FnMut<()> + ~const Destruct,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/fn_trait_refs.rs:48:27
+ |
+LL | T: ~const FnMut<()> + ~const Destruct,
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
@@ -111,10 +183,6 @@
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0015]: cannot call non-const operator in constants
--> $DIR/fn_trait_refs.rs:73:17
@@ -123,10 +191,6 @@
| ^^^^^^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0015]: cannot call non-const closure in constant functions
--> $DIR/fn_trait_refs.rs:15:5
@@ -139,10 +203,6 @@
|
LL | T: ~const Fn<()> + ~const Destruct + ~const Fn(),
| +++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/fn_trait_refs.rs:11:23
@@ -164,10 +224,6 @@
|
LL | T: ~const FnMut<()> + ~const Destruct + ~const FnMut(),
| ++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/fn_trait_refs.rs:18:27
@@ -189,10 +245,6 @@
|
LL | T: ~const FnOnce<()> + ~const FnOnce(),
| +++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/fn_trait_refs.rs:32:21
@@ -212,7 +264,7 @@
LL | }
| - value is dropped here
-error: aborting due to 25 previous errors
+error: aborting due to 34 previous errors
Some errors have detailed explanations: E0015, E0493, E0635.
For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/intrinsic_without_const_stab.rs b/tests/ui/consts/intrinsic_without_const_stab.rs
deleted file mode 100644
index 40ec65d..0000000
--- a/tests/ui/consts/intrinsic_without_const_stab.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-#![feature(intrinsics, staged_api)]
-#![stable(feature = "core", since = "1.6.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
-#[inline]
-pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
- // Const stability attributes are not inherited from parent items.
- extern "rust-intrinsic" {
- fn copy<T>(src: *const T, dst: *mut T, count: usize);
- }
-
- unsafe { copy(src, dst, count) }
- //~^ ERROR cannot call non-const fn
-}
-
-fn main() {}
diff --git a/tests/ui/consts/intrinsic_without_const_stab.stderr b/tests/ui/consts/intrinsic_without_const_stab.stderr
deleted file mode 100644
index e314308..0000000
--- a/tests/ui/consts/intrinsic_without_const_stab.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0015]: cannot call non-const fn `copy::copy::<T>` in constant functions
- --> $DIR/intrinsic_without_const_stab.rs:13:14
- |
-LL | unsafe { copy(src, dst, count) }
- | ^^^^^^^^^^^^^^^^^^^^^
- |
- = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/intrinsic_without_const_stab_fail.rs b/tests/ui/consts/intrinsic_without_const_stab_fail.rs
deleted file mode 100644
index 2b0745b..0000000
--- a/tests/ui/consts/intrinsic_without_const_stab_fail.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(intrinsics, staged_api)]
-#![stable(feature = "core", since = "1.6.0")]
-
-extern "rust-intrinsic" {
- fn copy<T>(src: *const T, dst: *mut T, count: usize);
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
-#[inline]
-pub const unsafe fn stuff<T>(src: *const T, dst: *mut T, count: usize) {
- unsafe { copy(src, dst, count) } //~ ERROR cannot call non-const fn
-}
-
-fn main() {}
diff --git a/tests/ui/consts/intrinsic_without_const_stab_fail.stderr b/tests/ui/consts/intrinsic_without_const_stab_fail.stderr
deleted file mode 100644
index 8ade68e..0000000
--- a/tests/ui/consts/intrinsic_without_const_stab_fail.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0015]: cannot call non-const fn `copy::<T>` in constant functions
- --> $DIR/intrinsic_without_const_stab_fail.rs:12:14
- |
-LL | unsafe { copy(src, dst, count) }
- | ^^^^^^^^^^^^^^^^^^^^^
- |
- = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
index 0e41053..2e48837 100644
--- a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
+++ b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
@@ -6,10 +6,6 @@
|
= note: closures need an RFC before allowed to be called in constants
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: could not evaluate constant pattern
--> $DIR/invalid-inline-const-in-match-arm.rs:5:9
diff --git a/tests/ui/consts/issue-28113.stderr b/tests/ui/consts/issue-28113.stderr
index c2f5387..401536c 100644
--- a/tests/ui/consts/issue-28113.stderr
+++ b/tests/ui/consts/issue-28113.stderr
@@ -6,10 +6,6 @@
|
= note: closures need an RFC before allowed to be called in constants
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 1 previous error
diff --git a/tests/ui/consts/issue-56164.stderr b/tests/ui/consts/issue-56164.stderr
index 6ec4ce0..de5a53c 100644
--- a/tests/ui/consts/issue-56164.stderr
+++ b/tests/ui/consts/issue-56164.stderr
@@ -6,10 +6,6 @@
|
= note: closures need an RFC before allowed to be called in constant functions
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: function pointer calls are not allowed in constant functions
--> $DIR/issue-56164.rs:5:5
diff --git a/tests/ui/consts/issue-68542-closure-in-array-len.stderr b/tests/ui/consts/issue-68542-closure-in-array-len.stderr
index b414a6e..9f323b2 100644
--- a/tests/ui/consts/issue-68542-closure-in-array-len.stderr
+++ b/tests/ui/consts/issue-68542-closure-in-array-len.stderr
@@ -6,10 +6,6 @@
|
= note: closures need an RFC before allowed to be called in constants
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 1 previous error
diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr
index 79dbed4..ef754b2 100644
--- a/tests/ui/consts/issue-73976-monomorphic.stderr
+++ b/tests/ui/consts/issue-73976-monomorphic.stderr
@@ -7,10 +7,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/any.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 1 previous error
diff --git a/tests/ui/consts/issue-90870.rs b/tests/ui/consts/issue-90870.rs
index e1929c6..b62769a 100644
--- a/tests/ui/consts/issue-90870.rs
+++ b/tests/ui/consts/issue-90870.rs
@@ -3,9 +3,6 @@
#![allow(dead_code)]
const fn f(a: &u8, b: &u8) -> bool {
-//~^ HELP: add `#![feature(const_trait_impl)]`
-//~| HELP: add `#![feature(const_trait_impl)]`
-//~| HELP: add `#![feature(const_trait_impl)]`
a == b
//~^ ERROR: cannot call non-const operator in constant functions [E0015]
//~| HELP: consider dereferencing here
diff --git a/tests/ui/consts/issue-90870.stderr b/tests/ui/consts/issue-90870.stderr
index df88a0c..ea98792 100644
--- a/tests/ui/consts/issue-90870.stderr
+++ b/tests/ui/consts/issue-90870.stderr
@@ -1,5 +1,5 @@
error[E0015]: cannot call non-const operator in constant functions
- --> $DIR/issue-90870.rs:9:5
+ --> $DIR/issue-90870.rs:6:5
|
LL | a == b
| ^^^^^^
@@ -9,13 +9,9 @@
|
LL | *a == *b
| + +
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: cannot call non-const operator in constant functions
- --> $DIR/issue-90870.rs:15:5
+ --> $DIR/issue-90870.rs:12:5
|
LL | a == b
| ^^^^^^
@@ -25,13 +21,9 @@
|
LL | ****a == ****b
| ++++ ++++
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: cannot call non-const operator in constant functions
- --> $DIR/issue-90870.rs:22:12
+ --> $DIR/issue-90870.rs:19:12
|
LL | if l == r {
| ^^^^^^
@@ -41,10 +33,6 @@
|
LL | if *l == *r {
| + +
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 3 previous errors
diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr
index a85c5e1..8cad137 100644
--- a/tests/ui/consts/issue-94675.stderr
+++ b/tests/ui/consts/issue-94675.stderr
@@ -7,10 +7,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 1 previous error
diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
index 461499e..d6f0799 100644
--- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
+++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
@@ -5,7 +5,7 @@
issue = "none")]
#![feature(foo, foo2)]
-#![feature(const_async_blocks, staged_api)]
+#![feature(const_async_blocks, staged_api, rustc_attrs)]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
@@ -14,33 +14,55 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
-const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn
+const fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]`
#[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature = "foo2", issue = "none")]
const fn foo2() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
-const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn
+const fn bar2() -> u32 { foo2() } //~ ERROR cannot use `#[feature(foo2)]`
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// conformity is required
const fn bar3() -> u32 {
let x = async { 13 };
- //~^ ERROR const-stable function cannot use `#[feature(const_async_blocks)]`
+ //~^ ERROR cannot use `#[feature(const_async_blocks)]`
foo()
- //~^ ERROR is not yet stable as a const fn
+ //~^ ERROR cannot use `#[feature(foo)]`
}
// check whether this function cannot be called even with the feature gate active
#[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature = "foo2", issue = "none")]
const fn foo2_gated() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
-const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn
+const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
+
+// Functions without any attribute are checked like stable functions,
+// even if they are in a stable module.
+mod stable {
+ #![stable(feature = "rust1", since = "1.0.0")]
+
+ pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
+}
+// And same for const-unstable functions that are marked as "stable_indirect".
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo", issue = "none")]
+#[rustc_const_stable_indirect]
+const fn stable_indirect() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
+
+// These functiuons *can* be called from fully stable functions.
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
+const fn bar2_gated_exposed() -> u32 {
+ stable::bar2_gated_stable_indirect() + stable_indirect()
+}
fn main() {}
diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
index fedc5a4..899cec0 100644
--- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
+++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
@@ -1,51 +1,127 @@
-error: `foo` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
--> $DIR/min_const_fn_libstd_stability.rs:17:25
|
LL | const fn bar() -> u32 { foo() }
| ^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn bar() -> u32 { foo() }
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo)]
+LL | const fn bar() -> u32 { foo() }
+ |
-error: `foo2` is not yet stable as a const fn
- --> $DIR/min_const_fn_libstd_stability.rs:25:26
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+ --> $DIR/min_const_fn_libstd_stability.rs:26:26
|
LL | const fn bar2() -> u32 { foo2() }
| ^^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn bar2() -> u32 { foo2() }
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const fn bar2() -> u32 { foo2() }
+ |
-error: const-stable function cannot use `#[feature(const_async_blocks)]`
- --> $DIR/min_const_fn_libstd_stability.rs:31:13
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_async_blocks)]`
+ --> $DIR/min_const_fn_libstd_stability.rs:32:13
|
LL | let x = async { 13 };
| ^^^^^^^^^^^^
|
-help: if the function is not (yet) meant to be stable, make this function unstably const
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
|
LL + #[rustc_const_unstable(feature = "...", issue = "...")]
LL | const fn bar3() -> u32 {
|
-help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval)
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
|
LL + #[rustc_allow_const_fn_unstable(const_async_blocks)]
LL | const fn bar3() -> u32 {
|
-error: `foo` is not yet stable as a const fn
- --> $DIR/min_const_fn_libstd_stability.rs:33:5
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
+ --> $DIR/min_const_fn_libstd_stability.rs:34:5
|
LL | foo()
| ^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn bar3() -> u32 {
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo)]
+LL | const fn bar3() -> u32 {
+ |
-error: `foo2_gated` is not yet stable as a const fn
- --> $DIR/min_const_fn_libstd_stability.rs:44:32
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+ --> $DIR/min_const_fn_libstd_stability.rs:46:32
|
LL | const fn bar2_gated() -> u32 { foo2_gated() }
| ^^^^^^^^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn bar2_gated() -> u32 { foo2_gated() }
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const fn bar2_gated() -> u32 { foo2_gated() }
+ |
-error: aborting due to 5 previous errors
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+ --> $DIR/min_const_fn_libstd_stability.rs:53:63
+ |
+LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() }
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() }
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() }
+ |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+ --> $DIR/min_const_fn_libstd_stability.rs:59:37
+ |
+LL | const fn stable_indirect() -> u32 { foo2_gated() }
+ | ^^^^^^^^^^^^
+ |
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_indirect() -> u32 { foo2_gated() }
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const fn stable_indirect() -> u32 { foo2_gated() }
+ |
+
+error: aborting due to 7 previous errors
diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
index 274b444..3e82b9f 100644
--- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
+++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
@@ -13,24 +13,26 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
-const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn
+const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR cannot use `#[feature(foo)]`
#[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature = "foo2", issue = "none")]
const unsafe fn foo2() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
-const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn
+const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR cannot use `#[feature(foo2)]`
// check whether this function cannot be called even with the feature gate active
#[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature = "foo2", issue = "none")]
const unsafe fn foo2_gated() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
-//~^ ERROR not yet stable as a const fn
+//~^ ERROR cannot use `#[feature(foo2)]`
fn main() {}
diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
index 353b117..442a079 100644
--- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
+++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
@@ -1,26 +1,56 @@
-error: `foo` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41
|
LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
| ^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo)]
+LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
+ |
-error: `foo2` is not yet stable as a const fn
- --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+ --> $DIR/min_const_unsafe_fn_libstd_stability.rs:25:42
|
LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
| ^^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
+ |
-error: `foo2_gated` is not yet stable as a const fn
- --> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:48
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+ --> $DIR/min_const_unsafe_fn_libstd_stability.rs:35:48
|
LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
| ^^^^^^^^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
+ |
error: aborting due to 3 previous errors
diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
index 94b6207..cc7eaa5 100644
--- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
+++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
@@ -13,23 +13,25 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
-const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn
+const unsafe fn bar() -> u32 { foo() } //~ ERROR cannot use `#[feature(foo)]`
#[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature="foo2", issue = "none")]
const fn foo2() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
-const unsafe fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn
+const unsafe fn bar2() -> u32 { foo2() } //~ ERROR cannot use `#[feature(foo2)]`
// check whether this function cannot be called even with the feature gate active
#[unstable(feature = "foo2", issue = "none")]
+#[rustc_const_unstable(feature="foo2", issue = "none")]
const fn foo2_gated() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
-const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn
+const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR cannot use `#[feature(foo2)]`
fn main() {}
diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
index e90ba9b..ff37cba 100644
--- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
+++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
@@ -1,26 +1,56 @@
-error: `foo` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo)]`
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32
|
LL | const unsafe fn bar() -> u32 { foo() }
| ^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar() -> u32 { foo() }
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo)]
+LL | const unsafe fn bar() -> u32 { foo() }
+ |
-error: `foo2` is not yet stable as a const fn
- --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+ --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:25:33
|
LL | const unsafe fn bar2() -> u32 { foo2() }
| ^^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar2() -> u32 { foo2() }
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const unsafe fn bar2() -> u32 { foo2() }
+ |
-error: `foo2_gated` is not yet stable as a const fn
- --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(foo2)]`
+ --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:35:39
|
LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
| ^^^^^^^^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(foo2)]
+LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
+ |
error: aborting due to 3 previous errors
diff --git a/tests/ui/consts/rustc-const-stability-require-const.rs b/tests/ui/consts/rustc-const-stability-require-const.rs
index 4fb259b..6cc3f0f 100644
--- a/tests/ui/consts/rustc-const-stability-require-const.rs
+++ b/tests/ui/consts/rustc-const-stability-require-const.rs
@@ -1,16 +1,16 @@
#![crate_type = "lib"]
-#![feature(staged_api)]
+#![feature(staged_api, rustc_attrs)]
#![stable(feature = "foo", since = "1.0.0")]
#[stable(feature = "foo", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_foo", issue = "none")]
pub fn foo() {}
-//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+//~^ ERROR require the function or method to be `const`
#[stable(feature = "bar", since = "1.0.0")]
#[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
pub fn bar() {}
-//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+//~^ ERROR require the function or method to be `const`
#[stable(feature = "potato", since = "1.0.0")]
pub struct Potato;
@@ -19,23 +19,23 @@
#[stable(feature = "salad", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_salad", issue = "none")]
pub fn salad(&self) -> &'static str { "mmmmmm" }
- //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+ //~^ ERROR require the function or method to be `const`
#[stable(feature = "roasted", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_roasted", issue = "none")]
pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
- //~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+ //~^ ERROR require the function or method to be `const`
}
#[stable(feature = "bar", since = "1.0.0")]
#[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
pub extern "C" fn bar_c() {}
-//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+//~^ ERROR require the function or method to be `const`
#[stable(feature = "foo", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_foo", issue = "none")]
pub extern "C" fn foo_c() {}
-//~^ ERROR attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+//~^ ERROR require the function or method to be `const`
#[stable(feature = "foobar", since = "1.0.0")]
@@ -45,3 +45,20 @@
#[stable(feature = "barfoo", since = "1.0.0")]
#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
pub const fn barfoo() {}
+
+// `rustc_const_stable` also requires the function to be stable.
+
+#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+const fn barfoo_unmarked() {}
+//~^ ERROR can only be applied to functions that are declared `#[stable]`
+
+#[unstable(feature = "unstable", issue = "none")]
+#[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+pub const fn barfoo_unstable() {}
+//~^ ERROR can only be applied to functions that are declared `#[stable]`
+
+// `#[rustc_const_stable_indirect]` also requires a const fn
+#[rustc_const_stable_indirect]
+#[unstable(feature = "unstable", issue = "none")]
+pub fn not_a_const_fn() {}
+//~^ ERROR require the function or method to be `const`
diff --git a/tests/ui/consts/rustc-const-stability-require-const.stderr b/tests/ui/consts/rustc-const-stability-require-const.stderr
index 1027b93..d9a7d37 100644
--- a/tests/ui/consts/rustc-const-stability-require-const.stderr
+++ b/tests/ui/consts/rustc-const-stability-require-const.stderr
@@ -1,8 +1,6 @@
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
--> $DIR/rustc-const-stability-require-const.rs:7:1
|
-LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")]
- | -------------------------------------------------------------- attribute specified here
LL | pub fn foo() {}
| ^^^^^^^^^^^^
|
@@ -12,11 +10,9 @@
LL | pub fn foo() {}
| ^^^^^^^^^^^^
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
--> $DIR/rustc-const-stability-require-const.rs:12:1
|
-LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
- | ------------------------------------------------------------- attribute specified here
LL | pub fn bar() {}
| ^^^^^^^^^^^^
|
@@ -26,11 +22,9 @@
LL | pub fn bar() {}
| ^^^^^^^^^^^^
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
--> $DIR/rustc-const-stability-require-const.rs:21:5
|
-LL | #[rustc_const_unstable(feature = "const_salad", issue = "none")]
- | ---------------------------------------------------------------- attribute specified here
LL | pub fn salad(&self) -> &'static str { "mmmmmm" }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
@@ -40,11 +34,9 @@
LL | pub fn salad(&self) -> &'static str { "mmmmmm" }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
--> $DIR/rustc-const-stability-require-const.rs:26:5
|
-LL | #[rustc_const_unstable(feature = "const_roasted", issue = "none")]
- | ------------------------------------------------------------------ attribute specified here
LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
@@ -54,11 +46,9 @@
LL | pub fn roasted(&self) -> &'static str { "mmmmmmmmmm" }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
--> $DIR/rustc-const-stability-require-const.rs:32:1
|
-LL | #[rustc_const_stable(feature = "const_bar", since = "1.0.0")]
- | ------------------------------------------------------------- attribute specified here
LL | pub extern "C" fn bar_c() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
@@ -68,11 +58,9 @@
LL | pub extern "C" fn bar_c() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
--> $DIR/rustc-const-stability-require-const.rs:37:1
|
-LL | #[rustc_const_unstable(feature = "const_foo", issue = "none")]
- | -------------------------------------------------------------- attribute specified here
LL | pub extern "C" fn foo_c() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
@@ -82,5 +70,33 @@
LL | pub extern "C" fn foo_c() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 6 previous errors
+error: attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
+ --> $DIR/rustc-const-stability-require-const.rs:52:1
+ |
+LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+ | ---------------------------------------------------------------- attribute specified here
+LL | const fn barfoo_unmarked() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
+ --> $DIR/rustc-const-stability-require-const.rs:57:1
+ |
+LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+ | ---------------------------------------------------------------- attribute specified here
+LL | pub const fn barfoo_unstable() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
+ --> $DIR/rustc-const-stability-require-const.rs:63:1
+ |
+LL | pub fn not_a_const_fn() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: make the function or method const
+ --> $DIR/rustc-const-stability-require-const.rs:63:1
+ |
+LL | pub fn not_a_const_fn() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
diff --git a/tests/ui/consts/try-operator.stderr b/tests/ui/consts/try-operator.stderr
index 2c8b4c7..40d96ed 100644
--- a/tests/ui/consts/try-operator.stderr
+++ b/tests/ui/consts/try-operator.stderr
@@ -13,10 +13,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/result.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0015]: `?` cannot convert from residual of `Result<bool, ()>` in constant functions
--> $DIR/try-operator.rs:10:9
@@ -27,10 +23,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/result.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0015]: `?` cannot determine the branch of `Option<()>` in constant functions
--> $DIR/try-operator.rs:18:9
@@ -41,10 +33,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/option.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions
--> $DIR/try-operator.rs:18:9
@@ -55,10 +43,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/option.rs:LL:COL
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 5 previous errors
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
index 6c83eff..2bdec1b 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -1,8 +1,16 @@
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/unstable-const-fn-in-libcore.rs:19:39
+ --> $DIR/unstable-const-fn-in-libcore.rs:19:32
|
LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
- | ^^^^^^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/unstable-const-fn-in-libcore.rs:19:32
+ |
+LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0015]: cannot call non-const closure in constant functions
--> $DIR/unstable-const-fn-in-libcore.rs:24:26
@@ -15,10 +23,6 @@
|
LL | const fn unwrap_or_else<F: ~const FnOnce() -> T + ~const FnOnce()>(self, f: F) -> T {
| +++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0493]: destructor of `F` cannot be evaluated at compile-time
--> $DIR/unstable-const-fn-in-libcore.rs:19:60
@@ -38,7 +42,7 @@
LL | }
| - value is dropped here
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
Some errors have detailed explanations: E0015, E0493.
For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/unstable-const-stable.rs b/tests/ui/consts/unstable-const-stable.rs
deleted file mode 100644
index f69e8d0..0000000
--- a/tests/ui/consts/unstable-const-stable.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-//@ aux-build:unstable_but_const_stable.rs
-
-extern crate unstable_but_const_stable;
-use unstable_but_const_stable::*;
-
-fn main() {
- some_unstable_fn(); //~ERROR use of unstable library feature
- unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature
-}
-
-const fn const_main() {
- some_unstable_fn(); //~ERROR use of unstable library feature
- unsafe { write_bytes(4 as *mut u8, 0, 0) }; //~ERROR use of unstable library feature
-}
diff --git a/tests/ui/consts/unstable-const-stable.stderr b/tests/ui/consts/unstable-const-stable.stderr
deleted file mode 100644
index c4ffbbb..0000000
--- a/tests/ui/consts/unstable-const-stable.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error[E0658]: use of unstable library feature 'unstable'
- --> $DIR/unstable-const-stable.rs:7:5
- |
-LL | some_unstable_fn();
- | ^^^^^^^^^^^^^^^^
- |
- = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
- = help: add `#![feature(unstable)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature 'unstable'
- --> $DIR/unstable-const-stable.rs:8:14
- |
-LL | unsafe { write_bytes(4 as *mut u8, 0, 0) };
- | ^^^^^^^^^^^
- |
- = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
- = help: add `#![feature(unstable)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature 'unstable'
- --> $DIR/unstable-const-stable.rs:12:5
- |
-LL | some_unstable_fn();
- | ^^^^^^^^^^^^^^^^
- |
- = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
- = help: add `#![feature(unstable)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature 'unstable'
- --> $DIR/unstable-const-stable.rs:13:14
- |
-LL | unsafe { write_bytes(4 as *mut u8, 0, 0) };
- | ^^^^^^^^^^^
- |
- = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
- = help: add `#![feature(unstable)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/consts/zst_no_llvm_alloc.rs b/tests/ui/consts/zst_no_llvm_alloc.rs
index 48ef11e..1e92e3b 100644
--- a/tests/ui/consts/zst_no_llvm_alloc.rs
+++ b/tests/ui/consts/zst_no_llvm_alloc.rs
@@ -17,8 +17,11 @@
// The exact addresses returned by these library functions are not necessarily stable guarantees
// but for now we assert that we're still matching.
- assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
- assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
+ #[allow(dangling_pointers_from_temporaries)]
+ {
+ assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
+ assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
+ };
// statics must have a unique address (see https://github.com/rust-lang/rust/issues/18297, not
// clear whether this is a stable guarantee)
diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs
index ee2bf9e..b2b3c61 100644
--- a/tests/ui/delegation/ice-issue-124347.rs
+++ b/tests/ui/delegation/ice-issue-124347.rs
@@ -4,7 +4,7 @@
// FIXME(fn_delegation): `recursive delegation` error should be emitted here
trait Trait {
reuse Trait::foo { &self.0 }
- //~^ ERROR cycle detected when computing generics of `Trait::foo`
+ //~^ ERROR recursive delegation is not supported yet
}
reuse foo;
diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr
index bd0bc97..74c4b5c 100644
--- a/tests/ui/delegation/ice-issue-124347.stderr
+++ b/tests/ui/delegation/ice-issue-124347.stderr
@@ -1,16 +1,8 @@
-error[E0391]: cycle detected when computing generics of `Trait::foo`
+error: recursive delegation is not supported yet
--> $DIR/ice-issue-124347.rs:6:18
|
LL | reuse Trait::foo { &self.0 }
- | ^^^
- |
- = note: ...which immediately requires computing generics of `Trait::foo` again
-note: cycle used when inheriting delegation signature
- --> $DIR/ice-issue-124347.rs:6:18
- |
-LL | reuse Trait::foo { &self.0 }
- | ^^^
- = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+ | ^^^ callee defined here
error[E0391]: cycle detected when computing generics of `foo`
--> $DIR/ice-issue-124347.rs:10:7
diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs
index e57efff..56296db 100644
--- a/tests/ui/delegation/unsupported.rs
+++ b/tests/ui/delegation/unsupported.rs
@@ -51,7 +51,7 @@
}
reuse Trait::foo;
- //~^ ERROR delegation to a function with effect parameter is not supported yet
+ //~^ ERROR type annotations needed
}
fn main() {}
diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr
index 6a627be..2f64d23 100644
--- a/tests/ui/delegation/unsupported.stderr
+++ b/tests/ui/delegation/unsupported.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>::{synthetic#0}`
--> $DIR/unsupported.rs:27:25
|
@@ -81,15 +76,15 @@
LL | reuse to_reuse1::foo;
| ^^^
-error: delegation to a function with effect parameter is not supported yet
+error[E0283]: type annotations needed
--> $DIR/unsupported.rs:53:18
|
-LL | fn foo();
- | --------- callee defined here
-...
LL | reuse Trait::foo;
- | ^^^
+ | ^^^ cannot infer type
+ |
+ = note: cannot satisfy `_: effects::Trait`
-error: aborting due to 5 previous errors; 2 warnings emitted
+error: aborting due to 4 previous errors; 2 warnings emitted
-For more information about this error, try `rustc --explain E0391`.
+Some errors have detailed explanations: E0283, E0391.
+For more information about an error, try `rustc --explain E0283`.
diff --git a/tests/ui/deriving/auxiliary/another-proc-macro.rs b/tests/ui/deriving/auxiliary/another-proc-macro.rs
index a05175c..c992cde 100644
--- a/tests/ui/deriving/auxiliary/another-proc-macro.rs
+++ b/tests/ui/deriving/auxiliary/another-proc-macro.rs
@@ -6,7 +6,7 @@
extern crate proc_macro;
-use proc_macro::{quote, TokenStream};
+use proc_macro::{TokenStream, quote};
#[proc_macro_derive(AnotherMacro, attributes(pointee))]
pub fn derive(_input: TokenStream) -> TokenStream {
diff --git a/tests/ui/deriving/built-in-proc-macro-scope.rs b/tests/ui/deriving/built-in-proc-macro-scope.rs
index 41c95f6..6c473ae 100644
--- a/tests/ui/deriving/built-in-proc-macro-scope.rs
+++ b/tests/ui/deriving/built-in-proc-macro-scope.rs
@@ -2,14 +2,14 @@
//@ aux-build: another-proc-macro.rs
//@ compile-flags: -Zunpretty=expanded
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
#[macro_use]
extern crate another_proc_macro;
-use another_proc_macro::{pointee, AnotherMacro};
+use another_proc_macro::{AnotherMacro, pointee};
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
#[repr(transparent)]
pub struct Ptr<'a, #[pointee] T: ?Sized> {
data: &'a mut T,
diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout
index c649b7a..07767dc 100644
--- a/tests/ui/deriving/built-in-proc-macro-scope.stdout
+++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout
@@ -4,7 +4,7 @@
//@ aux-build: another-proc-macro.rs
//@ compile-flags: -Zunpretty=expanded
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
@@ -13,7 +13,7 @@
#[macro_use]
extern crate another_proc_macro;
-use another_proc_macro::{pointee, AnotherMacro};
+use another_proc_macro::{AnotherMacro, pointee};
#[repr(transparent)]
pub struct Ptr<'a, #[pointee] T: ?Sized> {
diff --git a/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs b/tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs
similarity index 82%
rename from tests/ui/deriving/smart-pointer-bounds-issue-127647.rs
rename to tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs
index 4cae1b3..a1aabf1 100644
--- a/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs
+++ b/tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs
@@ -1,8 +1,8 @@
//@ check-pass
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
#[repr(transparent)]
pub struct Ptr<'a, #[pointee] T: OnDrop + ?Sized, X> {
data: &'a mut T,
@@ -13,7 +13,7 @@
fn on_drop(&mut self);
}
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
#[repr(transparent)]
pub struct Ptr2<'a, #[pointee] T: ?Sized, X>
where
@@ -25,7 +25,7 @@
pub trait MyTrait<T: ?Sized> {}
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
#[repr(transparent)]
pub struct Ptr3<'a, #[pointee] T: ?Sized, X>
where
@@ -35,14 +35,14 @@
x: core::marker::PhantomData<X>,
}
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
#[repr(transparent)]
pub struct Ptr4<'a, #[pointee] T: MyTrait<T> + ?Sized, X> {
data: &'a mut T,
x: core::marker::PhantomData<X>,
}
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
#[repr(transparent)]
pub struct Ptr5<'a, #[pointee] T: ?Sized, X>
where
@@ -56,7 +56,7 @@
pub struct Ptr5Companion<T: ?Sized>(core::marker::PhantomData<T>);
pub struct Ptr5Companion2;
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
#[repr(transparent)]
pub struct Ptr6<'a, #[pointee] T: ?Sized, X: MyTrait<T> = (), const PARAM: usize = 0> {
data: &'a mut T,
@@ -65,7 +65,7 @@
// a reduced example from https://lore.kernel.org/all/20240402-linked-list-v1-1-b1c59ba7ae3b@google.com/
#[repr(transparent)]
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
pub struct ListArc<#[pointee] T, const ID: u64 = 0>
where
T: ListArcSafe<ID> + ?Sized,
diff --git a/tests/ui/deriving/deriving-smart-pointer-expanded.rs b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs
similarity index 74%
rename from tests/ui/deriving/deriving-smart-pointer-expanded.rs
rename to tests/ui/deriving/deriving-coerce-pointee-expanded.rs
index e48ad3d..94be703 100644
--- a/tests/ui/deriving/deriving-smart-pointer-expanded.rs
+++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs
@@ -1,17 +1,17 @@
//@ check-pass
//@ compile-flags: -Zunpretty=expanded
-#![feature(derive_smart_pointer)]
-use std::marker::SmartPointer;
+#![feature(derive_coerce_pointee)]
+use std::marker::CoercePointee;
pub trait MyTrait<T: ?Sized> {}
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
#[repr(transparent)]
struct MyPointer<'a, #[pointee] T: ?Sized> {
ptr: &'a T,
}
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
#[repr(transparent)]
pub struct MyPointer2<'a, Y, Z: MyTrait<T>, #[pointee] T: ?Sized + MyTrait<T>, X: MyTrait<T> = ()>
where
@@ -21,7 +21,7 @@
x: core::marker::PhantomData<X>,
}
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
#[repr(transparent)]
struct MyPointerWithoutPointee<'a, T: ?Sized> {
ptr: &'a T,
diff --git a/tests/ui/deriving/deriving-smart-pointer-expanded.stdout b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
similarity index 96%
rename from tests/ui/deriving/deriving-smart-pointer-expanded.stdout
rename to tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
index 68ef17f..d6eaca5 100644
--- a/tests/ui/deriving/deriving-smart-pointer-expanded.stdout
+++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
@@ -2,12 +2,12 @@
#![no_std]
//@ check-pass
//@ compile-flags: -Zunpretty=expanded
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
-use std::marker::SmartPointer;
+use std::marker::CoercePointee;
pub trait MyTrait<T: ?Sized> {}
diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.rs b/tests/ui/deriving/deriving-coerce-pointee-neg.rs
new file mode 100644
index 0000000..deef35c
--- /dev/null
+++ b/tests/ui/deriving/deriving-coerce-pointee-neg.rs
@@ -0,0 +1,134 @@
+#![feature(derive_coerce_pointee, arbitrary_self_types)]
+
+extern crate core;
+use std::marker::CoercePointee;
+
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
+enum NotStruct<'a, T: ?Sized> {
+ Variant(&'a T),
+}
+
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s with at least one field
+#[repr(transparent)]
+struct NoField<'a, #[pointee] T: ?Sized> {}
+//~^ ERROR: lifetime parameter `'a` is never used
+//~| ERROR: type parameter `T` is never used
+
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s with at least one field
+#[repr(transparent)]
+struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
+//~^ ERROR: lifetime parameter `'a` is never used
+//~| ERROR: type parameter `T` is never used
+
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s that are generic over at least one type
+#[repr(transparent)]
+struct NoGeneric<'a>(&'a u8);
+
+#[derive(CoercePointee)]
+//~^ ERROR: exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits
+#[repr(transparent)]
+struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> {
+ a: (&'a T1, &'a T2),
+}
+
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
+//~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits
+
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
+struct NotTransparent<'a, #[pointee] T: ?Sized> {
+ ptr: &'a T,
+}
+
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct NoMaybeSized<'a, #[pointee] T> {
+ //~^ ERROR: `derive(CoercePointee)` requires T to be marked `?Sized`
+ ptr: &'a T,
+}
+
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct PointeeOnField<'a, #[pointee] T: ?Sized> {
+ #[pointee]
+ //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+ ptr: &'a T,
+}
+
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct PointeeInTypeConstBlock<
+ 'a,
+ T: ?Sized = [u32; const {
+ struct UhOh<#[pointee] T>(T);
+ //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+ 10
+ }],
+> {
+ ptr: &'a T,
+}
+
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct PointeeInConstConstBlock<
+ 'a,
+ T: ?Sized,
+ const V: u32 = {
+ struct UhOh<#[pointee] T>(T);
+ //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+ 10
+ },
+> {
+ ptr: &'a T,
+}
+
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct PointeeInAnotherTypeConstBlock<'a, #[pointee] T: ?Sized> {
+ ptr: PointeeInConstConstBlock<
+ 'a,
+ T,
+ {
+ struct UhOh<#[pointee] T>(T);
+ //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+ 0
+ },
+ >,
+}
+
+// However, reordering attributes should work nevertheless.
+#[repr(transparent)]
+#[derive(CoercePointee)]
+struct ThisIsAPossibleCoercePointee<'a, #[pointee] T: ?Sized> {
+ ptr: &'a T,
+}
+
+// Also, these paths to Sized should work
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct StdSized<'a, #[pointee] T: ?std::marker::Sized> {
+ ptr: &'a T,
+}
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct CoreSized<'a, #[pointee] T: ?core::marker::Sized> {
+ ptr: &'a T,
+}
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct GlobalStdSized<'a, #[pointee] T: ?::std::marker::Sized> {
+ ptr: &'a T,
+}
+#[derive(CoercePointee)]
+#[repr(transparent)]
+struct GlobalCoreSized<'a, #[pointee] T: ?::core::marker::Sized> {
+ ptr: &'a T,
+}
+
+fn main() {}
diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr
new file mode 100644
index 0000000..e590d63
--- /dev/null
+++ b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr
@@ -0,0 +1,119 @@
+error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
+ --> $DIR/deriving-coerce-pointee-neg.rs:6:10
+ |
+LL | #[derive(CoercePointee)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `CoercePointee` can only be derived on `struct`s with at least one field
+ --> $DIR/deriving-coerce-pointee-neg.rs:12:10
+ |
+LL | #[derive(CoercePointee)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `CoercePointee` can only be derived on `struct`s with at least one field
+ --> $DIR/deriving-coerce-pointee-neg.rs:19:10
+ |
+LL | #[derive(CoercePointee)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `CoercePointee` can only be derived on `struct`s that are generic over at least one type
+ --> $DIR/deriving-coerce-pointee-neg.rs:26:10
+ |
+LL | #[derive(CoercePointee)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits
+ --> $DIR/deriving-coerce-pointee-neg.rs:31:10
+ |
+LL | #[derive(CoercePointee)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits
+ --> $DIR/deriving-coerce-pointee-neg.rs:40:39
+ |
+LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
+ | ^ ^
+
+error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
+ --> $DIR/deriving-coerce-pointee-neg.rs:43:10
+ |
+LL | #[derive(CoercePointee)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `derive(CoercePointee)` requires T to be marked `?Sized`
+ --> $DIR/deriving-coerce-pointee-neg.rs:51:36
+ |
+LL | struct NoMaybeSized<'a, #[pointee] T> {
+ | ^
+
+error: the `#[pointee]` attribute may only be used on generic parameters
+ --> $DIR/deriving-coerce-pointee-neg.rs:59:5
+ |
+LL | #[pointee]
+ | ^^^^^^^^^^
+
+error: the `#[pointee]` attribute may only be used on generic parameters
+ --> $DIR/deriving-coerce-pointee-neg.rs:69:33
+ |
+LL | struct UhOh<#[pointee] T>(T);
+ | ^^^^^^^^^^
+
+error: the `#[pointee]` attribute may only be used on generic parameters
+ --> $DIR/deriving-coerce-pointee-neg.rs:83:21
+ |
+LL | struct UhOh<#[pointee] T>(T);
+ | ^^^^^^^^^^
+
+error: the `#[pointee]` attribute may only be used on generic parameters
+ --> $DIR/deriving-coerce-pointee-neg.rs:98:25
+ |
+LL | struct UhOh<#[pointee] T>(T);
+ | ^^^^^^^^^^
+
+error[E0392]: lifetime parameter `'a` is never used
+ --> $DIR/deriving-coerce-pointee-neg.rs:15:16
+ |
+LL | struct NoField<'a, #[pointee] T: ?Sized> {}
+ | ^^ unused lifetime parameter
+ |
+ = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: type parameter `T` is never used
+ --> $DIR/deriving-coerce-pointee-neg.rs:15:31
+ |
+LL | struct NoField<'a, #[pointee] T: ?Sized> {}
+ | ^ unused type parameter
+ |
+ = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: lifetime parameter `'a` is never used
+ --> $DIR/deriving-coerce-pointee-neg.rs:22:20
+ |
+LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
+ | ^^ unused lifetime parameter
+ |
+ = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: type parameter `T` is never used
+ --> $DIR/deriving-coerce-pointee-neg.rs:22:35
+ |
+LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
+ | ^ unused type parameter
+ |
+ = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 16 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/tests/ui/deriving/deriving-smart-pointer.rs b/tests/ui/deriving/deriving-coerce-pointee.rs
similarity index 90%
rename from tests/ui/deriving/deriving-smart-pointer.rs
rename to tests/ui/deriving/deriving-coerce-pointee.rs
index d34a502..26762e4 100644
--- a/tests/ui/deriving/deriving-smart-pointer.rs
+++ b/tests/ui/deriving/deriving-coerce-pointee.rs
@@ -1,9 +1,9 @@
//@ run-pass
-#![feature(derive_smart_pointer, arbitrary_self_types)]
+#![feature(derive_coerce_pointee, arbitrary_self_types)]
-use std::marker::SmartPointer;
+use std::marker::CoercePointee;
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
#[repr(transparent)]
struct MyPointer<'a, #[pointee] T: ?Sized> {
ptr: &'a T,
diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.rs b/tests/ui/deriving/deriving-smart-pointer-neg.rs
deleted file mode 100644
index 41d3039..0000000
--- a/tests/ui/deriving/deriving-smart-pointer-neg.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-#![feature(derive_smart_pointer, arbitrary_self_types)]
-
-extern crate core;
-use std::marker::SmartPointer;
-
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
-enum NotStruct<'a, T: ?Sized> {
- Variant(&'a T),
-}
-
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field
-#[repr(transparent)]
-struct NoField<'a, #[pointee] T: ?Sized> {}
-//~^ ERROR: lifetime parameter `'a` is never used
-//~| ERROR: type parameter `T` is never used
-
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field
-#[repr(transparent)]
-struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
-//~^ ERROR: lifetime parameter `'a` is never used
-//~| ERROR: type parameter `T` is never used
-
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s that are generic over at least one type
-#[repr(transparent)]
-struct NoGeneric<'a>(&'a u8);
-
-#[derive(SmartPointer)]
-//~^ ERROR: exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits
-#[repr(transparent)]
-struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> {
- a: (&'a T1, &'a T2),
-}
-
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
-//~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits
-
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
-struct NotTransparent<'a, #[pointee] T: ?Sized> {
- ptr: &'a T,
-}
-
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct NoMaybeSized<'a, #[pointee] T> {
- //~^ ERROR: `derive(SmartPointer)` requires T to be marked `?Sized`
- ptr: &'a T,
-}
-
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct PointeeOnField<'a, #[pointee] T: ?Sized> {
- #[pointee]
- //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
- ptr: &'a T
-}
-
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> {
- //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
- ptr: &'a T,
-}
-
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct PointeeInConstConstBlock<
- 'a,
- T: ?Sized,
- const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }>
- //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
-{
- ptr: &'a T,
-}
-
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct PointeeInAnotherTypeConstBlock<'a, #[pointee] T: ?Sized> {
- ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }>
- //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
-}
-
-// However, reordering attributes should work nevertheless.
-#[repr(transparent)]
-#[derive(SmartPointer)]
-struct ThisIsAPossibleSmartPointer<'a, #[pointee] T: ?Sized> {
- ptr: &'a T,
-}
-
-// Also, these paths to Sized should work
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct StdSized<'a, #[pointee] T: ?std::marker::Sized> {
- ptr: &'a T,
-}
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct CoreSized<'a, #[pointee] T: ?core::marker::Sized> {
- ptr: &'a T,
-}
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct GlobalStdSized<'a, #[pointee] T: ?::std::marker::Sized> {
- ptr: &'a T,
-}
-#[derive(SmartPointer)]
-#[repr(transparent)]
-struct GlobalCoreSized<'a, #[pointee] T: ?::core::marker::Sized> {
- ptr: &'a T,
-}
-
-fn main() {}
diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.stderr b/tests/ui/deriving/deriving-smart-pointer-neg.stderr
deleted file mode 100644
index 9ab1176..0000000
--- a/tests/ui/deriving/deriving-smart-pointer-neg.stderr
+++ /dev/null
@@ -1,119 +0,0 @@
-error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
- --> $DIR/deriving-smart-pointer-neg.rs:6:10
- |
-LL | #[derive(SmartPointer)]
- | ^^^^^^^^^^^^
- |
- = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `SmartPointer` can only be derived on `struct`s with at least one field
- --> $DIR/deriving-smart-pointer-neg.rs:12:10
- |
-LL | #[derive(SmartPointer)]
- | ^^^^^^^^^^^^
- |
- = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `SmartPointer` can only be derived on `struct`s with at least one field
- --> $DIR/deriving-smart-pointer-neg.rs:19:10
- |
-LL | #[derive(SmartPointer)]
- | ^^^^^^^^^^^^
- |
- = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `SmartPointer` can only be derived on `struct`s that are generic over at least one type
- --> $DIR/deriving-smart-pointer-neg.rs:26:10
- |
-LL | #[derive(SmartPointer)]
- | ^^^^^^^^^^^^
- |
- = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits
- --> $DIR/deriving-smart-pointer-neg.rs:31:10
- |
-LL | #[derive(SmartPointer)]
- | ^^^^^^^^^^^^
- |
- = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits
- --> $DIR/deriving-smart-pointer-neg.rs:40:39
- |
-LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
- | ^ ^
-
-error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
- --> $DIR/deriving-smart-pointer-neg.rs:43:10
- |
-LL | #[derive(SmartPointer)]
- | ^^^^^^^^^^^^
- |
- = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `derive(SmartPointer)` requires T to be marked `?Sized`
- --> $DIR/deriving-smart-pointer-neg.rs:51:36
- |
-LL | struct NoMaybeSized<'a, #[pointee] T> {
- | ^
-
-error: the `#[pointee]` attribute may only be used on generic parameters
- --> $DIR/deriving-smart-pointer-neg.rs:59:5
- |
-LL | #[pointee]
- | ^^^^^^^^^^
-
-error: the `#[pointee]` attribute may only be used on generic parameters
- --> $DIR/deriving-smart-pointer-neg.rs:66:74
- |
-LL | struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> {
- | ^^^^^^^^^^
-
-error: the `#[pointee]` attribute may only be used on generic parameters
- --> $DIR/deriving-smart-pointer-neg.rs:76:34
- |
-LL | const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }>
- | ^^^^^^^^^^
-
-error: the `#[pointee]` attribute may only be used on generic parameters
- --> $DIR/deriving-smart-pointer-neg.rs:85:56
- |
-LL | ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }>
- | ^^^^^^^^^^
-
-error[E0392]: lifetime parameter `'a` is never used
- --> $DIR/deriving-smart-pointer-neg.rs:15:16
- |
-LL | struct NoField<'a, #[pointee] T: ?Sized> {}
- | ^^ unused lifetime parameter
- |
- = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
-
-error[E0392]: type parameter `T` is never used
- --> $DIR/deriving-smart-pointer-neg.rs:15:31
- |
-LL | struct NoField<'a, #[pointee] T: ?Sized> {}
- | ^ unused type parameter
- |
- = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-
-error[E0392]: lifetime parameter `'a` is never used
- --> $DIR/deriving-smart-pointer-neg.rs:22:20
- |
-LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
- | ^^ unused lifetime parameter
- |
- = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
-
-error[E0392]: type parameter `T` is never used
- --> $DIR/deriving-smart-pointer-neg.rs:22:35
- |
-LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
- | ^ unused type parameter
- |
- = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-
-error: aborting due to 16 previous errors
-
-For more information about this error, try `rustc --explain E0392`.
diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.rs b/tests/ui/deriving/proc-macro-attribute-mixing.rs
index 489665e..80a0d06 100644
--- a/tests/ui/deriving/proc-macro-attribute-mixing.rs
+++ b/tests/ui/deriving/proc-macro-attribute-mixing.rs
@@ -1,5 +1,5 @@
// This test certify that we can mix attribute macros from Rust and external proc-macros.
-// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(SmartPointer)]` uses
+// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(CoercePointee)]` uses
// `#[pointee]`.
// The scoping rule should allow the use of the said two attributes when external proc-macros
// are in scope.
@@ -8,7 +8,7 @@
//@ aux-build: another-proc-macro.rs
//@ compile-flags: -Zunpretty=expanded
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
#[macro_use]
extern crate another_proc_macro;
diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.stdout b/tests/ui/deriving/proc-macro-attribute-mixing.stdout
index f314f6e..03128c6 100644
--- a/tests/ui/deriving/proc-macro-attribute-mixing.stdout
+++ b/tests/ui/deriving/proc-macro-attribute-mixing.stdout
@@ -1,7 +1,7 @@
#![feature(prelude_import)]
#![no_std]
// This test certify that we can mix attribute macros from Rust and external proc-macros.
-// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(SmartPointer)]` uses
+// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(CoercePointee)]` uses
// `#[pointee]`.
// The scoping rule should allow the use of the said two attributes when external proc-macros
// are in scope.
@@ -10,7 +10,7 @@
//@ aux-build: another-proc-macro.rs
//@ compile-flags: -Zunpretty=expanded
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
diff --git a/tests/ui/drop/drop_order.rs b/tests/ui/drop/drop_order.rs
index 9706cb6..7a999c7 100644
--- a/tests/ui/drop/drop_order.rs
+++ b/tests/ui/drop/drop_order.rs
@@ -105,6 +105,7 @@
() => self.print(10),
}
+ #[cfg(edition2021)]
match {
match self.option_loud_drop(14) {
_ => {
@@ -115,6 +116,17 @@
} {
_ => self.print(12),
}
+ #[cfg(edition2024)]
+ match {
+ match self.option_loud_drop(12) {
+ _ => {
+ self.print(11);
+ self.option_loud_drop(14)
+ }
+ }
+ } {
+ _ => self.print(13),
+ }
match {
loop {
diff --git a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs
index b22e72b..fde542c 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs
+++ b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs
@@ -1,15 +1,11 @@
-// This test ensures that `tail_expr_drop_order` does not activate in case Edition 2024 is not used
-// or the feature gate `shorter_tail_lifetimes` is disabled.
+// This test is to demonstrate that the lint is gated behind Edition and
+// is triggered only for Edition 2021 and before.
-//@ revisions: neither no_feature_gate edition_less_than_2024
//@ check-pass
-//@ [neither] edition: 2021
-//@ [no_feature_gate] compile-flags: -Z unstable-options
-//@ [no_feature_gate] edition: 2024
-//@ [edition_less_than_2024] edition: 2021
+//@ edition: 2024
+//@ compile-flags: -Z unstable-options
#![deny(tail_expr_drop_order)]
-#![cfg_attr(edition_less_than_2024, feature(shorter_tail_lifetimes))]
struct LoudDropper;
impl Drop for LoudDropper {
diff --git a/tests/ui/drop/lint-tail-expr-drop-order.rs b/tests/ui/drop/lint-tail-expr-drop-order.rs
index 0aa0ef0..d61abae 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order.rs
+++ b/tests/ui/drop/lint-tail-expr-drop-order.rs
@@ -1,12 +1,10 @@
-//@ compile-flags: -Z unstable-options
-//@ edition: 2024
+//@ edition: 2021
// Edition 2024 lint for change in drop order at tail expression
// This lint is to capture potential change in program semantics
// due to implementation of RFC 3606 <https://github.com/rust-lang/rfcs/pull/3606>
#![deny(tail_expr_drop_order)]
-#![feature(shorter_tail_lifetimes)]
struct LoudDropper;
impl Drop for LoudDropper {
diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr
index 630f0a8..6775c4c 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order.stderr
+++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr
@@ -1,5 +1,5 @@
error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
- --> $DIR/lint-tail-expr-drop-order.rs:29:15
+ --> $DIR/lint-tail-expr-drop-order.rs:27:15
|
LL | let x = LoudDropper;
| - these values have significant drop implementation and will observe changes in drop order under Edition 2024
@@ -10,13 +10,13 @@
= warning: this changes meaning in Rust 2024
= note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
note: the lint level is defined here
- --> $DIR/lint-tail-expr-drop-order.rs:8:9
+ --> $DIR/lint-tail-expr-drop-order.rs:7:9
|
LL | #![deny(tail_expr_drop_order)]
| ^^^^^^^^^^^^^^^^^^^^
error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
- --> $DIR/lint-tail-expr-drop-order.rs:36:23
+ --> $DIR/lint-tail-expr-drop-order.rs:34:23
|
LL | let x = LoudDropper;
| - these values have significant drop implementation and will observe changes in drop order under Edition 2024
@@ -27,7 +27,7 @@
= note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
- --> $DIR/lint-tail-expr-drop-order.rs:65:19
+ --> $DIR/lint-tail-expr-drop-order.rs:63:19
|
LL | let x = LoudDropper;
| - these values have significant drop implementation and will observe changes in drop order under Edition 2024
diff --git a/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr b/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr
index 75fc34e..bcce796 100644
--- a/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr
+++ b/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr
@@ -1,5 +1,5 @@
error[E0716]: temporary value dropped while borrowed
- --> $DIR/tail-expr-drop-order-negative.rs:11:15
+ --> $DIR/tail-expr-drop-order-negative.rs:9:15
|
LL | x.replace(std::cell::RefCell::new(123).borrow()).is_some()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
diff --git a/tests/ui/drop/tail-expr-drop-order-negative.rs b/tests/ui/drop/tail-expr-drop-order-negative.rs
index c570b3a..5ad04d0 100644
--- a/tests/ui/drop/tail-expr-drop-order-negative.rs
+++ b/tests/ui/drop/tail-expr-drop-order-negative.rs
@@ -3,8 +3,6 @@
//@ [edition2024] edition: 2024
//@ [edition2021] check-pass
-#![feature(shorter_tail_lifetimes)]
-
fn why_would_you_do_this() -> bool {
let mut x = None;
// Make a temporary `RefCell` and put a `Ref` that borrows it in `x`.
diff --git a/tests/ui/drop/tail-expr-drop-order.rs b/tests/ui/drop/tail-expr-drop-order.rs
index 5d87f98..80968b8 100644
--- a/tests/ui/drop/tail-expr-drop-order.rs
+++ b/tests/ui/drop/tail-expr-drop-order.rs
@@ -4,7 +4,6 @@
//@ edition: 2024
//@ run-pass
-#![feature(shorter_tail_lifetimes)]
#![allow(unused_imports)]
#![allow(dead_code)]
#![allow(unused_variables)]
diff --git a/tests/ui/dropck/const_drop_is_valid.stderr b/tests/ui/dropck/const_drop_is_valid.stderr
index f15b7ba..2383a66 100644
--- a/tests/ui/dropck/const_drop_is_valid.stderr
+++ b/tests/ui/dropck/const_drop_is_valid.stderr
@@ -17,11 +17,6 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: const `impl` for trait `Drop` which is not marked with `#[const_trait]`
--> $DIR/const_drop_is_valid.rs:6:12
|
@@ -39,7 +34,7 @@
|
= help: implement the missing item: `fn drop(&mut self) { todo!() }`
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors; 1 warning emitted
Some errors have detailed explanations: E0046, E0658.
For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/error-codes/E0081.rs b/tests/ui/error-codes/E0081.rs
index f53fda8..8fdb27c 100644
--- a/tests/ui/error-codes/E0081.rs
+++ b/tests/ui/error-codes/E0081.rs
@@ -50,5 +50,47 @@
//~^ NOTE `-2` assigned here
}
+// Test for #131902
+// Ensure that casting an enum with too many variants for its repr
+// does not ICE
+#[repr(u8)]
+enum TooManyVariants {
+ //~^ ERROR discriminant value `0` assigned more than once
+ X000, X001, X002, X003, X004, X005, X006, X007, X008, X009,
+ //~^ NOTE `0` assigned here
+ //~| NOTE discriminant for `X256` incremented from this startpoint
+ X010, X011, X012, X013, X014, X015, X016, X017, X018, X019,
+ X020, X021, X022, X023, X024, X025, X026, X027, X028, X029,
+ X030, X031, X032, X033, X034, X035, X036, X037, X038, X039,
+ X040, X041, X042, X043, X044, X045, X046, X047, X048, X049,
+ X050, X051, X052, X053, X054, X055, X056, X057, X058, X059,
+ X060, X061, X062, X063, X064, X065, X066, X067, X068, X069,
+ X070, X071, X072, X073, X074, X075, X076, X077, X078, X079,
+ X080, X081, X082, X083, X084, X085, X086, X087, X088, X089,
+ X090, X091, X092, X093, X094, X095, X096, X097, X098, X099,
+ X100, X101, X102, X103, X104, X105, X106, X107, X108, X109,
+ X110, X111, X112, X113, X114, X115, X116, X117, X118, X119,
+ X120, X121, X122, X123, X124, X125, X126, X127, X128, X129,
+ X130, X131, X132, X133, X134, X135, X136, X137, X138, X139,
+ X140, X141, X142, X143, X144, X145, X146, X147, X148, X149,
+ X150, X151, X152, X153, X154, X155, X156, X157, X158, X159,
+ X160, X161, X162, X163, X164, X165, X166, X167, X168, X169,
+ X170, X171, X172, X173, X174, X175, X176, X177, X178, X179,
+ X180, X181, X182, X183, X184, X185, X186, X187, X188, X189,
+ X190, X191, X192, X193, X194, X195, X196, X197, X198, X199,
+ X200, X201, X202, X203, X204, X205, X206, X207, X208, X209,
+ X210, X211, X212, X213, X214, X215, X216, X217, X218, X219,
+ X220, X221, X222, X223, X224, X225, X226, X227, X228, X229,
+ X230, X231, X232, X233, X234, X235, X236, X237, X238, X239,
+ X240, X241, X242, X243, X244, X245, X246, X247, X248, X249,
+ X250, X251, X252, X253, X254, X255,
+ X256,
+ //~^ ERROR enum discriminant overflowed
+ //~| NOTE overflowed on value after 255
+ //~| NOTE explicitly set `X256 = 0`
+ //~| NOTE `0` assigned here
+}
+
fn main() {
+ TooManyVariants::X256 as u8;
}
diff --git a/tests/ui/error-codes/E0081.stderr b/tests/ui/error-codes/E0081.stderr
index d4b21f6..91445ee 100644
--- a/tests/ui/error-codes/E0081.stderr
+++ b/tests/ui/error-codes/E0081.stderr
@@ -73,6 +73,30 @@
LL | V9,
| -- `-2` assigned here
-error: aborting due to 5 previous errors
+error[E0370]: enum discriminant overflowed
+ --> $DIR/E0081.rs:87:5
+ |
+LL | X256,
+ | ^^^^ overflowed on value after 255
+ |
+ = note: explicitly set `X256 = 0` if that is desired outcome
-For more information about this error, try `rustc --explain E0081`.
+error[E0081]: discriminant value `0` assigned more than once
+ --> $DIR/E0081.rs:57:1
+ |
+LL | enum TooManyVariants {
+ | ^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | X000, X001, X002, X003, X004, X005, X006, X007, X008, X009,
+ | ----
+ | |
+ | `0` assigned here
+ | discriminant for `X256` incremented from this startpoint (`X000` + 256 variants later => `X256` = 0)
+...
+LL | X256,
+ | ---- `0` assigned here
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0081, E0370.
+For more information about an error, try `rustc --explain E0081`.
diff --git a/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs
new file mode 100644
index 0000000..69bc70e
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs
@@ -0,0 +1,9 @@
+use std::marker::CoercePointee; //~ ERROR use of unstable library feature 'derive_coerce_pointee'
+
+#[derive(CoercePointee)] //~ ERROR use of unstable library feature 'derive_coerce_pointee'
+#[repr(transparent)]
+struct MyPointer<'a, #[pointee] T: ?Sized> {
+ ptr: &'a T,
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr
new file mode 100644
index 0000000..0b52ceb
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr
@@ -0,0 +1,23 @@
+error[E0658]: use of unstable library feature 'derive_coerce_pointee'
+ --> $DIR/feature-gate-derive-coerce-pointee.rs:3:10
+ |
+LL | #[derive(CoercePointee)]
+ | ^^^^^^^^^^^^^
+ |
+ = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
+ = help: add `#![feature(derive_coerce_pointee)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'derive_coerce_pointee'
+ --> $DIR/feature-gate-derive-coerce-pointee.rs:1:5
+ |
+LL | use std::marker::CoercePointee;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
+ = help: add `#![feature(derive_coerce_pointee)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs
deleted file mode 100644
index 7b4764e..0000000
--- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use std::marker::SmartPointer; //~ ERROR use of unstable library feature 'derive_smart_pointer'
-
-#[derive(SmartPointer)] //~ ERROR use of unstable library feature 'derive_smart_pointer'
-#[repr(transparent)]
-struct MyPointer<'a, #[pointee] T: ?Sized> {
- ptr: &'a T,
-}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr
deleted file mode 100644
index ea4d127..0000000
--- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0658]: use of unstable library feature 'derive_smart_pointer'
- --> $DIR/feature-gate-derive-smart-pointer.rs:3:10
- |
-LL | #[derive(SmartPointer)]
- | ^^^^^^^^^^^^
- |
- = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
- = help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature 'derive_smart_pointer'
- --> $DIR/feature-gate-derive-smart-pointer.rs:1:5
- |
-LL | use std::marker::SmartPointer;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
- = help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr
index 319056a..d599523 100644
--- a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr
+++ b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr
@@ -1,4 +1,18 @@
error: can't mark as unstable using an already stable feature
+ --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
+ |
+LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
+LL | const fn my_fun() {}
+ | -------------------- the stability attribute annotates this item
+ |
+help: consider removing the attribute
+ --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
+ |
+LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: can't mark as unstable using an already stable feature
--> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1
|
LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
@@ -13,19 +27,5 @@
LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: can't mark as unstable using an already stable feature
- --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
- |
-LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable
-LL | const fn my_fun() {}
- | -------------------- the stability attribute annotates this item
- |
-help: consider removing the attribute
- --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1
- |
-LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
error: aborting due to 2 previous errors
diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs
new file mode 100644
index 0000000..f1c196a
--- /dev/null
+++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs
@@ -0,0 +1,20 @@
+//@ only-linux
+//@ compile-flags: --error-format=human --color=always
+//@ error-pattern: the trait bound
+
+trait Foo<T>: Bar<T> {}
+
+trait Bar<T> {}
+
+struct Struct;
+
+impl<T, K> Foo<K> for T where T: Bar<K>
+{}
+
+impl<'a> Bar<()> for Struct {}
+
+fn foo() -> impl Foo<i32> {
+ Struct
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
new file mode 100644
index 0000000..e09b96e
--- /dev/null
+++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
@@ -0,0 +1,62 @@
+<svg width="1104px" height="344px" xmlns="http://www.w3.org/2000/svg">
+ <style>
+ .fg { fill: #AAAAAA }
+ .bg { background: #000000 }
+ .fg-ansi256-009 { fill: #FF5555 }
+ .fg-ansi256-010 { fill: #55FF55 }
+ .fg-ansi256-012 { fill: #5555FF }
+ .fg-magenta { fill: #AA00AA }
+ .container {
+ padding: 0 10px;
+ line-height: 18px;
+ }
+ .bold { font-weight: bold; }
+ tspan {
+ font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
+ white-space: pre;
+ line-height: 18px;
+ }
+ </style>
+
+ <rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
+
+ <text xml:space="preserve" class="container fg">
+ <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: the trait bound `Struct: Foo<i32>` is not satisfied</tspan>
+</tspan>
+ <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/highlight-difference-between-expected-trait-and-found-trait.rs:16:13</tspan>
+</tspan>
+ <tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+</tspan>
+ <tspan x="10px" y="82px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> fn foo() -> impl Foo<i32> {</tspan>
+</tspan>
+ <tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">the trait `Bar<i32>` is not implemented for `Struct`, which is required by `Struct: Foo<i32>`</tspan>
+</tspan>
+ <tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+</tspan>
+ <tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Bar<()>` </tspan><tspan class="fg-magenta bold">is</tspan><tspan> implemented for `Struct`</tspan>
+</tspan>
+ <tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: for that trait implementation, expected `</tspan><tspan class="fg-magenta bold">()</tspan><tspan>`, found `</tspan><tspan class="fg-magenta bold">i32</tspan><tspan>`</tspan>
+</tspan>
+ <tspan x="10px" y="172px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required for `Struct` to implement `Foo<i32>`</tspan>
+</tspan>
+ <tspan x="10px" y="190px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/highlight-difference-between-expected-trait-and-found-trait.rs:11:12</tspan>
+</tspan>
+ <tspan x="10px" y="208px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+</tspan>
+ <tspan x="10px" y="226px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> impl<T, K> Foo<K> for T where T: Bar<K></tspan>
+</tspan>
+ <tspan x="10px" y="244px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010 bold">^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-010 bold">^</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">------</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">unsatisfied trait bound introduced here</tspan>
+</tspan>
+ <tspan x="10px" y="262px">
+</tspan>
+ <tspan x="10px" y="280px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 1 previous error</tspan>
+</tspan>
+ <tspan x="10px" y="298px">
+</tspan>
+ <tspan x="10px" y="316px"><tspan class="bold">For more information about this error, try `rustc --explain E0277`.</tspan>
+</tspan>
+ <tspan x="10px" y="334px">
+</tspan>
+ </text>
+
+</svg>
diff --git a/tests/ui/impl-trait/impl_trait_projections.rs b/tests/ui/impl-trait/impl_trait_projections.rs
index 365ac85..2c277ae 100644
--- a/tests/ui/impl-trait/impl_trait_projections.rs
+++ b/tests/ui/impl-trait/impl_trait_projections.rs
@@ -10,30 +10,27 @@
}
fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
-//~^ ERROR `impl Trait` is not allowed in path parameters
-//~| ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
x.next().unwrap()
}
fn projection_with_named_trait_is_disallowed(mut x: impl Iterator)
-> <impl Iterator as Iterator>::Item
-//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
{
x.next().unwrap()
}
fn projection_with_named_trait_inside_path_is_disallowed()
-> <::std::ops::Range<impl Debug> as Iterator>::Item
-//~^ ERROR `impl Trait` is not allowed in path parameters
-//~| ERROR `impl Debug: Step` is not satisfied
+//~^ ERROR `impl Trait` is not allowed in paths
{
- //~^ ERROR `impl Debug: Step` is not satisfied
(1i32..100).next().unwrap()
}
fn projection_from_impl_trait_inside_dyn_trait_is_disallowed()
-> <dyn Iterator<Item = impl Debug> as Iterator>::Item
-//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
{
panic!()
}
diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr
index d62e3ac..5e0b80f 100644
--- a/tests/ui/impl-trait/impl_trait_projections.stderr
+++ b/tests/ui/impl-trait/impl_trait_projections.stderr
@@ -1,73 +1,35 @@
-error[E0667]: `impl Trait` is not allowed in path parameters
+error[E0562]: `impl Trait` is not allowed in paths
--> $DIR/impl_trait_projections.rs:12:51
|
LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
| ^^^^^^^^^^^^^
+ |
+ = note: `impl Trait` is only allowed in arguments and return types of functions and methods
-error[E0667]: `impl Trait` is not allowed in path parameters
- --> $DIR/impl_trait_projections.rs:19:9
+error[E0562]: `impl Trait` is not allowed in paths
+ --> $DIR/impl_trait_projections.rs:18:9
|
LL | -> <impl Iterator as Iterator>::Item
| ^^^^^^^^^^^^^
+ |
+ = note: `impl Trait` is only allowed in arguments and return types of functions and methods
-error[E0667]: `impl Trait` is not allowed in path parameters
- --> $DIR/impl_trait_projections.rs:26:27
+error[E0562]: `impl Trait` is not allowed in paths
+ --> $DIR/impl_trait_projections.rs:25:27
|
LL | -> <::std::ops::Range<impl Debug> as Iterator>::Item
| ^^^^^^^^^^
+ |
+ = note: `impl Trait` is only allowed in arguments and return types of functions and methods
-error[E0667]: `impl Trait` is not allowed in path parameters
- --> $DIR/impl_trait_projections.rs:35:29
+error[E0562]: `impl Trait` is not allowed in paths
+ --> $DIR/impl_trait_projections.rs:32:29
|
LL | -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
| ^^^^^^^^^^
-
-error[E0667]: `impl Trait` is not allowed in path parameters
- --> $DIR/impl_trait_projections.rs:12:51
|
-LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
- | ^^^^^^^^^^^^^
+ = note: `impl Trait` is only allowed in arguments and return types of functions and methods
-error[E0277]: the trait bound `impl Debug: Step` is not satisfied
- --> $DIR/impl_trait_projections.rs:26:8
- |
-LL | -> <::std::ops::Range<impl Debug> as Iterator>::Item
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator`
- |
- = help: the following other types implement trait `Step`:
- Char
- Ipv4Addr
- Ipv6Addr
- char
- i128
- i16
- i32
- i64
- and 8 others
- = note: required for `std::ops::Range<impl Debug>` to implement `Iterator`
+error: aborting due to 4 previous errors
-error[E0277]: the trait bound `impl Debug: Step` is not satisfied
- --> $DIR/impl_trait_projections.rs:29:1
- |
-LL | / {
-LL | |
-LL | | (1i32..100).next().unwrap()
-LL | | }
- | |_^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator`
- |
- = help: the following other types implement trait `Step`:
- Char
- Ipv4Addr
- Ipv6Addr
- char
- i128
- i16
- i32
- i64
- and 8 others
- = note: required for `std::ops::Range<impl Debug>` to implement `Iterator`
-
-error: aborting due to 7 previous errors
-
-Some errors have detailed explanations: E0277, E0667.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs
new file mode 100644
index 0000000..c2c22cd
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs
@@ -0,0 +1,22 @@
+// issue: rust-lang/rust#126725
+
+trait Foo {
+ fn foo<'a>() -> <&'a impl Sized as Bar>::Output;
+ //~^ ERROR `impl Trait` is not allowed in paths
+}
+
+trait Bar {
+ type Output;
+}
+
+impl<'a> Bar for &'a () {
+ type Output = &'a i32;
+}
+
+impl Foo for () {
+ fn foo<'a>() -> <&'a Self as Bar>::Output {
+ &0
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr
new file mode 100644
index 0000000..bea7ccd
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr
@@ -0,0 +1,11 @@
+error[E0562]: `impl Trait` is not allowed in paths
+ --> $DIR/bad-projection-from-opaque.rs:4:26
+ |
+LL | fn foo<'a>() -> <&'a impl Sized as Bar>::Output;
+ | ^^^^^^^^^^
+ |
+ = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
index c5ecd1c..9466668 100644
--- a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
+++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
@@ -6,7 +6,7 @@
pub trait Bar { }
pub trait Quux<T> { type Assoc; }
pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
-//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
impl<T> Quux<T> for () { type Assoc = u32; }
fn main() { }
diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr
index 55f4778..25547df 100644
--- a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr
+++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr
@@ -1,9 +1,11 @@
-error[E0667]: `impl Trait` is not allowed in path parameters
+error[E0562]: `impl Trait` is not allowed in paths
--> $DIR/issue-57979-impl-trait-in-path.rs:8:48
|
LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
| ^^^^^^^^
+ |
+ = note: `impl Trait` is only allowed in arguments and return types of functions and methods
error: aborting due to 1 previous error
-For more information about this error, try `rustc --explain E0667`.
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr
index e0d193b..f914266 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.stderr
+++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr
@@ -1,14 +1,30 @@
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/normalize-tait-in-const.rs:26:42
+ --> $DIR/normalize-tait-in-const.rs:26:35
|
LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/normalize-tait-in-const.rs:26:69
+ --> $DIR/normalize-tait-in-const.rs:26:62
|
LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
- | ^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/normalize-tait-in-const.rs:26:35
+ |
+LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/normalize-tait-in-const.rs:26:62
+ |
+LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0015]: cannot call non-const closure in constant functions
--> $DIR/normalize-tait-in-const.rs:27:5
@@ -21,10 +37,6 @@
|
LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct + ~const Fn(&foo::Alias<'_>)>(fun: F) {
| ++++++++++++++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0493]: destructor of `F` cannot be evaluated at compile-time
--> $DIR/normalize-tait-in-const.rs:26:79
@@ -35,7 +47,7 @@
LL | }
| - value is dropped here
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
Some errors have detailed explanations: E0015, E0493.
For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/intrinsics/const-eval-select-stability.rs b/tests/ui/intrinsics/const-eval-select-stability.rs
index 575bc0c..25cbada 100644
--- a/tests/ui/intrinsics/const-eval-select-stability.rs
+++ b/tests/ui/intrinsics/const-eval-select-stability.rs
@@ -15,7 +15,7 @@
#[rustc_const_stable(since = "1.0", feature = "const_hey")]
pub const fn hey() {
const_eval_select((), nothing, log);
- //~^ ERROR `const_eval_select` is not yet stable as a const fn
+ //~^ ERROR cannot use `#[feature(const_eval_select)]`
}
fn main() {}
diff --git a/tests/ui/intrinsics/const-eval-select-stability.stderr b/tests/ui/intrinsics/const-eval-select-stability.stderr
index 335b987..5f443b1 100644
--- a/tests/ui/intrinsics/const-eval-select-stability.stderr
+++ b/tests/ui/intrinsics/const-eval-select-stability.stderr
@@ -1,10 +1,19 @@
-error: `const_eval_select` is not yet stable as a const fn
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_eval_select)]`
--> $DIR/const-eval-select-stability.rs:17:5
|
LL | const_eval_select((), nothing, log);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | pub const fn hey() {
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(const_eval_select)]
+LL | pub const fn hey() {
+ |
error: aborting due to 1 previous error
diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr
index 55983a4..c59e357 100644
--- a/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
--> $DIR/safe-intrinsic-mismatch.rs:11:5
|
@@ -47,6 +42,6 @@
= note: expected signature `unsafe fn(_, _, _)`
found signature `fn(_, _, _)`
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/issues/issue-25901.stderr b/tests/ui/issues/issue-25901.stderr
index 3fedfd9..bcbc805 100644
--- a/tests/ui/issues/issue-25901.stderr
+++ b/tests/ui/issues/issue-25901.stderr
@@ -17,10 +17,6 @@
| ^^^^^^^^^^^^^^^^
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 1 previous error
diff --git a/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr b/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr
index 858be42..157a1c5 100644
--- a/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr
+++ b/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr
@@ -1,5 +1,5 @@
error[E0597]: `cell` does not live long enough
- --> $DIR/refcell-in-tail-expr.rs:12:27
+ --> $DIR/refcell-in-tail-expr.rs:10:27
|
LL | let cell = std::cell::RefCell::new(0u8);
| ---- binding `cell` declared here
diff --git a/tests/ui/lifetimes/refcell-in-tail-expr.rs b/tests/ui/lifetimes/refcell-in-tail-expr.rs
index b1814c1..595e951 100644
--- a/tests/ui/lifetimes/refcell-in-tail-expr.rs
+++ b/tests/ui/lifetimes/refcell-in-tail-expr.rs
@@ -4,8 +4,6 @@
//@ [edition2024] compile-flags: -Zunstable-options
//@ [edition2024] check-pass
-#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))]
-
fn main() {
let cell = std::cell::RefCell::new(0u8);
diff --git a/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr b/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr
index ad28ae2..3c074c5 100644
--- a/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr
+++ b/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr
@@ -1,5 +1,5 @@
error[E0597]: `c` does not live long enough
- --> $DIR/shorter-tail-expr-lifetime.rs:10:5
+ --> $DIR/shorter-tail-expr-lifetime.rs:8:5
|
LL | let c = std::cell::RefCell::new("..");
| - binding `c` declared here
diff --git a/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs b/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs
index 0392b6c..4195a8b 100644
--- a/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs
+++ b/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs
@@ -3,8 +3,6 @@
//@ [edition2024] edition: 2024
//@ [edition2024] run-pass
-#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))]
-
fn f() -> usize {
let c = std::cell::RefCell::new("..");
c.borrow().len() //[edition2021]~ ERROR: `c` does not live long enough
diff --git a/tests/ui/lifetimes/tail-expr-in-nested-expr.rs b/tests/ui/lifetimes/tail-expr-in-nested-expr.rs
index a8989f2..2ac97af 100644
--- a/tests/ui/lifetimes/tail-expr-in-nested-expr.rs
+++ b/tests/ui/lifetimes/tail-expr-in-nested-expr.rs
@@ -1,8 +1,6 @@
//@ edition: 2024
//@ compile-flags: -Zunstable-options
-#![feature(shorter_tail_lifetimes)]
-
fn main() {
let _ = { String::new().as_str() }.len();
//~^ ERROR temporary value dropped while borrowed
diff --git a/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr b/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr
index f699d18..96e88ea 100644
--- a/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr
+++ b/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr
@@ -1,5 +1,5 @@
error[E0716]: temporary value dropped while borrowed
- --> $DIR/tail-expr-in-nested-expr.rs:7:15
+ --> $DIR/tail-expr-in-nested-expr.rs:5:15
|
LL | let _ = { String::new().as_str() }.len();
| ^^^^^^^^^^^^^---------
diff --git a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs
index cdfd353..ec74596 100644
--- a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs
+++ b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs
@@ -4,7 +4,6 @@
//@ [edition2024] edition: 2024
//@ run-pass
//@ needs-unwind
-#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))]
use std::sync::Mutex;
diff --git a/tests/ui/linkage-attr/framework.omit.stderr b/tests/ui/linkage-attr/framework.omit.stderr
deleted file mode 100644
index 23e017c..0000000
--- a/tests/ui/linkage-attr/framework.omit.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: linking with `LINKER` failed: exit status: 1
- |
- ld: Undefined symbols:
- _CFRunLoopGetTypeID, referenced from:
- clang: error: linker command failed with exit code 1 (use -v to see invocation)
-
-
-error: aborting due to 1 previous error
diff --git a/tests/ui/linkage-attr/framework.rs b/tests/ui/linkage-attr/framework.rs
deleted file mode 100644
index 08f4394..0000000
--- a/tests/ui/linkage-attr/framework.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Check that linking frameworks on Apple platforms works.
-//@ only-apple
-//@ revisions: omit link weak both
-//@ [omit]build-fail
-//@ [link]run-pass
-//@ [weak]run-pass
-//@ [both]run-pass
-
-// The linker's exact error output changes between Xcode versions, depends on
-// linker invocation details, and the linker sometimes outputs more warnings.
-//@ compare-output-lines-by-subset
-//@ normalize-stderr-test: "linking with `.*` failed" -> "linking with `LINKER` failed"
-//@ normalize-stderr-test: "Undefined symbols for architecture .*" -> "ld: Undefined symbols:"
-//@ normalize-stderr-test: "._CFRunLoopGetTypeID.," -> "_CFRunLoopGetTypeID,"
-
-#![cfg_attr(any(weak, both), feature(link_arg_attribute))]
-
-#[cfg_attr(any(link, both), link(name = "CoreFoundation", kind = "framework"))]
-#[cfg_attr(
- any(weak, both),
- link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim"),
- link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim")
-)]
-extern "C" {
- fn CFRunLoopGetTypeID() -> core::ffi::c_ulong;
-}
-
-pub fn main() {
- unsafe {
- CFRunLoopGetTypeID();
- }
-}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs b/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs
new file mode 100644
index 0000000..d892ebd
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs
@@ -0,0 +1,23 @@
+#![allow(dangling_pointers_from_temporaries)]
+
+fn main() {
+ dbg!(String::new().as_ptr());
+ // ^ no error
+
+ #[deny(dangling_pointers_from_temporaries)]
+ {
+ dbg!(String::new().as_ptr());
+ //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+ }
+ S.foo()
+}
+
+struct S;
+
+impl S {
+ #[warn(dangling_pointers_from_temporaries)]
+ fn foo(self) {
+ dbg!(String::new().as_ptr());
+ //~^ WARNING a dangling pointer will be produced because the temporary `String` will be dropped
+ }
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr
new file mode 100644
index 0000000..fd434ea
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr
@@ -0,0 +1,34 @@
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+ --> $DIR/allow.rs:9:28
+ |
+LL | dbg!(String::new().as_ptr());
+ | ------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+ --> $DIR/allow.rs:7:12
+ |
+LL | #[deny(dangling_pointers_from_temporaries)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: a dangling pointer will be produced because the temporary `String` will be dropped
+ --> $DIR/allow.rs:20:28
+ |
+LL | dbg!(String::new().as_ptr());
+ | ------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+ --> $DIR/allow.rs:18:12
+ |
+LL | #[warn(dangling_pointers_from_temporaries)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error; 1 warning emitted
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs b/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs
new file mode 100644
index 0000000..b376582
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs
@@ -0,0 +1,52 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+use std::ffi::{c_char, CString};
+
+fn cstring() -> CString {
+ CString::new("hello").unwrap()
+}
+
+fn consume(ptr: *const c_char) {
+ let c = unsafe { ptr.read() };
+ dbg!(c);
+}
+
+// None of these should trigger the lint.
+fn ok() {
+ consume(cstring().as_ptr());
+ consume({ cstring() }.as_ptr());
+ consume({ cstring().as_ptr() });
+ consume(cstring().as_ptr().cast());
+ consume({ cstring() }.as_ptr().cast());
+ consume({ cstring().as_ptr() }.cast());
+}
+
+// All of these should trigger the lint.
+fn not_ok() {
+ {
+ let ptr = cstring().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+ consume(ptr);
+ }
+ consume({
+ let ptr = cstring().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+ ptr
+ });
+ consume({
+ let s = cstring();
+ s.as_ptr()
+ //^ FIXME: should error
+ });
+ let _ptr: *const u8 = cstring().as_ptr().cast();
+ //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+ let _ptr: *const u8 = { cstring() }.as_ptr().cast();
+ //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+ let _ptr: *const u8 = { cstring().as_ptr() }.cast();
+ //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+}
+
+fn main() {
+ ok();
+ not_ok();
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr
new file mode 100644
index 0000000..d1615b7
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr
@@ -0,0 +1,62 @@
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+ --> $DIR/calls.rs:27:29
+ |
+LL | let ptr = cstring().as_ptr();
+ | --------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+ --> $DIR/calls.rs:1:9
+ |
+LL | #![deny(dangling_pointers_from_temporaries)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+ --> $DIR/calls.rs:32:29
+ |
+LL | let ptr = cstring().as_ptr();
+ | --------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+ --> $DIR/calls.rs:41:37
+ |
+LL | let _ptr: *const u8 = cstring().as_ptr().cast();
+ | --------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+ --> $DIR/calls.rs:43:41
+ |
+LL | let _ptr: *const u8 = { cstring() }.as_ptr().cast();
+ | ------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+ --> $DIR/calls.rs:45:39
+ |
+LL | let _ptr: *const u8 = { cstring().as_ptr() }.cast();
+ | --------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/lint/lint-temporary-cstring-as-param.rs b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs
similarity index 62%
rename from tests/ui/lint/lint-temporary-cstring-as-param.rs
rename to tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs
index 9f58053..fb6ed36 100644
--- a/tests/ui/lint/lint-temporary-cstring-as-param.rs
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs
@@ -1,4 +1,7 @@
+//@ check-pass
+
#![deny(temporary_cstring_as_ptr)]
+//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
use std::ffi::CString;
use std::os::raw::c_char;
@@ -7,5 +10,4 @@
fn main() {
some_function(CString::new("").unwrap().as_ptr());
- //~^ ERROR getting the inner pointer of a temporary `CString`
}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr
new file mode 100644
index 0000000..dd54b49
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr
@@ -0,0 +1,10 @@
+warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+ --> $DIR/cstring-as-param.rs:3:9
+ |
+LL | #![deny(temporary_cstring_as_ptr)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
+ |
+ = note: `#[warn(renamed_and_removed_lints)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs
new file mode 100644
index 0000000..a983787
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs
@@ -0,0 +1,18 @@
+// this program is not technically incorrect, but is an obscure enough style to be worth linting
+#![deny(temporary_cstring_as_ptr)]
+//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+
+use std::ffi::CString;
+
+macro_rules! mymacro {
+ () => {
+ let s = CString::new("some text").unwrap().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+ }
+}
+
+fn main() {
+ let s = CString::new("some text").unwrap().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+ mymacro!();
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr
new file mode 100644
index 0000000..5289fbb
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr
@@ -0,0 +1,41 @@
+warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+ --> $DIR/cstring-as-ptr.rs:2:9
+ |
+LL | #![deny(temporary_cstring_as_ptr)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
+ |
+ = note: `#[warn(renamed_and_removed_lints)]` on by default
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+ --> $DIR/cstring-as-ptr.rs:15:48
+ |
+LL | let s = CString::new("some text").unwrap().as_ptr();
+ | ---------------------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+ --> $DIR/cstring-as-ptr.rs:2:9
+ |
+LL | #![deny(temporary_cstring_as_ptr)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+ --> $DIR/cstring-as-ptr.rs:9:52
+ |
+LL | let s = CString::new("some text").unwrap().as_ptr();
+ | ---------------------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+...
+LL | mymacro!();
+ | ---------- in this macro invocation
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+ = note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs b/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs
new file mode 100644
index 0000000..b9b7bd3
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+
+#![deny(dangling_pointers_from_temporaries)]
+
+// The original code example comes from bindgen-produced code for emacs.
+// Hence the name of the test.
+// https://github.com/rust-lang/rust/pull/128985#issuecomment-2338951363
+
+use std::ffi::{c_char, CString};
+
+fn read(ptr: *const c_char) -> c_char {
+ unsafe { ptr.read() }
+}
+
+fn main() {
+ let fnptr: Option<fn(ptr: *const c_char) -> c_char> = Some(read);
+ let x = fnptr.unwrap()(CString::new("foo").unwrap().as_ptr());
+ assert_eq!(x as u8, b'f');
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs
new file mode 100644
index 0000000..0fb07a3
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs
@@ -0,0 +1,13 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+const MAX_PATH: usize = 260;
+fn main() {
+ let str1 = String::with_capacity(MAX_PATH).as_mut_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+ let str2 = String::from("TotototototototototototototototototoT").as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+ unsafe {
+ std::ptr::copy_nonoverlapping(str2, str1, 30);
+ println!("{:?}", String::from_raw_parts(str1, 30, 30));
+ }
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr
new file mode 100644
index 0000000..0de794f
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr
@@ -0,0 +1,29 @@
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+ --> $DIR/example-from-issue123613.rs:5:48
+ |
+LL | let str1 = String::with_capacity(MAX_PATH).as_mut_ptr();
+ | ------------------------------- ^^^^^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+ --> $DIR/example-from-issue123613.rs:1:9
+ |
+LL | #![deny(dangling_pointers_from_temporaries)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+ --> $DIR/example-from-issue123613.rs:7:70
+ |
+LL | let str2 = String::from("TotototototototototototototototototoT").as_ptr();
+ | ----------------------------------------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs b/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs
new file mode 100644
index 0000000..a5e84d3
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs
@@ -0,0 +1,32 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+use std::fmt::Debug;
+
+trait Ext1 {
+ fn dbg(self) -> Self
+ where
+ Self: Sized + Debug,
+ {
+ dbg!(&self);
+ self
+ }
+}
+
+impl<T> Ext1 for *const T {}
+
+trait Ext2 {
+ fn foo(self);
+}
+
+impl Ext2 for *const u32 {
+ fn foo(self) {
+ dbg!(unsafe { self.read() });
+ }
+}
+
+fn main() {
+ let _ptr1 = Vec::<u32>::new().as_ptr().dbg();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
+ let _ptr2 = vec![0].as_ptr().foo();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr
new file mode 100644
index 0000000..5d401c8
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr
@@ -0,0 +1,29 @@
+error: a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
+ --> $DIR/ext.rs:28:35
+ |
+LL | let _ptr1 = Vec::<u32>::new().as_ptr().dbg();
+ | ----------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+ --> $DIR/ext.rs:1:9
+ |
+LL | #![deny(dangling_pointers_from_temporaries)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
+ --> $DIR/ext.rs:30:25
+ |
+LL | let _ptr2 = vec![0].as_ptr().foo();
+ | ------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs
new file mode 100644
index 0000000..26019b3
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs
@@ -0,0 +1,8 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+fn main() {
+ vec![0u8].as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+ vec![0u8].as_mut_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr
new file mode 100644
index 0000000..11c052c
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr
@@ -0,0 +1,29 @@
+error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+ --> $DIR/methods.rs:4:15
+ |
+LL | vec![0u8].as_ptr();
+ | --------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+ --> $DIR/methods.rs:1:9
+ |
+LL | #![deny(dangling_pointers_from_temporaries)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+ --> $DIR/methods.rs:6:15
+ |
+LL | vec![0u8].as_mut_ptr();
+ | --------- ^^^^^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs
new file mode 100644
index 0000000..1f21658
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs
@@ -0,0 +1,136 @@
+#![allow(unused)]
+#![deny(dangling_pointers_from_temporaries)]
+
+fn string() -> String {
+ "hello".into()
+}
+
+struct Wrapper(String);
+
+fn main() {
+ // ConstBlock
+ const { String::new() }.as_ptr();
+
+ // Array
+ {
+ [string()].as_ptr(); // False negative
+ [true].as_ptr();
+ }
+
+ // Call
+ string().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+
+ // MethodCall
+ "hello".to_string().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+
+ // Tup
+ // impossible
+
+ // Binary
+ (string() + "hello").as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+
+ // Path
+ {
+ let x = string();
+ x.as_ptr();
+ }
+
+ // Unary
+ {
+ let x = string();
+ let x: &String = &x;
+ (*x).as_ptr();
+ (&[0u8]).as_ptr();
+ (&string()).as_ptr(); // False negative
+ (*&string()).as_ptr(); // False negative
+ }
+
+ // Lit
+ "hello".as_ptr();
+
+ // Cast
+ // impossible
+
+ // Type
+ // impossible
+
+ // DropTemps
+ // impossible
+
+ // Let
+ // impossible
+
+ // If
+ {
+ (if true { String::new() } else { "hello".into() }).as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+ }
+
+ // Loop
+ {
+ (loop {
+ break String::new();
+ })
+ .as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+ }
+
+ // Match
+ {
+ match string() {
+ s => s,
+ }
+ .as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+ }
+
+ // Closure
+ // impossible
+
+ // Block
+ { string() }.as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+
+ // Assign, AssignOp
+ // impossible
+
+ // Field
+ {
+ Wrapper(string()).0.as_ptr(); // False negative
+ let x = Wrapper(string());
+ x.0.as_ptr();
+ }
+
+ // Index
+ {
+ vec![string()][0].as_ptr(); // False negative
+ let x = vec![string()];
+ x[0].as_ptr();
+ }
+
+ // AddrOf, InlineAsm, OffsetOf
+ // impossible
+
+ // Break, Continue, Ret
+ // are !
+
+ // Become, Yield
+ // unstable, are !
+
+ // Repeat
+ [0u8; 100].as_ptr();
+ [const { String::new() }; 100].as_ptr();
+
+ // Struct
+ // Cannot test this without access to private fields of the linted types.
+
+ // Err
+ // impossible
+
+ // Macro
+ vec![0u8].as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr
new file mode 100644
index 0000000..d2e9ac8
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr
@@ -0,0 +1,99 @@
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+ --> $DIR/temporaries.rs:21:14
+ |
+LL | string().as_ptr();
+ | -------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+ --> $DIR/temporaries.rs:2:9
+ |
+LL | #![deny(dangling_pointers_from_temporaries)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+ --> $DIR/temporaries.rs:25:25
+ |
+LL | "hello".to_string().as_ptr();
+ | ------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+ --> $DIR/temporaries.rs:32:26
+ |
+LL | (string() + "hello").as_ptr();
+ | -------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+ --> $DIR/temporaries.rs:68:61
+ |
+LL | (if true { String::new() } else { "hello".into() }).as_ptr();
+ | --------------------------------------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+ --> $DIR/temporaries.rs:77:10
+ |
+LL | / (loop {
+LL | | break String::new();
+LL | | })
+ | |__________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+LL | .as_ptr();
+ | ^^^^^^ this pointer will immediately be invalid
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+ --> $DIR/temporaries.rs:86:10
+ |
+LL | / match string() {
+LL | | s => s,
+LL | | }
+ | |_________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+LL | .as_ptr();
+ | ^^^^^^ this pointer will immediately be invalid
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+ --> $DIR/temporaries.rs:94:18
+ |
+LL | { string() }.as_ptr();
+ | ------------ ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+ --> $DIR/temporaries.rs:134:15
+ |
+LL | vec![0u8].as_ptr();
+ | --------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs
new file mode 100644
index 0000000..2b515d3
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs
@@ -0,0 +1,52 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+use std::cell::Cell;
+use std::ffi::{CStr, CString};
+use std::mem::MaybeUninit;
+
+struct AsPtrFake;
+
+impl AsPtrFake {
+ fn as_ptr(&self) -> *const () {
+ std::ptr::null()
+ }
+}
+
+fn declval<T>() -> T {
+ loop {}
+}
+
+fn main() {
+ declval::<CString>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+ declval::<String>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+ declval::<Vec<u8>>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+ declval::<Box<CString>>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
+ declval::<Box<[u8]>>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
+ declval::<Box<str>>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Box<str>` will be dropped
+ declval::<Box<CStr>>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
+ declval::<[u8; 10]>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
+ declval::<Box<[u8; 10]>>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
+ declval::<Box<Vec<u8>>>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
+ declval::<Box<String>>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Box<String>` will be dropped
+ declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
+ declval::<Cell<u8>>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
+ declval::<MaybeUninit<u8>>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
+ declval::<Vec<AsPtrFake>>().as_ptr();
+ //~^ ERROR a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
+ declval::<Box<AsPtrFake>>().as_ptr();
+ declval::<AsPtrFake>().as_ptr();
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
new file mode 100644
index 0000000..c582a4c
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
@@ -0,0 +1,172 @@
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+ --> $DIR/types.rs:20:26
+ |
+LL | declval::<CString>().as_ptr();
+ | -------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+ --> $DIR/types.rs:1:9
+ |
+LL | #![deny(dangling_pointers_from_temporaries)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+ --> $DIR/types.rs:22:25
+ |
+LL | declval::<String>().as_ptr();
+ | ------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+ --> $DIR/types.rs:24:26
+ |
+LL | declval::<Vec<u8>>().as_ptr();
+ | -------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
+ --> $DIR/types.rs:26:31
+ |
+LL | declval::<Box<CString>>().as_ptr();
+ | ------------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Box<CString>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CString>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
+ --> $DIR/types.rs:28:28
+ |
+LL | declval::<Box<[u8]>>().as_ptr();
+ | ---------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Box<[u8]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<str>` will be dropped
+ --> $DIR/types.rs:30:27
+ |
+LL | declval::<Box<str>>().as_ptr();
+ | --------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Box<str>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<str>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
+ --> $DIR/types.rs:32:28
+ |
+LL | declval::<Box<CStr>>().as_ptr();
+ | ---------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Box<CStr>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CStr>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
+ --> $DIR/types.rs:34:27
+ |
+LL | declval::<[u8; 10]>().as_ptr();
+ | --------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `[u8; 10]` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `[u8; 10]` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
+ --> $DIR/types.rs:36:32
+ |
+LL | declval::<Box<[u8; 10]>>().as_ptr();
+ | -------------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Box<[u8; 10]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8; 10]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
+ --> $DIR/types.rs:38:31
+ |
+LL | declval::<Box<Vec<u8>>>().as_ptr();
+ | ------------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Box<Vec<u8>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Vec<u8>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<String>` will be dropped
+ --> $DIR/types.rs:40:30
+ |
+LL | declval::<Box<String>>().as_ptr();
+ | ------------------------ ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Box<String>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<String>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
+ --> $DIR/types.rs:42:43
+ |
+LL | declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
+ | ------------------------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Box<Box<Box<Box<[u8]>>>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Box<Box<Box<[u8]>>>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
+ --> $DIR/types.rs:44:27
+ |
+LL | declval::<Cell<u8>>().as_ptr();
+ | --------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Cell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Cell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
+ --> $DIR/types.rs:46:34
+ |
+LL | declval::<MaybeUninit<u8>>().as_ptr();
+ | ---------------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `MaybeUninit<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `MaybeUninit<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
+ --> $DIR/types.rs:48:33
+ |
+LL | declval::<Vec<AsPtrFake>>().as_ptr();
+ | --------------------------- ^^^^^^ this pointer will immediately be invalid
+ | |
+ | this `Vec<AsPtrFake>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ |
+ = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<AsPtrFake>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 15 previous errors
+
diff --git a/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs b/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs
new file mode 100644
index 0000000..08d6733
--- /dev/null
+++ b/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs
@@ -0,0 +1,10 @@
+// Submodule file used by test `../multi-file.rs`.
+
+// Keywords reserved from Rust 2018:
+fn async() {}
+fn await() {}
+fn try() {}
+fn dyn() {}
+
+// Keywords reserved from Rust 2024:
+fn gen() {}
diff --git a/tests/ui/lint/keyword-idents/multi-file.rs b/tests/ui/lint/keyword-idents/multi-file.rs
new file mode 100644
index 0000000..703e13f
--- /dev/null
+++ b/tests/ui/lint/keyword-idents/multi-file.rs
@@ -0,0 +1,14 @@
+#![deny(keyword_idents)] // Should affect the submodule, but doesn't.
+//@ edition: 2015
+//@ known-bug: #132218
+//@ check-pass (known bug; should be check-fail)
+
+// Because `keyword_idents_2018` and `keyword_idents_2024` are pre-expansion
+// lints, configuring them via lint attributes doesn't propagate to submodules
+// in other files.
+// <https://github.com/rust-lang/rust/issues/132218>
+
+#[path = "./auxiliary/multi_file_submod.rs"]
+mod multi_file_submod;
+
+fn main() {}
diff --git a/tests/ui/lint/lint-deref-nullptr.rs b/tests/ui/lint/lint-deref-nullptr.rs
index d052dbd..f83d883 100644
--- a/tests/ui/lint/lint-deref-nullptr.rs
+++ b/tests/ui/lint/lint-deref-nullptr.rs
@@ -27,9 +27,9 @@
let ub = &*ptr::null_mut::<i32>();
//~^ ERROR dereferencing a null pointer
ptr::addr_of!(*ptr::null::<i32>());
- //~^ ERROR dereferencing a null pointer
+ // ^^ OKAY
ptr::addr_of_mut!(*ptr::null_mut::<i32>());
- //~^ ERROR dereferencing a null pointer
+ // ^^ OKAY
let offset = ptr::addr_of!((*ptr::null::<Struct>()).field);
//~^ ERROR dereferencing a null pointer
}
diff --git a/tests/ui/lint/lint-deref-nullptr.stderr b/tests/ui/lint/lint-deref-nullptr.stderr
index c6f432e..175431b 100644
--- a/tests/ui/lint/lint-deref-nullptr.stderr
+++ b/tests/ui/lint/lint-deref-nullptr.stderr
@@ -47,22 +47,10 @@
| ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
error: dereferencing a null pointer
- --> $DIR/lint-deref-nullptr.rs:29:23
- |
-LL | ptr::addr_of!(*ptr::null::<i32>());
- | ^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
-
-error: dereferencing a null pointer
- --> $DIR/lint-deref-nullptr.rs:31:27
- |
-LL | ptr::addr_of_mut!(*ptr::null_mut::<i32>());
- | ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
-
-error: dereferencing a null pointer
--> $DIR/lint-deref-nullptr.rs:33:36
|
LL | let offset = ptr::addr_of!((*ptr::null::<Struct>()).field);
| ^^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
-error: aborting due to 10 previous errors
+error: aborting due to 8 previous errors
diff --git a/tests/ui/lint/lint-missing-doc-expect.rs b/tests/ui/lint/lint-missing-doc-expect.rs
index 991f650..b1abf8b 100644
--- a/tests/ui/lint/lint-missing-doc-expect.rs
+++ b/tests/ui/lint/lint-missing-doc-expect.rs
@@ -1,10 +1,10 @@
// Make sure that `#[expect(missing_docs)]` is always correctly fulfilled.
//@ check-pass
-//@ revisions: lib bin test
+//@ revisions: lib bin test_
//@ [lib]compile-flags: --crate-type lib
//@ [bin]compile-flags: --crate-type bin
-//@ [test]compile-flags: --test
+//@ [test_]compile-flags: --test
#[expect(missing_docs)]
pub fn foo() {}
diff --git a/tests/ui/lint/lint-temporary-cstring-as-param.stderr b/tests/ui/lint/lint-temporary-cstring-as-param.stderr
deleted file mode 100644
index 7aa21f2..0000000
--- a/tests/ui/lint/lint-temporary-cstring-as-param.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: getting the inner pointer of a temporary `CString`
- --> $DIR/lint-temporary-cstring-as-param.rs:9:45
- |
-LL | some_function(CString::new("").unwrap().as_ptr());
- | ------------------------- ^^^^^^ this pointer will be invalid
- | |
- | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
- |
- = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
- = help: for more information, see https://doc.rust-lang.org/reference/destructors.html
-note: the lint level is defined here
- --> $DIR/lint-temporary-cstring-as-param.rs:1:9
- |
-LL | #![deny(temporary_cstring_as_ptr)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/lint/lint-temporary-cstring-as-ptr.rs b/tests/ui/lint/lint-temporary-cstring-as-ptr.rs
deleted file mode 100644
index fab792f..0000000
--- a/tests/ui/lint/lint-temporary-cstring-as-ptr.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// this program is not technically incorrect, but is an obscure enough style to be worth linting
-#![deny(temporary_cstring_as_ptr)]
-
-use std::ffi::CString;
-
-macro_rules! mymacro {
- () => {
- let s = CString::new("some text").unwrap().as_ptr();
- //~^ ERROR getting the inner pointer of a temporary `CString`
- }
-}
-
-fn main() {
- let s = CString::new("some text").unwrap().as_ptr();
- //~^ ERROR getting the inner pointer of a temporary `CString`
- mymacro!();
-}
diff --git a/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr b/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr
deleted file mode 100644
index 4e5c8aa..0000000
--- a/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error: getting the inner pointer of a temporary `CString`
- --> $DIR/lint-temporary-cstring-as-ptr.rs:14:48
- |
-LL | let s = CString::new("some text").unwrap().as_ptr();
- | ---------------------------------- ^^^^^^ this pointer will be invalid
- | |
- | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
- |
- = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
- = help: for more information, see https://doc.rust-lang.org/reference/destructors.html
-note: the lint level is defined here
- --> $DIR/lint-temporary-cstring-as-ptr.rs:2:9
- |
-LL | #![deny(temporary_cstring_as_ptr)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: getting the inner pointer of a temporary `CString`
- --> $DIR/lint-temporary-cstring-as-ptr.rs:8:52
- |
-LL | let s = CString::new("some text").unwrap().as_ptr();
- | ---------------------------------- ^^^^^^ this pointer will be invalid
- | |
- | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
-...
-LL | mymacro!();
- | ---------- in this macro invocation
- |
- = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
- = help: for more information, see https://doc.rust-lang.org/reference/destructors.html
- = note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
index 131d416..8ca4532 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
@@ -6,9 +6,9 @@
macro_rules! one_nested_count_and_len {
( $( [ $( $l:literal ),* ] ),* ) => {
[
- // outer-most repetition
+ // outermost repetition
$(
- // inner-most repetition
+ // innermost repetition
$(
${ignore($l)} ${index()}, ${len()},
)*
@@ -23,34 +23,34 @@
[
// # ["foo"]
- // ## inner-most repetition (first iteration)
+ // ## innermost repetition (first iteration)
//
- // `index` is 0 because this is the first inner-most iteration.
- // `len` is 1 because there is only one inner-most repetition, "foo".
+ // `index` is 0 because this is the first innermost iteration.
+ // `len` is 1 because there is only one innermost repetition, "foo".
0, 1,
- // ## outer-most repetition (first iteration)
+ // ## outermost repetition (first iteration)
//
// `count` is 1 because of "foo", i,e, `$l` has only one repetition,
- // `index` is 0 because this is the first outer-most iteration.
- // `len` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
+ // `index` is 0 because this is the first outermost iteration.
+ // `len` is 2 because there are 2 outermost repetitions, ["foo"] and ["bar", "baz"]
1, 0, 2,
// # ["bar", "baz"]
- // ## inner-most repetition (first iteration)
+ // ## innermost repetition (first iteration)
//
- // `index` is 0 because this is the first inner-most iteration
+ // `index` is 0 because this is the first innermost iteration
// `len` is 2 because there are repetitions, "bar" and "baz"
0, 2,
- // ## inner-most repetition (second iteration)
+ // ## innermost repetition (second iteration)
//
- // `index` is 1 because this is the second inner-most iteration
+ // `index` is 1 because this is the second innermost iteration
// `len` is 2 because there are repetitions, "bar" and "baz"
1, 2,
- // ## outer-most repetition (second iteration)
+ // ## outermost repetition (second iteration)
//
// `count` is 2 because of "bar" and "baz", i,e, `$l` has two repetitions,
- // `index` is 1 because this is the second outer-most iteration
- // `len` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
+ // `index` is 1 because this is the second outermost iteration
+ // `len` is 2 because there are 2 outermost repetitions, ["foo"] and ["bar", "baz"]
2, 1, 2,
// # last count
@@ -61,7 +61,7 @@
// Based on the above explanation, the following macros should be straightforward
- // Grouped from the outer-most to the inner-most
+ // Grouped from the outermost to the innermost
macro_rules! three_nested_count {
( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
&[
@@ -156,7 +156,7 @@
][..]
);
- // Grouped from the outer-most to the inner-most
+ // Grouped from the outermost to the innermost
macro_rules! three_nested_len {
( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
&[
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
index 1eda5f5..78cede9 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
@@ -10,12 +10,12 @@
macro_rules! curly__no_rhs_dollar__no_round {
( $i:ident ) => { ${ count($i) } };
- //~^ ERROR `count` can not be placed inside the inner-most repetition
+ //~^ ERROR `count` can not be placed inside the innermost repetition
}
macro_rules! curly__rhs_dollar__no_round {
( $i:ident ) => { ${ count($i) } };
- //~^ ERROR `count` can not be placed inside the inner-most repetition
+ //~^ ERROR `count` can not be placed inside the innermost repetition
}
#[rustfmt::skip] // autoformatters can break a few of the error traces
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
index 2c44ad2..ce7694e 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
@@ -196,13 +196,13 @@
LL | ( $( $i:ident ),* ) => { ${ {} } };
| ^^
-error: `count` can not be placed inside the inner-most repetition
+error: `count` can not be placed inside the innermost repetition
--> $DIR/syntax-errors.rs:12:24
|
LL | ( $i:ident ) => { ${ count($i) } };
| ^^^^^^^^^^^^^
-error: `count` can not be placed inside the inner-most repetition
+error: `count` can not be placed inside the innermost repetition
--> $DIR/syntax-errors.rs:17:24
|
LL | ( $i:ident ) => { ${ count($i) } };
diff --git a/tests/ui/never_type/issue-52443.stderr b/tests/ui/never_type/issue-52443.stderr
index adcff66..2207ceb 100644
--- a/tests/ui/never_type/issue-52443.stderr
+++ b/tests/ui/never_type/issue-52443.stderr
@@ -50,10 +50,6 @@
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: cannot call non-const fn `<RangeFrom<usize> as Iterator>::next` in constants
--> $DIR/issue-52443.rs:9:21
@@ -62,10 +58,6 @@
| ^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 5 previous errors; 1 warning emitted
diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
index 66b57c7..e34371b 100644
--- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
+++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
@@ -353,10 +353,6 @@
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 40 previous errors
diff --git a/tests/ui/privacy/privacy1.rs b/tests/ui/privacy/privacy1.rs
index fcb2108..31f3960 100644
--- a/tests/ui/privacy/privacy1.rs
+++ b/tests/ui/privacy/privacy1.rs
@@ -12,14 +12,14 @@
type Target;
}
-#[lang="receiver"]
-pub trait Receiver: Deref {}
+#[lang="legacy_receiver"]
+pub trait LegacyReceiver: Deref {}
impl<'a, T> Deref for &'a T {
type Target = T;
}
-impl<'a, T> Receiver for &'a T {}
+impl<'a, T> LegacyReceiver for &'a T {}
mod bar {
// shouldn't bring in too much
diff --git a/tests/ui/repr/repr_align_greater_usize.msp430.stderr b/tests/ui/repr/repr_align_greater_usize.msp430.stderr
new file mode 100644
index 0000000..7c85249
--- /dev/null
+++ b/tests/ui/repr/repr_align_greater_usize.msp430.stderr
@@ -0,0 +1,19 @@
+error[E0589]: alignment must not be greater than `isize::MAX` bytes
+ --> $DIR/repr_align_greater_usize.rs:21:8
+ |
+LL | #[repr(align(32768))]
+ | ^^^^^^^^^^^^
+ |
+ = note: `isize::MAX` is 32767 for the current target
+
+error[E0589]: alignment must not be greater than `isize::MAX` bytes
+ --> $DIR/repr_align_greater_usize.rs:24:8
+ |
+LL | #[repr(align(65536))]
+ | ^^^^^^^^^^^^
+ |
+ = note: `isize::MAX` is 32767 for the current target
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0589`.
diff --git a/tests/ui/repr/repr_align_greater_usize.rs b/tests/ui/repr/repr_align_greater_usize.rs
new file mode 100644
index 0000000..b47320b
--- /dev/null
+++ b/tests/ui/repr/repr_align_greater_usize.rs
@@ -0,0 +1,25 @@
+//@ revisions: msp430 aarch32
+//@[msp430] needs-llvm-components: msp430
+//@[msp430] compile-flags: --target=msp430-none-elf
+//@[aarch32] build-pass
+//@[aarch32] needs-llvm-components: arm
+//@[aarch32] compile-flags: --target=thumbv7m-none-eabi
+
+// We should fail to compute alignment for types aligned higher than usize::MAX.
+// We can't handle alignments that require all 32 bits, so this only affects 16-bit.
+
+#![feature(lang_items, no_core)]
+#![no_core]
+#![crate_type = "lib"]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[repr(align(16384))]
+struct Kitten;
+
+#[repr(align(32768))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX`
+struct Cat;
+
+#[repr(align(65536))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX`
+struct BigCat;
diff --git a/tests/ui/resolve/issue-39559-2.stderr b/tests/ui/resolve/issue-39559-2.stderr
index 7f51357..ea27e7b 100644
--- a/tests/ui/resolve/issue-39559-2.stderr
+++ b/tests/ui/resolve/issue-39559-2.stderr
@@ -5,10 +5,6 @@
| ^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: cannot call non-const fn `<Dim3 as Dim>::dim` in constants
--> $DIR/issue-39559-2.rs:16:15
@@ -17,10 +13,6 @@
| ^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 2 previous errors
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
index 505b0a1..6ae60e7 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
@@ -5,10 +5,6 @@
| ^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0493]: destructor of `R` cannot be evaluated at compile-time
--> $DIR/arbitrary-self-from-method-substs-ice.rs:10:43
diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr
index 643f1de..40ac350 100644
--- a/tests/ui/specialization/const_trait_impl.stderr
+++ b/tests/ui/specialization/const_trait_impl.stderr
@@ -1,69 +1,42 @@
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const_trait_impl.rs:6:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub unsafe trait Sup {
-LL | fn foo() -> u32;
- | - expected 0 const parameters
-
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const_trait_impl.rs:6:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub unsafe trait Sup {
-LL | fn foo() -> u32;
- | - expected 0 const parameters
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const_trait_impl.rs:34:16
+ --> $DIR/const_trait_impl.rs:34:9
|
LL | impl<T: ~const Default> const A for T {
- | ^^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const_trait_impl.rs:40:16
+ --> $DIR/const_trait_impl.rs:40:9
|
LL | impl<T: ~const Default + ~const Sup> const A for T {
- | ^^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const_trait_impl.rs:46:16
+ --> $DIR/const_trait_impl.rs:46:9
|
LL | impl<T: ~const Default + ~const Sub> const A for T {
- | ^^^^^^^
+ | ^^^^^^
-error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const_trait_impl.rs:29:1
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const_trait_impl.rs:40:9
|
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait A {
-LL | fn a() -> u32;
- | - expected 0 const parameters
-
-error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const_trait_impl.rs:29:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait A {
-LL | fn a() -> u32;
- | - expected 0 const parameters
+LL | impl<T: ~const Default + ~const Sup> const A for T {
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const_trait_impl.rs:29:1
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const_trait_impl.rs:34:9
|
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait A {
-LL | fn a() -> u32;
- | - expected 0 const parameters
+LL | impl<T: ~const Default> const A for T {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const_trait_impl.rs:46:9
+ |
+LL | impl<T: ~const Default + ~const Sub> const A for T {
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
@@ -115,7 +88,6 @@
LL + #![feature(effects)]
|
-error: aborting due to 12 previous errors
+error: aborting due to 10 previous errors
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs
index 4089ec7..6d6d793 100644
--- a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs
@@ -14,4 +14,3 @@
}
const VAR: u32 = foobar();
-//~^ ERROR: `foobar` is not yet stable as a const fn
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr
index 918d6eb..232de41 100644
--- a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr
@@ -4,13 +4,5 @@
LL | #[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: `foobar` is not yet stable as a const fn
- --> $DIR/const-stability-attribute-implies-missing.rs:16:18
- |
-LL | const VAR: u32 = foobar();
- | ^^^^^^^^
- |
- = help: add `#![feature(const_foobar)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
diff --git a/tests/ui/stability-attribute/missing-const-stability.rs b/tests/ui/stability-attribute/missing-const-stability.rs
index 82da18c..f113965 100644
--- a/tests/ui/stability-attribute/missing-const-stability.rs
+++ b/tests/ui/stability-attribute/missing-const-stability.rs
@@ -1,6 +1,6 @@
//@ compile-flags: -Znext-solver
#![feature(staged_api)]
-#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
+#![feature(const_trait_impl, effects, rustc_attrs, intrinsics)] //~ WARN the feature `effects` is incomplete
#![stable(feature = "stable", since = "1.0.0")]
#[stable(feature = "stable", since = "1.0.0")]
@@ -31,4 +31,15 @@
fn fun() {}
}
+#[stable(feature = "stable", since = "1.0.0")]
+#[rustc_intrinsic]
+pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
+//~^ ERROR function has missing const stability attribute
+
+extern "rust-intrinsic" {
+ #[stable(feature = "stable", since = "1.0.0")]
+ #[rustc_const_stable_indirect]
+ pub fn min_align_of_val<T>(x: *const T) -> usize;
+}
+
fn main() {}
diff --git a/tests/ui/stability-attribute/missing-const-stability.stderr b/tests/ui/stability-attribute/missing-const-stability.stderr
index adf60c3..e62a8b8 100644
--- a/tests/ui/stability-attribute/missing-const-stability.stderr
+++ b/tests/ui/stability-attribute/missing-const-stability.stderr
@@ -1,7 +1,7 @@
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/missing-const-stability.rs:3:30
|
-LL | #![feature(const_trait_impl, effects)]
+LL | #![feature(const_trait_impl, effects, rustc_attrs, intrinsics)]
| ^^^^^^^
|
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
@@ -22,11 +22,17 @@
LL | | }
| |_^
+error: function has missing const stability attribute
+ --> $DIR/missing-const-stability.rs:36:1
+ |
+LL | pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error: associated function has missing const stability attribute
--> $DIR/missing-const-stability.rs:16:5
|
LL | pub const fn foo() {}
| ^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 4 previous errors; 1 warning emitted
diff --git a/tests/ui/static/raw-ref-deref-with-unsafe.rs b/tests/ui/static/raw-ref-deref-with-unsafe.rs
index 0974948..5beed69 100644
--- a/tests/ui/static/raw-ref-deref-with-unsafe.rs
+++ b/tests/ui/static/raw-ref-deref-with-unsafe.rs
@@ -1,13 +1,14 @@
//@ check-pass
use std::ptr;
-// This code should remain unsafe because of the two unsafe operations here,
-// even if in a hypothetical future we deem all &raw (const|mut) *ptr exprs safe.
-
static mut BYTE: u8 = 0;
static mut BYTE_PTR: *mut u8 = ptr::addr_of_mut!(BYTE);
+
+// This code should remain unsafe because reading from a static mut is *always* unsafe.
+
// An unsafe static's ident is a place expression in its own right, so despite the above being safe
-// (it's fine to create raw refs to places!) the following derefs the ptr before creating its ref
+// (it's fine to create raw refs to places!) the following *reads* from the static mut place before
+// derefing it explicitly with the `*` below.
static mut DEREF_BYTE_PTR: *mut u8 = unsafe { ptr::addr_of_mut!(*BYTE_PTR) };
fn main() {
diff --git a/tests/ui/static/raw-ref-deref-without-unsafe.rs b/tests/ui/static/raw-ref-deref-without-unsafe.rs
index 289e55b..97d08c8 100644
--- a/tests/ui/static/raw-ref-deref-without-unsafe.rs
+++ b/tests/ui/static/raw-ref-deref-without-unsafe.rs
@@ -1,15 +1,14 @@
use std::ptr;
-// This code should remain unsafe because of the two unsafe operations here,
-// even if in a hypothetical future we deem all &raw (const|mut) *ptr exprs safe.
-
static mut BYTE: u8 = 0;
static mut BYTE_PTR: *mut u8 = ptr::addr_of_mut!(BYTE);
+
+// This code should remain unsafe because reading from a static mut is *always* unsafe.
+
// An unsafe static's ident is a place expression in its own right, so despite the above being safe
// (it's fine to create raw refs to places!) the following derefs the ptr before creating its ref!
static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR);
//~^ ERROR: use of mutable static
-//~| ERROR: dereference of raw pointer
fn main() {
let _ = unsafe { DEREF_BYTE_PTR };
diff --git a/tests/ui/static/raw-ref-deref-without-unsafe.stderr b/tests/ui/static/raw-ref-deref-without-unsafe.stderr
index f034499..b9c294e 100644
--- a/tests/ui/static/raw-ref-deref-without-unsafe.stderr
+++ b/tests/ui/static/raw-ref-deref-without-unsafe.stderr
@@ -1,11 +1,3 @@
-error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
- --> $DIR/raw-ref-deref-without-unsafe.rs:10:56
- |
-LL | static mut DEREF_BYTE_PTR: *mut u8 = ptr::addr_of_mut!(*BYTE_PTR);
- | ^^^^^^^^^ dereference of raw pointer
- |
- = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-
error[E0133]: use of mutable static is unsafe and requires unsafe function or block
--> $DIR/raw-ref-deref-without-unsafe.rs:10:57
|
@@ -14,6 +6,6 @@
|
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/statics/check-values-constraints.stderr b/tests/ui/statics/check-values-constraints.stderr
index 24763c1..b4ee345 100644
--- a/tests/ui/statics/check-values-constraints.stderr
+++ b/tests/ui/statics/check-values-constraints.stderr
@@ -37,10 +37,6 @@
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0010]: allocations are not allowed in statics
--> $DIR/check-values-constraints.rs:96:5
diff --git a/tests/ui/target-feature/feature-hierarchy.rs b/tests/ui/target-feature/feature-hierarchy.rs
index 4cf9112..7f14d70 100644
--- a/tests/ui/target-feature/feature-hierarchy.rs
+++ b/tests/ui/target-feature/feature-hierarchy.rs
@@ -19,6 +19,7 @@
impl Copy for bool {}
extern "rust-intrinsic" {
+ #[stable(feature = "test", since = "1.0.0")]
#[rustc_const_stable(feature = "test", since = "1.0.0")]
fn unreachable() -> !;
}
diff --git a/tests/ui/target-feature/no-llvm-leaks.rs b/tests/ui/target-feature/no-llvm-leaks.rs
index 9f5dec4..f0c887b 100644
--- a/tests/ui/target-feature/no-llvm-leaks.rs
+++ b/tests/ui/target-feature/no-llvm-leaks.rs
@@ -17,6 +17,7 @@
impl Copy for bool {}
extern "rust-intrinsic" {
+ #[stable(feature = "test", since = "1.0.0")]
#[rustc_const_stable(feature = "test", since = "1.0.0")]
fn unreachable() -> !;
}
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index b243169..8cff788 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -41,7 +41,7 @@
Block {
targeted_by_break: false
span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
- region_scope: Node(25)
+ region_scope: Node(3)
safety_mode: Safe
stmts: []
expr:
@@ -51,8 +51,8 @@
span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
kind:
Scope {
- region_scope: Node(3)
- lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).3))
+ region_scope: Node(4)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4))
value:
Expr {
ty: bool
@@ -67,8 +67,8 @@
span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
kind:
Scope {
- region_scope: Node(4)
- lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4))
+ region_scope: Node(5)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).5))
value:
Expr {
ty: Foo
@@ -123,16 +123,16 @@
body:
Expr {
ty: bool
- temp_lifetime: Some(Node(12))
+ temp_lifetime: Some(Node(13))
span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
kind:
Scope {
- region_scope: Node(13)
- lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).13))
+ region_scope: Node(14)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).14))
value:
Expr {
ty: bool
- temp_lifetime: Some(Node(12))
+ temp_lifetime: Some(Node(13))
span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
kind:
Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
@@ -140,8 +140,8 @@
}
}
}
- lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).12))
- scope: Node(12)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).13))
+ scope: Node(13)
span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0)
}
Arm {
@@ -175,16 +175,16 @@
body:
Expr {
ty: bool
- temp_lifetime: Some(Node(18))
+ temp_lifetime: Some(Node(19))
span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
kind:
Scope {
- region_scope: Node(19)
- lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).19))
+ region_scope: Node(20)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).20))
value:
Expr {
ty: bool
- temp_lifetime: Some(Node(18))
+ temp_lifetime: Some(Node(19))
span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
kind:
Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
@@ -192,8 +192,8 @@
}
}
}
- lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).18))
- scope: Node(18)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).19))
+ scope: Node(19)
span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0)
}
Arm {
@@ -219,16 +219,16 @@
body:
Expr {
ty: bool
- temp_lifetime: Some(Node(23))
+ temp_lifetime: Some(Node(24))
span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
kind:
Scope {
- region_scope: Node(24)
- lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).24))
+ region_scope: Node(25)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).25))
value:
Expr {
ty: bool
- temp_lifetime: Some(Node(23))
+ temp_lifetime: Some(Node(24))
span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
kind:
Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)
@@ -236,8 +236,8 @@
}
}
}
- lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).23))
- scope: Node(23)
+ lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).24))
+ scope: Node(24)
span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0)
}
]
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs
index 4399ae2..bbf8891 100644
--- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs
@@ -1,4 +1,5 @@
-//@ known-bug: unknown
+//@ compile-flags: -Znext-solver
+//@ check-pass
#![allow(incomplete_features)]
#![feature(const_trait_impl, effects)]
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.stderr
deleted file mode 100644
index 8288c66..0000000
--- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.stderr
+++ /dev/null
@@ -1,46 +0,0 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
-error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
- --> $DIR/assoc-type-const-bound-usage-0.rs:13:5
- |
-LL | T::Assoc::func()
- | ^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
- |
-note: required by a bound in `Trait::func`
- --> $DIR/assoc-type-const-bound-usage-0.rs:6:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ required by this bound in `Trait::func`
-...
-LL | fn func() -> i32;
- | ---- required by a bound in this associated function
-help: consider further restricting the associated type
- |
-LL | const fn unqualified<T: ~const Trait>() -> i32 where <T as Trait>::Assoc: Trait {
- | ++++++++++++++++++++++++++++++++
-
-error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
- --> $DIR/assoc-type-const-bound-usage-0.rs:17:5
- |
-LL | <T as Trait>::Assoc::func()
- | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
- |
-note: required by a bound in `Trait::func`
- --> $DIR/assoc-type-const-bound-usage-0.rs:6:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ required by this bound in `Trait::func`
-...
-LL | fn func() -> i32;
- | ---- required by a bound in this associated function
-help: consider further restricting the associated type
- |
-LL | const fn qualified<T: ~const Trait>() -> i32 where <T as Trait>::Assoc: Trait {
- | ++++++++++++++++++++++++++++++++
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs
index 8a1bf75..04ad945 100644
--- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs
@@ -1,5 +1,5 @@
+//@ compile-flags: -Znext-solver
//@ known-bug: unknown
-// FIXME(effects)
#![feature(const_trait_impl, effects, generic_const_exprs)]
#![allow(incomplete_features)]
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr
index 0792d09..b8768bd 100644
--- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr
@@ -1,46 +1,35 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
+error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed
+ --> $DIR/assoc-type-const-bound-usage-1.rs:4:39
|
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
+LL | #![feature(const_trait_impl, effects, generic_const_exprs)]
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = help: remove one of these features
-error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
- --> $DIR/assoc-type-const-bound-usage-1.rs:15:44
+error[E0284]: type annotations needed: cannot normalize `unqualified<T>::{constant#0}`
+ --> $DIR/assoc-type-const-bound-usage-1.rs:15:37
|
LL | fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> {
- | ^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
- |
-note: required by a bound in `Trait::func`
- --> $DIR/assoc-type-const-bound-usage-1.rs:7:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ required by this bound in `Trait::func`
-...
-LL | fn func() -> i32;
- | ---- required by a bound in this associated function
-help: consider further restricting the associated type
- |
-LL | fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> where <T as Trait>::Assoc: Trait {
- | ++++++++++++++++++++++++++++++++
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `unqualified<T>::{constant#0}`
-error[E0277]: the trait bound `<T as Trait>::Assoc: Trait` is not satisfied
- --> $DIR/assoc-type-const-bound-usage-1.rs:19:42
+error[E0284]: type annotations needed: cannot normalize `qualified<T>::{constant#0}`
+ --> $DIR/assoc-type-const-bound-usage-1.rs:19:35
|
LL | fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> {
- | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `<T as Trait>::Assoc`
- |
-note: required by a bound in `Trait::func`
- --> $DIR/assoc-type-const-bound-usage-1.rs:7:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ required by this bound in `Trait::func`
-...
-LL | fn func() -> i32;
- | ---- required by a bound in this associated function
-help: consider further restricting the associated type
- |
-LL | fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> where <T as Trait>::Assoc: Trait {
- | ++++++++++++++++++++++++++++++++
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `qualified<T>::{constant#0}`
-error: aborting due to 3 previous errors
+error[E0284]: type annotations needed: cannot normalize `unqualified<T>::{constant#0}`
+ --> $DIR/assoc-type-const-bound-usage-1.rs:16:5
+ |
+LL | Type
+ | ^^^^ cannot normalize `unqualified<T>::{constant#0}`
-For more information about this error, try `rustc --explain E0277`.
+error[E0284]: type annotations needed: cannot normalize `qualified<T>::{constant#0}`
+ --> $DIR/assoc-type-const-bound-usage-1.rs:20:5
+ |
+LL | Type
+ | ^^^^ cannot normalize `qualified<T>::{constant#0}`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0284`.
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs
new file mode 100644
index 0000000..5e87308
--- /dev/null
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -Znext-solver
+
+// Check that `~const` item bounds only hold if the where clauses on the
+// associated type are also const.
+// i.e. check that we validate the const conditions for the associated type
+// when considering one of implied const bounds.
+
+#![allow(incomplete_features)]
+#![feature(const_trait_impl, effects)]
+
+#[const_trait]
+trait Trait {
+ type Assoc<U>: ~const Trait
+ where
+ U: ~const Other;
+
+ fn func();
+}
+
+#[const_trait]
+trait Other {}
+
+const fn fails<T: ~const Trait, U: Other>() {
+ T::Assoc::<U>::func();
+ //~^ ERROR the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
+ <T as Trait>::Assoc::<U>::func();
+ //~^ ERROR the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
+}
+
+const fn works<T: ~const Trait, U: ~const Other>() {
+ T::Assoc::<U>::func();
+ <T as Trait>::Assoc::<U>::func();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr
new file mode 100644
index 0000000..1f6532c
--- /dev/null
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
+ --> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5
+ |
+LL | T::Assoc::<U>::func();
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
+ --> $DIR/assoc-type-const-bound-usage-fail-2.rs:26:5
+ |
+LL | <T as Trait>::Assoc::<U>::func();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs
new file mode 100644
index 0000000..73b3d14
--- /dev/null
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Znext-solver
+
+// Check that `~const` item bounds only hold if the parent trait is `~const`.
+// i.e. check that we validate the const conditions for the associated type
+// when considering one of implied const bounds.
+
+#![allow(incomplete_features)]
+#![feature(const_trait_impl, effects)]
+
+#[const_trait]
+trait Trait {
+ type Assoc: ~const Trait;
+ fn func();
+}
+
+const fn unqualified<T: Trait>() {
+ T::Assoc::func();
+ //~^ ERROR the trait bound `T: ~const Trait` is not satisfied
+ <T as Trait>::Assoc::func();
+ //~^ ERROR the trait bound `T: ~const Trait` is not satisfied
+}
+
+const fn works<T: ~const Trait>() {
+ T::Assoc::func();
+ <T as Trait>::Assoc::func();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr
new file mode 100644
index 0000000..fb08e74
--- /dev/null
+++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `T: ~const Trait` is not satisfied
+ --> $DIR/assoc-type-const-bound-usage-fail.rs:17:5
+ |
+LL | T::Assoc::func();
+ | ^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `T: ~const Trait` is not satisfied
+ --> $DIR/assoc-type-const-bound-usage-fail.rs:19:5
+ |
+LL | <T as Trait>::Assoc::func();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/assoc-type.rs b/tests/ui/traits/const-traits/assoc-type.rs
index ea3cbab..a9394d9 100644
--- a/tests/ui/traits/const-traits/assoc-type.rs
+++ b/tests/ui/traits/const-traits/assoc-type.rs
@@ -1,4 +1,5 @@
-// FIXME(effects): Replace `Add` with `std::ops::Add` once the latter a `#[const_trait]` again.
+//@ compile-flags: -Znext-solver
+
#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
#[const_trait]
@@ -33,7 +34,7 @@
impl const Foo for NonConstAdd {
type Bar = NonConstAdd;
- // FIXME(effects) ERROR the trait bound `NonConstAdd: ~const Add` is not satisfied
+ //~^ ERROR the trait bound `NonConstAdd: ~const Add` is not satisfied
}
#[const_trait]
diff --git a/tests/ui/traits/const-traits/assoc-type.stderr b/tests/ui/traits/const-traits/assoc-type.stderr
index c20b53c..672eaf2 100644
--- a/tests/ui/traits/const-traits/assoc-type.stderr
+++ b/tests/ui/traits/const-traits/assoc-type.stderr
@@ -1,5 +1,5 @@
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/assoc-type.rs:2:30
+ --> $DIR/assoc-type.rs:3:30
|
LL | #![feature(const_trait_impl, effects)]
| ^^^^^^^
@@ -7,10 +7,18 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
+error[E0277]: the trait bound `NonConstAdd: ~const Add` is not satisfied
+ --> $DIR/assoc-type.rs:36:16
|
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
+LL | type Bar = NonConstAdd;
+ | ^^^^^^^^^^^
+ |
+note: required by a bound in `Foo::Bar`
+ --> $DIR/assoc-type.rs:32:15
+ |
+LL | type Bar: ~const Add;
+ | ^^^^^^ required by this bound in `Foo::Bar`
error: aborting due to 1 previous error; 1 warning emitted
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/auxiliary/staged-api.rs b/tests/ui/traits/const-traits/auxiliary/staged-api.rs
index 986165e..bb59132 100644
--- a/tests/ui/traits/const-traits/auxiliary/staged-api.rs
+++ b/tests/ui/traits/const-traits/auxiliary/staged-api.rs
@@ -19,3 +19,12 @@
impl const MyTrait for Unstable {
fn func() {}
}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Unstable2;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "unstable2", issue = "none")]
+impl const MyTrait for Unstable2 {
+ fn func() {}
+}
diff --git a/tests/ui/traits/const-traits/call-const-closure.rs b/tests/ui/traits/const-traits/call-const-closure.rs
new file mode 100644
index 0000000..cbf3e6c
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-const-closure.rs
@@ -0,0 +1,22 @@
+//@ compile-flags: -Znext-solver
+//@ edition:2021
+
+#![feature(const_trait_impl, effects, const_closures)]
+#![allow(incomplete_features)]
+
+#[const_trait]
+trait Bar {
+ fn foo(&self);
+}
+
+impl Bar for () {
+ fn foo(&self) {}
+}
+
+const FOO: () = {
+ (const || ().foo())();
+ //~^ ERROR the trait bound `(): ~const Bar` is not satisfied
+ // FIXME(effects): The constness environment for const closures is wrong.
+};
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/call-const-closure.stderr b/tests/ui/traits/const-traits/call-const-closure.stderr
new file mode 100644
index 0000000..3fed67f
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-const-closure.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `(): ~const Bar` is not satisfied
+ --> $DIR/call-const-closure.rs:17:15
+ |
+LL | (const || ().foo())();
+ | ^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/call-const-in-tilde-const.rs b/tests/ui/traits/const-traits/call-const-in-tilde-const.rs
new file mode 100644
index 0000000..970ee93
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-const-in-tilde-const.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Znext-solver
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Foo {
+ fn foo();
+}
+
+const fn foo<T: ~const Foo>() {
+ const { T::foo() }
+ //~^ ERROR the trait bound `T: const Foo` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/call-const-in-tilde-const.stderr b/tests/ui/traits/const-traits/call-const-in-tilde-const.stderr
new file mode 100644
index 0000000..49c310f
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-const-in-tilde-const.stderr
@@ -0,0 +1,18 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/call-const-in-tilde-const.rs:2:30
+ |
+LL | #![feature(const_trait_impl, effects)]
+ | ^^^^^^^
+ |
+ = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the trait bound `T: const Foo` is not satisfied
+ --> $DIR/call-const-in-tilde-const.rs:10:13
+ |
+LL | const { T::foo() }
+ | ^^^^^^^^
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr b/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr
index 5d2333d..40a06af 100644
--- a/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr
+++ b/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr
@@ -2,20 +2,7 @@
--> $DIR/call-const-trait-method-fail.rs:27:5
|
LL | a.plus(b)
- | ^ the trait `Plus` is not implemented for `u32`
- |
-note: required by a bound in `Plus::plus`
- --> $DIR/call-const-trait-method-fail.rs:5:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ required by this bound in `Plus::plus`
-LL | pub trait Plus {
-LL | fn plus(self, rhs: Self) -> Self;
- | ---- required by a bound in this associated function
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
- |
-LL | pub const fn add_u32(a: u32, b: u32) -> u32 where u32: Plus {
- | +++++++++++++++
+ | ^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr
index bf455a7..32f5313 100644
--- a/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr
+++ b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr
@@ -16,15 +16,6 @@
= note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
= note: adding a non-const method body in the future would be a breaking change
-error[E0049]: method `plus` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/call-const-trait-method-pass.rs:24:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait Plus {
-LL | fn plus(self, rhs: Self) -> Self;
- | - expected 0 const parameters
-
error[E0015]: cannot call non-const operator in constants
--> $DIR/call-const-trait-method-pass.rs:39:22
|
@@ -32,10 +23,6 @@
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0015]: cannot call non-const fn `<i32 as Plus>::plus` in constant functions
--> $DIR/call-const-trait-method-pass.rs:11:20
@@ -56,10 +43,6 @@
| ^^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0015]: cannot call non-const fn `<i32 as Plus>::plus` in constant functions
--> $DIR/call-const-trait-method-pass.rs:36:7
@@ -73,7 +56,6 @@
LL + #![feature(effects)]
|
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/call-generic-in-impl.stderr b/tests/ui/traits/const-traits/call-generic-in-impl.stderr
index 5cd274c..52ee044 100644
--- a/tests/ui/traits/const-traits/call-generic-in-impl.stderr
+++ b/tests/ui/traits/const-traits/call-generic-in-impl.stderr
@@ -1,17 +1,16 @@
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/call-generic-in-impl.rs:10:16
+ --> $DIR/call-generic-in-impl.rs:10:9
|
LL | impl<T: ~const PartialEq> const MyPartialEq for T {
- | ^^^^^^^^^
+ | ^^^^^^
-error[E0049]: method `eq` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/call-generic-in-impl.rs:5:1
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/call-generic-in-impl.rs:10:9
|
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait MyPartialEq {
-LL | fn eq(&self, other: &Self) -> bool;
- | - expected 0 const parameters
+LL | impl<T: ~const PartialEq> const MyPartialEq for T {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0015]: cannot call non-const fn `<T as PartialEq>::eq` in constant functions
--> $DIR/call-generic-in-impl.rs:12:9
@@ -20,12 +19,7 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.rs b/tests/ui/traits/const-traits/call-generic-method-chain.rs
index 9df694a..e5baeda 100644
--- a/tests/ui/traits/const-traits/call-generic-method-chain.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-chain.rs
@@ -1,6 +1,7 @@
//! Basic test for calling methods on generic type parameters in `const fn`.
//@ known-bug: #110395
+//@ compile-flags: -Znext-solver
// FIXME(effects) check-pass
#![feature(const_trait_impl, effects)]
diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.stderr b/tests/ui/traits/const-traits/call-generic-method-chain.stderr
index 57d57df..6dbf3ad 100644
--- a/tests/ui/traits/const-traits/call-generic-method-chain.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-chain.stderr
@@ -1,5 +1,5 @@
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/call-generic-method-chain.rs:6:30
+ --> $DIR/call-generic-method-chain.rs:7:30
|
LL | #![feature(const_trait_impl, effects)]
| ^^^^^^^
@@ -7,13 +7,8 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
- --> $DIR/call-generic-method-chain.rs:10:12
+ --> $DIR/call-generic-method-chain.rs:11:12
|
LL | impl const PartialEq for S {
| ^^^^^^^^^
@@ -22,16 +17,53 @@
= note: adding a non-const method body in the future would be a breaking change
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/call-generic-method-chain.rs:19:32
+ --> $DIR/call-generic-method-chain.rs:20:25
|
LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
- | ^^^^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/call-generic-method-chain.rs:23:40
+ --> $DIR/call-generic-method-chain.rs:20:25
+ |
+LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/call-generic-method-chain.rs:24:33
|
LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool {
- | ^^^^^^^^^
+ | ^^^^^^
-error: aborting due to 4 previous errors; 1 warning emitted
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/call-generic-method-chain.rs:24:33
+ |
+LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+error[E0015]: cannot call non-const operator in constant functions
+ --> $DIR/call-generic-method-chain.rs:21:5
+ |
+LL | *t == *t
+ | ^^^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+ |
+LL | const fn equals_self<T: ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+ | ++++++++++++++++++++++++++++
+
+error[E0015]: cannot call non-const fn `<S as PartialEq>::eq` in constant functions
+ --> $DIR/call-generic-method-chain.rs:16:15
+ |
+LL | !self.eq(other)
+ | ^^^^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 7 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs b/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs
index f46a349..83a4bb2 100644
--- a/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs
@@ -1,3 +1,4 @@
+//@ compile-flags: -Znext-solver
//@ known-bug: #110395
// FIXME(effects) check-pass
diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
index 0088ed2..08877da 100644
--- a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
@@ -1,5 +1,5 @@
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/call-generic-method-dup-bound.rs:4:30
+ --> $DIR/call-generic-method-dup-bound.rs:5:30
|
LL | #![feature(const_trait_impl, effects)]
| ^^^^^^^
@@ -7,13 +7,8 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
- --> $DIR/call-generic-method-dup-bound.rs:8:12
+ --> $DIR/call-generic-method-dup-bound.rs:9:12
|
LL | impl const PartialEq for S {
| ^^^^^^^^^
@@ -22,16 +17,65 @@
= note: adding a non-const method body in the future would be a breaking change
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/call-generic-method-dup-bound.rs:19:44
+ --> $DIR/call-generic-method-dup-bound.rs:20:37
|
LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool {
- | ^^^^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/call-generic-method-dup-bound.rs:26:37
+ --> $DIR/call-generic-method-dup-bound.rs:20:37
+ |
+LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/call-generic-method-dup-bound.rs:27:30
|
LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool {
- | ^^^^^^^^^
+ | ^^^^^^
-error: aborting due to 4 previous errors; 1 warning emitted
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/call-generic-method-dup-bound.rs:27:30
+ |
+LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+error[E0015]: cannot call non-const operator in constant functions
+ --> $DIR/call-generic-method-dup-bound.rs:21:5
+ |
+LL | *t == *t
+ | ^^^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+ |
+LL | const fn equals_self<T: PartialEq + ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+ | ++++++++++++++++++++++++++++
+
+error[E0015]: cannot call non-const fn `<S as PartialEq>::eq` in constant functions
+ --> $DIR/call-generic-method-dup-bound.rs:14:15
+ |
+LL | !self.eq(other)
+ | ^^^^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const operator in constant functions
+ --> $DIR/call-generic-method-dup-bound.rs:28:5
+ |
+LL | *t == *t
+ | ^^^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+ |
+LL | const fn equals_self2<T: A + ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+ | ++++++++++++++++++++++++++++
+
+error: aborting due to 8 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.rs b/tests/ui/traits/const-traits/call-generic-method-fail.rs
index 86e0eae..6bfbbef 100644
--- a/tests/ui/traits/const-traits/call-generic-method-fail.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-fail.rs
@@ -1,12 +1,10 @@
-//@ check-pass
//@ compile-flags: -Znext-solver
#![allow(incomplete_features)]
#![feature(const_trait_impl, effects)]
pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
*t == *t
- // FIXME(effects) ~^ ERROR mismatched types
- // FIXME(effects): diagnostic
+ //~^ ERROR cannot call non-const operator in constant functions
}
fn main() {}
diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.stderr b/tests/ui/traits/const-traits/call-generic-method-fail.stderr
new file mode 100644
index 0000000..5cd4216
--- /dev/null
+++ b/tests/ui/traits/const-traits/call-generic-method-fail.stderr
@@ -0,0 +1,15 @@
+error[E0015]: cannot call non-const operator in constant functions
+ --> $DIR/call-generic-method-fail.rs:6:5
+ |
+LL | *t == *t
+ | ^^^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+ |
+LL | pub const fn equals_self<T: PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+ | ++++++++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr b/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr
index 68c9fc4..06b9937 100644
--- a/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr
@@ -1,20 +1,8 @@
error[E0277]: the trait bound `S: const Foo` is not satisfied
- --> $DIR/call-generic-method-nonconst.rs:25:34
+ --> $DIR/call-generic-method-nonconst.rs:25:22
|
LL | pub const EQ: bool = equals_self(&S);
- | ----------- ^^ the trait `Foo` is not implemented for `S`
- | |
- | required by a bound introduced by this call
- |
-note: required by a bound in `equals_self`
- --> $DIR/call-generic-method-nonconst.rs:18:25
- |
-LL | const fn equals_self<T: ~const Foo>(t: &T) -> bool {
- | ^^^^^^^^^^ required by this bound in `equals_self`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
- |
-LL | pub const EQ: bool where S: Foo = equals_self(&S);
- | ++++++++++++
+ | ^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.rs b/tests/ui/traits/const-traits/call-generic-method-pass.rs
index 413685d..cbeeb25 100644
--- a/tests/ui/traits/const-traits/call-generic-method-pass.rs
+++ b/tests/ui/traits/const-traits/call-generic-method-pass.rs
@@ -1,5 +1,6 @@
//! Basic test for calling methods on generic type parameters in `const fn`.
+//@ compile-flags: -Znext-solver
//@ known-bug: #110395
// FIXME(effects) check-pass
diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.stderr b/tests/ui/traits/const-traits/call-generic-method-pass.stderr
index 4a6100c..ac08c05 100644
--- a/tests/ui/traits/const-traits/call-generic-method-pass.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-pass.stderr
@@ -1,5 +1,5 @@
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/call-generic-method-pass.rs:6:30
+ --> $DIR/call-generic-method-pass.rs:7:30
|
LL | #![feature(const_trait_impl, effects)]
| ^^^^^^^
@@ -7,13 +7,8 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
- --> $DIR/call-generic-method-pass.rs:10:12
+ --> $DIR/call-generic-method-pass.rs:11:12
|
LL | impl const PartialEq for S {
| ^^^^^^^^^
@@ -22,10 +17,39 @@
= note: adding a non-const method body in the future would be a breaking change
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/call-generic-method-pass.rs:19:32
+ --> $DIR/call-generic-method-pass.rs:20:25
|
LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
- | ^^^^^^^^^
+ | ^^^^^^
-error: aborting due to 3 previous errors; 1 warning emitted
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/call-generic-method-pass.rs:20:25
+ |
+LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+error[E0015]: cannot call non-const operator in constant functions
+ --> $DIR/call-generic-method-pass.rs:21:5
+ |
+LL | *t == *t
+ | ^^^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+ |
+LL | const fn equals_self<T: ~const PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+ | ++++++++++++++++++++++++++++
+
+error[E0015]: cannot call non-const fn `<S as PartialEq>::eq` in constant functions
+ --> $DIR/call-generic-method-pass.rs:16:15
+ |
+LL | !self.eq(other)
+ | ^^^^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 5 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/call.rs b/tests/ui/traits/const-traits/call.rs
index af2f7ca..f96fb61 100644
--- a/tests/ui/traits/const-traits/call.rs
+++ b/tests/ui/traits/const-traits/call.rs
@@ -1,10 +1,11 @@
-//@ check-pass
+// FIXME(effects) check-pass
//@ compile-flags: -Znext-solver
#![feature(const_closures, const_trait_impl, effects)]
#![allow(incomplete_features)]
pub const _: () = {
assert!((const || true)());
+ //~^ ERROR cannot call non-const closure in constants
};
fn main() {}
diff --git a/tests/ui/traits/const-traits/call.stderr b/tests/ui/traits/const-traits/call.stderr
new file mode 100644
index 0000000..e9bf640
--- /dev/null
+++ b/tests/ui/traits/const-traits/call.stderr
@@ -0,0 +1,12 @@
+error[E0015]: cannot call non-const closure in constants
+ --> $DIR/call.rs:7:13
+ |
+LL | assert!((const || true)());
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: closures need an RFC before allowed to be called in constants
+ = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const-bound-in-host.rs b/tests/ui/traits/const-traits/const-bound-in-host.rs
new file mode 100644
index 0000000..6fbc210
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-bound-in-host.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Foo {
+ fn foo();
+}
+
+fn foo<T: const Foo>() {
+ const { T::foo() }
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/const-bound-in-host.stderr b/tests/ui/traits/const-traits/const-bound-in-host.stderr
new file mode 100644
index 0000000..b815f74
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-bound-in-host.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/const-bound-in-host.rs:4:30
+ |
+LL | #![feature(const_trait_impl, effects)]
+ | ^^^^^^^
+ |
+ = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs
index 099cf0b..7c3e2af 100644
--- a/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs
+++ b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.rs
@@ -1,3 +1,5 @@
+//@ compile-flags: -Znext-solver
+
#![allow(incomplete_features)]
#![feature(const_trait_impl, effects)]
diff --git a/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr
index b5d9b1f..ae1260f 100644
--- a/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr
+++ b/tests/ui/traits/const-traits/const-bound-on-not-const-associated-fn.stderr
@@ -1,31 +1,26 @@
error: `~const` is not allowed here
- --> $DIR/const-bound-on-not-const-associated-fn.rs:10:40
+ --> $DIR/const-bound-on-not-const-associated-fn.rs:12:40
|
LL | fn do_something_else() where Self: ~const MyTrait;
| ^^^^^^
|
note: this function is not `const`, so it cannot have `~const` trait bounds
- --> $DIR/const-bound-on-not-const-associated-fn.rs:10:8
+ --> $DIR/const-bound-on-not-const-associated-fn.rs:12:8
|
LL | fn do_something_else() where Self: ~const MyTrait;
| ^^^^^^^^^^^^^^^^^
error: `~const` is not allowed here
- --> $DIR/const-bound-on-not-const-associated-fn.rs:21:32
+ --> $DIR/const-bound-on-not-const-associated-fn.rs:23:32
|
LL | pub fn foo(&self) where T: ~const MyTrait {
| ^^^^^^
|
note: this function is not `const`, so it cannot have `~const` trait bounds
- --> $DIR/const-bound-on-not-const-associated-fn.rs:21:12
+ --> $DIR/const-bound-on-not-const-associated-fn.rs:23:12
|
LL | pub fn foo(&self) where T: ~const MyTrait {
| ^^^
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs
index db446f8..d51d231 100644
--- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs
+++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs
@@ -5,6 +5,7 @@
const fn perform<T: ~const NonConst>() {}
//~^ ERROR `~const` can only be applied to `#[const_trait]` traits
+//~| ERROR `~const` can only be applied to `#[const_trait]` traits
fn operate<T: const NonConst>() {}
//~^ ERROR `const` can only be applied to `#[const_trait]` traits
diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
index e1a85fc..8e83668 100644
--- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
+++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
@@ -7,22 +7,25 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-bounds-non-const-trait.rs:6:28
+ --> $DIR/const-bounds-non-const-trait.rs:6:21
|
LL | const fn perform<T: ~const NonConst>() {}
- | ^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-bounds-non-const-trait.rs:6:21
+ |
+LL | const fn perform<T: ~const NonConst>() {}
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-bounds-non-const-trait.rs:9:21
+ --> $DIR/const-bounds-non-const-trait.rs:10:15
|
LL | fn operate<T: const NonConst>() {}
- | ^^^^^^^^
+ | ^^^^^
error: aborting due to 3 previous errors; 1 warning emitted
diff --git a/tests/ui/traits/const-traits/const-check-fns-in-const-impl.rs b/tests/ui/traits/const-traits/const-check-fns-in-const-impl.rs
index a1710e6..7f9b38b 100644
--- a/tests/ui/traits/const-traits/const-check-fns-in-const-impl.rs
+++ b/tests/ui/traits/const-traits/const-check-fns-in-const-impl.rs
@@ -1,3 +1,5 @@
+//@ compile-flags: -Znext-solver
+
#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
struct S;
diff --git a/tests/ui/traits/const-traits/const-check-fns-in-const-impl.stderr b/tests/ui/traits/const-traits/const-check-fns-in-const-impl.stderr
index 49cd172..ba12854 100644
--- a/tests/ui/traits/const-traits/const-check-fns-in-const-impl.stderr
+++ b/tests/ui/traits/const-traits/const-check-fns-in-const-impl.stderr
@@ -1,5 +1,5 @@
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/const-check-fns-in-const-impl.rs:1:30
+ --> $DIR/const-check-fns-in-const-impl.rs:3:30
|
LL | #![feature(const_trait_impl, effects)]
| ^^^^^^^
@@ -7,19 +7,14 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error[E0015]: cannot call non-const fn `non_const` in constant functions
- --> $DIR/const-check-fns-in-const-impl.rs:12:16
+ --> $DIR/const-check-fns-in-const-impl.rs:14:16
|
LL | fn foo() { non_const() }
| ^^^^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
index 12cc79f..25c81ff 100644
--- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
+++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
@@ -1,14 +1,14 @@
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-closure-parse-not-item.rs:7:32
+ --> $DIR/const-closure-parse-not-item.rs:7:25
|
LL | const fn test() -> impl ~const Fn() {
- | ^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-closure-parse-not-item.rs:7:32
+ --> $DIR/const-closure-parse-not-item.rs:7:25
|
LL | const fn test() -> impl ~const Fn() {
- | ^^^^
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
index 507ceaa..cb4c994 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
+++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
@@ -1,17 +1,16 @@
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const-closure-trait-method-fail.rs:5:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Tr {
-LL | fn a(self) -> i32;
- | - expected 0 const parameters
-
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-closure-trait-method-fail.rs:14:39
+ --> $DIR/const-closure-trait-method-fail.rs:14:32
|
LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-closure-trait-method-fail.rs:14:32
+ |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0015]: cannot call non-const closure in constant functions
--> $DIR/const-closure-trait-method-fail.rs:15:5
@@ -24,12 +23,7 @@
|
LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const FnOnce(())>(x: T) -> i32 {
| +++++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method.stderr b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
index 2a54cd5..43af435 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method.stderr
+++ b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
@@ -1,17 +1,16 @@
-error[E0049]: method `a` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const-closure-trait-method.rs:5:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Tr {
-LL | fn a(self) -> i32;
- | - expected 0 const parameters
-
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-closure-trait-method.rs:14:39
+ --> $DIR/const-closure-trait-method.rs:14:32
|
LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-closure-trait-method.rs:14:32
+ |
+LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0015]: cannot call non-const closure in constant functions
--> $DIR/const-closure-trait-method.rs:15:5
@@ -24,12 +23,7 @@
|
LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32 + ~const FnOnce(())>(x: T) -> i32 {
| +++++++++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const-closures.stderr b/tests/ui/traits/const-traits/const-closures.stderr
index a0f0532..2e9e37b 100644
--- a/tests/ui/traits/const-traits/const-closures.stderr
+++ b/tests/ui/traits/const-traits/const-closures.stderr
@@ -1,26 +1,58 @@
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-closures.rs:8:19
+ --> $DIR/const-closures.rs:8:12
|
LL | F: ~const FnOnce() -> u8,
- | ^^^^^^^^^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-closures.rs:9:19
+ --> $DIR/const-closures.rs:9:12
|
LL | F: ~const FnMut() -> u8,
- | ^^^^^^^^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-closures.rs:10:19
+ --> $DIR/const-closures.rs:10:12
|
LL | F: ~const Fn() -> u8,
- | ^^^^^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-closures.rs:23:27
+ --> $DIR/const-closures.rs:8:12
+ |
+LL | F: ~const FnOnce() -> u8,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-closures.rs:9:12
+ |
+LL | F: ~const FnMut() -> u8,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-closures.rs:10:12
+ |
+LL | F: ~const Fn() -> u8,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-closures.rs:23:20
|
LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
- | ^^^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-closures.rs:23:20
+ |
+LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0015]: cannot call non-const closure in constant functions
--> $DIR/const-closures.rs:24:5
@@ -33,10 +65,6 @@
|
LL | const fn answer<F: ~const Fn() -> u8 + ~const Fn()>(f: &F) -> u8 {
| +++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0015]: cannot call non-const closure in constant functions
--> $DIR/const-closures.rs:24:11
@@ -49,10 +77,6 @@
|
LL | const fn answer<F: ~const Fn() -> u8 + ~const Fn()>(f: &F) -> u8 {
| +++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error[E0015]: cannot call non-const closure in constant functions
--> $DIR/const-closures.rs:12:5
@@ -65,11 +89,7 @@
|
LL | F: ~const FnOnce() -> u8 + ~const Fn(),
| +++++++++++++
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
-error: aborting due to 7 previous errors
+error: aborting due to 11 previous errors
For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const-default-method-bodies.stderr b/tests/ui/traits/const-traits/const-default-method-bodies.stderr
index 0809d9c..071eaf4 100644
--- a/tests/ui/traits/const-traits/const-default-method-bodies.stderr
+++ b/tests/ui/traits/const-traits/const-default-method-bodies.stderr
@@ -1,21 +1,8 @@
error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
- --> $DIR/const-default-method-bodies.rs:26:18
+ --> $DIR/const-default-method-bodies.rs:26:5
|
LL | NonConstImpl.a();
- | ^ the trait `ConstDefaultFn` is not implemented for `NonConstImpl`
- |
-note: required by a bound in `ConstDefaultFn::a`
- --> $DIR/const-default-method-bodies.rs:5:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ required by this bound in `ConstDefaultFn::a`
-...
-LL | fn a(self) {
- | - required by a bound in this associated function
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
- |
-LL | const fn test() where NonConstImpl: ConstDefaultFn {
- | ++++++++++++++++++++++++++++++++++
+ | ^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/const-drop-bound.stderr b/tests/ui/traits/const-traits/const-drop-bound.stderr
index be19700..3f71864 100644
--- a/tests/ui/traits/const-traits/const-drop-bound.stderr
+++ b/tests/ui/traits/const-traits/const-drop-bound.stderr
@@ -1,20 +1,44 @@
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-drop-bound.rs:9:68
+ --> $DIR/const-drop-bound.rs:9:61
|
LL | const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct {
- | ^^^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-drop-bound.rs:20:15
+ --> $DIR/const-drop-bound.rs:9:61
+ |
+LL | const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-drop-bound.rs:20:8
|
LL | T: ~const Destruct,
- | ^^^^^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-drop-bound.rs:21:15
+ --> $DIR/const-drop-bound.rs:21:8
|
LL | E: ~const Destruct,
- | ^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-drop-bound.rs:20:8
+ |
+LL | T: ~const Destruct,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-drop-bound.rs:21:8
+ |
+LL | E: ~const Destruct,
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0493]: destructor of `E` cannot be evaluated at compile-time
--> $DIR/const-drop-bound.rs:12:13
@@ -22,6 +46,6 @@
LL | Err(_e) => None,
| ^^ the destructor for this type cannot be evaluated in constant functions
-error: aborting due to 4 previous errors
+error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.stderr
index faf24c6d..82d6412 100644
--- a/tests/ui/traits/const-traits/const-drop-fail-2.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail-2.stderr
@@ -8,10 +8,18 @@
= note: adding a non-const method body in the future would be a breaking change
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-drop-fail-2.rs:20:26
+ --> $DIR/const-drop-fail-2.rs:20:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-drop-fail-2.rs:20:19
+ |
+LL | const fn check<T: ~const Destruct>(_: T) {}
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/const-drop-fail-2.rs:20:36
@@ -33,7 +41,7 @@
LL + #![feature(effects)]
|
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
Some errors have detailed explanations: E0015, E0493.
For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const-drop-fail.precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.precise.stderr
index 3d400bf..859fdfa 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.precise.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.precise.stderr
@@ -8,10 +8,18 @@
= note: adding a non-const method body in the future would be a breaking change
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-drop-fail.rs:23:26
+ --> $DIR/const-drop-fail.rs:23:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-drop-fail.rs:23:19
+ |
+LL | const fn check<T: ~const Destruct>(_: T) {}
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/const-drop-fail.rs:23:36
@@ -71,7 +79,7 @@
| |_- in this macro invocation
= note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
Some errors have detailed explanations: E0080, E0493.
For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/traits/const-traits/const-drop-fail.stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.stock.stderr
index fd0f6d0..20dea28 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.stock.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.stock.stderr
@@ -8,10 +8,18 @@
= note: adding a non-const method body in the future would be a breaking change
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-drop-fail.rs:23:26
+ --> $DIR/const-drop-fail.rs:23:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-drop-fail.rs:23:19
+ |
+LL | const fn check<T: ~const Destruct>(_: T) {}
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/const-drop-fail.rs:23:36
@@ -21,6 +29,6 @@
| |
| the destructor for this type cannot be evaluated in constant functions
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/traits/const-traits/const-drop.precise.stderr b/tests/ui/traits/const-traits/const-drop.precise.stderr
index dd3ea5d..381e4d7 100644
--- a/tests/ui/traits/const-traits/const-drop.precise.stderr
+++ b/tests/ui/traits/const-traits/const-drop.precise.stderr
@@ -35,31 +35,43 @@
= note: adding a non-const method body in the future would be a breaking change
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-drop.rs:18:22
+ --> $DIR/const-drop.rs:18:15
|
LL | const fn a<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^
+ | ^^^^^^
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const-drop.rs:53:5
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-drop.rs:18:15
|
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait SomeTrait {
-LL | fn foo();
- | - expected 0 const parameters
-
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const-drop.rs:53:5
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait SomeTrait {
-LL | fn foo();
- | - expected 0 const parameters
+LL | const fn a<T: ~const Destruct>(_: T) {}
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+error[E0277]: the trait bound `T: const SomeTrait` is not satisfied
+ --> $DIR/const-drop.rs:67:46
+ |
+LL | impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> {
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+note: required by a bound in `t::ConstDropWithBound`
+ --> $DIR/const-drop.rs:65:38
+ |
+LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
+ | ^^^^^ required by this bound in `ConstDropWithBound`
+
+error[E0277]: the trait bound `T: const SomeTrait` is not satisfied
+ --> $DIR/const-drop.rs:68:22
+ |
+LL | fn drop(&mut self) {
+ | ^^^^
+ |
+note: required by a bound in `t::ConstDropWithBound`
+ --> $DIR/const-drop.rs:65:38
+ |
+LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
+ | ^^^^^ required by this bound in `ConstDropWithBound`
+
error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/const-drop.rs:18:32
|
@@ -78,7 +90,7 @@
LL + #![feature(effects)]
|
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
-Some errors have detailed explanations: E0015, E0049, E0493.
+Some errors have detailed explanations: E0015, E0277, E0493.
For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const-drop.stock.stderr b/tests/ui/traits/const-traits/const-drop.stock.stderr
index aa59e1c..399e784 100644
--- a/tests/ui/traits/const-traits/const-drop.stock.stderr
+++ b/tests/ui/traits/const-traits/const-drop.stock.stderr
@@ -35,31 +35,43 @@
= note: adding a non-const method body in the future would be a breaking change
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-drop.rs:18:22
+ --> $DIR/const-drop.rs:18:15
|
LL | const fn a<T: ~const Destruct>(_: T) {}
- | ^^^^^^^^
+ | ^^^^^^
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const-drop.rs:53:5
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/const-drop.rs:18:15
|
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait SomeTrait {
-LL | fn foo();
- | - expected 0 const parameters
-
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const-drop.rs:53:5
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait SomeTrait {
-LL | fn foo();
- | - expected 0 const parameters
+LL | const fn a<T: ~const Destruct>(_: T) {}
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+error[E0277]: the trait bound `T: const SomeTrait` is not satisfied
+ --> $DIR/const-drop.rs:67:46
+ |
+LL | impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> {
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+note: required by a bound in `t::ConstDropWithBound`
+ --> $DIR/const-drop.rs:65:38
+ |
+LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
+ | ^^^^^ required by this bound in `ConstDropWithBound`
+
+error[E0277]: the trait bound `T: const SomeTrait` is not satisfied
+ --> $DIR/const-drop.rs:68:22
+ |
+LL | fn drop(&mut self) {
+ | ^^^^
+ |
+note: required by a bound in `t::ConstDropWithBound`
+ --> $DIR/const-drop.rs:65:38
+ |
+LL | pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
+ | ^^^^^ required by this bound in `ConstDropWithBound`
+
error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/const-drop.rs:18:32
|
@@ -80,7 +92,7 @@
LL + #![feature(effects)]
|
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
-Some errors have detailed explanations: E0015, E0049, E0493.
+Some errors have detailed explanations: E0015, E0277, E0493.
For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs b/tests/ui/traits/const-traits/const-fns-are-early-bound.rs
index b308734..6d08d8b 100644
--- a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs
+++ b/tests/ui/traits/const-traits/const-fns-are-early-bound.rs
@@ -1,4 +1,6 @@
//@ known-bug: #110395
+//@ failure-status: 101
+//@ dont-check-compiler-stderr
// FIXME(effects) check-pass
//@ compile-flags: -Znext-solver
@@ -82,55 +84,7 @@
#[lang = "tuple_trait"]
trait Tuple {}
-#[lang = "receiver"]
-trait Receiver {}
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {}
-impl<T: ?Sized> Receiver for &T {}
-
-impl<T: ?Sized> Receiver for &mut T {}
-
-#[stable(feature = "minicore", since = "1.0.0")]
-pub mod effects {
- use super::Sized;
-
- #[lang = "EffectsNoRuntime"]
- #[stable(feature = "minicore", since = "1.0.0")]
- pub struct NoRuntime;
- #[lang = "EffectsMaybe"]
- #[stable(feature = "minicore", since = "1.0.0")]
- pub struct Maybe;
- #[lang = "EffectsRuntime"]
- #[stable(feature = "minicore", since = "1.0.0")]
- pub struct Runtime;
-
- #[lang = "EffectsCompat"]
- #[stable(feature = "minicore", since = "1.0.0")]
- pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {}
-
- #[stable(feature = "minicore", since = "1.0.0")]
- impl Compat<false> for NoRuntime {}
- #[stable(feature = "minicore", since = "1.0.0")]
- impl Compat<true> for Runtime {}
- #[stable(feature = "minicore", since = "1.0.0")]
- impl<#[rustc_runtime] const RUNTIME: bool> Compat<RUNTIME> for Maybe {}
-
- #[lang = "EffectsTyCompat"]
- #[marker]
- #[stable(feature = "minicore", since = "1.0.0")]
- pub trait TyCompat<T: ?Sized> {}
-
- #[stable(feature = "minicore", since = "1.0.0")]
- impl<T: ?Sized> TyCompat<T> for T {}
- #[stable(feature = "minicore", since = "1.0.0")]
- impl<T: ?Sized> TyCompat<T> for Maybe {}
- #[stable(feature = "minicore", since = "1.0.0")]
- impl<T: ?Sized> TyCompat<Maybe> for T {}
-
- #[lang = "EffectsIntersection"]
- #[stable(feature = "minicore", since = "1.0.0")]
- pub trait Intersection {
- #[lang = "EffectsIntersectionOutput"]
- #[stable(feature = "minicore", since = "1.0.0")]
- type Output: ?Sized;
- }
-}
+impl<T: ?Sized> LegacyReceiver for &T {}
diff --git a/tests/ui/traits/const-traits/const-fns-are-early-bound.stderr b/tests/ui/traits/const-traits/const-fns-are-early-bound.stderr
deleted file mode 100644
index 9eda9d9..0000000
--- a/tests/ui/traits/const-traits/const-fns-are-early-bound.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0277]: the trait bound `fn() {foo}: const FnOnce()` is not satisfied
- --> $DIR/const-fns-are-early-bound.rs:31:17
- |
-LL | is_const_fn(foo);
- | ----------- ^^^ the trait `FnOnce()` is not implemented for fn item `fn() {foo}`
- | |
- | required by a bound introduced by this call
- |
-note: required by a bound in `is_const_fn`
- --> $DIR/const-fns-are-early-bound.rs:25:12
- |
-LL | fn is_const_fn<F>(_: F)
- | ----------- required by a bound in this function
-LL | where
-LL | F: const FnOnce<()>,
- | ^^^^^^^^^^^^^^^^ required by this bound in `is_const_fn`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs
index bd6f476..e49e909 100644
--- a/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs
+++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs
@@ -1,11 +1,10 @@
-//@ known-bug: #110395
-
+//@ compile-flags: -Znext-solver
#![feature(const_trait_impl, effects)]
+#![allow(incomplete_features)]
pub trait A {}
-// FIXME ~^ HELP: mark `A` as const
impl const A for () {}
-// FIXME ~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]`
+//~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]`
fn main() {}
diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr
index 2a03036..828e217 100644
--- a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr
+++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr
@@ -1,28 +1,14 @@
-warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/const-impl-requires-const-trait.rs:3:30
- |
-LL | #![feature(const_trait_impl, effects)]
- | ^^^^^^^
- |
- = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
- = note: `#[warn(incomplete_features)]` on by default
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: const `impl` for trait `A` which is not marked with `#[const_trait]`
- --> $DIR/const-impl-requires-const-trait.rs:8:12
+ --> $DIR/const-impl-requires-const-trait.rs:7:12
|
LL | pub trait A {}
| - help: mark `A` as const: `#[const_trait]`
-...
+LL |
LL | impl const A for () {}
| ^
|
= note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
= note: adding a non-const method body in the future would be a breaking change
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/const-impl-trait.rs b/tests/ui/traits/const-traits/const-impl-trait.rs
index 51dfe29..61b8c9a 100644
--- a/tests/ui/traits/const-traits/const-impl-trait.rs
+++ b/tests/ui/traits/const-traits/const-impl-trait.rs
@@ -1,4 +1,7 @@
+//@ compile-flags: -Znext-solver
//@ known-bug: #110395
+//@ failure-status: 101
+//@ dont-check-compiler-stderr
// Broken until we have `&T: const Deref` impl in stdlib
#![allow(incomplete_features)]
diff --git a/tests/ui/traits/const-traits/const-impl-trait.stderr b/tests/ui/traits/const-traits/const-impl-trait.stderr
deleted file mode 100644
index 1040af7..0000000
--- a/tests/ui/traits/const-traits/const-impl-trait.stderr
+++ /dev/null
@@ -1,249 +0,0 @@
-error[E0635]: unknown feature `const_cmp`
- --> $DIR/const-impl-trait.rs:8:5
- |
-LL | const_cmp,
- | ^^^^^^^^^
-
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:13:30
- |
-LL | const fn cmp(a: &impl ~const PartialEq) -> bool {
- | ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:17:30
- |
-LL | const fn wrap(x: impl ~const PartialEq + ~const Destruct)
- | ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:17:49
- |
-LL | const fn wrap(x: impl ~const PartialEq + ~const Destruct)
- | ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:18:20
- |
-LL | -> impl ~const PartialEq + ~const Destruct
- | ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:18:39
- |
-LL | -> impl ~const PartialEq + ~const Destruct
- | ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:18:20
- |
-LL | -> impl ~const PartialEq + ~const Destruct
- | ^^^^^^^^^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:18:39
- |
-LL | -> impl ~const PartialEq + ~const Destruct
- | ^^^^^^^^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:25:29
- |
-LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
- | ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:25:48
- |
-LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
- | ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:29:29
- |
-LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
- | ^^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:29:48
- |
-LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
- | ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:29:29
- |
-LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
- | ^^^^^^^^^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:29:48
- |
-LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
- | ^^^^^^^^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:50:41
- |
-LL | const fn apit(_: impl ~const T + ~const Destruct) {}
- | ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:54:73
- |
-LL | const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {}
- | ^^^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:25:29
- |
-LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
- | ^^^^^^^^^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:25:48
- |
-LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
- | ^^^^^^^^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:25:29
- |
-LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
- | ^^^^^^^^^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:25:48
- |
-LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
- | ^^^^^^^^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:25:29
- |
-LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
- | ^^^^^^^^^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/const-impl-trait.rs:25:48
- |
-LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
- | ^^^^^^^^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
- --> $DIR/const-impl-trait.rs:37:26
- |
-LL | assert!(wrap(123) == wrap(123));
- | ^^^^^^^^^- value is dropped here
- | |
- | the destructor for this type cannot be evaluated in constants
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
- --> $DIR/const-impl-trait.rs:37:26
- |
-LL | assert!(wrap(123) == wrap(123));
- | ^^^^^^^^^- value is dropped here
- | |
- | the destructor for this type cannot be evaluated in constants
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
- --> $DIR/const-impl-trait.rs:37:13
- |
-LL | assert!(wrap(123) == wrap(123));
- | ^^^^^^^^^ - value is dropped here
- | |
- | the destructor for this type cannot be evaluated in constants
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
- --> $DIR/const-impl-trait.rs:37:13
- |
-LL | assert!(wrap(123) == wrap(123));
- | ^^^^^^^^^ - value is dropped here
- | |
- | the destructor for this type cannot be evaluated in constants
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
- --> $DIR/const-impl-trait.rs:38:26
- |
-LL | assert!(wrap(123) != wrap(456));
- | ^^^^^^^^^- value is dropped here
- | |
- | the destructor for this type cannot be evaluated in constants
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
- --> $DIR/const-impl-trait.rs:38:26
- |
-LL | assert!(wrap(123) != wrap(456));
- | ^^^^^^^^^- value is dropped here
- | |
- | the destructor for this type cannot be evaluated in constants
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
- --> $DIR/const-impl-trait.rs:38:13
- |
-LL | assert!(wrap(123) != wrap(456));
- | ^^^^^^^^^ - value is dropped here
- | |
- | the destructor for this type cannot be evaluated in constants
-
-error[E0493]: destructor of `impl PartialEq + Destruct` cannot be evaluated at compile-time
- --> $DIR/const-impl-trait.rs:38:13
- |
-LL | assert!(wrap(123) != wrap(456));
- | ^^^^^^^^^ - value is dropped here
- | |
- | the destructor for this type cannot be evaluated in constants
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0493]: destructor of `impl ~const T + ~const Destruct` cannot be evaluated at compile-time
- --> $DIR/const-impl-trait.rs:50:15
- |
-LL | const fn apit(_: impl ~const T + ~const Destruct) {}
- | ^ - value is dropped here
- | |
- | the destructor for this type cannot be evaluated in constant functions
-
-error[E0493]: destructor of `impl IntoIterator<Item : ~const T> + ~const Destruct` cannot be evaluated at compile-time
- --> $DIR/const-impl-trait.rs:54:27
- |
-LL | const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {}
- | ^ - value is dropped here
- | |
- | the destructor for this type cannot be evaluated in constant functions
-
-error: aborting due to 33 previous errors
-
-Some errors have detailed explanations: E0493, E0635.
-For more information about an error, try `rustc --explain E0493`.
diff --git a/tests/ui/traits/const-traits/const-in-closure.rs b/tests/ui/traits/const-traits/const-in-closure.rs
new file mode 100644
index 0000000..51b22c5
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-in-closure.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Trait {
+ fn method();
+}
+
+const fn foo<T: Trait>() {
+ let _ = || {
+ // Make sure this doesn't enforce `T: ~const Trait`
+ T::method();
+ };
+}
+
+fn bar<T: const Trait>() {
+ let _ = || {
+ // Make sure unconditionally const bounds propagate from parent.
+ const { T::method(); };
+ };
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/const-in-closure.stderr b/tests/ui/traits/const-traits/const-in-closure.stderr
new file mode 100644
index 0000000..f4b03b9
--- /dev/null
+++ b/tests/ui/traits/const-traits/const-in-closure.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/const-in-closure.rs:4:30
+ |
+LL | #![feature(const_trait_impl, effects)]
+ | ^^^^^^^
+ |
+ = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
index 777b331..8f4235d 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
@@ -7,11 +7,6 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: const `impl` for trait `Default` which is not marked with `#[const_trait]`
--> $DIR/derive-const-non-const-type.rs:10:16
|
@@ -22,5 +17,17 @@
= note: adding a non-const method body in the future would be a breaking change
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
+error[E0015]: cannot call non-const fn `<A as Default>::default` in constant functions
+ --> $DIR/derive-const-non-const-type.rs:11:14
+ |
+LL | #[derive_const(Default)]
+ | ------- in this derive macro expansion
+LL | pub struct S(A);
+ | ^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
+
error: aborting due to 2 previous errors; 1 warning emitted
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
index ad727fc..7fc4422 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
@@ -19,11 +19,6 @@
LL | #![feature(const_trait_impl, const_cmp, const_default_impls, derive_const, effects)]
| ^^^^^^^^^^^^^^^^^^^
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: const `impl` for trait `Default` which is not marked with `#[const_trait]`
--> $DIR/derive-const-use.rs:7:12
|
@@ -62,29 +57,67 @@
= note: adding a non-const method body in the future would be a breaking change
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0080]: evaluation of constant value failed
- --> $DIR/derive-const-use.rs:16:14
+error[E0015]: cannot call non-const fn `<S as Default>::default` in constants
+ --> $DIR/derive-const-use.rs:18:35
|
-LL | #[derive_const(Default, PartialEq)]
- | ------- in this derive macro expansion
-LL | pub struct S((), A);
- | ^^ calling non-const function `<() as Default>::default`
+LL | const _: () = assert!(S((), A) == S::default());
+ | ^^^^^^^^^^^^
|
-note: inside `<S as Default>::default`
+ = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const operator in constants
+ --> $DIR/derive-const-use.rs:18:23
+ |
+LL | const _: () = assert!(S((), A) == S::default());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+
+error[E0015]: cannot call non-const fn `<() as Default>::default` in constant functions
--> $DIR/derive-const-use.rs:16:14
|
LL | #[derive_const(Default, PartialEq)]
| ------- in this derive macro expansion
LL | pub struct S((), A);
| ^^
-note: inside `_`
- --> $DIR/derive-const-use.rs:18:35
|
-LL | const _: () = assert!(S((), A) == S::default());
- | ^^^^^^^^^^^^
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 8 previous errors; 1 warning emitted
+error[E0015]: cannot call non-const fn `<A as Default>::default` in constant functions
+ --> $DIR/derive-const-use.rs:16:18
+ |
+LL | #[derive_const(Default, PartialEq)]
+ | ------- in this derive macro expansion
+LL | pub struct S((), A);
+ | ^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
-Some errors have detailed explanations: E0080, E0635.
-For more information about an error, try `rustc --explain E0080`.
+error[E0015]: cannot call non-const operator in constant functions
+ --> $DIR/derive-const-use.rs:16:14
+ |
+LL | #[derive_const(Default, PartialEq)]
+ | --------- in this derive macro expansion
+LL | pub struct S((), A);
+ | ^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0015]: cannot call non-const operator in constant functions
+ --> $DIR/derive-const-use.rs:16:18
+ |
+LL | #[derive_const(Default, PartialEq)]
+ | --------- in this derive macro expansion
+LL | pub struct S((), A);
+ | ^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 12 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0015, E0635.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
index addce8d..1395947 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
@@ -7,11 +7,6 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
--> $DIR/derive-const-with-params.rs:7:16
|
@@ -23,12 +18,26 @@
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/derive-const-with-params.rs:7:16
+
+error[E0015]: cannot call non-const operator in constant functions
+ --> $DIR/derive-const-with-params.rs:8:23
|
LL | #[derive_const(PartialEq)]
- | ^^^^^^^^^
+ | --------- in this derive macro expansion
+LL | pub struct Reverse<T>(T);
+ | ^
|
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 3 previous errors; 1 warning emitted
+error[E0015]: cannot call non-const operator in constant functions
+ --> $DIR/derive-const-with-params.rs:11:5
+ |
+LL | a == b
+ | ^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error: aborting due to 4 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/cross-crate.gatednc.stderr b/tests/ui/traits/const-traits/cross-crate.gatednc.stderr
index a34bae8..b6f2434 100644
--- a/tests/ui/traits/const-traits/cross-crate.gatednc.stderr
+++ b/tests/ui/traits/const-traits/cross-crate.gatednc.stderr
@@ -1,21 +1,8 @@
error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
- --> $DIR/cross-crate.rs:19:14
+ --> $DIR/cross-crate.rs:19:5
|
LL | NonConst.func();
- | ^^^^ the trait `cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
- |
-note: required by a bound in `func`
- --> $DIR/auxiliary/cross-crate.rs:5:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ required by this bound in `MyTrait::func`
-...
-LL | fn func(self);
- | ---- required by a bound in this associated function
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
- |
-LL | const fn const_context() where cross_crate::NonConst: cross_crate::MyTrait {
- | +++++++++++++++++++++++++++++++++++++++++++++++++
+ | ^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr
index d0f22c0..7b4d512 100644
--- a/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr
+++ b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr
@@ -1,21 +1,8 @@
error[E0277]: the trait bound `(): ~const Tr` is not satisfied
- --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+ --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:9
|
LL | ().a()
- | ^ the trait `Tr` is not implemented for `()`
- |
-note: required by a bound in `Tr::a`
- --> $DIR/default-method-body-is-const-same-trait-ck.rs:5:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ required by this bound in `Tr::a`
-LL | pub trait Tr {
-LL | fn a(&self) {}
- | - required by a bound in this associated function
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
- |
-LL | pub trait Tr where (): Tr {
- | ++++++++++++
+ | ^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/dont-observe-host-opaque.rs b/tests/ui/traits/const-traits/dont-observe-host-opaque.rs
new file mode 100644
index 0000000..4a5ae34
--- /dev/null
+++ b/tests/ui/traits/const-traits/dont-observe-host-opaque.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+const fn opaque() -> impl Sized {}
+
+fn main() {
+ let mut x = const { opaque() };
+ x = opaque();
+}
diff --git a/tests/ui/traits/const-traits/dont-observe-host-opaque.stderr b/tests/ui/traits/const-traits/dont-observe-host-opaque.stderr
new file mode 100644
index 0000000..1b457ab
--- /dev/null
+++ b/tests/ui/traits/const-traits/dont-observe-host-opaque.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/dont-observe-host-opaque.rs:4:30
+ |
+LL | #![feature(const_trait_impl, effects)]
+ | ^^^^^^^
+ |
+ = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/const-traits/dont-observe-host.rs b/tests/ui/traits/const-traits/dont-observe-host.rs
new file mode 100644
index 0000000..d027d57
--- /dev/null
+++ b/tests/ui/traits/const-traits/dont-observe-host.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait]
+trait Trait {
+ fn method() {}
+}
+
+impl const Trait for () {}
+
+fn main() {
+ let mut x = const {
+ let x = <()>::method;
+ x();
+ x
+ };
+ let y = <()>::method;
+ y();
+ x = y;
+}
diff --git a/tests/ui/traits/const-traits/dont-observe-host.stderr b/tests/ui/traits/const-traits/dont-observe-host.stderr
new file mode 100644
index 0000000..64ef611
--- /dev/null
+++ b/tests/ui/traits/const-traits/dont-observe-host.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/dont-observe-host.rs:4:30
+ |
+LL | #![feature(const_trait_impl, effects)]
+ | ^^^^^^^
+ |
+ = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs
index 3debc22..8f8e9f0 100644
--- a/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs
+++ b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.rs
@@ -1,5 +1,3 @@
-//@ check-pass
-// FIXME(effects) this shouldn't pass
//@ compile-flags: -Znext-solver
#![feature(const_closures, const_trait_impl, effects)]
#![allow(incomplete_features)]
@@ -14,5 +12,6 @@
fn main() {
(const || { (()).foo() })();
- // FIXME(effects) ~^ ERROR: cannot call non-const fn
+ //~^ ERROR: cannot call non-const fn `<() as Foo>::foo` in constant functions
+ // FIXME(effects) this should probably say constant closures
}
diff --git a/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr
new file mode 100644
index 0000000..243e940
--- /dev/null
+++ b/tests/ui/traits/const-traits/effects/const_closure-const_trait_impl-ice-113381.stderr
@@ -0,0 +1,11 @@
+error[E0015]: cannot call non-const fn `<() as Foo>::foo` in constant functions
+ --> $DIR/const_closure-const_trait_impl-ice-113381.rs:14:22
+ |
+LL | (const || { (()).foo() })();
+ | ^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
index 9a9016d..ab530b1 100644
--- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
+++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.rs
@@ -10,6 +10,7 @@
[first, remainder @ ..] => {
assert_eq!(first, &b'f');
//~^ ERROR cannot call non-const fn
+ //~| ERROR cannot call non-const operator
}
[] => panic!(),
}
diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
index 526746e..3618485 100644
--- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
+++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
@@ -17,25 +17,29 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/ice-112822-expected-type-for-param.rs:3:32
+ --> $DIR/ice-112822-expected-type-for-param.rs:3:25
|
LL | const fn test() -> impl ~const Fn() {
- | ^^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/ice-112822-expected-type-for-param.rs:3:32
+ --> $DIR/ice-112822-expected-type-for-param.rs:3:25
|
LL | const fn test() -> impl ~const Fn() {
- | ^^^^
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+error[E0015]: cannot call non-const operator in constant functions
+ --> $DIR/ice-112822-expected-type-for-param.rs:11:17
+ |
+LL | assert_eq!(first, &b'f');
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
error[E0015]: cannot call non-const fn `core::panicking::assert_failed::<&u8, &u8>` in constant functions
--> $DIR/ice-112822-expected-type-for-param.rs:11:17
|
diff --git a/tests/ui/traits/const-traits/effects/minicore.rs b/tests/ui/traits/const-traits/effects/minicore.rs
index 1c3c66b..1f0d22e 100644
--- a/tests/ui/traits/const-traits/effects/minicore.rs
+++ b/tests/ui/traits/const-traits/effects/minicore.rs
@@ -137,12 +137,12 @@
//impl_fn_mut_tuple!(A B C D);
//impl_fn_mut_tuple!(A B C D E);
-#[lang = "receiver"]
-trait Receiver {}
+#[lang = "legacy_receiver"]
+trait LegacyReceiver {}
-impl<T: ?Sized> Receiver for &T {}
+impl<T: ?Sized> LegacyReceiver for &T {}
-impl<T: ?Sized> Receiver for &mut T {}
+impl<T: ?Sized> LegacyReceiver for &mut T {}
#[lang = "destruct"]
#[const_trait]
@@ -454,7 +454,7 @@
}
}
-impl<P: Receiver> Receiver for Pin<P> {}
+impl<P: LegacyReceiver> LegacyReceiver for Pin<P> {}
impl<T: Clone> Clone for RefCell<T> {
fn clone(&self) -> RefCell<T> {
@@ -515,7 +515,7 @@
const fn drop<T: ~const Destruct>(_: T) {}
-#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
+#[rustc_const_stable_indirect]
#[rustc_intrinsic_must_be_overridden]
#[rustc_intrinsic]
const fn const_eval_select<ARG: Tuple, F, G, RET>(
@@ -536,35 +536,3 @@
const_eval_select((), const_fn, rt_fn);
}
-
-mod effects {
- use super::Sized;
-
- #[lang = "EffectsNoRuntime"]
- pub struct NoRuntime;
- #[lang = "EffectsMaybe"]
- pub struct Maybe;
- #[lang = "EffectsRuntime"]
- pub struct Runtime;
-
- #[lang = "EffectsCompat"]
- pub trait Compat<#[rustc_runtime] const RUNTIME: bool> {}
-
- impl Compat<false> for NoRuntime {}
- impl Compat<true> for Runtime {}
- impl<#[rustc_runtime] const RUNTIME: bool> Compat<RUNTIME> for Maybe {}
-
- #[lang = "EffectsTyCompat"]
- #[marker]
- pub trait TyCompat<T: ?Sized> {}
-
- impl<T: ?Sized> TyCompat<T> for T {}
- impl<T: ?Sized> TyCompat<T> for Maybe {}
- impl<T: ?Sized> TyCompat<Maybe> for T {}
-
- #[lang = "EffectsIntersection"]
- pub trait Intersection {
- #[lang = "EffectsIntersectionOutput"]
- type Output: ?Sized;
- }
-}
diff --git a/tests/ui/traits/const-traits/effects/minicore.stderr b/tests/ui/traits/const-traits/effects/minicore.stderr
index 823ab69..568d98c 100644
--- a/tests/ui/traits/const-traits/effects/minicore.stderr
+++ b/tests/ui/traits/const-traits/effects/minicore.stderr
@@ -1,13 +1,13 @@
error: the compiler unexpectedly panicked. this is a bug.
query stack during panic:
-#0 [check_well_formed] checking that `<impl at $DIR/minicore.rs:459:1: 459:36>` is well-formed
-#1 [check_mod_type_wf] checking that types are well-formed in top-level module
+#0 [typeck] type-checking `Clone::clone_from`
+#1 [analysis] running analysis passes on this crate
end of query stack
error: the compiler unexpectedly panicked. this is a bug.
query stack during panic:
-#0 [check_well_formed] checking that `drop` is well-formed
-#1 [check_mod_type_wf] checking that types are well-formed in top-level module
+#0 [typeck] type-checking `test_const_eval_select`
+#1 [analysis] running analysis passes on this crate
end of query stack
diff --git a/tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.stderr b/tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.stderr
index 8c591ed..eea6a06 100644
--- a/tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.stderr
+++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params-cross-crate.stderr
@@ -16,17 +16,15 @@
--> $DIR/no-explicit-const-params-cross-crate.rs:16:12
|
LL | <() as Bar<false>>::bar();
- | ^^^ expected 0 generic arguments
+ | ^^^------- help: remove the unnecessary generics
+ | |
+ | expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
--> $DIR/auxiliary/cross-crate.rs:8:11
|
LL | pub trait Bar {
| ^^^
-help: replace the generic bound with the associated type
- |
-LL | <() as Bar< = false>>::bar();
- | +
error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/no-explicit-const-params-cross-crate.rs:7:5
@@ -46,17 +44,15 @@
--> $DIR/no-explicit-const-params-cross-crate.rs:9:12
|
LL | <() as Bar<true>>::bar();
- | ^^^ expected 0 generic arguments
+ | ^^^------ help: remove the unnecessary generics
+ | |
+ | expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
--> $DIR/auxiliary/cross-crate.rs:8:11
|
LL | pub trait Bar {
| ^^^
-help: replace the generic bound with the associated type
- |
-LL | <() as Bar< = true>>::bar();
- | +
error: aborting due to 4 previous errors
diff --git a/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs b/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs
index 84f5f28..c6b94fa 100644
--- a/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs
+++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs
@@ -23,5 +23,5 @@
//~^ ERROR: function takes 0 generic arguments but 1 generic argument was supplied
<() as Bar<false>>::bar();
//~^ ERROR: trait takes 0 generic arguments but 1 generic argument was supplied
- //~| ERROR: mismatched types
+ //~| ERROR the trait bound `(): const Bar` is not satisfied
};
diff --git a/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr b/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr
index cc08114..bd9acc7 100644
--- a/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr
+++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr
@@ -7,11 +7,6 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/no-explicit-const-params.rs:22:5
|
@@ -30,26 +25,21 @@
--> $DIR/no-explicit-const-params.rs:24:12
|
LL | <() as Bar<false>>::bar();
- | ^^^ expected 0 generic arguments
+ | ^^^------- help: remove the unnecessary generics
+ | |
+ | expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
--> $DIR/no-explicit-const-params.rs:6:7
|
LL | trait Bar {
| ^^^
-help: replace the generic bound with the associated type
- |
-LL | <() as Bar< = false>>::bar();
- | +
-error[E0308]: mismatched types
+error[E0277]: the trait bound `(): const Bar` is not satisfied
--> $DIR/no-explicit-const-params.rs:24:5
|
LL | <() as Bar<false>>::bar();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true`
- |
- = note: expected constant `false`
- found constant `true`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/no-explicit-const-params.rs:15:5
@@ -69,19 +59,17 @@
--> $DIR/no-explicit-const-params.rs:17:12
|
LL | <() as Bar<true>>::bar();
- | ^^^ expected 0 generic arguments
+ | ^^^------ help: remove the unnecessary generics
+ | |
+ | expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
--> $DIR/no-explicit-const-params.rs:6:7
|
LL | trait Bar {
| ^^^
-help: replace the generic bound with the associated type
- |
-LL | <() as Bar< = true>>::bar();
- | +
-error: aborting due to 6 previous errors; 1 warning emitted
+error: aborting due to 5 previous errors; 1 warning emitted
-Some errors have detailed explanations: E0107, E0308.
+Some errors have detailed explanations: E0107, E0277.
For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr b/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr
index 5ff1c6c..313ba4f 100644
--- a/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr
+++ b/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr
@@ -17,11 +17,6 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error[E0308]: mismatched types
--> $DIR/span-bug-issue-121418.rs:9:27
|
@@ -44,7 +39,7 @@
--> $SRC_DIR/std/src/sync/mutex.rs:LL:COL
= note: the return type of a function must have a statically known size
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors; 1 warning emitted
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/effects/spec-effectvar-ice.rs b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.rs
index 0508b1c..d29cd93 100644
--- a/tests/ui/traits/const-traits/effects/spec-effectvar-ice.rs
+++ b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.rs
@@ -1,4 +1,3 @@
-//@ check-fail
// Fixes #119830
#![feature(effects)] //~ WARN the feature `effects` is incomplete
diff --git a/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr
index e97a961..273f994 100644
--- a/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr
+++ b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr
@@ -1,5 +1,5 @@
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/spec-effectvar-ice.rs:4:12
+ --> $DIR/spec-effectvar-ice.rs:3:12
|
LL | #![feature(effects)]
| ^^^^^^^
@@ -7,13 +7,8 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: const `impl` for trait `Foo` which is not marked with `#[const_trait]`
- --> $DIR/spec-effectvar-ice.rs:12:15
+ --> $DIR/spec-effectvar-ice.rs:11:15
|
LL | trait Foo {}
| - help: mark `Foo` as const: `#[const_trait]`
@@ -25,7 +20,7 @@
= note: adding a non-const method body in the future would be a breaking change
error: const `impl` for trait `Foo` which is not marked with `#[const_trait]`
- --> $DIR/spec-effectvar-ice.rs:15:15
+ --> $DIR/spec-effectvar-ice.rs:14:15
|
LL | trait Foo {}
| - help: mark `Foo` as const: `#[const_trait]`
@@ -37,28 +32,28 @@
= note: adding a non-const method body in the future would be a breaking change
error: `const` can only be applied to `#[const_trait]` traits
- --> $DIR/spec-effectvar-ice.rs:15:40
+ --> $DIR/spec-effectvar-ice.rs:14:34
|
LL | impl<T> const Foo for T where T: const Specialize {}
- | ^^^^^^^^^^
+ | ^^^^^
error: specialization impl does not specialize any associated items
- --> $DIR/spec-effectvar-ice.rs:15:1
+ --> $DIR/spec-effectvar-ice.rs:14:1
|
LL | impl<T> const Foo for T where T: const Specialize {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: impl is a specialization of this impl
- --> $DIR/spec-effectvar-ice.rs:12:1
+ --> $DIR/spec-effectvar-ice.rs:11:1
|
LL | impl<T> const Foo for T {}
| ^^^^^^^^^^^^^^^^^^^^^^^
error: cannot specialize on trait `Specialize`
- --> $DIR/spec-effectvar-ice.rs:15:34
+ --> $DIR/spec-effectvar-ice.rs:14:34
|
LL | impl<T> const Foo for T where T: const Specialize {}
| ^^^^^^^^^^^^^^^^
-error: aborting due to 6 previous errors; 1 warning emitted
+error: aborting due to 5 previous errors; 1 warning emitted
diff --git a/tests/ui/traits/const-traits/effects/trait-fn-const.stderr b/tests/ui/traits/const-traits/effects/trait-fn-const.stderr
index 15cb840..33914cb3 100644
--- a/tests/ui/traits/const-traits/effects/trait-fn-const.stderr
+++ b/tests/ui/traits/const-traits/effects/trait-fn-const.stderr
@@ -63,11 +63,6 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
-error: aborting due to 5 previous errors; 1 warning emitted
+error: aborting due to 4 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0379`.
diff --git a/tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr b/tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr
deleted file mode 100644
index 20448f5..0000000
--- a/tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr
+++ /dev/null
@@ -1,7 +0,0 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/traits/const-traits/effects/with-without-next-solver.rs b/tests/ui/traits/const-traits/effects/with-without-next-solver.rs
deleted file mode 100644
index f022af0..0000000
--- a/tests/ui/traits/const-traits/effects/with-without-next-solver.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// test that we error correctly when effects is used without the next-solver flag.
-//@ revisions: stock coherence full
-//@[coherence] compile-flags: -Znext-solver=coherence
-//@[full] compile-flags: -Znext-solver
-//@[full] check-pass
-
-#![feature(effects)]
-#![allow(incomplete_features)]
-
-fn main() {}
diff --git a/tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr b/tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr
deleted file mode 100644
index 20448f5..0000000
--- a/tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr
+++ /dev/null
@@ -1,7 +0,0 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/traits/const-traits/fn-ptr-lub.rs b/tests/ui/traits/const-traits/fn-ptr-lub.rs
new file mode 100644
index 0000000..0fc3267
--- /dev/null
+++ b/tests/ui/traits/const-traits/fn-ptr-lub.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+const fn foo() {}
+const fn bar() {}
+fn baz() {}
+
+const fn caller(branch: bool) {
+ let mut x = if branch {
+ foo
+ } else {
+ bar
+ };
+ x = baz;
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/fn-ptr-lub.stderr b/tests/ui/traits/const-traits/fn-ptr-lub.stderr
new file mode 100644
index 0000000..b333311
--- /dev/null
+++ b/tests/ui/traits/const-traits/fn-ptr-lub.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/fn-ptr-lub.rs:4:30
+ |
+LL | #![feature(const_trait_impl, effects)]
+ | ^^^^^^^
+ |
+ = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/const-traits/generic-bound.stderr b/tests/ui/traits/const-traits/generic-bound.stderr
index 2baac1d..0444c31 100644
--- a/tests/ui/traits/const-traits/generic-bound.stderr
+++ b/tests/ui/traits/const-traits/generic-bound.stderr
@@ -14,10 +14,6 @@
| ^^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/hir-const-check.rs b/tests/ui/traits/const-traits/hir-const-check.rs
index f5fb0fd..0ffd606 100644
--- a/tests/ui/traits/const-traits/hir-const-check.rs
+++ b/tests/ui/traits/const-traits/hir-const-check.rs
@@ -1,3 +1,5 @@
+//@ compile-flags: -Znext-solver
+
// Regression test for #69615.
#![feature(const_trait_impl, effects)] //~ WARN the feature `effects` is incomplete
@@ -10,6 +12,8 @@
impl const MyTrait for () {
fn method(&self) -> Option<()> {
Some(())?; //~ ERROR `?` is not allowed in a `const fn`
+ //~^ ERROR `?` cannot determine the branch of `Option<()>` in constant functions
+ //~| ERROR `?` cannot convert from residual of `Option<()>` in constant functions
None
}
}
diff --git a/tests/ui/traits/const-traits/hir-const-check.stderr b/tests/ui/traits/const-traits/hir-const-check.stderr
index 598129d..a22ac2c 100644
--- a/tests/ui/traits/const-traits/hir-const-check.stderr
+++ b/tests/ui/traits/const-traits/hir-const-check.stderr
@@ -1,5 +1,5 @@
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/hir-const-check.rs:3:30
+ --> $DIR/hir-const-check.rs:5:30
|
LL | #![feature(const_trait_impl, effects)]
| ^^^^^^^
@@ -8,7 +8,7 @@
= note: `#[warn(incomplete_features)]` on by default
error[E0658]: `?` is not allowed in a `const fn`
- --> $DIR/hir-const-check.rs:12:9
+ --> $DIR/hir-const-check.rs:14:9
|
LL | Some(())?;
| ^^^^^^^^^
@@ -17,11 +17,27 @@
= help: add `#![feature(const_try)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-error: using `#![feature(effects)]` without enabling next trait solver globally
+error[E0015]: `?` cannot determine the branch of `Option<()>` in constant functions
+ --> $DIR/hir-const-check.rs:14:9
|
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
+LL | Some(())?;
+ | ^^^^^^^^^
+ |
+note: impl defined here, but it is not `const`
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-error: aborting due to 2 previous errors; 1 warning emitted
+error[E0015]: `?` cannot convert from residual of `Option<()>` in constant functions
+ --> $DIR/hir-const-check.rs:14:9
+ |
+LL | Some(())?;
+ | ^^^^^^^^^
+ |
+note: impl defined here, but it is not `const`
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-For more information about this error, try `rustc --explain E0658`.
+error: aborting due to 3 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0015, E0658.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
index 50cdded..9e22422 100644
--- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
+++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
--> $DIR/ice-119717-constant-lifetime.rs:6:15
|
@@ -32,7 +27,7 @@
LL | fn from_residual(t: T) -> T {
| ~
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0121, E0210.
For more information about an error, try `rustc --explain E0121`.
diff --git a/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr b/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr
index 90771c3..1a11aec 100644
--- a/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr
+++ b/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr
@@ -55,11 +55,6 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error[E0425]: cannot find function `main8` in this scope
--> $DIR/ice-120503-async-const-method.rs:12:9
|
@@ -69,7 +64,7 @@
LL | fn main() {}
| --------- similarly named function `main` defined here
-error: aborting due to 6 previous errors; 1 warning emitted
+error: aborting due to 5 previous errors; 1 warning emitted
Some errors have detailed explanations: E0379, E0407, E0425.
For more information about an error, try `rustc --explain E0379`.
diff --git a/tests/ui/traits/const-traits/ice-121536-const-method.stderr b/tests/ui/traits/const-traits/ice-121536-const-method.stderr
index 2918765..4fe88f2 100644
--- a/tests/ui/traits/const-traits/ice-121536-const-method.stderr
+++ b/tests/ui/traits/const-traits/ice-121536-const-method.stderr
@@ -23,11 +23,6 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0379`.
diff --git a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs
index 64634e7..29f4060 100644
--- a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs
+++ b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs
@@ -3,5 +3,6 @@
const fn with_positive<F: ~const Fn()>() {}
//~^ ERROR `~const` can only be applied to `#[const_trait]` traits
+//~| ERROR `~const` can only be applied to `#[const_trait]` traits
pub fn main() {}
diff --git a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
index c937430..1178c90 100644
--- a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
+++ b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
@@ -1,13 +1,16 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/ice-123664-unexpected-bound-var.rs:4:34
+ --> $DIR/ice-123664-unexpected-bound-var.rs:4:27
|
LL | const fn with_positive<F: ~const Fn()>() {}
- | ^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/ice-123664-unexpected-bound-var.rs:4:27
+ |
+LL | const fn with_positive<F: ~const Fn()>() {}
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr
index 284757c..0b1f8b4 100644
--- a/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr
+++ b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error[E0119]: conflicting implementations of trait `Foo` for type `i32`
--> $DIR/ice-124857-combine-effect-const-infer-vars.rs:11:1
|
@@ -12,6 +7,6 @@
LL | impl<T> const Foo for T where T: ~const Foo {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32`
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs
index 717c0e7..da97a0e 100644
--- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs
+++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs
@@ -18,6 +18,8 @@
const fn t() -> TryMe {
TryMe?;
+ //~^ ERROR `?` cannot determine the branch of `TryMe` in constant functions
+ //~| ERROR `?` cannot convert from residual of `TryMe` in constant functions
TryMe
}
diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
index e49436c..db047bf 100644
--- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
+++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
--> $DIR/ice-126148-failed-to-normalize.rs:8:12
|
@@ -38,6 +33,23 @@
= help: implement the missing item: `fn from_output(_: <Self as Try>::Output) -> Self { todo!() }`
= help: implement the missing item: `fn branch(self) -> ControlFlow<<Self as Try>::Residual, <Self as Try>::Output> { todo!() }`
-error: aborting due to 5 previous errors
+error[E0015]: `?` cannot determine the branch of `TryMe` in constant functions
+ --> $DIR/ice-126148-failed-to-normalize.rs:20:5
+ |
+LL | TryMe?;
+ | ^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-For more information about this error, try `rustc --explain E0046`.
+error[E0015]: `?` cannot convert from residual of `TryMe` in constant functions
+ --> $DIR/ice-126148-failed-to-normalize.rs:20:5
+ |
+LL | TryMe?;
+ | ^^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0015, E0046.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr b/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr
index 2ea2036..0135296 100644
--- a/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr
+++ b/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error[E0046]: not all trait items implemented, missing: `req`
--> $DIR/impl-with-default-fn-fail.rs:13:1
|
@@ -12,6 +7,6 @@
LL | impl const Tr for u16 {
| ^^^^^^^^^^^^^^^^^^^^^ missing `req` in implementation
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0046`.
diff --git a/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs
index e3adcce..8638c4b 100644
--- a/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs
+++ b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.rs
@@ -25,6 +25,7 @@
const fn foo() {
().foo();
+ //~^ ERROR cannot call non-const fn `<() as Trait>::foo` in constant functions
}
const UWU: () = foo();
diff --git a/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr
index 2e7801c..096b00d 100644
--- a/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr
+++ b/tests/ui/traits/const-traits/inline-incorrect-early-bound-in-ctfe.stderr
@@ -16,6 +16,15 @@
LL | fn foo<T>(self) {
| ^ found 1 type parameter
-error: aborting due to 1 previous error; 1 warning emitted
+error[E0015]: cannot call non-const fn `<() as Trait>::foo` in constant functions
+ --> $DIR/inline-incorrect-early-bound-in-ctfe.rs:27:8
+ |
+LL | ().foo();
+ | ^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-For more information about this error, try `rustc --explain E0049`.
+error: aborting due to 2 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0015, E0049.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/issue-102985.stderr b/tests/ui/traits/const-traits/issue-102985.stderr
index 8401d1b..7c5c5ac 100644
--- a/tests/ui/traits/const-traits/issue-102985.stderr
+++ b/tests/ui/traits/const-traits/issue-102985.stderr
@@ -6,10 +6,6 @@
|
= note: closures need an RFC before allowed to be called in constants
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/issue-79450.rs b/tests/ui/traits/const-traits/issue-79450.rs
index b8b9e07..cdefebc 100644
--- a/tests/ui/traits/const-traits/issue-79450.rs
+++ b/tests/ui/traits/const-traits/issue-79450.rs
@@ -1,6 +1,5 @@
//@ compile-flags: -Znext-solver
#![allow(incomplete_features)]
-#![feature(const_fmt_arguments_new)]
#![feature(const_trait_impl, effects)]
#[const_trait]
diff --git a/tests/ui/traits/const-traits/issue-79450.stderr b/tests/ui/traits/const-traits/issue-79450.stderr
index 9e6348d..49f380c 100644
--- a/tests/ui/traits/const-traits/issue-79450.stderr
+++ b/tests/ui/traits/const-traits/issue-79450.stderr
@@ -1,5 +1,5 @@
error[E0015]: cannot call non-const fn `_print` in constant functions
- --> $DIR/issue-79450.rs:11:9
+ --> $DIR/issue-79450.rs:10:9
|
LL | println!("lul");
| ^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/const-traits/issue-88155.stderr b/tests/ui/traits/const-traits/issue-88155.stderr
index afe1ea3..157b542 100644
--- a/tests/ui/traits/const-traits/issue-88155.stderr
+++ b/tests/ui/traits/const-traits/issue-88155.stderr
@@ -5,10 +5,6 @@
| ^^^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/issue-92111.stderr b/tests/ui/traits/const-traits/issue-92111.stderr
index ecc994a..51c6a22 100644
--- a/tests/ui/traits/const-traits/issue-92111.stderr
+++ b/tests/ui/traits/const-traits/issue-92111.stderr
@@ -1,8 +1,16 @@
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/issue-92111.rs:20:22
+ --> $DIR/issue-92111.rs:20:15
|
LL | const fn a<T: ~const Destruct>(t: T) {}
- | ^^^^^^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/issue-92111.rs:20:15
+ |
+LL | const fn a<T: ~const Destruct>(t: T) {}
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/issue-92111.rs:20:32
@@ -12,6 +20,6 @@
| |
| the destructor for this type cannot be evaluated in constant functions
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.rs b/tests/ui/traits/const-traits/item-bound-entailment-fails.rs
new file mode 100644
index 0000000..42799e3
--- /dev/null
+++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -Znext-solver
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Foo {
+ type Assoc<T>: ~const Bar
+ where
+ T: ~const Bar;
+}
+
+#[const_trait] trait Bar {}
+struct N<T>(T);
+impl<T> Bar for N<T> where T: Bar {}
+struct C<T>(T);
+impl<T> const Bar for C<T> where T: ~const Bar {}
+
+impl const Foo for u32 {
+ type Assoc<T> = N<T>
+ //~^ ERROR the trait bound `N<T>: ~const Bar` is not satisfied
+ where
+ T: ~const Bar;
+}
+
+impl const Foo for i32 {
+ type Assoc<T> = C<T>
+ //~^ ERROR the trait bound `T: ~const Bar` is not satisfied
+ where
+ T: Bar;
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr
new file mode 100644
index 0000000..054a8ac
--- /dev/null
+++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr
@@ -0,0 +1,36 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/item-bound-entailment-fails.rs:2:30
+ |
+LL | #![feature(const_trait_impl, effects)]
+ | ^^^^^^^
+ |
+ = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the trait bound `N<T>: ~const Bar` is not satisfied
+ --> $DIR/item-bound-entailment-fails.rs:18:21
+ |
+LL | type Assoc<T> = N<T>
+ | ^^^^
+ |
+note: required by a bound in `Foo::Assoc`
+ --> $DIR/item-bound-entailment-fails.rs:6:20
+ |
+LL | type Assoc<T>: ~const Bar
+ | ^^^^^^ required by this bound in `Foo::Assoc`
+
+error[E0277]: the trait bound `T: ~const Bar` is not satisfied
+ --> $DIR/item-bound-entailment-fails.rs:25:21
+ |
+LL | type Assoc<T> = C<T>
+ | ^^^^
+ |
+note: required by a bound in `Foo::Assoc`
+ --> $DIR/item-bound-entailment-fails.rs:6:20
+ |
+LL | type Assoc<T>: ~const Bar
+ | ^^^^^^ required by this bound in `Foo::Assoc`
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/item-bound-entailment.rs b/tests/ui/traits/const-traits/item-bound-entailment.rs
new file mode 100644
index 0000000..3670eab
--- /dev/null
+++ b/tests/ui/traits/const-traits/item-bound-entailment.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Foo {
+ type Assoc<T>: ~const Bar
+ where
+ T: ~const Bar;
+}
+
+#[const_trait] trait Bar {}
+struct N<T>(T);
+impl<T> Bar for N<T> where T: Bar {}
+struct C<T>(T);
+impl<T> const Bar for C<T> where T: ~const Bar {}
+
+impl Foo for u32 {
+ type Assoc<T> = N<T>
+ where
+ T: Bar;
+}
+
+impl const Foo for i32 {
+ type Assoc<T> = C<T>
+ where
+ T: ~const Bar;
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/item-bound-entailment.stderr b/tests/ui/traits/const-traits/item-bound-entailment.stderr
new file mode 100644
index 0000000..b4a4ebd
--- /dev/null
+++ b/tests/ui/traits/const-traits/item-bound-entailment.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/item-bound-entailment.rs:4:30
+ |
+LL | #![feature(const_trait_impl, effects)]
+ | ^^^^^^^
+ |
+ = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr b/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr
index c7d2115..89e59e5 100644
--- a/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr
+++ b/tests/ui/traits/const-traits/match-non-const-eq.gated.stderr
@@ -6,10 +6,6 @@
|
= note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr
index 0f5ecac..89e59e5 100644
--- a/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr
+++ b/tests/ui/traits/const-traits/match-non-const-eq.stock.stderr
@@ -6,10 +6,6 @@
|
= note: `str` cannot be compared in compile-time, and therefore cannot be used in `match`es
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr
index c362a10..97ad831 100644
--- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr
+++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr
@@ -5,10 +5,6 @@
| ^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
index de4783b..837effb 100644
--- a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
+++ b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
@@ -1,17 +1,16 @@
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/non-const-op-in-closure-in-const.rs:10:51
+ --> $DIR/non-const-op-in-closure-in-const.rs:10:44
|
LL | impl<A, B> const Convert<B> for A where B: ~const From<A> {
- | ^^^^^^^
+ | ^^^^^^
-error[E0049]: method `to` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/non-const-op-in-closure-in-const.rs:5:1
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/non-const-op-in-closure-in-const.rs:10:44
|
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Convert<T> {
-LL | fn to(self) -> T;
- | - expected 0 const parameters
+LL | impl<A, B> const Convert<B> for A where B: ~const From<A> {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0015]: cannot call non-const fn `<B as From<A>>::from` in constant functions
--> $DIR/non-const-op-in-closure-in-const.rs:12:9
@@ -20,12 +19,7 @@
| ^^^^^^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/predicate-entailment-fails.rs b/tests/ui/traits/const-traits/predicate-entailment-fails.rs
new file mode 100644
index 0000000..5d6109b
--- /dev/null
+++ b/tests/ui/traits/const-traits/predicate-entailment-fails.rs
@@ -0,0 +1,43 @@
+//@ compile-flags: -Znext-solver
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Bar {}
+impl const Bar for () {}
+
+
+#[const_trait] trait TildeConst {
+ type Bar<T> where T: ~const Bar;
+
+ fn foo<T>() where T: ~const Bar;
+}
+impl TildeConst for () {
+ type Bar<T> = () where T: const Bar;
+ //~^ ERROR impl has stricter requirements than trait
+
+ fn foo<T>() where T: const Bar {}
+ //~^ ERROR impl has stricter requirements than trait
+}
+
+
+#[const_trait] trait NeverConst {
+ type Bar<T> where T: Bar;
+
+ fn foo<T>() where T: Bar;
+}
+impl NeverConst for i32 {
+ type Bar<T> = () where T: const Bar;
+ //~^ ERROR impl has stricter requirements than trait
+
+ fn foo<T>() where T: const Bar {}
+ //~^ ERROR impl has stricter requirements than trait
+}
+impl const NeverConst for u32 {
+ type Bar<T> = () where T: ~const Bar;
+ //~^ ERROR impl has stricter requirements than trait
+
+ fn foo<T>() where T: ~const Bar {}
+ //~^ ERROR impl has stricter requirements than trait
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/predicate-entailment-fails.stderr b/tests/ui/traits/const-traits/predicate-entailment-fails.stderr
new file mode 100644
index 0000000..c50009e
--- /dev/null
+++ b/tests/ui/traits/const-traits/predicate-entailment-fails.stderr
@@ -0,0 +1,66 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/predicate-entailment-fails.rs:2:30
+ |
+LL | #![feature(const_trait_impl, effects)]
+ | ^^^^^^^
+ |
+ = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/predicate-entailment-fails.rs:15:31
+ |
+LL | type Bar<T> where T: ~const Bar;
+ | ----------- definition of `Bar` from trait
+...
+LL | type Bar<T> = () where T: const Bar;
+ | ^^^^^ impl has extra requirement `T: const Bar`
+
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/predicate-entailment-fails.rs:18:26
+ |
+LL | fn foo<T>() where T: ~const Bar;
+ | -------------------------------- definition of `foo` from trait
+...
+LL | fn foo<T>() where T: const Bar {}
+ | ^^^^^ impl has extra requirement `T: const Bar`
+
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/predicate-entailment-fails.rs:29:31
+ |
+LL | type Bar<T> where T: Bar;
+ | ----------- definition of `Bar` from trait
+...
+LL | type Bar<T> = () where T: const Bar;
+ | ^^^^^ impl has extra requirement `T: const Bar`
+
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/predicate-entailment-fails.rs:32:26
+ |
+LL | fn foo<T>() where T: Bar;
+ | ------------------------- definition of `foo` from trait
+...
+LL | fn foo<T>() where T: const Bar {}
+ | ^^^^^ impl has extra requirement `T: const Bar`
+
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/predicate-entailment-fails.rs:36:31
+ |
+LL | type Bar<T> where T: Bar;
+ | ----------- definition of `Bar` from trait
+...
+LL | type Bar<T> = () where T: ~const Bar;
+ | ^^^^^^ impl has extra requirement `T: ~const Bar`
+
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/predicate-entailment-fails.rs:39:26
+ |
+LL | fn foo<T>() where T: Bar;
+ | ------------------------- definition of `foo` from trait
+...
+LL | fn foo<T>() where T: ~const Bar {}
+ | ^^^^^^ impl has extra requirement `T: ~const Bar`
+
+error: aborting due to 6 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0276`.
diff --git a/tests/ui/traits/const-traits/predicate-entailment-passes.rs b/tests/ui/traits/const-traits/predicate-entailment-passes.rs
new file mode 100644
index 0000000..b660329
--- /dev/null
+++ b/tests/ui/traits/const-traits/predicate-entailment-passes.rs
@@ -0,0 +1,39 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+//~^ WARN the feature `effects` is incomplete
+
+#[const_trait] trait Bar {}
+impl const Bar for () {}
+
+
+#[const_trait] trait TildeConst {
+ type Bar<T> where T: ~const Bar;
+
+ fn foo<T>() where T: ~const Bar;
+}
+impl TildeConst for () {
+ type Bar<T> = () where T: Bar;
+
+ fn foo<T>() where T: Bar {}
+}
+
+
+#[const_trait] trait AlwaysConst {
+ type Bar<T> where T: const Bar;
+
+ fn foo<T>() where T: const Bar;
+}
+impl AlwaysConst for i32 {
+ type Bar<T> = () where T: Bar;
+
+ fn foo<T>() where T: Bar {}
+}
+impl const AlwaysConst for u32 {
+ type Bar<T> = () where T: ~const Bar;
+
+ fn foo<T>() where T: ~const Bar {}
+}
+
+fn main() {}
diff --git a/tests/ui/traits/const-traits/predicate-entailment-passes.stderr b/tests/ui/traits/const-traits/predicate-entailment-passes.stderr
new file mode 100644
index 0000000..dcaeea7
--- /dev/null
+++ b/tests/ui/traits/const-traits/predicate-entailment-passes.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/predicate-entailment-passes.rs:4:30
+ |
+LL | #![feature(const_trait_impl, effects)]
+ | ^^^^^^^
+ |
+ = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr
index 7643697..bffc60c 100644
--- a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr
+++ b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr
@@ -1,12 +1,3 @@
-error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const-default-bound-non-const-specialized-bound.rs:16:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Bar {
-LL | fn bar();
- | - expected 0 const parameters
-
error: cannot specialize on const impl with non-const impl
--> $DIR/const-default-bound-non-const-specialized-bound.rs:28:1
|
@@ -16,26 +7,5 @@
LL | | T: Specialize,
| |__________________^
-error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const-default-bound-non-const-specialized-bound.rs:36:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Baz {
-LL | fn baz();
- | - expected 0 const parameters
+error: aborting due to 1 previous error
-error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const-default-bound-non-const-specialized-bound.rs:36:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Baz {
-LL | fn baz();
- | - expected 0 const parameters
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0049`.
diff --git a/tests/ui/traits/const-traits/specialization/const-default-const-specialized.stderr b/tests/ui/traits/const-traits/specialization/const-default-const-specialized.stderr
index 9b2ae8d..f127268 100644
--- a/tests/ui/traits/const-traits/specialization/const-default-const-specialized.stderr
+++ b/tests/ui/traits/const-traits/specialization/const-default-const-specialized.stderr
@@ -1,23 +1,3 @@
-error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const-default-const-specialized.rs:10:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Value {
-LL | fn value() -> u32;
- | - expected 0 const parameters
-
-error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/const-default-const-specialized.rs:10:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Value {
-LL | fn value() -> u32;
- | - expected 0 const parameters
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
error[E0015]: cannot call non-const fn `<T as Value>::value` in constant functions
--> $DIR/const-default-const-specialized.rs:16:5
|
@@ -30,7 +10,6 @@
LL + #![feature(effects)]
|
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr
index c51d169..363fbee 100644
--- a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr
+++ b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr
@@ -7,16 +7,11 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: cannot specialize on const impl with non-const impl
--> $DIR/const-default-impl-non-const-specialized-impl.rs:19:1
|
LL | impl Value for FortyTwo {
| ^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 1 previous error; 1 warning emitted
diff --git a/tests/ui/traits/const-traits/specialization/default-keyword.rs b/tests/ui/traits/const-traits/specialization/default-keyword.rs
index d9ffd23..bc45a70 100644
--- a/tests/ui/traits/const-traits/specialization/default-keyword.rs
+++ b/tests/ui/traits/const-traits/specialization/default-keyword.rs
@@ -1,5 +1,4 @@
-//@ known-bug: #110395
-// FIXME check-pass
+//@ check-pass
#![feature(const_trait_impl)]
#![feature(min_specialization)]
diff --git a/tests/ui/traits/const-traits/specialization/default-keyword.stderr b/tests/ui/traits/const-traits/specialization/default-keyword.stderr
deleted file mode 100644
index 18a2504..0000000
--- a/tests/ui/traits/const-traits/specialization/default-keyword.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/default-keyword.rs:7:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Foo {
-LL | fn foo();
- | - expected 0 const parameters
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0049`.
diff --git a/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs b/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs
index 219e5f3..d80370a 100644
--- a/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs
+++ b/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.rs
@@ -1,7 +1,6 @@
// Tests that `~const` trait bounds can be used to specialize const trait impls.
-//@ known-bug: #110395
-// FIXME check-pass
+//@ check-pass
#![feature(const_trait_impl)]
#![feature(rustc_attrs)]
diff --git a/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.stderr b/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.stderr
deleted file mode 100644
index ecdc7b9..0000000
--- a/tests/ui/traits/const-traits/specialization/issue-95186-specialize-on-tilde-const.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/issue-95186-specialize-on-tilde-const.rs:14:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Foo {
-LL | fn foo();
- | - expected 0 const parameters
-
-error[E0049]: associated function `foo` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/issue-95186-specialize-on-tilde-const.rs:14:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Foo {
-LL | fn foo();
- | - expected 0 const parameters
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/issue-95186-specialize-on-tilde-const.rs:30:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Bar {
-LL | fn bar() {}
- | - expected 0 const parameters
-
-error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/issue-95186-specialize-on-tilde-const.rs:30:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Bar {
-LL | fn bar() {}
- | - expected 0 const parameters
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0049`.
diff --git a/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs b/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs
index 7514baa..d97469e 100644
--- a/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs
+++ b/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs
@@ -2,8 +2,7 @@
// `T: Foo` in the default impl for the purposes of specialization (i.e., it
// does not think that the user is attempting to specialize on trait `Foo`).
-//@ known-bug: #110395
-// FIXME check-pass
+//@ check-pass
#![feature(rustc_attrs)]
#![feature(min_specialization)]
diff --git a/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.stderr b/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.stderr
deleted file mode 100644
index 6679bb4..0000000
--- a/tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/issue-95187-same-trait-bound-different-constness.rs:18:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Bar {
-LL | fn bar();
- | - expected 0 const parameters
-
-error[E0049]: associated function `bar` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/issue-95187-same-trait-bound-different-constness.rs:18:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Bar {
-LL | fn bar();
- | - expected 0 const parameters
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/issue-95187-same-trait-bound-different-constness.rs:38:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Baz {
-LL | fn baz();
- | - expected 0 const parameters
-
-error[E0049]: associated function `baz` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/issue-95187-same-trait-bound-different-constness.rs:38:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Baz {
-LL | fn baz();
- | - expected 0 const parameters
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0049`.
diff --git a/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.stderr b/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.stderr
index 7f36392..a4095d7 100644
--- a/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.stderr
+++ b/tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.stderr
@@ -1,23 +1,3 @@
-error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/non-const-default-const-specialized.rs:9:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Value {
-LL | fn value() -> u32;
- | - expected 0 const parameters
-
-error[E0049]: associated function `value` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/non-const-default-const-specialized.rs:9:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | trait Value {
-LL | fn value() -> u32;
- | - expected 0 const parameters
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
error[E0015]: cannot call non-const fn `<T as Value>::value` in constant functions
--> $DIR/non-const-default-const-specialized.rs:15:5
|
@@ -30,7 +10,6 @@
LL + #![feature(effects)]
|
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/specializing-constness-2.stderr b/tests/ui/traits/const-traits/specializing-constness-2.stderr
index bf273f3..8e6f694 100644
--- a/tests/ui/traits/const-traits/specializing-constness-2.stderr
+++ b/tests/ui/traits/const-traits/specializing-constness-2.stderr
@@ -1,23 +1,3 @@
-error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/specializing-constness-2.rs:9:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait A {
-LL | fn a() -> u32;
- | - expected 0 const parameters
-
-error[E0049]: associated function `a` has 1 const parameter but its trait declaration has 0 const parameters
- --> $DIR/specializing-constness-2.rs:9:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ found 1 const parameter
-LL | pub trait A {
-LL | fn a() -> u32;
- | - expected 0 const parameters
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
error[E0015]: cannot call non-const fn `<T as A>::a` in constant functions
--> $DIR/specializing-constness-2.rs:27:5
|
@@ -30,7 +10,6 @@
LL + #![feature(effects)]
|
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
-Some errors have detailed explanations: E0015, E0049.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/specializing-constness.rs b/tests/ui/traits/const-traits/specializing-constness.rs
index 4501a21..3aabaf1 100644
--- a/tests/ui/traits/const-traits/specializing-constness.rs
+++ b/tests/ui/traits/const-traits/specializing-constness.rs
@@ -22,8 +22,6 @@
impl<T: Spec + Sup> A for T {
//~^ ERROR: cannot specialize
-//~| ERROR: cannot specialize
-//~| ERROR: cannot specialize
//FIXME(effects) ~| ERROR: missing `~const` qualifier
fn a() -> u32 {
3
diff --git a/tests/ui/traits/const-traits/specializing-constness.stderr b/tests/ui/traits/const-traits/specializing-constness.stderr
index 90721af..226295b 100644
--- a/tests/ui/traits/const-traits/specializing-constness.stderr
+++ b/tests/ui/traits/const-traits/specializing-constness.stderr
@@ -7,28 +7,11 @@
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
= note: `#[warn(incomplete_features)]` on by default
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
error: cannot specialize on const impl with non-const impl
--> $DIR/specializing-constness.rs:23:1
|
LL | impl<T: Spec + Sup> A for T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: cannot specialize on trait `Compat`
- --> $DIR/specializing-constness.rs:23:16
- |
-LL | impl<T: Spec + Sup> A for T {
- | ^^^
-
-error: cannot specialize on trait `Compat`
- --> $DIR/specializing-constness.rs:23:9
- |
-LL | impl<T: Spec + Sup> A for T {
- | ^^^^
-
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 1 previous error; 1 warning emitted
diff --git a/tests/ui/traits/const-traits/staged-api.rs b/tests/ui/traits/const-traits/staged-api.rs
index f87e723..59fe6d5 100644
--- a/tests/ui/traits/const-traits/staged-api.rs
+++ b/tests/ui/traits/const-traits/staged-api.rs
@@ -2,6 +2,7 @@
//@ compile-flags: -Znext-solver
#![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file.
+#![cfg_attr(unstable, feature(local_feature))]
#![feature(const_trait_impl, effects)]
#![allow(incomplete_features)]
#![feature(staged_api)]
@@ -16,8 +17,8 @@
pub struct Foo;
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
-#[cfg_attr(stable, rustc_const_stable(feature = "foo", since = "1.0.0"))]
+#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))]
+#[cfg_attr(stable, rustc_const_stable(feature = "local_feature", since = "1.0.0"))]
impl const MyTrait for Foo {
//[stable]~^ ERROR trait implementations cannot be const stable yet
fn func() {}
@@ -32,32 +33,43 @@
#[unstable(feature = "none", issue = "none")]
const fn const_context() {
Unstable::func();
- //[stable]~^ ERROR not yet stable as a const fn
+ //[unstable]~^ ERROR cannot use `#[feature(unstable)]`
+ //[stable]~^^ ERROR not yet stable as a const fn
Foo::func();
- //[unstable]~^ ERROR not yet stable as a const fn
- // ^ fails, because the `foo` feature is not active
+ //[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
+ //[stable]~^^ cannot be (indirectly) exposed to stable
+ // We get the error on `stable` since this is a trait function.
+ Unstable2::func();
+ //~^ ERROR not yet stable as a const fn
+ // ^ fails, because the `unstable2` feature is not active
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(unstable, rustc_const_unstable(feature = "foo", issue = "none"))]
+#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))]
pub const fn const_context_not_const_stable() {
//[stable]~^ ERROR function has missing const stability attribute
Unstable::func();
//[stable]~^ ERROR not yet stable as a const fn
Foo::func();
- //[unstable]~^ ERROR not yet stable as a const fn
- // ^ fails, because the `foo` feature is not active
+ //[stable]~^ cannot be (indirectly) exposed to stable
+ // We get the error on `stable` since this is a trait function.
+ Unstable2::func();
+ //~^ ERROR not yet stable as a const fn
+ // ^ fails, because the `unstable2` feature is not active
}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "cheese", since = "1.0.0")]
const fn stable_const_context() {
Unstable::func();
- //~^ ERROR not yet stable as a const fn
+ //[unstable]~^ ERROR cannot use `#[feature(unstable)]`
+ //[stable]~^^ ERROR not yet stable as a const fn
Foo::func();
- //[unstable]~^ ERROR not yet stable as a const fn
+ //[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
+ //[stable]~^^ cannot be (indirectly) exposed to stable
+ // We get the error on `stable` since this is a trait function.
const_context_not_const_stable()
- //[unstable]~^ ERROR not yet stable as a const fn
+ //[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
}
fn main() {}
diff --git a/tests/ui/traits/const-traits/staged-api.stable.stderr b/tests/ui/traits/const-traits/staged-api.stable.stderr
index 6c07a25..4004508 100644
--- a/tests/ui/traits/const-traits/staged-api.stable.stderr
+++ b/tests/ui/traits/const-traits/staged-api.stable.stderr
@@ -1,5 +1,5 @@
error: trait implementations cannot be const stable yet
- --> $DIR/staged-api.rs:21:1
+ --> $DIR/staged-api.rs:22:1
|
LL | / impl const MyTrait for Foo {
LL | |
@@ -10,40 +10,80 @@
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
error: function has missing const stability attribute
- --> $DIR/staged-api.rs:43:1
+ --> $DIR/staged-api.rs:49:1
|
LL | / pub const fn const_context_not_const_stable() {
LL | |
LL | | Unstable::func();
LL | |
... |
-LL | | // ^ fails, because the `foo` feature is not active
+LL | | // ^ fails, because the `unstable2` feature is not active
LL | | }
| |_^
error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
- --> $DIR/staged-api.rs:34:5
+ --> $DIR/staged-api.rs:35:5
|
LL | Unstable::func();
| ^^^^^^^^^^^^^^^^
|
= help: add `#![feature(unstable)]` to the crate attributes to enable
+error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable
+ --> $DIR/staged-api.rs:38:5
+ |
+LL | Foo::func();
+ | ^^^^^^^^^^^
+ |
+ = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
+
+error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
+ --> $DIR/staged-api.rs:42:5
+ |
+LL | Unstable2::func();
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: add `#![feature(unstable2)]` to the crate attributes to enable
+
error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
- --> $DIR/staged-api.rs:45:5
+ --> $DIR/staged-api.rs:51:5
|
LL | Unstable::func();
| ^^^^^^^^^^^^^^^^
|
= help: add `#![feature(unstable)]` to the crate attributes to enable
+error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable
+ --> $DIR/staged-api.rs:53:5
+ |
+LL | Foo::func();
+ | ^^^^^^^^^^^
+ |
+ = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
+
+error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
+ --> $DIR/staged-api.rs:56:5
+ |
+LL | Unstable2::func();
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: add `#![feature(unstable2)]` to the crate attributes to enable
+
error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
- --> $DIR/staged-api.rs:55:5
+ --> $DIR/staged-api.rs:64:5
|
LL | Unstable::func();
| ^^^^^^^^^^^^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: add `#![feature(unstable)]` to the crate attributes to enable
-error: aborting due to 5 previous errors
+error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable
+ --> $DIR/staged-api.rs:67:5
+ |
+LL | Foo::func();
+ | ^^^^^^^^^^^
+ |
+ = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
+
+error: aborting due to 10 previous errors
diff --git a/tests/ui/traits/const-traits/staged-api.unstable.stderr b/tests/ui/traits/const-traits/staged-api.unstable.stderr
index 1c772f1..64b3a8a 100644
--- a/tests/ui/traits/const-traits/staged-api.unstable.stderr
+++ b/tests/ui/traits/const-traits/staged-api.unstable.stderr
@@ -1,42 +1,108 @@
-error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
- --> $DIR/staged-api.rs:36:5
- |
-LL | Foo::func();
- | ^^^^^^^^^^^
- |
- = help: add `#![feature(foo)]` to the crate attributes to enable
-
-error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
- --> $DIR/staged-api.rs:47:5
- |
-LL | Foo::func();
- | ^^^^^^^^^^^
- |
- = help: add `#![feature(foo)]` to the crate attributes to enable
-
-error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
- --> $DIR/staged-api.rs:55:5
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
+ --> $DIR/staged-api.rs:35:5
|
LL | Unstable::func();
| ^^^^^^^^^^^^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn const_context() {
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(unstable)]
+LL | const fn const_context() {
+ |
-error: `<Foo as staged_api::MyTrait>::func` is not yet stable as a const fn
- --> $DIR/staged-api.rs:57:5
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
+ --> $DIR/staged-api.rs:38:5
|
LL | Foo::func();
| ^^^^^^^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn const_context() {
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(local_feature)]
+LL | const fn const_context() {
+ |
-error: `const_context_not_const_stable` is not yet stable as a const fn
- --> $DIR/staged-api.rs:59:5
+error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
+ --> $DIR/staged-api.rs:42:5
+ |
+LL | Unstable2::func();
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: add `#![feature(unstable2)]` to the crate attributes to enable
+
+error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
+ --> $DIR/staged-api.rs:56:5
+ |
+LL | Unstable2::func();
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: add `#![feature(unstable2)]` to the crate attributes to enable
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
+ --> $DIR/staged-api.rs:64:5
+ |
+LL | Unstable::func();
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(unstable)]
+LL | const fn stable_const_context() {
+ |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
+ --> $DIR/staged-api.rs:67:5
+ |
+LL | Foo::func();
+ | ^^^^^^^^^^^
+ |
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(local_feature)]
+LL | const fn stable_const_context() {
+ |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
+ --> $DIR/staged-api.rs:71:5
|
LL | const_context_not_const_stable()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: const-stable functions can only call other const-stable functions
+ = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+ |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+ |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+ |
+LL + #[rustc_allow_const_fn_unstable(local_feature)]
+LL | const fn stable_const_context() {
+ |
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
diff --git a/tests/ui/traits/const-traits/std-impl-gate.gated.stderr b/tests/ui/traits/const-traits/std-impl-gate.gated.stderr
index d761fdc..f3b1713 100644
--- a/tests/ui/traits/const-traits/std-impl-gate.gated.stderr
+++ b/tests/ui/traits/const-traits/std-impl-gate.gated.stderr
@@ -11,10 +11,6 @@
| ^^^^^^^^^^^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(effects)]` to the crate attributes to enable
- |
-LL + #![feature(effects)]
- |
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/std-impl-gate.stock.stderr b/tests/ui/traits/const-traits/std-impl-gate.stock.stderr
index b63ea69..7240b5f 100644
--- a/tests/ui/traits/const-traits/std-impl-gate.stock.stderr
+++ b/tests/ui/traits/const-traits/std-impl-gate.stock.stderr
@@ -5,10 +5,6 @@
| ^^^^^^^^^^^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
index 48bb190..8de1bb0 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
@@ -11,26 +11,35 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-2.rs:12:19
+ --> $DIR/super-traits-fail-2.rs:12:12
|
LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-2.rs:12:19
+ --> $DIR/super-traits-fail-2.rs:12:12
|
LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-2.rs:12:19
+ --> $DIR/super-traits-fail-2.rs:12:12
|
LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: aborting due to 4 previous errors
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+ --> $DIR/super-traits-fail-2.rs:21:7
+ |
+LL | x.a();
+ | ^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
index 029c3b4..82b306a 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
@@ -1,24 +1,49 @@
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-2.rs:12:19
+ --> $DIR/super-traits-fail-2.rs:12:12
|
LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-2.rs:12:19
+ --> $DIR/super-traits-fail-2.rs:12:12
|
LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-2.rs:12:19
+ --> $DIR/super-traits-fail-2.rs:12:12
|
LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: aborting due to 3 previous errors
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/super-traits-fail-2.rs:12:12
+ |
+LL | trait Bar: ~const Foo {}
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/super-traits-fail-2.rs:12:12
+ |
+LL | trait Bar: ~const Foo {}
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+ --> $DIR/super-traits-fail-2.rs:21:7
+ |
+LL | x.a();
+ | ^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.rs b/tests/ui/traits/const-traits/super-traits-fail-2.rs
index 93a6f38..1e41d70 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.rs
@@ -13,11 +13,14 @@
//[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[yn,nn]~^^^^ ERROR: `~const` is not allowed here
+//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]`
+//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]`
+//[yn,nn]~^^^^^^ ERROR: `~const` is not allowed here
const fn foo<T: Bar>(x: &T) {
x.a();
//[yy,yn]~^ ERROR the trait bound `T: ~const Foo`
+ //[nn,ny]~^^ ERROR cannot call non-const fn `<T as Foo>::a` in constant functions
}
fn main() {}
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr
index 873c57e..ec6ca10 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr
@@ -11,23 +11,10 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `T: ~const Foo` is not satisfied
- --> $DIR/super-traits-fail-2.rs:19:7
+ --> $DIR/super-traits-fail-2.rs:21:5
|
LL | x.a();
- | ^ the trait `Foo` is not implemented for `T`
- |
-note: required by a bound in `Foo::a`
- --> $DIR/super-traits-fail-2.rs:6:25
- |
-LL | #[cfg_attr(any(yy, yn), const_trait)]
- | ^^^^^^^^^^^ required by this bound in `Foo::a`
-LL | trait Foo {
-LL | fn a(&self);
- | - required by a bound in this associated function
-help: consider further restricting this bound
- |
-LL | const fn foo<T: Bar + Foo>(x: &T) {
- | +++++
+ | ^^^^^
error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr
index bea3aea..3fa6256 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr
@@ -1,21 +1,8 @@
error[E0277]: the trait bound `T: ~const Foo` is not satisfied
- --> $DIR/super-traits-fail-2.rs:19:7
+ --> $DIR/super-traits-fail-2.rs:21:5
|
LL | x.a();
- | ^ the trait `Foo` is not implemented for `T`
- |
-note: required by a bound in `Foo::a`
- --> $DIR/super-traits-fail-2.rs:6:25
- |
-LL | #[cfg_attr(any(yy, yn), const_trait)]
- | ^^^^^^^^^^^ required by this bound in `Foo::a`
-LL | trait Foo {
-LL | fn a(&self);
- | - required by a bound in this associated function
-help: consider further restricting this bound
- |
-LL | const fn foo<T: Bar + Foo>(x: &T) {
- | +++++
+ | ^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
index f40583f..1dd4a2e 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
@@ -11,32 +11,49 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-3.rs:14:19
+ --> $DIR/super-traits-fail-3.rs:14:12
|
LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-3.rs:14:19
+ --> $DIR/super-traits-fail-3.rs:14:12
|
LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-3.rs:14:19
+ --> $DIR/super-traits-fail-3.rs:14:12
|
LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-3.rs:20:24
+ --> $DIR/super-traits-fail-3.rs:22:17
|
LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^
+ | ^^^^^^
-error: aborting due to 5 previous errors
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/super-traits-fail-3.rs:22:17
+ |
+LL | const fn foo<T: ~const Bar>(x: &T) {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+ --> $DIR/super-traits-fail-3.rs:25:7
+ |
+LL | x.a();
+ | ^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
index 3f6dfa7..e619b8b 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
@@ -1,24 +1,49 @@
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-3.rs:14:19
+ --> $DIR/super-traits-fail-3.rs:14:12
|
LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-3.rs:14:19
+ --> $DIR/super-traits-fail-3.rs:14:12
|
LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-3.rs:14:19
+ --> $DIR/super-traits-fail-3.rs:14:12
|
LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: aborting due to 3 previous errors
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/super-traits-fail-3.rs:14:12
+ |
+LL | trait Bar: ~const Foo {}
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/super-traits-fail-3.rs:14:12
+ |
+LL | trait Bar: ~const Foo {}
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
+ --> $DIR/super-traits-fail-3.rs:25:7
+ |
+LL | x.a();
+ | ^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.rs b/tests/ui/traits/const-traits/super-traits-fail-3.rs
index b5643b1..414337956 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.rs
@@ -15,12 +15,16 @@
//[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[yn,nn]~^^^^ ERROR: `~const` is not allowed here
+//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]`
+//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]`
+//[yn,nn]~^^^^^^ ERROR: `~const` is not allowed here
const fn foo<T: ~const Bar>(x: &T) {
//[yn,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
+ //[yn,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
x.a();
//[yn]~^ ERROR: the trait bound `T: ~const Foo` is not satisfied
+ //[nn,ny]~^^ ERROR: cannot call non-const fn `<T as Foo>::a` in constant functions
}
fn main() {}
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr
index bbc9594..0a36d40 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr
@@ -11,30 +11,25 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: `~const` can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-3.rs:20:24
+ --> $DIR/super-traits-fail-3.rs:22:17
|
LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^
+ | ^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> $DIR/super-traits-fail-3.rs:22:17
+ |
+LL | const fn foo<T: ~const Bar>(x: &T) {
+ | ^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0277]: the trait bound `T: ~const Foo` is not satisfied
- --> $DIR/super-traits-fail-3.rs:22:7
+ --> $DIR/super-traits-fail-3.rs:25:5
|
LL | x.a();
- | ^ the trait `Foo` is not implemented for `T`
- |
-note: required by a bound in `Foo::a`
- --> $DIR/super-traits-fail-3.rs:8:25
- |
-LL | #[cfg_attr(any(yy, yn), const_trait)]
- | ^^^^^^^^^^^ required by this bound in `Foo::a`
-LL | trait Foo {
-LL | fn a(&self);
- | - required by a bound in this associated function
-help: consider further restricting this bound
- |
-LL | const fn foo<T: ~const Bar + Foo>(x: &T) {
- | +++++
+ | ^^^^^
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail.rs b/tests/ui/traits/const-traits/super-traits-fail.rs
index da41d7f..c07619f 100644
--- a/tests/ui/traits/const-traits/super-traits-fail.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail.rs
@@ -1,4 +1,3 @@
-//~ ERROR the trait bound
//@ compile-flags: -Znext-solver
#![allow(incomplete_features)]
diff --git a/tests/ui/traits/const-traits/super-traits-fail.stderr b/tests/ui/traits/const-traits/super-traits-fail.stderr
index 3870f0f..7a734a6 100644
--- a/tests/ui/traits/const-traits/super-traits-fail.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail.stderr
@@ -1,24 +1,9 @@
-error[E0277]: the trait bound `Bar::{synthetic#0}: TyCompat<Foo::{synthetic#0}>` is not satisfied
- --> $DIR/super-traits-fail.rs:19:12
+error[E0277]: the trait bound `S: ~const Foo` is not satisfied
+ --> $DIR/super-traits-fail.rs:18:20
|
LL | impl const Bar for S {}
- | ^^^ the trait `TyCompat<Foo::{synthetic#0}>` is not implemented for `Bar::{synthetic#0}`, which is required by `S: Bar`
- |
- = help: the trait `Bar` is implemented for `S`
-note: required for `S` to implement `Bar`
- --> $DIR/super-traits-fail.rs:12:7
- |
-LL | trait Bar: ~const Foo {}
- | ^^^
+ | ^
-error[E0277]: the trait bound `Maybe: TyCompat<Foo::{synthetic#0}>` is not satisfied
- |
-note: required by a bound in `Bar::{synthetic#0}`
- --> $DIR/super-traits-fail.rs:12:12
- |
-LL | trait Bar: ~const Foo {}
- | ^^^^^^^^^^ required by this bound in `Bar::{synthetic#0}`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/tilde-const-and-const-params.rs b/tests/ui/traits/const-traits/tilde-const-and-const-params.rs
index 4b720b5..b316ac75 100644
--- a/tests/ui/traits/const-traits/tilde-const-and-const-params.rs
+++ b/tests/ui/traits/const-traits/tilde-const-and-const-params.rs
@@ -8,7 +8,7 @@
impl<const N: usize> Foo<N> {
fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
//~^ ERROR `~const` is not allowed here
- //~| ERROR mismatched types
+ //~| ERROR the trait bound `A: const Add42` is not satisfied
Foo
}
}
@@ -26,7 +26,7 @@
fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
//~^ ERROR `~const` is not allowed here
- //~| ERROR mismatched types
+ //~| ERROR the trait bound `A: const Add42` is not satisfied
Foo
}
diff --git a/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr b/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr
index 73526a2..78bf85e 100644
--- a/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr
+++ b/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr
@@ -22,29 +22,18 @@
LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
| ^^^
-error: using `#![feature(effects)]` without enabling next trait solver globally
- |
- = note: the next trait solver must be enabled globally for the effects feature to work correctly
- = help: use `-Znext-solver` to enable
-
-error[E0308]: mismatched types
+error[E0277]: the trait bound `A: const Add42` is not satisfied
--> $DIR/tilde-const-and-const-params.rs:27:61
|
LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
- | ^^^^^^^^^ expected `false`, found `true`
- |
- = note: expected constant `false`
- found constant `true`
+ | ^^^^^^^^^
-error[E0308]: mismatched types
+error[E0277]: the trait bound `A: const Add42` is not satisfied
--> $DIR/tilde-const-and-const-params.rs:9:44
|
LL | fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
- | ^^^^^^^^^ expected `false`, found `true`
- |
- = note: expected constant `false`
- found constant `true`
+ | ^^^^^^^^^
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/tilde-const-in-struct-args.rs b/tests/ui/traits/const-traits/tilde-const-in-struct-args.rs
new file mode 100644
index 0000000..4722be9
--- /dev/null
+++ b/tests/ui/traits/const-traits/tilde-const-in-struct-args.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Znext-solver
+//@ known-bug: #132067
+//@ check-pass
+
+#![feature(const_trait_impl, effects)]
+
+struct S;
+#[const_trait]
+trait Trait<const N: u32> {}
+
+const fn f<
+ T: Trait<
+ {
+ struct I<U: ~const Trait<0>>(U);
+ 0
+ },
+ >,
+>() {
+}
+
+pub fn main() {}
diff --git a/tests/ui/traits/const-traits/tilde-const-in-struct-args.stderr b/tests/ui/traits/const-traits/tilde-const-in-struct-args.stderr
new file mode 100644
index 0000000..a9759f1
--- /dev/null
+++ b/tests/ui/traits/const-traits/tilde-const-in-struct-args.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/tilde-const-in-struct-args.rs:5:30
+ |
+LL | #![feature(const_trait_impl, effects)]
+ | ^^^^^^^
+ |
+ = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/traits/const-traits/trait-default-body-stability.stderr b/tests/ui/traits/const-traits/trait-default-body-stability.stderr
index 49fbef9..5806b6d 100644
--- a/tests/ui/traits/const-traits/trait-default-body-stability.stderr
+++ b/tests/ui/traits/const-traits/trait-default-body-stability.stderr
@@ -16,5 +16,22 @@
= note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
= note: adding a non-const method body in the future would be a breaking change
-error: aborting due to 2 previous errors
+error[E0015]: `?` cannot determine the branch of `T` in constant functions
+ --> $DIR/trait-default-body-stability.rs:45:9
+ |
+LL | T?
+ | ^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: `?` cannot convert from residual of `T` in constant functions
+ --> $DIR/trait-default-body-stability.rs:45:9
+ |
+LL | T?
+ | ^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/trait-where-clause-const.rs b/tests/ui/traits/const-traits/trait-where-clause-const.rs
index 8ca9b7c..61e2bc3 100644
--- a/tests/ui/traits/const-traits/trait-where-clause-const.rs
+++ b/tests/ui/traits/const-traits/trait-where-clause-const.rs
@@ -20,11 +20,9 @@
const fn test1<T: ~const Foo + Bar>() {
T::a();
T::b();
- //~^ ERROR mismatched types
- //~| ERROR the trait bound
+ //~^ ERROR the trait bound
T::c::<T>();
- //~^ ERROR mismatched types
- //~| ERROR the trait bound
+ //~^ ERROR the trait bound
}
const fn test2<T: ~const Foo + ~const Bar>() {
diff --git a/tests/ui/traits/const-traits/trait-where-clause-const.stderr b/tests/ui/traits/const-traits/trait-where-clause-const.stderr
index eaa981e..30a7ef1 100644
--- a/tests/ui/traits/const-traits/trait-where-clause-const.stderr
+++ b/tests/ui/traits/const-traits/trait-where-clause-const.stderr
@@ -1,52 +1,15 @@
-error[E0277]: the trait bound `T: Foo` is not satisfied
+error[E0277]: the trait bound `T: ~const Bar` is not satisfied
--> $DIR/trait-where-clause-const.rs:22:5
|
LL | T::b();
- | ^ the trait `Foo` is not implemented for `T`
- |
-note: required by a bound in `Foo::b`
- --> $DIR/trait-where-clause-const.rs:13:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ required by this bound in `Foo::b`
-...
-LL | fn b() where Self: ~const Bar;
- | - required by a bound in this associated function
+ | ^^^^^^
-error[E0308]: mismatched types
- --> $DIR/trait-where-clause-const.rs:22:5
- |
-LL | T::b();
- | ^^^^^^ expected `host`, found `true`
- |
- = note: expected constant `host`
- found constant `true`
-
-error[E0277]: the trait bound `T: Foo` is not satisfied
- --> $DIR/trait-where-clause-const.rs:25:5
+error[E0277]: the trait bound `T: ~const Bar` is not satisfied
+ --> $DIR/trait-where-clause-const.rs:24:5
|
LL | T::c::<T>();
- | ^ the trait `Foo` is not implemented for `T`
- |
-note: required by a bound in `Foo::c`
- --> $DIR/trait-where-clause-const.rs:13:1
- |
-LL | #[const_trait]
- | ^^^^^^^^^^^^^^ required by this bound in `Foo::c`
-...
-LL | fn c<T: ~const Bar>();
- | - required by a bound in this associated function
+ | ^^^^^^^^^^^
-error[E0308]: mismatched types
- --> $DIR/trait-where-clause-const.rs:25:5
- |
-LL | T::c::<T>();
- | ^^^^^^^^^^^ expected `host`, found `true`
- |
- = note: expected constant `host`
- found constant `true`
+error: aborting due to 2 previous errors
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
index 848aa68..35f3019 100644
--- a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
+++ b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
@@ -6,41 +6,30 @@
|
= help: remove one of these features
-error[E0308]: mismatched types
+error[E0277]: the trait bound `T: const Trait` is not satisfied
--> $DIR/unsatisfied-const-trait-bound.rs:29:37
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^ expected `false`, found `true`
- |
- = note: expected constant `false`
- found constant `true`
+ | ^^^^^^^^^
-error[E0308]: mismatched types
+error[E0277]: the trait bound `T: const Trait` is not satisfied
--> $DIR/unsatisfied-const-trait-bound.rs:33:50
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
- | ^^^^^^^^^ expected `false`, found `host`
- |
- = note: expected constant `false`
- found constant `host`
+ | ^^^^^^^^^
error[E0277]: the trait bound `Ty: const Trait` is not satisfied
- --> $DIR/unsatisfied-const-trait-bound.rs:22:15
+ --> $DIR/unsatisfied-const-trait-bound.rs:22:5
|
LL | require::<Ty>();
- | ^^ the trait `Trait` is not implemented for `Ty`
+ | ^^^^^^^^^^^^^^^
|
note: required by a bound in `require`
--> $DIR/unsatisfied-const-trait-bound.rs:8:15
|
LL | fn require<T: const Trait>() {}
- | ^^^^^^^^^^^ required by this bound in `require`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
- |
-LL | fn main() where Ty: Trait {
- | +++++++++++++++
+ | ^^^^^ required by this bound in `require`
error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/error-reporting/apit-with-bad-path.rs b/tests/ui/traits/error-reporting/apit-with-bad-path.rs
new file mode 100644
index 0000000..57184b9
--- /dev/null
+++ b/tests/ui/traits/error-reporting/apit-with-bad-path.rs
@@ -0,0 +1,10 @@
+// Ensure that we don't emit an E0270 for "`impl AsRef<Path>: AsRef<Path>` not satisfied".
+
+fn foo(filename: impl AsRef<Path>) {
+ //~^ ERROR cannot find type `Path` in this scope
+ std::fs::write(filename, "hello").unwrap();
+}
+
+fn main() {
+ foo("/tmp/hello");
+}
diff --git a/tests/ui/traits/error-reporting/apit-with-bad-path.stderr b/tests/ui/traits/error-reporting/apit-with-bad-path.stderr
new file mode 100644
index 0000000..19bd5e7
--- /dev/null
+++ b/tests/ui/traits/error-reporting/apit-with-bad-path.stderr
@@ -0,0 +1,14 @@
+error[E0412]: cannot find type `Path` in this scope
+ --> $DIR/apit-with-bad-path.rs:3:29
+ |
+LL | fn foo(filename: impl AsRef<Path>) {
+ | ^^^^ not found in this scope
+ |
+help: consider importing this struct
+ |
+LL + use std::path::Path;
+ |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/traits/error-reporting/where-clause-with-bad-path.rs b/tests/ui/traits/error-reporting/where-clause-with-bad-path.rs
new file mode 100644
index 0000000..cbe1488
--- /dev/null
+++ b/tests/ui/traits/error-reporting/where-clause-with-bad-path.rs
@@ -0,0 +1,10 @@
+// Ensure that we don't emit an E0270 for "`impl AsRef<Path>: AsRef<Path>` not satisfied".
+
+fn foo<T: AsRef<Path>>(filename: T) {
+ //~^ ERROR cannot find type `Path` in this scope
+ std::fs::write(filename, "hello").unwrap();
+}
+
+fn main() {
+ foo("/tmp/hello");
+}
diff --git a/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr b/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr
new file mode 100644
index 0000000..1137178
--- /dev/null
+++ b/tests/ui/traits/error-reporting/where-clause-with-bad-path.stderr
@@ -0,0 +1,14 @@
+error[E0412]: cannot find type `Path` in this scope
+ --> $DIR/where-clause-with-bad-path.rs:3:17
+ |
+LL | fn foo<T: AsRef<Path>>(filename: T) {
+ | ^^^^ not found in this scope
+ |
+help: consider importing this struct
+ |
+LL + use std::path::Path;
+ |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.rs b/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.rs
new file mode 100644
index 0000000..5c53b74
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Znext-solver
+
+// Make sure we try to mention a deeply normalized type in a type mismatch error.
+
+trait Mirror {
+ type Assoc;
+}
+impl<T> Mirror for T {
+ type Assoc = T;
+}
+
+fn needs<T>(_: <T as Mirror>::Assoc) {}
+
+fn main() {
+ needs::<i32>(());
+ //~^ ERROR mismatched types
+}
diff --git a/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.stderr b/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.stderr
new file mode 100644
index 0000000..8864394
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/deeply-normalize-type-expectation.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+ --> $DIR/deeply-normalize-type-expectation.rs:15:18
+ |
+LL | needs::<i32>(());
+ | ------------ ^^ expected `i32`, found `()`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/deeply-normalize-type-expectation.rs:12:4
+ |
+LL | fn needs<T>(_: <T as Mirror>::Assoc) {}
+ | ^^^^^ -----------------------
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr
index 8a765c2..5e32d5c 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr
@@ -675,10 +675,6 @@
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error[E0015]: cannot call non-const fn `<Filter<std::ops::Range<i32>, {closure@$DIR/typeck_type_placeholder_item.rs:230:29: 230:32}> as Iterator>::map::<i32, {closure@$DIR/typeck_type_placeholder_item.rs:230:49: 230:52}>` in constants
--> $DIR/typeck_type_placeholder_item.rs:230:45
@@ -687,10 +683,6 @@
| ^^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
- |
-LL + #![feature(const_trait_impl)]
- |
error: aborting due to 74 previous errors
diff --git a/tests/ui/unpretty/extern-static.rs b/tests/ui/unpretty/extern-static.rs
new file mode 100644
index 0000000..fbd605b
--- /dev/null
+++ b/tests/ui/unpretty/extern-static.rs
@@ -0,0 +1,6 @@
+//@ compile-flags: -Zunpretty=normal
+//@ check-pass
+
+unsafe extern "C" {
+ pub unsafe static STATIC: ();
+}
diff --git a/tests/ui/unpretty/extern-static.stdout b/tests/ui/unpretty/extern-static.stdout
new file mode 100644
index 0000000..fbd605b
--- /dev/null
+++ b/tests/ui/unpretty/extern-static.stdout
@@ -0,0 +1,6 @@
+//@ compile-flags: -Zunpretty=normal
+//@ check-pass
+
+unsafe extern "C" {
+ pub unsafe static STATIC: ();
+}
diff --git a/tests/ui/unpretty/unsafe-attr.rs b/tests/ui/unpretty/unsafe-attr.rs
new file mode 100644
index 0000000..8734ea8
--- /dev/null
+++ b/tests/ui/unpretty/unsafe-attr.rs
@@ -0,0 +1,11 @@
+//@ compile-flags: -Zunpretty=normal
+//@ check-pass
+
+#[no_mangle]
+extern "C" fn foo() {}
+
+#[unsafe(no_mangle)]
+extern "C" fn bar() {}
+
+#[cfg_attr(FALSE, unsafe(no_mangle))]
+extern "C" fn zoo() {}
diff --git a/tests/ui/unpretty/unsafe-attr.stdout b/tests/ui/unpretty/unsafe-attr.stdout
new file mode 100644
index 0000000..8734ea8
--- /dev/null
+++ b/tests/ui/unpretty/unsafe-attr.stdout
@@ -0,0 +1,11 @@
+//@ compile-flags: -Zunpretty=normal
+//@ check-pass
+
+#[no_mangle]
+extern "C" fn foo() {}
+
+#[unsafe(no_mangle)]
+extern "C" fn bar() {}
+
+#[cfg_attr(FALSE, unsafe(no_mangle))]
+extern "C" fn zoo() {}
diff --git a/tests/ui/unsafe/place-expr-safe.rs b/tests/ui/unsafe/place-expr-safe.rs
new file mode 100644
index 0000000..2590ea7
--- /dev/null
+++ b/tests/ui/unsafe/place-expr-safe.rs
@@ -0,0 +1,14 @@
+//@ check-pass
+
+fn main() {
+ let ptr = std::ptr::null_mut::<i32>();
+ let addr = &raw const *ptr;
+
+ let local = 1;
+ let ptr = &local as *const i32;
+ let addr = &raw const *ptr;
+
+ let boxed = Box::new(1);
+ let ptr = &*boxed as *const i32;
+ let addr = &raw const *ptr;
+}
diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs
index 07e9053..6eba6b7 100644
--- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs
+++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs
@@ -22,8 +22,8 @@
Some(()) => &S,
None => &R, //~ ERROR E0308
}
- let t: &dyn Trait = match opt() { //~ ERROR E0038
+ let t: &dyn Trait = match opt() {
Some(()) => &S, //~ ERROR E0038
- None => &R,
+ None => &R, //~ ERROR E0038
};
}
diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
index d7366e1..6cd4ebf 100644
--- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
+++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
@@ -31,14 +31,10 @@
= note: required for the cast from `&S` to `&dyn Trait`
error[E0038]: the trait `Trait` cannot be made into an object
- --> $DIR/wf-dyn-incompat-trait-obj-match.rs:25:25
+ --> $DIR/wf-dyn-incompat-trait-obj-match.rs:27:17
|
-LL | let t: &dyn Trait = match opt() {
- | _________________________^
-LL | | Some(()) => &S,
-LL | | None => &R,
-LL | | };
- | |_____^ `Trait` cannot be made into an object
+LL | None => &R,
+ | ^^ `Trait` cannot be made into an object
|
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14
diff --git a/triagebot.toml b/triagebot.toml
index 17ce4cf..6fa92b4 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -135,6 +135,43 @@
"""
label = "O-rfl"
+[ping.wasm]
+alias = ["webassembly"]
+message = """\
+Hey WASM notification group! This issue or PR could use some WebAssembly-specific
+guidance. Could one of you weigh in? Thanks <3
+
+(In case it's useful, here are some [instructions] for tackling these sorts of
+issues).
+
+[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/wasm.html
+"""
+label = "O-wasm"
+
+[ping.wasi]
+message = """\
+Hey WASI notification group! This issue or PR could use some WASI-specific guidance.
+Could one of you weigh in? Thanks <3
+
+(In case it's useful, here are some [instructions] for tackling these sorts of
+issues).
+
+[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/wasi.html
+"""
+label = "O-wasi"
+
+[ping.emscripten]
+message = """\
+Hey Emscripten notification group! This issue or PR could use some Emscripten-specific
+guidance. Could one of you weigh in? Thanks <3
+
+(In case it's useful, here are some [instructions] for tackling these sorts of
+issues).
+
+[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/emscripten.html
+"""
+label = "O-emscripten"
+
[prioritize]
label = "I-prioritize"
@@ -688,9 +725,6 @@
instead of editing the library source file manually.
"""
-[mentions."src/librustdoc/clean/types.rs"]
-cc = ["@camelid"]
-
[mentions."src/librustdoc/html/static"]
message = "Some changes occurred in HTML/CSS/JS."
cc = [
@@ -901,9 +935,6 @@
[mentions."tests/ui/stack-protector"]
cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
-[mentions."tests/ui/check-cfg"]
-cc = ["@Urgau"]
-
[mentions."compiler/rustc_middle/src/mir/coverage.rs"]
message = "Some changes occurred in coverage instrumentation."
cc = ["@Zalathar"]