Auto merge of #145300 - Zalathar:rollup-0eqbt6a, r=Zalathar
Rollup of 17 pull requests Successful merges: - rust-lang/rust#131477 (Apple: Always pass SDK root when linking with `cc`, and pass it via `SDKROOT` env var) - rust-lang/rust#139806 (std: sys: pal: uefi: Overhaul Time) - rust-lang/rust#144386 (Extract TraitImplHeader in AST/HIR) - rust-lang/rust#144921 (Don't emit `rustdoc::broken_intra_doc_links` for GitHub-flavored Markdown admonitions like `[!NOTE]`) - rust-lang/rust#145155 (Port `#[allow_internal_unsafe]` to the new attribute system (attempt 2)) - rust-lang/rust#145214 (fix: re-enable self-assignment) - rust-lang/rust#145216 (rustdoc: correct negative-to-implicit discriminant display) - rust-lang/rust#145238 (Tweak invalid builtin attribute output) - rust-lang/rust#145249 (Rename entered trace span variables from `_span` to `_trace`) - rust-lang/rust#145251 (Support using #[unstable_feature_bound] on trait) - rust-lang/rust#145253 (Document compiler and stdlib in stage1 in `pr-check-2` CI job) - rust-lang/rust#145260 (Make explicit guarantees about `Vec`’s allocator) - rust-lang/rust#145263 (Update books) - rust-lang/rust#145273 (Account for new `assert!` desugaring in `!condition` suggestion) - rust-lang/rust#145283 (Make I-miscompile imply I-prioritize) - rust-lang/rust#145291 (bootstrap: Only warn about `rust.debug-assertions` if downloading rustc) - rust-lang/rust#145292 (Fix a typo in range docs) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
d9dba3a554
221 changed files with 2690 additions and 1192 deletions
|
|
@ -3661,17 +3661,21 @@ pub struct TyAlias {
|
|||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Impl {
|
||||
pub defaultness: Defaultness,
|
||||
pub safety: Safety,
|
||||
pub generics: Generics,
|
||||
pub constness: Const,
|
||||
pub polarity: ImplPolarity,
|
||||
/// The trait being implemented, if any.
|
||||
pub of_trait: Option<TraitRef>,
|
||||
pub of_trait: Option<Box<TraitImplHeader>>,
|
||||
pub self_ty: Box<Ty>,
|
||||
pub items: ThinVec<Box<AssocItem>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct TraitImplHeader {
|
||||
pub defaultness: Defaultness,
|
||||
pub safety: Safety,
|
||||
pub constness: Const,
|
||||
pub polarity: ImplPolarity,
|
||||
pub trait_ref: TraitRef,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Default, Walkable)]
|
||||
pub struct FnContract {
|
||||
pub requires: Option<Box<Expr>>,
|
||||
|
|
@ -3793,7 +3797,7 @@ pub enum ItemKind {
|
|||
/// An implementation.
|
||||
///
|
||||
/// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`.
|
||||
Impl(Box<Impl>),
|
||||
Impl(Impl),
|
||||
/// A macro invocation.
|
||||
///
|
||||
/// E.g., `foo!(..)`.
|
||||
|
|
@ -3880,7 +3884,7 @@ impl ItemKind {
|
|||
| Self::Union(_, generics, _)
|
||||
| Self::Trait(box Trait { generics, .. })
|
||||
| Self::TraitAlias(_, generics, _)
|
||||
| Self::Impl(box Impl { generics, .. }) => Some(generics),
|
||||
| Self::Impl(Impl { generics, .. }) => Some(generics),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -4040,7 +4044,7 @@ mod size_asserts {
|
|||
static_assert_size!(GenericArg, 24);
|
||||
static_assert_size!(GenericBound, 88);
|
||||
static_assert_size!(Generics, 40);
|
||||
static_assert_size!(Impl, 136);
|
||||
static_assert_size!(Impl, 64);
|
||||
static_assert_size!(Item, 144);
|
||||
static_assert_size!(ItemKind, 80);
|
||||
static_assert_size!(LitKind, 24);
|
||||
|
|
@ -4053,6 +4057,7 @@ mod size_asserts {
|
|||
static_assert_size!(PathSegment, 24);
|
||||
static_assert_size!(Stmt, 32);
|
||||
static_assert_size!(StmtKind, 16);
|
||||
static_assert_size!(TraitImplHeader, 80);
|
||||
static_assert_size!(Ty, 64);
|
||||
static_assert_size!(TyKind, 40);
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -929,8 +929,13 @@ macro_rules! common_visitor_and_walkers {
|
|||
}
|
||||
|
||||
impl_walkable!(|&$($mut)? $($lt)? self: Impl, vis: &mut V| {
|
||||
let Impl { defaultness, safety, generics, constness, polarity, of_trait, self_ty, items } = self;
|
||||
visit_visitable!($($mut)? vis, defaultness, safety, generics, constness, polarity, of_trait, self_ty);
|
||||
let Impl { generics, of_trait, self_ty, items } = self;
|
||||
try_visit!(vis.visit_generics(generics));
|
||||
if let Some(box of_trait) = of_trait {
|
||||
let TraitImplHeader { defaultness, safety, constness, polarity, trait_ref } = of_trait;
|
||||
visit_visitable!($($mut)? vis, defaultness, safety, constness, polarity, trait_ref);
|
||||
}
|
||||
try_visit!(vis.visit_ty(self_ty));
|
||||
visit_visitable_with!($($mut)? vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() });
|
||||
V::Result::output()
|
||||
});
|
||||
|
|
|
|||
|
|
@ -340,13 +340,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
hir::ItemKind::Union(ident, generics, vdata)
|
||||
}
|
||||
ItemKind::Impl(box Impl {
|
||||
safety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
ItemKind::Impl(Impl {
|
||||
generics: ast_generics,
|
||||
of_trait: trait_ref,
|
||||
of_trait,
|
||||
self_ty: ty,
|
||||
items: impl_items,
|
||||
}) => {
|
||||
|
|
@ -364,54 +360,30 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// lifetime to be added, but rather a reference to a
|
||||
// parent lifetime.
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, (trait_ref, lowered_ty)) =
|
||||
let (generics, (of_trait, lowered_ty)) =
|
||||
self.lower_generics(ast_generics, id, itctx, |this| {
|
||||
let modifiers = TraitBoundModifiers {
|
||||
constness: BoundConstness::Never,
|
||||
asyncness: BoundAsyncness::Normal,
|
||||
// we don't use this in bound lowering
|
||||
polarity: BoundPolarity::Positive,
|
||||
};
|
||||
|
||||
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
||||
this.lower_trait_ref(
|
||||
modifiers,
|
||||
trait_ref,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
|
||||
)
|
||||
});
|
||||
let of_trait = of_trait
|
||||
.as_deref()
|
||||
.map(|of_trait| this.lower_trait_impl_header(of_trait));
|
||||
|
||||
let lowered_ty = this.lower_ty(
|
||||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
|
||||
);
|
||||
|
||||
(trait_ref, lowered_ty)
|
||||
(of_trait, lowered_ty)
|
||||
});
|
||||
|
||||
let new_impl_items = self
|
||||
.arena
|
||||
.alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item)));
|
||||
|
||||
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
|
||||
// to not cause an assertion failure inside the `lower_defaultness` function.
|
||||
let has_val = true;
|
||||
let (defaultness, defaultness_span) = self.lower_defaultness(*defaultness, has_val);
|
||||
let polarity = match polarity {
|
||||
ImplPolarity::Positive => ImplPolarity::Positive,
|
||||
ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)),
|
||||
};
|
||||
hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
|
||||
constness: self.lower_constness(*constness),
|
||||
safety: self.lower_safety(*safety, hir::Safety::Safe),
|
||||
polarity,
|
||||
defaultness,
|
||||
defaultness_span,
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
generics,
|
||||
of_trait: trait_ref,
|
||||
of_trait,
|
||||
self_ty: lowered_ty,
|
||||
items: new_impl_items,
|
||||
}))
|
||||
})
|
||||
}
|
||||
ItemKind::Trait(box Trait {
|
||||
constness,
|
||||
|
|
@ -982,6 +954,44 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.expr(span, hir::ExprKind::Err(guar))
|
||||
}
|
||||
|
||||
fn lower_trait_impl_header(
|
||||
&mut self,
|
||||
trait_impl_header: &TraitImplHeader,
|
||||
) -> &'hir hir::TraitImplHeader<'hir> {
|
||||
let TraitImplHeader { constness, safety, polarity, defaultness, ref trait_ref } =
|
||||
*trait_impl_header;
|
||||
let constness = self.lower_constness(constness);
|
||||
let safety = self.lower_safety(safety, hir::Safety::Safe);
|
||||
let polarity = match polarity {
|
||||
ImplPolarity::Positive => ImplPolarity::Positive,
|
||||
ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)),
|
||||
};
|
||||
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
|
||||
// to not cause an assertion failure inside the `lower_defaultness` function.
|
||||
let has_val = true;
|
||||
let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
|
||||
let modifiers = TraitBoundModifiers {
|
||||
constness: BoundConstness::Never,
|
||||
asyncness: BoundAsyncness::Normal,
|
||||
// we don't use this in bound lowering
|
||||
polarity: BoundPolarity::Positive,
|
||||
};
|
||||
let trait_ref = self.lower_trait_ref(
|
||||
modifiers,
|
||||
trait_ref,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
|
||||
);
|
||||
|
||||
self.arena.alloc(hir::TraitImplHeader {
|
||||
constness,
|
||||
safety,
|
||||
polarity,
|
||||
defaultness,
|
||||
defaultness_span,
|
||||
trait_ref,
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_impl_item(
|
||||
&mut self,
|
||||
i: &AssocItem,
|
||||
|
|
|
|||
|
|
@ -175,11 +175,6 @@ ast_passes_generic_default_trailing = generic parameters with a default must be
|
|||
ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
|
||||
.help = remove one of these features
|
||||
|
||||
ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
|
||||
.because = {$annotation} because of this
|
||||
.type = inherent impl for this type
|
||||
.only_trait = only trait implementations may be annotated with {$annotation}
|
||||
|
||||
ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot be declared with `safe` safety qualifier
|
||||
.suggestion = remove safe from this item
|
||||
|
||||
|
|
|
|||
|
|
@ -954,13 +954,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
|
||||
match &item.kind {
|
||||
ItemKind::Impl(box Impl {
|
||||
safety,
|
||||
polarity,
|
||||
defaultness: _,
|
||||
constness,
|
||||
ItemKind::Impl(Impl {
|
||||
generics,
|
||||
of_trait: Some(t),
|
||||
of_trait:
|
||||
Some(box TraitImplHeader {
|
||||
safety,
|
||||
polarity,
|
||||
defaultness: _,
|
||||
constness,
|
||||
trait_ref: t,
|
||||
}),
|
||||
self_ty,
|
||||
items,
|
||||
}) => {
|
||||
|
|
@ -992,46 +995,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true });
|
||||
});
|
||||
}
|
||||
ItemKind::Impl(box Impl {
|
||||
safety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
generics,
|
||||
of_trait: None,
|
||||
self_ty,
|
||||
items,
|
||||
}) => {
|
||||
let error = |annotation_span, annotation, only_trait| errors::InherentImplCannot {
|
||||
span: self_ty.span,
|
||||
annotation_span,
|
||||
annotation,
|
||||
self_ty: self_ty.span,
|
||||
only_trait,
|
||||
};
|
||||
|
||||
ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items }) => {
|
||||
self.visit_attrs_vis(&item.attrs, &item.vis);
|
||||
self.visibility_not_permitted(
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::IndividualImplItems,
|
||||
);
|
||||
if let &Safety::Unsafe(span) = safety {
|
||||
self.dcx().emit_err(errors::InherentImplCannotUnsafe {
|
||||
span: self_ty.span,
|
||||
annotation_span: span,
|
||||
annotation: "unsafe",
|
||||
self_ty: self_ty.span,
|
||||
});
|
||||
}
|
||||
if let &ImplPolarity::Negative(span) = polarity {
|
||||
self.dcx().emit_err(error(span, "negative", false));
|
||||
}
|
||||
if let &Defaultness::Default(def_span) = defaultness {
|
||||
self.dcx().emit_err(error(def_span, "`default`", true));
|
||||
}
|
||||
if let &Const::Yes(span) = constness {
|
||||
self.dcx().emit_err(error(span, "`const`", true));
|
||||
}
|
||||
|
||||
self.with_tilde_const(Some(TildeConstReason::Impl { span: item.span }), |this| {
|
||||
this.visit_generics(generics)
|
||||
|
|
|
|||
|
|
@ -464,32 +464,6 @@ pub(crate) struct UnsafeNegativeImpl {
|
|||
pub r#unsafe: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_inherent_cannot_be)]
|
||||
pub(crate) struct InherentImplCannot<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label(ast_passes_because)]
|
||||
pub annotation_span: Span,
|
||||
pub annotation: &'a str,
|
||||
#[label(ast_passes_type)]
|
||||
pub self_ty: Span,
|
||||
#[note(ast_passes_only_trait)]
|
||||
pub only_trait: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_inherent_cannot_be, code = E0197)]
|
||||
pub(crate) struct InherentImplCannotUnsafe<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label(ast_passes_because)]
|
||||
pub annotation_span: Span,
|
||||
pub annotation: &'a str,
|
||||
#[label(ast_passes_type)]
|
||||
pub self_ty: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_unsafe_item)]
|
||||
pub(crate) struct UnsafeItem {
|
||||
|
|
|
|||
|
|
@ -217,18 +217,18 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, of_trait, .. }) => {
|
||||
if let &ast::ImplPolarity::Negative(span) = polarity {
|
||||
ast::ItemKind::Impl(ast::Impl { of_trait: Some(of_trait), .. }) => {
|
||||
if let ast::ImplPolarity::Negative(span) = of_trait.polarity {
|
||||
gate!(
|
||||
&self,
|
||||
negative_impls,
|
||||
span.to(of_trait.as_ref().map_or(span, |t| t.path.span)),
|
||||
span.to(of_trait.trait_ref.path.span),
|
||||
"negative trait bounds are not fully implemented; \
|
||||
use marker types for now"
|
||||
);
|
||||
}
|
||||
|
||||
if let ast::Defaultness::Default(_) = defaultness {
|
||||
if let ast::Defaultness::Default(_) = of_trait.defaultness {
|
||||
gate!(&self, specialization, i.span, "specialization is unstable");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -308,39 +308,41 @@ impl<'a> State<'a> {
|
|||
let (cb, ib) = self.head(visibility_qualified(&item.vis, "union"));
|
||||
self.print_struct(struct_def, generics, *ident, item.span, true, cb, ib);
|
||||
}
|
||||
ast::ItemKind::Impl(box ast::Impl {
|
||||
safety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
generics,
|
||||
of_trait,
|
||||
self_ty,
|
||||
items,
|
||||
}) => {
|
||||
ast::ItemKind::Impl(ast::Impl { generics, of_trait, self_ty, items }) => {
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_visibility(&item.vis);
|
||||
self.print_defaultness(*defaultness);
|
||||
self.print_safety(*safety);
|
||||
self.word("impl");
|
||||
|
||||
if generics.params.is_empty() {
|
||||
self.nbsp();
|
||||
} else {
|
||||
self.print_generic_params(&generics.params);
|
||||
self.space();
|
||||
}
|
||||
let impl_generics = |this: &mut Self| {
|
||||
this.word("impl");
|
||||
|
||||
self.print_constness(*constness);
|
||||
if generics.params.is_empty() {
|
||||
this.nbsp();
|
||||
} else {
|
||||
this.print_generic_params(&generics.params);
|
||||
this.space();
|
||||
}
|
||||
};
|
||||
|
||||
if let ast::ImplPolarity::Negative(_) = polarity {
|
||||
self.word("!");
|
||||
}
|
||||
|
||||
if let Some(t) = of_trait {
|
||||
self.print_trait_ref(t);
|
||||
if let Some(box of_trait) = of_trait {
|
||||
let ast::TraitImplHeader {
|
||||
defaultness,
|
||||
safety,
|
||||
constness,
|
||||
polarity,
|
||||
ref trait_ref,
|
||||
} = *of_trait;
|
||||
self.print_defaultness(defaultness);
|
||||
self.print_safety(safety);
|
||||
impl_generics(self);
|
||||
self.print_constness(constness);
|
||||
if let ast::ImplPolarity::Negative(_) = polarity {
|
||||
self.word("!");
|
||||
}
|
||||
self.print_trait_ref(trait_ref);
|
||||
self.space();
|
||||
self.word_space("for");
|
||||
} else {
|
||||
impl_generics(self);
|
||||
}
|
||||
|
||||
self.print_type(self_ty);
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ attr_parsing_unknown_version_literal =
|
|||
attr_parsing_unrecognized_repr_hint =
|
||||
unrecognized representation hint
|
||||
.help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
|
||||
.note = for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
|
||||
|
||||
attr_parsing_unstable_cfg_target_compact =
|
||||
compact `cfg(target(..))` is experimental and subject to change
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
|
|||
type Item = (Symbol, Span);
|
||||
const CONVERT: ConvertFn<Self::Item> =
|
||||
|items, span| AttributeKind::AllowInternalUnstable(items, span);
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
|
|
@ -32,7 +32,7 @@ impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
|
|||
const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
|
||||
type Item = (Symbol, Span);
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
|
|
@ -53,7 +53,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
|
|||
type Item = Symbol;
|
||||
const CONVERT: ConvertFn<Self::Item> =
|
||||
|items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span);
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,10 @@ use crate::{
|
|||
CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg,
|
||||
};
|
||||
|
||||
pub const CFG_TEMPLATE: AttributeTemplate = template!(List: "predicate");
|
||||
pub const CFG_TEMPLATE: AttributeTemplate = template!(
|
||||
List: &["predicate"],
|
||||
"https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute"
|
||||
);
|
||||
|
||||
pub fn parse_cfg_attr<'c, S: Stage>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
|
|||
const PATH: &[Symbol] = &[sym::optimize];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(List: "size|speed|none");
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let Some(list) = args.list() else {
|
||||
|
|
@ -253,7 +253,7 @@ pub(crate) struct UsedParser {
|
|||
impl<S: Stage> AttributeParser<S> for UsedParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
||||
&[sym::used],
|
||||
template!(Word, List: "compiler|linker"),
|
||||
template!(Word, List: &["compiler", "linker"]),
|
||||
|group: &mut Self, cx, args| {
|
||||
let used_by = match args {
|
||||
ArgParser::NoArgs => UsedBy::Linker,
|
||||
|
|
@ -327,7 +327,7 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
|
|||
type Item = (Symbol, Span);
|
||||
const PATH: &[Symbol] = &[sym::target_feature];
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: "enable = \"feat1, feat2\"");
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ pub(crate) struct ConfusablesParser {
|
|||
impl<S: Stage> AttributeParser<S> for ConfusablesParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
||||
&[sym::rustc_confusables],
|
||||
template!(List: r#""name1", "name2", ..."#),
|
||||
template!(List: &[r#""name1", "name2", ..."#]),
|
||||
|this, cx, args| {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
|||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
Word,
|
||||
List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
|
||||
List: &[r#"since = "version""#, r#"note = "reason""#, r#"since = "version", note = "reason""#],
|
||||
NameValueStr: "reason"
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
|||
const PATH: &'static [Symbol] = &[sym::inline];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "always|never");
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
Word,
|
||||
List: &["always", "never"],
|
||||
"https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
|
||||
);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
match args {
|
||||
|
|
@ -59,7 +63,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
|||
const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason");
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason");
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let reason = match args {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,10 @@ impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
|
|||
const PATH: &[Symbol] = &[sym::link_name];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
NameValueStr: "name",
|
||||
"https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"
|
||||
);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let Some(nv) = args.name_value() else {
|
||||
|
|
@ -38,7 +41,10 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
|
|||
const PATH: &[Symbol] = &[sym::link_section];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
NameValueStr: "name",
|
||||
"https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
|
||||
);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let Some(nv) = args.name_value() else {
|
||||
|
|
@ -94,7 +100,10 @@ impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
|
|||
const PATH: &[Symbol] = &[sym::link_ordinal];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(List: "ordinal");
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
List: &["ordinal"],
|
||||
"https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
|
||||
);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let ordinal = parse_single_integer(cx, args)?;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,10 @@ pub(crate) struct MacroUseParser {
|
|||
first_span: Option<Span>,
|
||||
}
|
||||
|
||||
const MACRO_USE_TEMPLATE: AttributeTemplate = template!(Word, List: "name1, name2, ...");
|
||||
const MACRO_USE_TEMPLATE: AttributeTemplate = template!(
|
||||
Word, List: &["name1, name2, ..."],
|
||||
"https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"
|
||||
);
|
||||
|
||||
impl<S: Stage> AttributeParser<S> for MacroUseParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
||||
|
|
@ -113,3 +116,11 @@ impl<S: Stage> AttributeParser<S> for MacroUseParser {
|
|||
Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state })
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct AllowInternalUnsafeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser {
|
||||
const PATH: &[Symbol] = &[sym::allow_internal_unsafe];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
|
||||
const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,10 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
|
|||
const PATH: &[Symbol] = &[sym::must_use];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, NameValueStr: "reason");
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
Word, NameValueStr: "reason",
|
||||
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"
|
||||
);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
Some(AttributeKind::MustUse {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ impl<S: Stage> SingleAttributeParser<S> for PathParser {
|
|||
const PATH: &[Symbol] = &[sym::path];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "file");
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
NameValueStr: "file",
|
||||
"https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"
|
||||
);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let Some(nv) = args.name_value() else {
|
||||
|
|
|
|||
|
|
@ -28,8 +28,10 @@ impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
|
|||
const PATH: &[Symbol] = &[sym::proc_macro_derive];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
List: &["TraitName", "TraitName, attributes(name1, name2, ...)"],
|
||||
"https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros"
|
||||
);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let (trait_name, helper_attrs) = parse_derive_like(cx, args, true)?;
|
||||
|
|
@ -47,7 +49,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
|
||||
template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?;
|
||||
|
|
|
|||
|
|
@ -26,8 +26,10 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
|
|||
const CONVERT: ConvertFn<Self::Item> =
|
||||
|items, first_span| AttributeKind::Repr { reprs: items, first_span };
|
||||
// FIXME(jdonszelmann): never used
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(List: "C | Rust | align(...) | packed(...) | <integer type> | transparent");
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
List: &["C", "Rust", "transparent", "align(...)", "packed(...)", "<integer type>"],
|
||||
"https://doc.rust-lang.org/reference/type-layout.html#representations"
|
||||
);
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
|
|
@ -275,7 +277,7 @@ pub(crate) struct AlignParser(Option<(Align, Span)>);
|
|||
|
||||
impl AlignParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_align];
|
||||
const TEMPLATE: AttributeTemplate = template!(List: "<alignment in bytes>");
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["<alignment in bytes>"]);
|
||||
|
||||
fn parse<'c, S: Stage>(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStart {
|
|||
const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(List: "start");
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["start"]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
parse_single_integer(cx, args)
|
||||
|
|
@ -26,7 +26,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEnd {
|
|||
const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(List: "end");
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["end"]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
parse_single_integer(cx, args)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ impl<S: Stage> AttributeParser<S> for StabilityParser {
|
|||
const ATTRIBUTES: AcceptMapping<Self, S> = &[
|
||||
(
|
||||
&[sym::stable],
|
||||
template!(List: r#"feature = "name", since = "version""#),
|
||||
template!(List: &[r#"feature = "name", since = "version""#]),
|
||||
|this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if !this.check_duplicate(cx)
|
||||
|
|
@ -60,7 +60,7 @@ impl<S: Stage> AttributeParser<S> for StabilityParser {
|
|||
),
|
||||
(
|
||||
&[sym::unstable],
|
||||
template!(List: r#"feature = "name", reason = "...", issue = "N""#),
|
||||
template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]),
|
||||
|this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if !this.check_duplicate(cx)
|
||||
|
|
@ -131,7 +131,7 @@ pub(crate) struct BodyStabilityParser {
|
|||
impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
||||
&[sym::rustc_default_body_unstable],
|
||||
template!(List: r#"feature = "name", reason = "...", issue = "N""#),
|
||||
template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]),
|
||||
|this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if this.stability.is_some() {
|
||||
|
|
@ -177,29 +177,37 @@ impl ConstStabilityParser {
|
|||
|
||||
impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[
|
||||
(&[sym::rustc_const_stable], template!(List: r#"feature = "name""#), |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
(
|
||||
&[sym::rustc_const_stable],
|
||||
template!(List: &[r#"feature = "name""#]),
|
||||
|this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
|
||||
if !this.check_duplicate(cx)
|
||||
&& let Some((feature, level)) = parse_stability(cx, args)
|
||||
{
|
||||
this.stability = Some((
|
||||
PartialConstStability { level, feature, promotable: false },
|
||||
cx.attr_span,
|
||||
));
|
||||
}
|
||||
}),
|
||||
(&[sym::rustc_const_unstable], template!(List: r#"feature = "name""#), |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if !this.check_duplicate(cx)
|
||||
&& let Some((feature, level)) = parse_unstability(cx, args)
|
||||
{
|
||||
this.stability = Some((
|
||||
PartialConstStability { level, feature, promotable: false },
|
||||
cx.attr_span,
|
||||
));
|
||||
}
|
||||
}),
|
||||
if !this.check_duplicate(cx)
|
||||
&& let Some((feature, level)) = parse_stability(cx, args)
|
||||
{
|
||||
this.stability = Some((
|
||||
PartialConstStability { level, feature, promotable: false },
|
||||
cx.attr_span,
|
||||
));
|
||||
}
|
||||
},
|
||||
),
|
||||
(
|
||||
&[sym::rustc_const_unstable],
|
||||
template!(List: &[r#"feature = "name""#]),
|
||||
|this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if !this.check_duplicate(cx)
|
||||
&& let Some((feature, level)) = parse_unstability(cx, args)
|
||||
{
|
||||
this.stability = Some((
|
||||
PartialConstStability { level, feature, promotable: false },
|
||||
cx.attr_span,
|
||||
));
|
||||
}
|
||||
},
|
||||
),
|
||||
(&[sym::rustc_promotable], template!(Word), |this, cx, _| {
|
||||
reject_outside_std!(cx);
|
||||
this.promotable = true;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
|
|||
const PATH: &[Symbol] = &[sym::ignore];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, NameValueStr: "reason");
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
Word, NameValueStr: "reason",
|
||||
"https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
|
||||
);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
Some(AttributeKind::Ignore {
|
||||
|
|
@ -51,8 +54,10 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
|
|||
const PATH: &[Symbol] = &[sym::should_panic];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason");
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
Word, List: &[r#"expected = "reason""#], NameValueStr: "reason",
|
||||
"https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
|
||||
);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
Some(AttributeKind::ShouldPanic {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
|
|||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
const TEMPLATE: AttributeTemplate = template!(List: "array, boxed_slice");
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let mut array = false;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
|||
cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes");
|
||||
});
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(NameValueStr: "transparent|semitransparent|opaque");
|
||||
template!(NameValueStr: ["transparent", "semitransparent", "opaque"]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let Some(nv) = args.name_value() else {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ use crate::attributes::lint_helpers::{
|
|||
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
|
||||
};
|
||||
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
|
||||
use crate::attributes::macro_attrs::{MacroEscapeParser, MacroUseParser};
|
||||
use crate::attributes::macro_attrs::{
|
||||
AllowInternalUnsafeParser, MacroEscapeParser, MacroUseParser,
|
||||
};
|
||||
use crate::attributes::must_use::MustUseParser;
|
||||
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
|
||||
use crate::attributes::non_exhaustive::NonExhaustiveParser;
|
||||
|
|
@ -178,6 +180,7 @@ attribute_parsers!(
|
|||
Single<SkipDuringMethodDispatchParser>,
|
||||
Single<TransparencyParser>,
|
||||
Single<WithoutArgs<AllowIncoherentImplParser>>,
|
||||
Single<WithoutArgs<AllowInternalUnsafeParser>>,
|
||||
Single<WithoutArgs<AsPtrParser>>,
|
||||
Single<WithoutArgs<AutomaticallyDerivedParser>>,
|
||||
Single<WithoutArgs<CoherenceIsCoreParser>>,
|
||||
|
|
|
|||
|
|
@ -498,6 +498,7 @@ pub(crate) struct ReprIdent {
|
|||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_unrecognized_repr_hint, code = E0552)]
|
||||
#[help]
|
||||
#[note]
|
||||
pub(crate) struct UnrecognizedReprHint {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -690,6 +691,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(link) = self.template.docs {
|
||||
diag.note(format!("for more information, visit <{link}>"));
|
||||
}
|
||||
let suggestions = self.template.suggestions(false, &name);
|
||||
diag.span_suggestions(
|
||||
self.attr_span,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ impl MultiItemModifier for Expander {
|
|||
item: Annotatable,
|
||||
_is_derive_const: bool,
|
||||
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
|
||||
let template = AttributeTemplate { list: Some("path"), ..Default::default() };
|
||||
let template = AttributeTemplate { list: Some(&["path"]), ..Default::default() };
|
||||
validate_attr::check_builtin_meta_item(
|
||||
&ecx.sess.psess,
|
||||
meta_item,
|
||||
|
|
|
|||
|
|
@ -34,8 +34,10 @@ impl MultiItemModifier for Expander {
|
|||
let (sess, features) = (ecx.sess, ecx.ecfg.features);
|
||||
let result =
|
||||
ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
|
||||
let template =
|
||||
AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() };
|
||||
let template = AttributeTemplate {
|
||||
list: Some(&["Trait1, Trait2, ..."]),
|
||||
..Default::default()
|
||||
};
|
||||
validate_attr::check_builtin_meta_item(
|
||||
&sess.psess,
|
||||
meta_item,
|
||||
|
|
|
|||
|
|
@ -108,11 +108,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
cx.item(
|
||||
span,
|
||||
attrs.clone(),
|
||||
ast::ItemKind::Impl(Box::new(ast::Impl {
|
||||
safety: ast::Safety::Default,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: ast::Const::No,
|
||||
ast::ItemKind::Impl(ast::Impl {
|
||||
generics: Generics {
|
||||
params: generics
|
||||
.params
|
||||
|
|
@ -137,10 +133,16 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
where_clause: generics.where_clause.clone(),
|
||||
span: generics.span,
|
||||
},
|
||||
of_trait: Some(trait_ref),
|
||||
of_trait: Some(Box::new(ast::TraitImplHeader {
|
||||
safety: ast::Safety::Default,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: ast::Const::No,
|
||||
trait_ref,
|
||||
})),
|
||||
self_ty: self_type.clone(),
|
||||
items: ThinVec::new(),
|
||||
})),
|
||||
}),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
|
@ -152,16 +154,18 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
let item = cx.item(
|
||||
span,
|
||||
attrs.clone(),
|
||||
ast::ItemKind::Impl(Box::new(ast::Impl {
|
||||
safety: ast::Safety::Default,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: ast::Const::No,
|
||||
ast::ItemKind::Impl(ast::Impl {
|
||||
generics,
|
||||
of_trait: Some(trait_ref),
|
||||
of_trait: Some(Box::new(ast::TraitImplHeader {
|
||||
safety: ast::Safety::Default,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: ast::Const::No,
|
||||
trait_ref,
|
||||
})),
|
||||
self_ty: self_type.clone(),
|
||||
items: ThinVec::new(),
|
||||
})),
|
||||
}),
|
||||
);
|
||||
push(Annotatable::Item(item));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -826,21 +826,25 @@ impl<'a> TraitDef<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
let opt_trait_ref = Some(trait_ref);
|
||||
|
||||
cx.item(
|
||||
self.span,
|
||||
attrs,
|
||||
ast::ItemKind::Impl(Box::new(ast::Impl {
|
||||
safety: ast::Safety::Default,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
|
||||
ast::ItemKind::Impl(ast::Impl {
|
||||
generics: trait_generics,
|
||||
of_trait: opt_trait_ref,
|
||||
of_trait: Some(Box::new(ast::TraitImplHeader {
|
||||
safety: ast::Safety::Default,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: if self.is_const {
|
||||
ast::Const::Yes(DUMMY_SP)
|
||||
} else {
|
||||
ast::Const::No
|
||||
},
|
||||
trait_ref,
|
||||
})),
|
||||
self_ty: self_type,
|
||||
items: methods.into_iter().chain(associated_types).collect(),
|
||||
})),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -401,6 +401,9 @@ codegen_ssa_version_script_write_failure = failed to write version script: {$err
|
|||
|
||||
codegen_ssa_visual_studio_not_installed = you may need to install Visual Studio build tools with the "C++ build tools" workload
|
||||
|
||||
codegen_ssa_xcrun_about =
|
||||
the SDK is needed by the linker to know where to find symbols in system libraries and for embedding the SDK version in the final object file
|
||||
|
||||
codegen_ssa_xcrun_command_line_tools_insufficient =
|
||||
when compiling for iOS, tvOS, visionOS or watchOS, you need a full installation of Xcode
|
||||
|
||||
|
|
|
|||
|
|
@ -160,6 +160,10 @@ pub(super) fn add_version_to_llvm_target(
|
|||
pub(super) fn get_sdk_root(sess: &Session) -> Option<PathBuf> {
|
||||
let sdk_name = sdk_name(&sess.target);
|
||||
|
||||
// Attempt to invoke `xcrun` to find the SDK.
|
||||
//
|
||||
// Note that when cross-compiling from e.g. Linux, the `xcrun` binary may sometimes be provided
|
||||
// as a shim by a cross-compilation helper tool. It usually isn't, but we still try nonetheless.
|
||||
match xcrun_show_sdk_path(sdk_name, sess.verbose_internals()) {
|
||||
Ok((path, stderr)) => {
|
||||
// Emit extra stderr, such as if `-verbose` was passed, or if `xcrun` emitted a warning.
|
||||
|
|
@ -169,7 +173,19 @@ pub(super) fn get_sdk_root(sess: &Session) -> Option<PathBuf> {
|
|||
Some(path)
|
||||
}
|
||||
Err(err) => {
|
||||
let mut diag = sess.dcx().create_err(err);
|
||||
// Failure to find the SDK is not a hard error, since the user might have specified it
|
||||
// in a manner unknown to us (moreso if cross-compiling):
|
||||
// - A compiler driver like `zig cc` which links using an internally bundled SDK.
|
||||
// - Extra linker arguments (`-Clink-arg=-syslibroot`).
|
||||
// - A custom linker or custom compiler driver.
|
||||
//
|
||||
// Though we still warn, since such cases are uncommon, and it is very hard to debug if
|
||||
// you do not know the details.
|
||||
//
|
||||
// FIXME(madsmtm): Make this a lint, to allow deny warnings to work.
|
||||
// (Or fix <https://github.com/rust-lang/rust/issues/21204>).
|
||||
let mut diag = sess.dcx().create_warn(err);
|
||||
diag.note(fluent::codegen_ssa_xcrun_about);
|
||||
|
||||
// Recognize common error cases, and give more Rust-specific error messages for those.
|
||||
if let Some(developer_dir) = xcode_select_developer_dir() {
|
||||
|
|
@ -209,6 +225,8 @@ fn xcrun_show_sdk_path(
|
|||
sdk_name: &'static str,
|
||||
verbose: bool,
|
||||
) -> Result<(PathBuf, String), XcrunError> {
|
||||
// Intentionally invoke the `xcrun` in PATH, since e.g. nixpkgs provide an `xcrun` shim, so we
|
||||
// don't want to require `/usr/bin/xcrun`.
|
||||
let mut cmd = Command::new("xcrun");
|
||||
if verbose {
|
||||
cmd.arg("--verbose");
|
||||
|
|
@ -280,7 +298,7 @@ fn stdout_to_path(mut stdout: Vec<u8>) -> PathBuf {
|
|||
}
|
||||
#[cfg(unix)]
|
||||
let path = <OsString as std::os::unix::ffi::OsStringExt>::from_vec(stdout);
|
||||
#[cfg(not(unix))] // Unimportant, this is only used on macOS
|
||||
let path = OsString::from(String::from_utf8(stdout).unwrap());
|
||||
#[cfg(not(unix))] // Not so important, this is mostly used on macOS
|
||||
let path = OsString::from(String::from_utf8(stdout).expect("stdout must be UTF-8"));
|
||||
PathBuf::from(path)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3194,39 +3194,60 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
|
|||
}
|
||||
|
||||
fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> Option<PathBuf> {
|
||||
let os = &sess.target.os;
|
||||
if sess.target.vendor != "apple"
|
||||
|| !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "visionos" | "macos")
|
||||
|| !matches!(flavor, LinkerFlavor::Darwin(..))
|
||||
{
|
||||
if !sess.target.is_like_darwin {
|
||||
return None;
|
||||
}
|
||||
|
||||
if os == "macos" && !matches!(flavor, LinkerFlavor::Darwin(Cc::No, _)) {
|
||||
let LinkerFlavor::Darwin(cc, _) = flavor else {
|
||||
return None;
|
||||
};
|
||||
|
||||
// The default compiler driver on macOS is at `/usr/bin/cc`. This is a trampoline binary that
|
||||
// effectively invokes `xcrun cc` internally to look up both the compiler binary and the SDK
|
||||
// root from the current Xcode installation. When cross-compiling, when `rustc` is invoked
|
||||
// inside Xcode, or when invoking the linker directly, this default logic is unsuitable, so
|
||||
// instead we invoke `xcrun` manually.
|
||||
//
|
||||
// (Note that this doesn't mean we get a duplicate lookup here - passing `SDKROOT` below will
|
||||
// cause the trampoline binary to skip looking up the SDK itself).
|
||||
let sdkroot = sess.time("get_apple_sdk_root", || get_apple_sdk_root(sess))?;
|
||||
|
||||
if cc == Cc::Yes {
|
||||
// There are a few options to pass the SDK root when linking with a C/C++ compiler:
|
||||
// - The `--sysroot` flag.
|
||||
// - The `-isysroot` flag.
|
||||
// - The `SDKROOT` environment variable.
|
||||
//
|
||||
// `--sysroot` isn't actually enough to get Clang to treat it as a platform SDK, you need
|
||||
// to specify `-isysroot`. This is admittedly a bit strange, as on most targets `-isysroot`
|
||||
// only applies to include header files, but on Apple targets it also applies to libraries
|
||||
// and frameworks.
|
||||
//
|
||||
// This leaves the choice between `-isysroot` and `SDKROOT`. Both are supported by Clang and
|
||||
// GCC, though they may not be supported by all compiler drivers. We choose `SDKROOT`,
|
||||
// primarily because that is the same interface that is used when invoking the tool under
|
||||
// `xcrun -sdk macosx $tool`.
|
||||
//
|
||||
// In that sense, if a given compiler driver does not support `SDKROOT`, the blame is fairly
|
||||
// clearly in the tool in question, since they also don't support being run under `xcrun`.
|
||||
//
|
||||
// Additionally, `SDKROOT` is an environment variable and thus optional. It also has lower
|
||||
// precedence than `-isysroot`, so a custom compiler driver that does not support it and
|
||||
// instead figures out the SDK on their own can easily do so by using `-isysroot`.
|
||||
//
|
||||
// (This in particular affects Clang built with the `DEFAULT_SYSROOT` CMake flag, such as
|
||||
// the one provided by some versions of Homebrew's `llvm` package. Those will end up
|
||||
// ignoring the value we set here, and instead use their built-in sysroot).
|
||||
cmd.cmd().env("SDKROOT", &sdkroot);
|
||||
} else {
|
||||
// When invoking the linker directly, we use the `-syslibroot` parameter. `SDKROOT` is not
|
||||
// read by the linker, so it's really the only option.
|
||||
//
|
||||
// This is also what Clang does.
|
||||
cmd.link_arg("-syslibroot");
|
||||
cmd.link_arg(&sdkroot);
|
||||
}
|
||||
|
||||
let sdk_root = sess.time("get_apple_sdk_root", || get_apple_sdk_root(sess))?;
|
||||
|
||||
match flavor {
|
||||
LinkerFlavor::Darwin(Cc::Yes, _) => {
|
||||
// Use `-isysroot` instead of `--sysroot`, as only the former
|
||||
// makes Clang treat it as a platform SDK.
|
||||
//
|
||||
// This is admittedly a bit strange, as on most targets
|
||||
// `-isysroot` only applies to include header files, but on Apple
|
||||
// targets this also applies to libraries and frameworks.
|
||||
cmd.cc_arg("-isysroot");
|
||||
cmd.cc_arg(&sdk_root);
|
||||
}
|
||||
LinkerFlavor::Darwin(Cc::No, _) => {
|
||||
cmd.link_arg("-syslibroot");
|
||||
cmd.link_arg(&sdk_root);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
Some(sdk_root)
|
||||
Some(sdkroot)
|
||||
}
|
||||
|
||||
fn get_apple_sdk_root(sess: &Session) -> Option<PathBuf> {
|
||||
|
|
@ -3255,7 +3276,13 @@ fn get_apple_sdk_root(sess: &Session) -> Option<PathBuf> {
|
|||
}
|
||||
"macosx"
|
||||
if sdkroot.contains("iPhoneOS.platform")
|
||||
|| sdkroot.contains("iPhoneSimulator.platform") => {}
|
||||
|| sdkroot.contains("iPhoneSimulator.platform")
|
||||
|| sdkroot.contains("AppleTVOS.platform")
|
||||
|| sdkroot.contains("AppleTVSimulator.platform")
|
||||
|| sdkroot.contains("WatchOS.platform")
|
||||
|| sdkroot.contains("WatchSimulator.platform")
|
||||
|| sdkroot.contains("XROS.platform")
|
||||
|| sdkroot.contains("XRSimulator.platform") => {}
|
||||
"watchos"
|
||||
if sdkroot.contains("WatchSimulator.platform")
|
||||
|| sdkroot.contains("MacOSX.platform") => {}
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
destination: &PlaceTy<'tcx, M::Provenance>,
|
||||
mut cont: ReturnContinuation,
|
||||
) -> InterpResult<'tcx> {
|
||||
let _span = enter_trace_span!(M, step::init_stack_frame, %instance, tracing_separate_thread = Empty);
|
||||
let _trace = enter_trace_span!(M, step::init_stack_frame, %instance, tracing_separate_thread = Empty);
|
||||
|
||||
// Compute callee information.
|
||||
// FIXME: for variadic support, do we have to somehow determine callee's extra_args?
|
||||
|
|
@ -527,7 +527,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
target: Option<mir::BasicBlock>,
|
||||
unwind: mir::UnwindAction,
|
||||
) -> InterpResult<'tcx> {
|
||||
let _span =
|
||||
let _trace =
|
||||
enter_trace_span!(M, step::init_fn_call, tracing_separate_thread = Empty, ?fn_val)
|
||||
.or_if_tracing_disabled(|| trace!("init_fn_call: {:#?}", fn_val));
|
||||
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
/// See [LayoutOf::layout_of] for the original documentation.
|
||||
#[inline(always)]
|
||||
pub fn layout_of(&self, ty: Ty<'tcx>) -> <Self as LayoutOfHelpers<'tcx>>::LayoutOfResult {
|
||||
let _span = enter_trace_span!(M, layouting::layout_of, ty = ?ty.kind());
|
||||
let _trace = enter_trace_span!(M, layouting::layout_of, ty = ?ty.kind());
|
||||
LayoutOf::layout_of(self, ty)
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
sig: ty::PolyFnSig<'tcx>,
|
||||
extra_args: &'tcx ty::List<Ty<'tcx>>,
|
||||
) -> <Self as FnAbiOfHelpers<'tcx>>::FnAbiOfResult {
|
||||
let _span = enter_trace_span!(M, layouting::fn_abi_of_fn_ptr, ?sig, ?extra_args);
|
||||
let _trace = enter_trace_span!(M, layouting::fn_abi_of_fn_ptr, ?sig, ?extra_args);
|
||||
FnAbiOf::fn_abi_of_fn_ptr(self, sig, extra_args)
|
||||
}
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
instance: ty::Instance<'tcx>,
|
||||
extra_args: &'tcx ty::List<Ty<'tcx>>,
|
||||
) -> <Self as FnAbiOfHelpers<'tcx>>::FnAbiOfResult {
|
||||
let _span = enter_trace_span!(M, layouting::fn_abi_of_instance, ?instance, ?extra_args);
|
||||
let _trace = enter_trace_span!(M, layouting::fn_abi_of_instance, ?instance, ?extra_args);
|
||||
FnAbiOf::fn_abi_of_instance(self, instance, extra_args)
|
||||
}
|
||||
}
|
||||
|
|
@ -322,7 +322,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
|
||||
value: T,
|
||||
) -> Result<T, ErrorHandled> {
|
||||
let _span = enter_trace_span!(
|
||||
let _trace = enter_trace_span!(
|
||||
M,
|
||||
"instantiate_from_frame_and_normalize_erasing_regions",
|
||||
"{}",
|
||||
|
|
|
|||
|
|
@ -773,7 +773,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
mir_place: mir::Place<'tcx>,
|
||||
layout: Option<TyAndLayout<'tcx>>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
let _span = enter_trace_span!(
|
||||
let _trace = enter_trace_span!(
|
||||
M,
|
||||
step::eval_place_to_op,
|
||||
?mir_place,
|
||||
|
|
@ -823,7 +823,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
mir_op: &mir::Operand<'tcx>,
|
||||
layout: Option<TyAndLayout<'tcx>>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
let _span =
|
||||
let _trace =
|
||||
enter_trace_span!(M, step::eval_operand, ?mir_op, tracing_separate_thread = Empty);
|
||||
|
||||
use rustc_middle::mir::Operand::*;
|
||||
|
|
|
|||
|
|
@ -526,7 +526,7 @@ where
|
|||
&self,
|
||||
mir_place: mir::Place<'tcx>,
|
||||
) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
|
||||
let _span =
|
||||
let _trace =
|
||||
enter_trace_span!(M, step::eval_place, ?mir_place, tracing_separate_thread = Empty);
|
||||
|
||||
let mut place = self.local_to_place(mir_place.local)?;
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
///
|
||||
/// This does NOT move the statement counter forward, the caller has to do that!
|
||||
pub fn eval_statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
|
||||
let _span = enter_trace_span!(
|
||||
let _trace = enter_trace_span!(
|
||||
M,
|
||||
step::eval_statement,
|
||||
stmt = ?stmt.kind,
|
||||
|
|
@ -465,7 +465,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
}
|
||||
|
||||
fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
|
||||
let _span = enter_trace_span!(
|
||||
let _trace = enter_trace_span!(
|
||||
M,
|
||||
step::eval_terminator,
|
||||
terminator = ?terminator.kind,
|
||||
|
|
|
|||
|
|
@ -85,11 +85,11 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan {
|
|||
/// # let my_debug_var = String::new();
|
||||
/// // logs a span named "hello" with a field named "arg" of value 42 (works only because
|
||||
/// // 42 implements the tracing::Value trait, otherwise use one of the options below)
|
||||
/// let _span = enter_trace_span!(M, "hello", arg = 42);
|
||||
/// let _trace = enter_trace_span!(M, "hello", arg = 42);
|
||||
/// // logs a field called "my_display_var" using the Display implementation
|
||||
/// let _span = enter_trace_span!(M, "hello", %my_display_var);
|
||||
/// let _trace = enter_trace_span!(M, "hello", %my_display_var);
|
||||
/// // logs a field called "my_debug_var" using the Debug implementation
|
||||
/// let _span = enter_trace_span!(M, "hello", ?my_debug_var);
|
||||
/// let _trace = enter_trace_span!(M, "hello", ?my_debug_var);
|
||||
/// ```
|
||||
///
|
||||
/// ### `NAME::SUBNAME` syntax
|
||||
|
|
@ -107,8 +107,8 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan {
|
|||
/// # use rustc_const_eval::enter_trace_span;
|
||||
/// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>;
|
||||
/// // for example, the first will expand to the second
|
||||
/// let _span = enter_trace_span!(M, borrow_tracker::on_stack_pop, /* ... */);
|
||||
/// let _span = enter_trace_span!(M, "borrow_tracker", borrow_tracker = "on_stack_pop", /* ... */);
|
||||
/// let _trace = enter_trace_span!(M, borrow_tracker::on_stack_pop, /* ... */);
|
||||
/// let _trace = enter_trace_span!(M, "borrow_tracker", borrow_tracker = "on_stack_pop", /* ... */);
|
||||
/// ```
|
||||
///
|
||||
/// ### `tracing_separate_thread` parameter
|
||||
|
|
@ -124,7 +124,7 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan {
|
|||
/// ```rust
|
||||
/// # use rustc_const_eval::enter_trace_span;
|
||||
/// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>;
|
||||
/// let _span = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty);
|
||||
/// let _trace = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty);
|
||||
/// ```
|
||||
///
|
||||
/// ### Executing something else when tracing is disabled
|
||||
|
|
@ -136,7 +136,7 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan {
|
|||
/// # use rustc_const_eval::enter_trace_span;
|
||||
/// # use rustc_const_eval::interpret::EnteredTraceSpan;
|
||||
/// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>;
|
||||
/// let _span = enter_trace_span!(M, step::eval_statement)
|
||||
/// let _trace = enter_trace_span!(M, step::eval_statement)
|
||||
/// .or_if_tracing_disabled(|| tracing::info!("eval_statement"));
|
||||
/// ```
|
||||
#[macro_export]
|
||||
|
|
|
|||
|
|
@ -1415,7 +1415,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
recursive: bool,
|
||||
reset_provenance_and_padding: bool,
|
||||
) -> InterpResult<'tcx> {
|
||||
let _span = enter_trace_span!(
|
||||
let _trace = enter_trace_span!(
|
||||
M,
|
||||
"validate_operand",
|
||||
"recursive={recursive}, reset_provenance_and_padding={reset_provenance_and_padding}, val={val:?}"
|
||||
|
|
|
|||
|
|
@ -904,10 +904,7 @@ impl SyntaxExtension {
|
|||
find_attr!(attrs, AttributeKind::AllowInternalUnstable(i, _) => i)
|
||||
.map(|i| i.as_slice())
|
||||
.unwrap_or_default();
|
||||
// FIXME(jdonszelman): allow_internal_unsafe isn't yet new-style
|
||||
// let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe);
|
||||
let allow_internal_unsafe =
|
||||
ast::attr::find_by_name(attrs, sym::allow_internal_unsafe).is_some();
|
||||
let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe(_));
|
||||
|
||||
let local_inner_macros = ast::attr::find_by_name(attrs, sym::macro_export)
|
||||
.and_then(|macro_export| macro_export.meta_item_list())
|
||||
|
|
|
|||
|
|
@ -120,13 +120,15 @@ pub struct AttributeTemplate {
|
|||
/// If `true`, the attribute is allowed to be a bare word like `#[test]`.
|
||||
pub word: bool,
|
||||
/// If `Some`, the attribute is allowed to take a list of items like `#[allow(..)]`.
|
||||
pub list: Option<&'static str>,
|
||||
pub list: Option<&'static [&'static str]>,
|
||||
/// If non-empty, the attribute is allowed to take a list containing exactly
|
||||
/// one of the listed words, like `#[coverage(off)]`.
|
||||
pub one_of: &'static [Symbol],
|
||||
/// If `Some`, the attribute is allowed to be a name/value pair where the
|
||||
/// value is a string, like `#[must_use = "reason"]`.
|
||||
pub name_value_str: Option<&'static str>,
|
||||
pub name_value_str: Option<&'static [&'static str]>,
|
||||
/// A link to the document for this attribute.
|
||||
pub docs: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl AttributeTemplate {
|
||||
|
|
@ -137,11 +139,15 @@ impl AttributeTemplate {
|
|||
suggestions.push(format!("#{inner}[{name}]"));
|
||||
}
|
||||
if let Some(descr) = self.list {
|
||||
suggestions.push(format!("#{inner}[{name}({descr})]"));
|
||||
for descr in descr {
|
||||
suggestions.push(format!("#{inner}[{name}({descr})]"));
|
||||
}
|
||||
}
|
||||
suggestions.extend(self.one_of.iter().map(|&word| format!("#{inner}[{name}({word})]")));
|
||||
if let Some(descr) = self.name_value_str {
|
||||
suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
|
||||
for descr in descr {
|
||||
suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
|
||||
}
|
||||
}
|
||||
suggestions.sort();
|
||||
|
||||
|
|
@ -205,20 +211,33 @@ pub enum AttributeDuplicates {
|
|||
/// supports forms `#[attr]` and `#[attr(description)]`.
|
||||
#[macro_export]
|
||||
macro_rules! template {
|
||||
(Word) => { $crate::template!(@ true, None, &[], None) };
|
||||
(List: $descr: expr) => { $crate::template!(@ false, Some($descr), &[], None) };
|
||||
(OneOf: $one_of: expr) => { $crate::template!(@ false, None, $one_of, None) };
|
||||
(NameValueStr: $descr: expr) => { $crate::template!(@ false, None, &[], Some($descr)) };
|
||||
(Word, List: $descr: expr) => { $crate::template!(@ true, Some($descr), &[], None) };
|
||||
(Word, NameValueStr: $descr: expr) => { $crate::template!(@ true, None, &[], Some($descr)) };
|
||||
(Word) => { $crate::template!(@ true, None, &[], None, None) };
|
||||
(Word, $link: literal) => { $crate::template!(@ true, None, &[], None, Some($link)) };
|
||||
(List: $descr: expr) => { $crate::template!(@ false, Some($descr), &[], None, None) };
|
||||
(List: $descr: expr, $link: literal) => { $crate::template!(@ false, Some($descr), &[], None, Some($link)) };
|
||||
(OneOf: $one_of: expr) => { $crate::template!(@ false, None, $one_of, None, None) };
|
||||
(NameValueStr: [$($descr: literal),* $(,)?]) => { $crate::template!(@ false, None, &[], Some(&[$($descr,)*]), None) };
|
||||
(NameValueStr: [$($descr: literal),* $(,)?], $link: literal) => { $crate::template!(@ false, None, &[], Some(&[$($descr,)*]), Some($link)) };
|
||||
(NameValueStr: $descr: literal) => { $crate::template!(@ false, None, &[], Some(&[$descr]), None) };
|
||||
(NameValueStr: $descr: literal, $link: literal) => { $crate::template!(@ false, None, &[], Some(&[$descr]), Some($link)) };
|
||||
(Word, List: $descr: expr) => { $crate::template!(@ true, Some($descr), &[], None, None) };
|
||||
(Word, List: $descr: expr, $link: literal) => { $crate::template!(@ true, Some($descr), &[], None, Some($link)) };
|
||||
(Word, NameValueStr: $descr: expr) => { $crate::template!(@ true, None, &[], Some(&[$descr]), None) };
|
||||
(Word, NameValueStr: $descr: expr, $link: literal) => { $crate::template!(@ true, None, &[], Some(&[$descr]), Some($link)) };
|
||||
(List: $descr1: expr, NameValueStr: $descr2: expr) => {
|
||||
$crate::template!(@ false, Some($descr1), &[], Some($descr2))
|
||||
$crate::template!(@ false, Some($descr1), &[], Some(&[$descr2]), None)
|
||||
};
|
||||
(List: $descr1: expr, NameValueStr: $descr2: expr, $link: literal) => {
|
||||
$crate::template!(@ false, Some($descr1), &[], Some(&[$descr2]), Some($link))
|
||||
};
|
||||
(Word, List: $descr1: expr, NameValueStr: $descr2: expr) => {
|
||||
$crate::template!(@ true, Some($descr1), &[], Some($descr2))
|
||||
$crate::template!(@ true, Some($descr1), &[], Some(&[$descr2]), None)
|
||||
};
|
||||
(@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr) => { $crate::AttributeTemplate {
|
||||
word: $word, list: $list, one_of: $one_of, name_value_str: $name_value_str
|
||||
(Word, List: $descr1: expr, NameValueStr: $descr2: expr, $link: literal) => {
|
||||
$crate::template!(@ true, Some($descr1), &[], Some(&[$descr2]), Some($link))
|
||||
};
|
||||
(@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr, $link: expr) => { $crate::AttributeTemplate {
|
||||
word: $word, list: $list, one_of: $one_of, name_value_str: $name_value_str, docs: $link,
|
||||
} };
|
||||
}
|
||||
|
||||
|
|
@ -391,18 +410,42 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
// ==========================================================================
|
||||
|
||||
// Conditional compilation:
|
||||
ungated!(cfg, Normal, template!(List: "predicate"), DuplicatesOk, EncodeCrossCrate::Yes),
|
||||
ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), DuplicatesOk, EncodeCrossCrate::Yes),
|
||||
ungated!(
|
||||
cfg, Normal,
|
||||
template!(
|
||||
List: &["predicate"],
|
||||
"https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute"
|
||||
),
|
||||
DuplicatesOk, EncodeCrossCrate::Yes
|
||||
),
|
||||
ungated!(
|
||||
cfg_attr, Normal,
|
||||
template!(
|
||||
List: &["predicate, attr1, attr2, ..."],
|
||||
"https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute"
|
||||
),
|
||||
DuplicatesOk, EncodeCrossCrate::Yes
|
||||
),
|
||||
|
||||
// Testing:
|
||||
ungated!(
|
||||
ignore, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
ignore, Normal,
|
||||
template!(
|
||||
Word,
|
||||
NameValueStr: "reason",
|
||||
"https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
|
||||
),
|
||||
WarnFollowing, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(
|
||||
should_panic, Normal,
|
||||
template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason"), FutureWarnFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
template!(
|
||||
Word,
|
||||
List: &[r#"expected = "reason""#],
|
||||
NameValueStr: "reason",
|
||||
"https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
|
||||
),
|
||||
FutureWarnFollowing, EncodeCrossCrate::No,
|
||||
),
|
||||
// FIXME(Centril): This can be used on stable but shouldn't.
|
||||
ungated!(
|
||||
|
|
@ -411,46 +454,102 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
|
||||
// Macros:
|
||||
ungated!(automatically_derived, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
|
||||
ungated!(
|
||||
macro_use, Normal, template!(Word, List: "name1, name2, ..."), WarnFollowingWordOnly,
|
||||
EncodeCrossCrate::No,
|
||||
automatically_derived, Normal,
|
||||
template!(
|
||||
Word,
|
||||
"https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute"
|
||||
),
|
||||
WarnFollowing, EncodeCrossCrate::Yes
|
||||
),
|
||||
ungated!(
|
||||
macro_use, Normal,
|
||||
template!(
|
||||
Word,
|
||||
List: &["name1, name2, ..."],
|
||||
"https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"
|
||||
),
|
||||
WarnFollowingWordOnly, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(macro_escape, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), // Deprecated synonym for `macro_use`.
|
||||
ungated!(
|
||||
macro_export, Normal, template!(Word, List: "local_inner_macros"),
|
||||
macro_export, Normal,
|
||||
template!(
|
||||
Word,
|
||||
List: &["local_inner_macros"],
|
||||
"https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope"
|
||||
),
|
||||
WarnFollowing, EncodeCrossCrate::Yes
|
||||
),
|
||||
ungated!(proc_macro, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No),
|
||||
ungated!(
|
||||
proc_macro_derive, Normal, template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"),
|
||||
proc_macro, Normal,
|
||||
template!(
|
||||
Word,
|
||||
"https://doc.rust-lang.org/reference/procedural-macros.html#function-like-procedural-macros"),
|
||||
ErrorFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
proc_macro_derive, Normal,
|
||||
template!(
|
||||
List: &["TraitName", "TraitName, attributes(name1, name2, ...)"],
|
||||
"https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros"
|
||||
),
|
||||
ErrorFollowing, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(proc_macro_attribute, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No),
|
||||
ungated!(
|
||||
proc_macro_attribute, Normal,
|
||||
template!(Word, "https://doc.rust-lang.org/reference/procedural-macros.html#attribute-macros"),
|
||||
ErrorFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
|
||||
// Lints:
|
||||
ungated!(
|
||||
warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
|
||||
warn, Normal,
|
||||
template!(
|
||||
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
|
||||
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
|
||||
),
|
||||
DuplicatesOk, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(
|
||||
allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
|
||||
allow, Normal,
|
||||
template!(
|
||||
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
|
||||
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
|
||||
),
|
||||
DuplicatesOk, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(
|
||||
expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
|
||||
expect, Normal,
|
||||
template!(
|
||||
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
|
||||
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
|
||||
),
|
||||
DuplicatesOk, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(
|
||||
forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
|
||||
forbid, Normal,
|
||||
template!(
|
||||
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
|
||||
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
|
||||
),
|
||||
DuplicatesOk, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
|
||||
deny, Normal,
|
||||
template!(
|
||||
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
|
||||
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
|
||||
),
|
||||
DuplicatesOk, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
must_use, Normal, template!(Word, NameValueStr: "reason"),
|
||||
must_use, Normal,
|
||||
template!(
|
||||
Word,
|
||||
NameValueStr: "reason",
|
||||
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"
|
||||
),
|
||||
FutureWarnFollowing, EncodeCrossCrate::Yes
|
||||
),
|
||||
gated!(
|
||||
|
|
@ -461,52 +560,104 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
deprecated, Normal,
|
||||
template!(
|
||||
Word,
|
||||
List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
|
||||
NameValueStr: "reason"
|
||||
List: &[r#"/*opt*/ since = "version", /*opt*/ note = "reason""#],
|
||||
NameValueStr: "reason",
|
||||
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute"
|
||||
),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes
|
||||
),
|
||||
|
||||
// Crate properties:
|
||||
ungated!(
|
||||
crate_name, CrateLevel, template!(NameValueStr: "name"), FutureWarnFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
crate_name, CrateLevel,
|
||||
template!(
|
||||
NameValueStr: "name",
|
||||
"https://doc.rust-lang.org/reference/crates-and-source-files.html#the-crate_name-attribute"
|
||||
),
|
||||
FutureWarnFollowing, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(
|
||||
crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), DuplicatesOk,
|
||||
EncodeCrossCrate::No,
|
||||
crate_type, CrateLevel,
|
||||
template!(
|
||||
NameValueStr: ["bin", "lib", "dylib", "cdylib", "rlib", "staticlib", "sdylib", "proc-macro"],
|
||||
"https://doc.rust-lang.org/reference/linkage.html"
|
||||
),
|
||||
DuplicatesOk, EncodeCrossCrate::No,
|
||||
),
|
||||
|
||||
// ABI, linking, symbols, and FFI
|
||||
ungated!(
|
||||
link, Normal,
|
||||
template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated""#),
|
||||
DuplicatesOk,
|
||||
EncodeCrossCrate::No,
|
||||
template!(List: &[
|
||||
r#"name = "...""#,
|
||||
r#"name = "...", kind = "dylib|static|...""#,
|
||||
r#"name = "...", wasm_import_module = "...""#,
|
||||
r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#,
|
||||
r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#,
|
||||
], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute"),
|
||||
DuplicatesOk, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(
|
||||
link_name, Normal, template!(NameValueStr: "name"),
|
||||
link_name, Normal,
|
||||
template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"),
|
||||
FutureWarnPreceding, EncodeCrossCrate::Yes
|
||||
),
|
||||
ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
|
||||
ungated!(
|
||||
no_link, Normal,
|
||||
template!(Word, "https://doc.rust-lang.org/reference/items/extern-crates.html#the-no_link-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
repr, Normal,
|
||||
template!(
|
||||
List: &["C", "Rust", "transparent", "align(...)", "packed(...)", "<integer type>"],
|
||||
"https://doc.rust-lang.org/reference/type-layout.html#representations"
|
||||
),
|
||||
DuplicatesOk, EncodeCrossCrate::No
|
||||
),
|
||||
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
|
||||
gated!(rustc_align, Normal, template!(List: "alignment"), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)),
|
||||
ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
|
||||
ungated!(unsafe naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
gated!(rustc_align, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)),
|
||||
ungated!(
|
||||
unsafe(Edition2024) export_name, Normal,
|
||||
template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"),
|
||||
FutureWarnPreceding, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
unsafe(Edition2024) link_section, Normal,
|
||||
template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"),
|
||||
FutureWarnPreceding, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
unsafe(Edition2024) no_mangle, Normal,
|
||||
template!(Word, "https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
used, Normal,
|
||||
template!(Word, List: &["compiler", "linker"], "https://doc.rust-lang.org/reference/abi.html#the-used-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
link_ordinal, Normal,
|
||||
template!(List: &["ordinal"], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"),
|
||||
ErrorPreceding, EncodeCrossCrate::Yes
|
||||
),
|
||||
ungated!(
|
||||
unsafe naked, Normal,
|
||||
template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-naked-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
|
||||
// Limits:
|
||||
ungated!(
|
||||
recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing,
|
||||
EncodeCrossCrate::No
|
||||
recursion_limit, CrateLevel,
|
||||
template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"),
|
||||
FutureWarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing,
|
||||
EncodeCrossCrate::No
|
||||
type_length_limit, CrateLevel,
|
||||
template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-type_length_limit-attribute"),
|
||||
FutureWarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
gated!(
|
||||
move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
|
||||
|
|
@ -514,35 +665,84 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
|
||||
// Entry point:
|
||||
ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(
|
||||
no_main, CrateLevel,
|
||||
template!(Word, "https://doc.rust-lang.org/reference/crates-and-source-files.html#the-no_main-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
|
||||
// Modules, prelude, and resolution:
|
||||
ungated!(path, Normal, template!(NameValueStr: "file"), FutureWarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(no_std, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(no_implicit_prelude, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(non_exhaustive, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
|
||||
ungated!(
|
||||
path, Normal,
|
||||
template!(NameValueStr: "file", "https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"),
|
||||
FutureWarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
no_std, CrateLevel,
|
||||
template!(Word, "https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
no_implicit_prelude, Normal,
|
||||
template!(Word, "https://doc.rust-lang.org/reference/names/preludes.html#the-no_implicit_prelude-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
non_exhaustive, Normal,
|
||||
template!(Word, "https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::Yes
|
||||
),
|
||||
|
||||
// Runtime
|
||||
ungated!(
|
||||
windows_subsystem, CrateLevel,
|
||||
template!(NameValueStr: "windows|console"), FutureWarnFollowing,
|
||||
EncodeCrossCrate::No
|
||||
template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"),
|
||||
FutureWarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!( // RFC 2070
|
||||
panic_handler, Normal,
|
||||
template!(Word, "https://doc.rust-lang.org/reference/panic.html#the-panic_handler-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::Yes
|
||||
),
|
||||
ungated!(panic_handler, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes), // RFC 2070
|
||||
|
||||
// Code generation:
|
||||
ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(cold, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
|
||||
ungated!(
|
||||
target_feature, Normal, template!(List: r#"enable = "name""#),
|
||||
inline, Normal,
|
||||
template!(
|
||||
Word,
|
||||
List: &["always", "never"],
|
||||
"https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
|
||||
),
|
||||
FutureWarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
cold, Normal,
|
||||
template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-cold-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(
|
||||
no_builtins, CrateLevel,
|
||||
template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-no_builtins-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::Yes
|
||||
),
|
||||
ungated!(
|
||||
target_feature, Normal,
|
||||
template!(List: &[r#"enable = "name""#], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute"),
|
||||
DuplicatesOk, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(track_caller, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
|
||||
ungated!(instruction_set, Normal, template!(List: "set"), ErrorPreceding, EncodeCrossCrate::No),
|
||||
ungated!(
|
||||
track_caller, Normal,
|
||||
template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-track_caller-attribute"),
|
||||
WarnFollowing, EncodeCrossCrate::Yes
|
||||
),
|
||||
ungated!(
|
||||
instruction_set, Normal,
|
||||
template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute"),
|
||||
ErrorPreceding, EncodeCrossCrate::No
|
||||
),
|
||||
gated!(
|
||||
no_sanitize, Normal,
|
||||
template!(List: "address, kcfi, memory, thread"), DuplicatesOk,
|
||||
template!(List: &["address, kcfi, memory, thread"]), DuplicatesOk,
|
||||
EncodeCrossCrate::No, experimental!(no_sanitize)
|
||||
),
|
||||
gated!(
|
||||
|
|
@ -552,18 +752,31 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
|
||||
ungated!(
|
||||
doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk,
|
||||
EncodeCrossCrate::Yes
|
||||
doc, Normal,
|
||||
template!(
|
||||
List: &["hidden", "inline"],
|
||||
NameValueStr: "string",
|
||||
"https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html"
|
||||
),
|
||||
DuplicatesOk, EncodeCrossCrate::Yes
|
||||
),
|
||||
|
||||
// Debugging
|
||||
ungated!(
|
||||
debugger_visualizer, Normal,
|
||||
template!(List: r#"natvis_file = "...", gdb_script_file = "...""#),
|
||||
template!(
|
||||
List: &[r#"natvis_file = "...", gdb_script_file = "...""#],
|
||||
"https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute"
|
||||
),
|
||||
DuplicatesOk, EncodeCrossCrate::No
|
||||
),
|
||||
ungated!(collapse_debuginfo, Normal, template!(List: "no|external|yes"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes
|
||||
ungated!(
|
||||
collapse_debuginfo, Normal,
|
||||
template!(
|
||||
List: &["no", "external", "yes"],
|
||||
"https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute"
|
||||
),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
|
|
@ -578,7 +791,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
|
||||
// Testing:
|
||||
gated!(
|
||||
test_runner, CrateLevel, template!(List: "path"), ErrorFollowing,
|
||||
test_runner, CrateLevel, template!(List: &["path"]), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes, custom_test_frameworks,
|
||||
"custom test frameworks are an unstable feature",
|
||||
),
|
||||
|
|
@ -597,7 +810,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
// RFC 2412
|
||||
gated!(
|
||||
optimize, Normal, template!(List: "none|size|speed"), ErrorPreceding,
|
||||
optimize, Normal, template!(List: &["none", "size", "speed"]), ErrorPreceding,
|
||||
EncodeCrossCrate::No, optimize_attribute, experimental!(optimize)
|
||||
),
|
||||
|
||||
|
|
@ -610,7 +823,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
EncodeCrossCrate::No, experimental!(ffi_const)
|
||||
),
|
||||
gated!(
|
||||
register_tool, CrateLevel, template!(List: "tool1, tool2, ..."), DuplicatesOk,
|
||||
register_tool, CrateLevel, template!(List: &["tool1, tool2, ..."]), DuplicatesOk,
|
||||
EncodeCrossCrate::No, experimental!(register_tool),
|
||||
),
|
||||
|
||||
|
|
@ -624,7 +837,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
// lang-team MCP 147
|
||||
gated!(
|
||||
deprecated_safe, Normal, template!(List: r#"since = "version", note = "...""#), ErrorFollowing,
|
||||
deprecated_safe, Normal, template!(List: &[r#"since = "version", note = "...""#]), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes, experimental!(deprecated_safe),
|
||||
),
|
||||
|
||||
|
|
@ -643,7 +856,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
// RFC 3543
|
||||
// `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]`
|
||||
gated!(
|
||||
patchable_function_entry, Normal, template!(List: "prefix_nops = m, entry_nops = n"), ErrorPreceding,
|
||||
patchable_function_entry, Normal, template!(List: &["prefix_nops = m, entry_nops = n"]), ErrorPreceding,
|
||||
EncodeCrossCrate::Yes, experimental!(patchable_function_entry)
|
||||
),
|
||||
|
||||
|
|
@ -673,37 +886,37 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
|
||||
ungated!(
|
||||
feature, CrateLevel,
|
||||
template!(List: "name1, name2, ..."), DuplicatesOk, EncodeCrossCrate::No,
|
||||
template!(List: &["name1, name2, ..."]), DuplicatesOk, EncodeCrossCrate::No,
|
||||
),
|
||||
// DuplicatesOk since it has its own validation
|
||||
ungated!(
|
||||
stable, Normal,
|
||||
template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, EncodeCrossCrate::No,
|
||||
template!(List: &[r#"feature = "name", since = "version""#]), DuplicatesOk, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(
|
||||
unstable, Normal,
|
||||
template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk,
|
||||
template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]), DuplicatesOk,
|
||||
EncodeCrossCrate::Yes
|
||||
),
|
||||
ungated!(
|
||||
unstable_feature_bound, Normal, template!(Word, List: "feat1, feat2, ..."),
|
||||
unstable_feature_bound, Normal, template!(Word, List: &["feat1, feat2, ..."]),
|
||||
DuplicatesOk, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(
|
||||
rustc_const_unstable, Normal, template!(List: r#"feature = "name""#),
|
||||
rustc_const_unstable, Normal, template!(List: &[r#"feature = "name""#]),
|
||||
DuplicatesOk, EncodeCrossCrate::Yes
|
||||
),
|
||||
ungated!(
|
||||
rustc_const_stable, Normal,
|
||||
template!(List: r#"feature = "name""#), DuplicatesOk, EncodeCrossCrate::No,
|
||||
template!(List: &[r#"feature = "name""#]), DuplicatesOk, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(
|
||||
rustc_default_body_unstable, Normal,
|
||||
template!(List: r#"feature = "name", reason = "...", issue = "N""#),
|
||||
template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]),
|
||||
DuplicatesOk, EncodeCrossCrate::No
|
||||
),
|
||||
gated!(
|
||||
allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
|
||||
allow_internal_unstable, Normal, template!(Word, List: &["feat1, feat2, ..."]),
|
||||
DuplicatesOk, EncodeCrossCrate::Yes,
|
||||
"allow_internal_unstable side-steps feature gating and stability checks",
|
||||
),
|
||||
|
|
@ -718,7 +931,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
through unstable paths"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_deprecated_safe_2024, Normal, template!(List: r#"audit_that = "...""#),
|
||||
rustc_deprecated_safe_2024, Normal, template!(List: &[r#"audit_that = "...""#]),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
"`#[rustc_deprecated_safe_2024]` is used to declare functions unsafe across the edition 2024 boundary",
|
||||
),
|
||||
|
|
@ -743,7 +956,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_attr!(
|
||||
rustc_never_type_options,
|
||||
Normal,
|
||||
template!(List: r#"/*opt*/ fallback = "unit|niko|never|no""#),
|
||||
template!(List: &[
|
||||
"",
|
||||
r#"fallback = "unit""#,
|
||||
r#"fallback = "niko""#,
|
||||
r#"fallback = "never""#,
|
||||
r#"fallback = "no""#,
|
||||
]),
|
||||
ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"`rustc_never_type_options` is used to experiment with never type fallback and work on \
|
||||
|
|
@ -808,7 +1027,17 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
// ==========================================================================
|
||||
|
||||
gated!(
|
||||
linkage, Normal, template!(NameValueStr: "external|internal|..."),
|
||||
linkage, Normal, template!(NameValueStr: [
|
||||
"available_externally",
|
||||
"common",
|
||||
"extern_weak",
|
||||
"external",
|
||||
"internal",
|
||||
"linkonce",
|
||||
"linkonce_odr",
|
||||
"weak",
|
||||
"weak_odr",
|
||||
], "https://doc.rust-lang.org/reference/linkage.html"),
|
||||
ErrorPreceding, EncodeCrossCrate::No,
|
||||
"the `linkage` attribute is experimental and not portable across platforms",
|
||||
),
|
||||
|
|
@ -823,7 +1052,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
|
||||
rustc_attr!(
|
||||
rustc_builtin_macro, Normal,
|
||||
template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing,
|
||||
template!(Word, List: &["name", "name, /*opt*/ attributes(name1, name2, ...)"]), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
),
|
||||
rustc_attr!(
|
||||
|
|
@ -832,12 +1061,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
rustc_attr!(
|
||||
rustc_macro_transparency, Normal,
|
||||
template!(NameValueStr: "transparent|semiopaque|opaque"), ErrorFollowing,
|
||||
template!(NameValueStr: ["transparent", "semiopaque", "opaque"]), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes, "used internally for testing macro hygiene",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_autodiff, Normal,
|
||||
template!(Word, List: r#""...""#), DuplicatesOk,
|
||||
template!(Word, List: &[r#""...""#]), DuplicatesOk,
|
||||
EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Traces that are left when `cfg` and `cfg_attr` attributes are expanded.
|
||||
|
|
@ -860,7 +1089,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_attr!(
|
||||
rustc_on_unimplemented, Normal,
|
||||
template!(
|
||||
List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
|
||||
List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#],
|
||||
NameValueStr: "message"
|
||||
),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
|
|
@ -868,7 +1097,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
rustc_attr!(
|
||||
rustc_confusables, Normal,
|
||||
template!(List: r#""name1", "name2", ..."#),
|
||||
template!(List: &[r#""name1", "name2", ..."#]),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Enumerates "identity-like" conversion methods to suggest on type mismatch.
|
||||
|
|
@ -909,7 +1138,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
// Used by the `rustc::bad_opt_access` lint on fields
|
||||
// types (as well as any others in future).
|
||||
rustc_attr!(
|
||||
rustc_lint_opt_deny_field_access, Normal, template!(List: "message"),
|
||||
rustc_lint_opt_deny_field_access, Normal, template!(List: &["message"]),
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
|
||||
|
|
@ -921,7 +1150,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_promotable, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, ),
|
||||
rustc_attr!(
|
||||
rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
|
||||
rustc_legacy_const_generics, Normal, template!(List: &["N"]), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Do not const-check this function's body. It will always get replaced during CTFE via `hook_special_const_fn`.
|
||||
|
|
@ -946,7 +1175,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
gated!(
|
||||
rustc_allow_const_fn_unstable, Normal,
|
||||
template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No,
|
||||
template!(Word, List: &["feat1, feat2, ..."]), DuplicatesOk, EncodeCrossCrate::No,
|
||||
"rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
|
||||
),
|
||||
|
||||
|
|
@ -955,13 +1184,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
// ==========================================================================
|
||||
|
||||
rustc_attr!(
|
||||
rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
|
||||
rustc_layout_scalar_valid_range_start, Normal, template!(List: &["value"]), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
|
||||
niche optimizations in the standard library",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
|
||||
rustc_layout_scalar_valid_range_end, Normal, template!(List: &["value"]), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
|
||||
niche optimizations in the standard library",
|
||||
|
|
@ -1097,14 +1326,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
"the `#[rustc_main]` attribute is used internally to specify test entry point function",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), ErrorFollowing,
|
||||
rustc_skip_during_method_dispatch, Normal, template!(List: &["array, boxed_slice"]), ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
|
||||
from method dispatch when the receiver is of the following type, for compatibility in \
|
||||
editions < 2021 (array) or editions < 2024 (boxed_slice)."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
|
||||
rustc_must_implement_one_of, Normal, template!(List: &["function1, function2, ..."]),
|
||||
ErrorFollowing, EncodeCrossCrate::No,
|
||||
"the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
|
||||
definition of a trait. Its syntax and semantics are highly experimental and will be \
|
||||
|
|
@ -1166,11 +1395,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."),
|
||||
TEST, rustc_layout, Normal, template!(List: &["field1, field2, ..."]),
|
||||
WarnFollowing, EncodeCrossCrate::Yes
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."),
|
||||
TEST, rustc_abi, Normal, template!(List: &["field1, field2, ..."]),
|
||||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
rustc_attr!(
|
||||
|
|
@ -1191,29 +1420,29 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
EncodeCrossCrate::Yes
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"), DuplicatesOk,
|
||||
TEST, rustc_if_this_changed, Normal, template!(Word, List: &["DepNode"]), DuplicatesOk,
|
||||
EncodeCrossCrate::No
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode"), DuplicatesOk,
|
||||
TEST, rustc_then_this_would_need, Normal, template!(List: &["DepNode"]), DuplicatesOk,
|
||||
EncodeCrossCrate::No
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_clean, Normal,
|
||||
template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
|
||||
template!(List: &[r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#]),
|
||||
DuplicatesOk, EncodeCrossCrate::No
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_partition_reused, Normal,
|
||||
template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, EncodeCrossCrate::No
|
||||
template!(List: &[r#"cfg = "...", module = "...""#]), DuplicatesOk, EncodeCrossCrate::No
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_partition_codegened, Normal,
|
||||
template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, EncodeCrossCrate::No
|
||||
template!(List: &[r#"cfg = "...", module = "...""#]), DuplicatesOk, EncodeCrossCrate::No
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_expected_cgu_reuse, Normal,
|
||||
template!(List: r#"cfg = "...", module = "...", kind = "...""#), DuplicatesOk,
|
||||
template!(List: &[r#"cfg = "...", module = "...", kind = "...""#]), DuplicatesOk,
|
||||
EncodeCrossCrate::No
|
||||
),
|
||||
rustc_attr!(
|
||||
|
|
@ -1225,11 +1454,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
WarnFollowing, EncodeCrossCrate::No
|
||||
),
|
||||
rustc_attr!(
|
||||
TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."),
|
||||
TEST, rustc_mir, Normal, template!(List: &["arg1, arg2, ..."]),
|
||||
DuplicatesOk, EncodeCrossCrate::Yes
|
||||
),
|
||||
gated!(
|
||||
custom_mir, Normal, template!(List: r#"dialect = "...", phase = "...""#),
|
||||
custom_mir, Normal, template!(List: &[r#"dialect = "...", phase = "...""#]),
|
||||
ErrorFollowing, EncodeCrossCrate::No,
|
||||
"the `#[custom_mir]` attribute is just used for the Rust test suite",
|
||||
),
|
||||
|
|
|
|||
|
|
@ -249,6 +249,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_allow_incoherent_impl]`.
|
||||
AllowIncoherentImpl(Span),
|
||||
|
||||
/// Represents `#[allow_internal_unsafe]`.
|
||||
AllowInternalUnsafe(Span),
|
||||
|
||||
/// Represents `#[allow_internal_unstable]`.
|
||||
AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span),
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ impl AttributeKind {
|
|||
Align { .. } => No,
|
||||
AllowConstFnUnstable(..) => No,
|
||||
AllowIncoherentImpl(..) => No,
|
||||
AllowInternalUnsafe(..) => Yes,
|
||||
AllowInternalUnstable(..) => Yes,
|
||||
AsPtr(..) => Yes,
|
||||
AutomaticallyDerived(..) => Yes,
|
||||
|
|
|
|||
|
|
@ -1310,6 +1310,7 @@ impl AttributeExt for Attribute {
|
|||
Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span,
|
||||
Attribute::Parsed(AttributeKind::ShouldPanic { span, .. }) => *span,
|
||||
Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span,
|
||||
Attribute::Parsed(AttributeKind::AllowInternalUnsafe(span)) => *span,
|
||||
a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"),
|
||||
}
|
||||
}
|
||||
|
|
@ -4194,7 +4195,7 @@ impl<'hir> Item<'hir> {
|
|||
expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
|
||||
ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds);
|
||||
|
||||
expect_impl, &'hir Impl<'hir>, ItemKind::Impl(imp), imp;
|
||||
expect_impl, &Impl<'hir>, ItemKind::Impl(imp), imp;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4372,7 +4373,7 @@ pub enum ItemKind<'hir> {
|
|||
TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
|
||||
|
||||
/// An implementation, e.g., `impl<A> Trait for Foo { .. }`.
|
||||
Impl(&'hir Impl<'hir>),
|
||||
Impl(Impl<'hir>),
|
||||
}
|
||||
|
||||
/// Represents an impl block declaration.
|
||||
|
|
@ -4381,6 +4382,14 @@ pub enum ItemKind<'hir> {
|
|||
/// Refer to [`ImplItem`] for an associated item within an impl block.
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct Impl<'hir> {
|
||||
pub generics: &'hir Generics<'hir>,
|
||||
pub of_trait: Option<&'hir TraitImplHeader<'hir>>,
|
||||
pub self_ty: &'hir Ty<'hir>,
|
||||
pub items: &'hir [ImplItemId],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct TraitImplHeader<'hir> {
|
||||
pub constness: Constness,
|
||||
pub safety: Safety,
|
||||
pub polarity: ImplPolarity,
|
||||
|
|
@ -4388,13 +4397,7 @@ pub struct Impl<'hir> {
|
|||
// We do not put a `Span` in `Defaultness` because it breaks foreign crate metadata
|
||||
// decoding as `Span`s cannot be decoded when a `Session` is not available.
|
||||
pub defaultness_span: Option<Span>,
|
||||
pub generics: &'hir Generics<'hir>,
|
||||
|
||||
/// The trait being implemented, if any.
|
||||
pub of_trait: Option<TraitRef<'hir>>,
|
||||
|
||||
pub self_ty: &'hir Ty<'hir>,
|
||||
pub items: &'hir [ImplItemId],
|
||||
pub trait_ref: TraitRef<'hir>,
|
||||
}
|
||||
|
||||
impl ItemKind<'_> {
|
||||
|
|
@ -4756,8 +4759,8 @@ impl<'hir> Node<'hir> {
|
|||
/// Get a `hir::Impl` if the node is an impl block for the given `trait_def_id`.
|
||||
pub fn impl_block_of_trait(self, trait_def_id: DefId) -> Option<&'hir Impl<'hir>> {
|
||||
if let Node::Item(Item { kind: ItemKind::Impl(impl_block), .. }) = self
|
||||
&& let Some(trait_ref) = impl_block.of_trait
|
||||
&& let Some(trait_id) = trait_ref.trait_def_id()
|
||||
&& let Some(of_trait) = impl_block.of_trait
|
||||
&& let Some(trait_id) = of_trait.trait_ref.trait_def_id()
|
||||
&& trait_id == trait_def_id
|
||||
{
|
||||
Some(impl_block)
|
||||
|
|
@ -4952,7 +4955,7 @@ mod size_asserts {
|
|||
static_assert_size!(GenericArg<'_>, 16);
|
||||
static_assert_size!(GenericBound<'_>, 64);
|
||||
static_assert_size!(Generics<'_>, 56);
|
||||
static_assert_size!(Impl<'_>, 80);
|
||||
static_assert_size!(Impl<'_>, 40);
|
||||
static_assert_size!(ImplItem<'_>, 96);
|
||||
static_assert_size!(ImplItemKind<'_>, 40);
|
||||
static_assert_size!(Item<'_>, 88);
|
||||
|
|
@ -4967,6 +4970,7 @@ mod size_asserts {
|
|||
static_assert_size!(Res, 12);
|
||||
static_assert_size!(Stmt<'_>, 32);
|
||||
static_assert_size!(StmtKind<'_>, 16);
|
||||
static_assert_size!(TraitImplHeader<'_>, 48);
|
||||
static_assert_size!(TraitItem<'_>, 88);
|
||||
static_assert_size!(TraitItemKind<'_>, 48);
|
||||
static_assert_size!(Ty<'_>, 48);
|
||||
|
|
|
|||
|
|
@ -590,21 +590,21 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
|
|||
try_visit!(visitor.visit_generics(generics));
|
||||
try_visit!(visitor.visit_enum_def(enum_definition));
|
||||
}
|
||||
ItemKind::Impl(Impl {
|
||||
constness: _,
|
||||
safety: _,
|
||||
defaultness: _,
|
||||
polarity: _,
|
||||
defaultness_span: _,
|
||||
generics,
|
||||
of_trait,
|
||||
self_ty,
|
||||
items,
|
||||
}) => {
|
||||
ItemKind::Impl(Impl { generics, of_trait, self_ty, items }) => {
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
visit_opt!(visitor, visit_trait_ref, of_trait);
|
||||
if let Some(TraitImplHeader {
|
||||
constness: _,
|
||||
safety: _,
|
||||
polarity: _,
|
||||
defaultness: _,
|
||||
defaultness_span: _,
|
||||
trait_ref,
|
||||
}) = of_trait
|
||||
{
|
||||
try_visit!(visitor.visit_trait_ref(trait_ref));
|
||||
}
|
||||
try_visit!(visitor.visit_ty_unambig(self_ty));
|
||||
walk_list!(visitor, visit_impl_item_ref, *items);
|
||||
walk_list!(visitor, visit_impl_item_ref, items);
|
||||
}
|
||||
ItemKind::Struct(ident, ref generics, ref struct_definition)
|
||||
| ItemKind::Union(ident, ref generics, ref struct_definition) => {
|
||||
|
|
|
|||
|
|
@ -244,48 +244,48 @@ pub(super) fn check_item<'tcx>(
|
|||
//
|
||||
// won't be allowed unless there's an *explicit* implementation of `Send`
|
||||
// for `T`
|
||||
hir::ItemKind::Impl(impl_) => {
|
||||
let header = tcx.impl_trait_header(def_id);
|
||||
let is_auto = header
|
||||
.is_some_and(|header| tcx.trait_is_auto(header.trait_ref.skip_binder().def_id));
|
||||
|
||||
hir::ItemKind::Impl(ref impl_) => {
|
||||
crate::impl_wf_check::check_impl_wf(tcx, def_id)?;
|
||||
let mut res = Ok(());
|
||||
if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
|
||||
let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
|
||||
res = Err(tcx
|
||||
.dcx()
|
||||
.struct_span_err(sp, "impls of auto traits cannot be default")
|
||||
.with_span_labels(impl_.defaultness_span, "default because of this")
|
||||
.with_span_label(sp, "auto trait")
|
||||
.emit());
|
||||
}
|
||||
// We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span.
|
||||
match header.map(|h| h.polarity) {
|
||||
// `None` means this is an inherent impl
|
||||
Some(ty::ImplPolarity::Positive) | None => {
|
||||
res = res.and(check_impl(tcx, item, impl_.self_ty, &impl_.of_trait));
|
||||
}
|
||||
Some(ty::ImplPolarity::Negative) => {
|
||||
let ast::ImplPolarity::Negative(span) = impl_.polarity else {
|
||||
bug!("impl_polarity query disagrees with impl's polarity in HIR");
|
||||
};
|
||||
// FIXME(#27579): what amount of WF checking do we need for neg impls?
|
||||
if let hir::Defaultness::Default { .. } = impl_.defaultness {
|
||||
let mut spans = vec![span];
|
||||
spans.extend(impl_.defaultness_span);
|
||||
res = Err(struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
spans,
|
||||
E0750,
|
||||
"negative impls cannot be default impls"
|
||||
)
|
||||
if let Some(of_trait) = impl_.of_trait {
|
||||
let header = tcx.impl_trait_header(def_id).unwrap();
|
||||
let is_auto = tcx.trait_is_auto(header.trait_ref.skip_binder().def_id);
|
||||
if let (hir::Defaultness::Default { .. }, true) = (of_trait.defaultness, is_auto) {
|
||||
let sp = of_trait.trait_ref.path.span;
|
||||
res = Err(tcx
|
||||
.dcx()
|
||||
.struct_span_err(sp, "impls of auto traits cannot be default")
|
||||
.with_span_labels(of_trait.defaultness_span, "default because of this")
|
||||
.with_span_label(sp, "auto trait")
|
||||
.emit());
|
||||
}
|
||||
match header.polarity {
|
||||
ty::ImplPolarity::Positive => {
|
||||
res = res.and(check_impl(tcx, item, impl_));
|
||||
}
|
||||
ty::ImplPolarity::Negative => {
|
||||
let ast::ImplPolarity::Negative(span) = of_trait.polarity else {
|
||||
bug!("impl_polarity query disagrees with impl's polarity in HIR");
|
||||
};
|
||||
// FIXME(#27579): what amount of WF checking do we need for neg impls?
|
||||
if let hir::Defaultness::Default { .. } = of_trait.defaultness {
|
||||
let mut spans = vec![span];
|
||||
spans.extend(of_trait.defaultness_span);
|
||||
res = Err(struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
spans,
|
||||
E0750,
|
||||
"negative impls cannot be default impls"
|
||||
)
|
||||
.emit());
|
||||
}
|
||||
}
|
||||
ty::ImplPolarity::Reservation => {
|
||||
// FIXME: what amount of WF checking do we need for reservation impls?
|
||||
}
|
||||
}
|
||||
Some(ty::ImplPolarity::Reservation) => {
|
||||
// FIXME: what amount of WF checking do we need for reservation impls?
|
||||
}
|
||||
} else {
|
||||
res = res.and(check_impl(tcx, item, impl_));
|
||||
}
|
||||
res
|
||||
}
|
||||
|
|
@ -1258,16 +1258,15 @@ pub(crate) fn check_const_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<()
|
|||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(tcx, hir_self_ty, hir_trait_ref))]
|
||||
#[instrument(level = "debug", skip(tcx, impl_))]
|
||||
fn check_impl<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item: &'tcx hir::Item<'tcx>,
|
||||
hir_self_ty: &hir::Ty<'_>,
|
||||
hir_trait_ref: &Option<hir::TraitRef<'_>>,
|
||||
impl_: &hir::Impl<'_>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| {
|
||||
match hir_trait_ref {
|
||||
Some(hir_trait_ref) => {
|
||||
match impl_.of_trait {
|
||||
Some(of_trait) => {
|
||||
// `#[rustc_reservation_impl]` impls are not real impls and
|
||||
// therefore don't need to be WF (the trait's `Self: Trait` predicate
|
||||
// won't hold).
|
||||
|
|
@ -1275,7 +1274,7 @@ fn check_impl<'tcx>(
|
|||
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
|
||||
// other `Foo` impls are incoherent.
|
||||
tcx.ensure_ok().coherent_trait(trait_ref.def_id)?;
|
||||
let trait_span = hir_trait_ref.path.span;
|
||||
let trait_span = of_trait.trait_ref.path.span;
|
||||
let trait_ref = wfcx.deeply_normalize(
|
||||
trait_span,
|
||||
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
|
||||
|
|
@ -1299,12 +1298,12 @@ fn check_impl<'tcx>(
|
|||
if let Some(pred) = obligation.predicate.as_trait_clause()
|
||||
&& pred.skip_binder().self_ty() == trait_ref.self_ty()
|
||||
{
|
||||
obligation.cause.span = hir_self_ty.span;
|
||||
obligation.cause.span = impl_.self_ty.span;
|
||||
}
|
||||
if let Some(pred) = obligation.predicate.as_projection_clause()
|
||||
&& pred.skip_binder().self_ty() == trait_ref.self_ty()
|
||||
{
|
||||
obligation.cause.span = hir_self_ty.span;
|
||||
obligation.cause.span = impl_.self_ty.span;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1321,7 +1320,7 @@ fn check_impl<'tcx>(
|
|||
wfcx.register_obligation(Obligation::new(
|
||||
tcx,
|
||||
ObligationCause::new(
|
||||
hir_self_ty.span,
|
||||
impl_.self_ty.span,
|
||||
wfcx.body_def_id,
|
||||
ObligationCauseCode::WellFormed(None),
|
||||
),
|
||||
|
|
@ -1342,7 +1341,7 @@ fn check_impl<'tcx>(
|
|||
self_ty,
|
||||
);
|
||||
wfcx.register_wf_obligation(
|
||||
hir_self_ty.span,
|
||||
impl_.self_ty.span,
|
||||
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
|
||||
self_ty.into(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -531,8 +531,10 @@ pub(crate) fn coerce_unsized_info<'tcx>(
|
|||
}));
|
||||
} else if diff_fields.len() > 1 {
|
||||
let item = tcx.hir_expect_item(impl_did);
|
||||
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
|
||||
t.path.span
|
||||
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) =
|
||||
&item.kind
|
||||
{
|
||||
of_trait.trait_ref.path.span
|
||||
} else {
|
||||
tcx.def_span(impl_did)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -384,7 +384,7 @@ fn emit_orphan_check_error<'tcx>(
|
|||
traits::OrphanCheckErr::NonLocalInputType(tys) => {
|
||||
let item = tcx.hir_expect_item(impl_def_id);
|
||||
let impl_ = item.expect_impl();
|
||||
let hir_trait_ref = impl_.of_trait.as_ref().unwrap();
|
||||
let of_trait = impl_.of_trait.unwrap();
|
||||
|
||||
let span = tcx.def_span(impl_def_id);
|
||||
let mut diag = tcx.dcx().create_err(match trait_ref.self_ty().kind() {
|
||||
|
|
@ -401,7 +401,7 @@ fn emit_orphan_check_error<'tcx>(
|
|||
impl_.self_ty.span
|
||||
} else {
|
||||
// Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
|
||||
hir_trait_ref.path.span
|
||||
of_trait.trait_ref.path.span
|
||||
};
|
||||
|
||||
ty = tcx.erase_regions(ty);
|
||||
|
|
|
|||
|
|
@ -1295,18 +1295,22 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
|
|||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
let item = tcx.hir_expect_item(def_id);
|
||||
let impl_ = item.expect_impl();
|
||||
impl_.of_trait.as_ref().map(|ast_trait_ref| {
|
||||
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
|
||||
if is_rustc_reservation && impl_.of_trait.is_none() {
|
||||
tcx.dcx().span_err(item.span, "reservation impls can't be inherent");
|
||||
}
|
||||
impl_.of_trait.map(|of_trait| {
|
||||
let selfty = tcx.type_of(def_id).instantiate_identity();
|
||||
|
||||
check_impl_constness(tcx, impl_.constness, ast_trait_ref);
|
||||
check_impl_constness(tcx, of_trait.constness, &of_trait.trait_ref);
|
||||
|
||||
let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty);
|
||||
let trait_ref = icx.lowerer().lower_impl_trait_ref(&of_trait.trait_ref, selfty);
|
||||
|
||||
ty::ImplTraitHeader {
|
||||
trait_ref: ty::EarlyBinder::bind(trait_ref),
|
||||
safety: impl_.safety,
|
||||
polarity: polarity_of_impl(tcx, def_id, impl_, item.span),
|
||||
constness: impl_.constness,
|
||||
safety: of_trait.safety,
|
||||
polarity: polarity_of_impl(tcx, of_trait, is_rustc_reservation),
|
||||
constness: of_trait.constness,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -1350,26 +1354,18 @@ fn check_impl_constness(
|
|||
|
||||
fn polarity_of_impl(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: LocalDefId,
|
||||
impl_: &hir::Impl<'_>,
|
||||
span: Span,
|
||||
of_trait: &hir::TraitImplHeader<'_>,
|
||||
is_rustc_reservation: bool,
|
||||
) -> ty::ImplPolarity {
|
||||
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
|
||||
match &impl_ {
|
||||
hir::Impl { polarity: hir::ImplPolarity::Negative(span), of_trait, .. } => {
|
||||
match of_trait.polarity {
|
||||
hir::ImplPolarity::Negative(span) => {
|
||||
if is_rustc_reservation {
|
||||
let span = span.to(of_trait.as_ref().map_or(*span, |t| t.path.span));
|
||||
let span = span.to(of_trait.trait_ref.path.span);
|
||||
tcx.dcx().span_err(span, "reservation impls can't be negative");
|
||||
}
|
||||
ty::ImplPolarity::Negative
|
||||
}
|
||||
hir::Impl { polarity: hir::ImplPolarity::Positive, of_trait: None, .. } => {
|
||||
if is_rustc_reservation {
|
||||
tcx.dcx().span_err(span, "reservation impls can't be inherent");
|
||||
}
|
||||
ty::ImplPolarity::Positive
|
||||
}
|
||||
hir::Impl { polarity: hir::ImplPolarity::Positive, of_trait: Some(_), .. } => {
|
||||
hir::ImplPolarity::Positive => {
|
||||
if is_rustc_reservation {
|
||||
ty::ImplPolarity::Reservation
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -158,7 +158,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
if let Node::Item(item) = node {
|
||||
match item.kind {
|
||||
ItemKind::Impl(impl_) => {
|
||||
if impl_.defaultness.is_default() {
|
||||
if let Some(of_trait) = impl_.of_trait
|
||||
&& of_trait.defaultness.is_default()
|
||||
{
|
||||
is_default_impl_trait = tcx
|
||||
.impl_trait_ref(def_id)
|
||||
.map(|t| ty::Binder::dummy(t.instantiate_identity()));
|
||||
|
|
|
|||
|
|
@ -604,13 +604,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
match &item.kind {
|
||||
hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
|
||||
if let Some(of_trait) = of_trait {
|
||||
self.record_late_bound_vars(of_trait.hir_ref_id, Vec::default());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
if let hir::ItemKind::Impl(impl_) = item.kind
|
||||
&& let Some(of_trait) = impl_.of_trait
|
||||
{
|
||||
self.record_late_bound_vars(of_trait.trait_ref.hir_ref_id, Vec::default());
|
||||
}
|
||||
match item.kind {
|
||||
hir::ItemKind::Fn { generics, .. } => {
|
||||
|
|
@ -636,7 +633,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
| hir::ItemKind::Union(_, generics, _)
|
||||
| hir::ItemKind::Trait(_, _, _, _, generics, ..)
|
||||
| hir::ItemKind::TraitAlias(_, generics, ..)
|
||||
| hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
|
||||
| hir::ItemKind::Impl(hir::Impl { generics, .. }) => {
|
||||
// These kinds of items have only early-bound lifetime parameters.
|
||||
self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item));
|
||||
}
|
||||
|
|
@ -2106,7 +2103,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
// If we have a self type alias (in an impl), try to resolve an
|
||||
// associated item from one of the supertraits of the impl's trait.
|
||||
Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. } => {
|
||||
let hir::ItemKind::Impl(hir::Impl { of_trait: Some(trait_ref), .. }) = self
|
||||
let hir::ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) = self
|
||||
.tcx
|
||||
.hir_node_by_def_id(impl_def_id.expect_local())
|
||||
.expect_item()
|
||||
|
|
@ -2114,7 +2111,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
else {
|
||||
return;
|
||||
};
|
||||
let Some(trait_def_id) = trait_ref.trait_def_id() else {
|
||||
let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else {
|
||||
return;
|
||||
};
|
||||
let Some((bound_vars, assoc_item)) = BoundVarContext::supertrait_hrtb_vars(
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
|
|||
.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
|
||||
Ty::new_error(tcx, guar)
|
||||
}
|
||||
_ => icx.lower_ty(*self_ty),
|
||||
_ => icx.lower_ty(self_ty),
|
||||
},
|
||||
ItemKind::Fn { .. } => {
|
||||
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
|
||||
|
|
|
|||
|
|
@ -147,7 +147,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
let hir::Node::Item(hir::Item {
|
||||
kind:
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }),
|
||||
of_trait:
|
||||
Some(hir::TraitImplHeader {
|
||||
trait_ref: hir::TraitRef { hir_ref_id: id_in_of_trait, .. },
|
||||
..
|
||||
}),
|
||||
..
|
||||
}),
|
||||
..
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}) = tcx.hir_node_by_def_id(parent_id)
|
||||
&& self_ty.hir_id == impl_self_ty.hir_id
|
||||
{
|
||||
let Some(of_trait_ref) = of_trait else {
|
||||
let Some(of_trait) = of_trait else {
|
||||
diag.span_suggestion_verbose(
|
||||
impl_self_ty.span.shrink_to_hi(),
|
||||
"you might have intended to implement this trait for a given type",
|
||||
|
|
@ -209,10 +209,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
);
|
||||
return;
|
||||
};
|
||||
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
|
||||
if !of_trait.trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
|
||||
return;
|
||||
}
|
||||
let of_trait_span = of_trait_ref.path.span;
|
||||
let of_trait_span = of_trait.trait_ref.path.span;
|
||||
// make sure that we are not calling unwrap to abort during the compilation
|
||||
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -2732,7 +2732,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
};
|
||||
let i = tcx.parent_hir_node(fn_hir_id).expect_item().expect_impl();
|
||||
|
||||
let trait_ref = self.lower_impl_trait_ref(i.of_trait.as_ref()?, self.lower_ty(i.self_ty));
|
||||
let trait_ref = self.lower_impl_trait_ref(&i.of_trait?.trait_ref, self.lower_ty(i.self_ty));
|
||||
|
||||
let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind(
|
||||
tcx,
|
||||
|
|
|
|||
|
|
@ -154,8 +154,9 @@ pub(super) fn diagnostic_hir_wf_check<'tcx>(
|
|||
hir::ItemKind::TyAlias(_, _, ty)
|
||||
| hir::ItemKind::Static(_, _, ty, _)
|
||||
| hir::ItemKind::Const(_, _, ty, _) => vec![ty],
|
||||
hir::ItemKind::Impl(impl_) => match &impl_.of_trait {
|
||||
Some(t) => t
|
||||
hir::ItemKind::Impl(impl_) => match impl_.of_trait {
|
||||
Some(of_trait) => of_trait
|
||||
.trait_ref
|
||||
.path
|
||||
.segments
|
||||
.last()
|
||||
|
|
|
|||
|
|
@ -690,39 +690,44 @@ impl<'a> State<'a> {
|
|||
let (cb, ib) = self.head("union");
|
||||
self.print_struct(ident.name, generics, struct_def, item.span, true, cb, ib);
|
||||
}
|
||||
hir::ItemKind::Impl(&hir::Impl {
|
||||
constness,
|
||||
safety,
|
||||
polarity,
|
||||
defaultness,
|
||||
defaultness_span: _,
|
||||
generics,
|
||||
ref of_trait,
|
||||
self_ty,
|
||||
items,
|
||||
}) => {
|
||||
hir::ItemKind::Impl(hir::Impl { generics, of_trait, self_ty, items }) => {
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_defaultness(defaultness);
|
||||
self.print_safety(safety);
|
||||
self.word_nbsp("impl");
|
||||
|
||||
if let hir::Constness::Const = constness {
|
||||
self.word_nbsp("const");
|
||||
}
|
||||
let impl_generics = |this: &mut Self| {
|
||||
this.word_nbsp("impl");
|
||||
if !generics.params.is_empty() {
|
||||
this.print_generic_params(generics.params);
|
||||
this.space();
|
||||
}
|
||||
};
|
||||
|
||||
if !generics.params.is_empty() {
|
||||
self.print_generic_params(generics.params);
|
||||
self.space();
|
||||
}
|
||||
match of_trait {
|
||||
None => impl_generics(self),
|
||||
Some(&hir::TraitImplHeader {
|
||||
constness,
|
||||
safety,
|
||||
polarity,
|
||||
defaultness,
|
||||
defaultness_span: _,
|
||||
ref trait_ref,
|
||||
}) => {
|
||||
self.print_defaultness(defaultness);
|
||||
self.print_safety(safety);
|
||||
|
||||
if let hir::ImplPolarity::Negative(_) = polarity {
|
||||
self.word("!");
|
||||
}
|
||||
impl_generics(self);
|
||||
|
||||
if let Some(t) = of_trait {
|
||||
self.print_trait_ref(t);
|
||||
self.space();
|
||||
self.word_space("for");
|
||||
if let hir::Constness::Const = constness {
|
||||
self.word_nbsp("const");
|
||||
}
|
||||
|
||||
if let hir::ImplPolarity::Negative(_) = polarity {
|
||||
self.word("!");
|
||||
}
|
||||
|
||||
self.print_trait_ref(trait_ref);
|
||||
self.space();
|
||||
self.word_space("for");
|
||||
}
|
||||
}
|
||||
|
||||
self.print_type(self_ty);
|
||||
|
|
|
|||
|
|
@ -936,7 +936,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Node::ImplItem(item) => {
|
||||
// If it doesn't impl a trait, we can add a return type
|
||||
let Node::Item(&hir::Item {
|
||||
kind: hir::ItemKind::Impl(&hir::Impl { of_trait, .. }),
|
||||
kind: hir::ItemKind::Impl(hir::Impl { of_trait, .. }),
|
||||
..
|
||||
}) = self.tcx.parent_hir_node(item.hir_id())
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -1103,7 +1103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self_ty.span.ctxt().outer_expn_data().kind,
|
||||
ExpnKind::Macro(MacroKind::Derive, _)
|
||||
) || matches!(
|
||||
of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
|
||||
of_trait.map(|t| t.trait_ref.path.span.ctxt().outer_expn_data().kind),
|
||||
Some(ExpnKind::Macro(MacroKind::Derive, _))
|
||||
) =>
|
||||
{
|
||||
|
|
@ -1165,13 +1165,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
entry.0.insert(cause_span);
|
||||
entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
|
||||
} else {
|
||||
if let Some(trait_ref) = of_trait {
|
||||
entry.0.insert(trait_ref.path.span);
|
||||
if let Some(of_trait) = of_trait {
|
||||
entry.0.insert(of_trait.trait_ref.path.span);
|
||||
}
|
||||
entry.0.insert(self_ty.span);
|
||||
};
|
||||
if let Some(trait_ref) = of_trait {
|
||||
entry.1.insert((trait_ref.path.span, ""));
|
||||
if let Some(of_trait) = of_trait {
|
||||
entry.1.insert((of_trait.trait_ref.path.span, ""));
|
||||
}
|
||||
entry.1.insert((self_ty.span, ""));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -349,6 +349,7 @@ lint_ill_formed_attribute_input = {$num_suggestions ->
|
|||
[1] attribute must be of the form {$suggestions}
|
||||
*[other] valid forms for the attribute are {$suggestions}
|
||||
}
|
||||
.note = for more information, visit <{$docs}>
|
||||
|
||||
lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than possibly intended in edition 2024
|
||||
.note = specifically, {$num_captured ->
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
|||
use rustc_ast::visit::{FnCtxt, FnKind};
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_ast_pretty::pprust::expr_to_string;
|
||||
use rustc_attr_parsing::AttributeParser;
|
||||
use rustc_errors::{Applicability, LintDiagnostic};
|
||||
use rustc_feature::GateIssue;
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -248,12 +249,6 @@ impl UnsafeCode {
|
|||
}
|
||||
|
||||
impl EarlyLintPass for UnsafeCode {
|
||||
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
|
||||
if attr.has_name(sym::allow_internal_unsafe) {
|
||||
self.report_unsafe(cx, attr.span, BuiltinUnsafe::AllowInternalUnsafe);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
|
||||
if let ast::ExprKind::Block(ref blk, _) = e.kind {
|
||||
|
|
@ -270,7 +265,10 @@ impl EarlyLintPass for UnsafeCode {
|
|||
self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait);
|
||||
}
|
||||
|
||||
ast::ItemKind::Impl(box ast::Impl { safety: ast::Safety::Unsafe(_), .. }) => {
|
||||
ast::ItemKind::Impl(ast::Impl {
|
||||
of_trait: Some(box ast::TraitImplHeader { safety: ast::Safety::Unsafe(_), .. }),
|
||||
..
|
||||
}) => {
|
||||
self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl);
|
||||
}
|
||||
|
||||
|
|
@ -312,6 +310,19 @@ impl EarlyLintPass for UnsafeCode {
|
|||
}
|
||||
}
|
||||
|
||||
ast::ItemKind::MacroDef(..) => {
|
||||
if let Some(attr) = AttributeParser::parse_limited(
|
||||
cx.builder.sess(),
|
||||
&it.attrs,
|
||||
sym::allow_internal_unsafe,
|
||||
it.span,
|
||||
DUMMY_NODE_ID,
|
||||
Some(cx.builder.features()),
|
||||
) {
|
||||
self.report_unsafe(cx, attr.span(), BuiltinUnsafe::AllowInternalUnsafe);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
|
|||
// `Deref` is being implemented for `t`
|
||||
if let hir::ItemKind::Impl(impl_) = item.kind
|
||||
// the trait is a `Deref` implementation
|
||||
&& let Some(trait_) = &impl_.of_trait
|
||||
&& let Some(did) = trait_.trait_def_id()
|
||||
&& let Some(of_trait) = &impl_.of_trait
|
||||
&& let Some(did) = of_trait.trait_ref.trait_def_id()
|
||||
&& tcx.is_lang_item(did, LangItem::Deref)
|
||||
// the self type is `dyn t_principal`
|
||||
&& let self_ty = tcx.type_of(item.owner_id).instantiate_identity()
|
||||
|
|
|
|||
|
|
@ -447,12 +447,14 @@ pub fn decorate_builtin_lint(
|
|||
BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => {
|
||||
lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
|
||||
}
|
||||
BuiltinLintDiag::IllFormedAttributeInput { suggestions } => {
|
||||
BuiltinLintDiag::IllFormedAttributeInput { suggestions, docs } => {
|
||||
lints::IllFormedAttributeInput {
|
||||
num_suggestions: suggestions.len(),
|
||||
suggestions: DiagArgValue::StrListSepByAnd(
|
||||
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
|
||||
),
|
||||
has_docs: docs.is_some(),
|
||||
docs: docs.unwrap_or(""),
|
||||
}
|
||||
.decorate_lint(diag)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -411,11 +411,11 @@ declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]);
|
|||
|
||||
impl EarlyLintPass for LintPassImpl {
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
||||
if let ast::ItemKind::Impl(box ast::Impl { of_trait: Some(lint_pass), .. }) = &item.kind
|
||||
&& let Some(last) = lint_pass.path.segments.last()
|
||||
if let ast::ItemKind::Impl(ast::Impl { of_trait: Some(of_trait), .. }) = &item.kind
|
||||
&& let Some(last) = of_trait.trait_ref.path.segments.last()
|
||||
&& last.ident.name == sym::LintPass
|
||||
{
|
||||
let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
|
||||
let expn_data = of_trait.trait_ref.path.span.ctxt().outer_expn_data();
|
||||
let call_site = expn_data.call_site;
|
||||
if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
|
||||
&& call_site.ctxt().outer_expn_data().kind
|
||||
|
|
@ -423,7 +423,7 @@ impl EarlyLintPass for LintPassImpl {
|
|||
{
|
||||
cx.emit_span_lint(
|
||||
LINT_PASS_IMPL_WITHOUT_MACRO,
|
||||
lint_pass.path.span,
|
||||
of_trait.trait_ref.path.span,
|
||||
LintPassByHand,
|
||||
);
|
||||
}
|
||||
|
|
@ -582,8 +582,8 @@ impl Diagnostics {
|
|||
for (_hir_id, parent) in cx.tcx.hir_parent_iter(current_id) {
|
||||
debug!(?parent);
|
||||
if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) = parent
|
||||
&& let hir::Impl { of_trait: Some(of_trait), .. } = impl_
|
||||
&& let Some(def_id) = of_trait.trait_def_id()
|
||||
&& let Some(of_trait) = impl_.of_trait
|
||||
&& let Some(def_id) = of_trait.trait_ref.trait_def_id()
|
||||
&& let Some(name) = cx.tcx.get_diagnostic_name(def_id)
|
||||
&& matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2685,6 +2685,9 @@ pub(crate) struct UnusedCrateDependency {
|
|||
pub(crate) struct IllFormedAttributeInput {
|
||||
pub num_suggestions: usize,
|
||||
pub suggestions: DiagArgValue,
|
||||
#[note]
|
||||
pub has_docs: bool,
|
||||
pub docs: &'static str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
|
|
|
|||
|
|
@ -129,8 +129,8 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
|||
// of the `impl` definition
|
||||
let mut collector = PathCollector { paths: Vec::new() };
|
||||
collector.visit_ty_unambig(&impl_.self_ty);
|
||||
if let Some(of_trait) = &impl_.of_trait {
|
||||
collector.visit_trait_ref(of_trait);
|
||||
if let Some(of_trait) = impl_.of_trait {
|
||||
collector.visit_trait_ref(&of_trait.trait_ref);
|
||||
}
|
||||
|
||||
// 1.5. Remove any path that doesn't resolve to a `DefId` or if it resolve to a
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ impl EarlyLintPass for NonCamelCaseTypes {
|
|||
|
||||
// N.B. This check is only for inherent associated types, so that we don't lint against
|
||||
// trait impls where we should have warned for the trait definition already.
|
||||
ast::ItemKind::Impl(box ast::Impl { of_trait: None, items, .. }) => {
|
||||
ast::ItemKind::Impl(ast::Impl { of_trait: None, items, .. }) => {
|
||||
for it in items {
|
||||
// FIXME: this doesn't respect `#[allow(..)]` on the item itself.
|
||||
if let ast::AssocItemKind::Type(alias) = &it.kind {
|
||||
|
|
|
|||
|
|
@ -793,6 +793,7 @@ pub enum BuiltinLintDiag {
|
|||
},
|
||||
IllFormedAttributeInput {
|
||||
suggestions: Vec<String>,
|
||||
docs: Option<&'static str>,
|
||||
},
|
||||
InnerAttributeUnstable {
|
||||
is_macro: bool,
|
||||
|
|
|
|||
|
|
@ -869,6 +869,11 @@ parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
|
|||
parse_trait_alias_cannot_be_const = trait aliases cannot be `const`
|
||||
parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
|
||||
|
||||
parse_trait_impl_modifier_in_inherent_impl = inherent impls cannot be {$modifier_name}
|
||||
.because = {$modifier_name} because of this
|
||||
.type = inherent impl for this type
|
||||
.note = only trait implementations may be annotated with `{$modifier}`
|
||||
|
||||
parse_transpose_dyn_or_impl = `for<...>` expected after `{$kw}`, not before
|
||||
.suggestion = move `{$kw}` before the `for<...>`
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,20 @@ pub(crate) struct BadQPathStage2 {
|
|||
pub wrap: WrapType,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_trait_impl_modifier_in_inherent_impl)]
|
||||
#[note]
|
||||
pub(crate) struct TraitImplModifierInInherentImpl {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub modifier: &'static str,
|
||||
pub modifier_name: &'static str,
|
||||
#[label(parse_because)]
|
||||
pub modifier_span: Span,
|
||||
#[label(parse_type)]
|
||||
pub self_ty: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
|
||||
pub(crate) struct WrapType {
|
||||
|
|
|
|||
|
|
@ -663,20 +663,44 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
let trait_ref = TraitRef { path, ref_id: ty_first.id };
|
||||
|
||||
(Some(trait_ref), ty_second)
|
||||
let of_trait = Some(Box::new(TraitImplHeader {
|
||||
defaultness,
|
||||
safety,
|
||||
constness,
|
||||
polarity,
|
||||
trait_ref,
|
||||
}));
|
||||
(of_trait, ty_second)
|
||||
}
|
||||
None => {
|
||||
let self_ty = ty_first;
|
||||
let error = |modifier, modifier_name, modifier_span| {
|
||||
self.dcx().create_err(errors::TraitImplModifierInInherentImpl {
|
||||
span: self_ty.span,
|
||||
modifier,
|
||||
modifier_name,
|
||||
modifier_span,
|
||||
self_ty: self_ty.span,
|
||||
})
|
||||
};
|
||||
|
||||
if let Safety::Unsafe(span) = safety {
|
||||
error("unsafe", "unsafe", span).with_code(E0197).emit();
|
||||
}
|
||||
if let ImplPolarity::Negative(span) = polarity {
|
||||
error("!", "negative", span).emit();
|
||||
}
|
||||
if let Defaultness::Default(def_span) = defaultness {
|
||||
error("default", "default", def_span).emit();
|
||||
}
|
||||
if let Const::Yes(span) = constness {
|
||||
error("const", "const", span).emit();
|
||||
}
|
||||
(None, self_ty)
|
||||
}
|
||||
None => (None, ty_first), // impl Type
|
||||
};
|
||||
Ok(ItemKind::Impl(Box::new(Impl {
|
||||
safety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
generics,
|
||||
of_trait,
|
||||
self_ty,
|
||||
items: impl_items,
|
||||
})))
|
||||
|
||||
Ok(ItemKind::Impl(Impl { generics, of_trait, self_ty, items: impl_items }))
|
||||
}
|
||||
|
||||
fn parse_item_delegation(&mut self) -> PResult<'a, ItemKind> {
|
||||
|
|
@ -1364,10 +1388,10 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
|
||||
match &mut item_kind {
|
||||
ItemKind::Impl(box Impl { of_trait: Some(trai), constness, .. }) => {
|
||||
*constness = Const::Yes(const_span);
|
||||
ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }) => {
|
||||
of_trait.constness = Const::Yes(const_span);
|
||||
|
||||
let before_trait = trai.path.span.shrink_to_lo();
|
||||
let before_trait = of_trait.trait_ref.path.span.shrink_to_lo();
|
||||
let const_up_to_impl = const_span.with_hi(impl_span.lo());
|
||||
err.with_multipart_suggestion(
|
||||
"you might have meant to write a const trait impl",
|
||||
|
|
|
|||
|
|
@ -298,35 +298,42 @@ fn emit_malformed_attribute(
|
|||
suggestions.push(format!("#{inner}[{name}]"));
|
||||
}
|
||||
if let Some(descr) = template.list {
|
||||
suggestions.push(format!("#{inner}[{name}({descr})]"));
|
||||
for descr in descr {
|
||||
suggestions.push(format!("#{inner}[{name}({descr})]"));
|
||||
}
|
||||
}
|
||||
suggestions.extend(template.one_of.iter().map(|&word| format!("#{inner}[{name}({word})]")));
|
||||
if let Some(descr) = template.name_value_str {
|
||||
suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
|
||||
for descr in descr {
|
||||
suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
|
||||
}
|
||||
}
|
||||
if should_warn(name) {
|
||||
psess.buffer_lint(
|
||||
ILL_FORMED_ATTRIBUTE_INPUT,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
BuiltinLintDiag::IllFormedAttributeInput { suggestions: suggestions.clone() },
|
||||
BuiltinLintDiag::IllFormedAttributeInput {
|
||||
suggestions: suggestions.clone(),
|
||||
docs: template.docs,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
suggestions.sort();
|
||||
psess
|
||||
.dcx()
|
||||
.struct_span_err(span, error_msg)
|
||||
.with_span_suggestions(
|
||||
span,
|
||||
if suggestions.len() == 1 {
|
||||
"must be of the form"
|
||||
} else {
|
||||
"the following are the possible correct uses"
|
||||
},
|
||||
suggestions,
|
||||
Applicability::HasPlaceholders,
|
||||
)
|
||||
.emit();
|
||||
let mut err = psess.dcx().struct_span_err(span, error_msg).with_span_suggestions(
|
||||
span,
|
||||
if suggestions.len() == 1 {
|
||||
"must be of the form"
|
||||
} else {
|
||||
"the following are the possible correct uses"
|
||||
},
|
||||
suggestions,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
if let Some(link) = template.docs {
|
||||
err.note(format!("for more information, visit <{link}>"));
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ passes_allow_incoherent_impl =
|
|||
`rustc_allow_incoherent_impl` attribute should be applied to impl items
|
||||
.label = the only currently supported targets are inherent methods
|
||||
|
||||
passes_allow_internal_unstable =
|
||||
passes_macro_only_attribute =
|
||||
attribute should be applied to a macro
|
||||
.label = not a macro
|
||||
|
||||
|
|
@ -669,8 +669,8 @@ passes_rustc_std_internal_symbol =
|
|||
.label = not a function or static
|
||||
|
||||
passes_rustc_unstable_feature_bound =
|
||||
attribute should be applied to `impl` or free function outside of any `impl` or trait
|
||||
.label = not an `impl` or free function
|
||||
attribute should be applied to `impl`, trait or free function
|
||||
.label = not an `impl`, trait or free function
|
||||
|
||||
passes_should_be_applied_to_fn =
|
||||
attribute should be applied to a function definition
|
||||
|
|
|
|||
|
|
@ -207,6 +207,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
Attribute::Parsed(AttributeKind::ConstContinue(attr_span)) => {
|
||||
self.check_const_continue(hir_id, *attr_span, target)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::AllowInternalUnsafe(attr_span)) => {
|
||||
self.check_allow_internal_unsafe(hir_id, *attr_span, span, target, attrs)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::AllowInternalUnstable(_, first_span)) => {
|
||||
self.check_allow_internal_unstable(hir_id, *first_span, span, target, attrs)
|
||||
}
|
||||
|
|
@ -413,7 +416,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
// internal
|
||||
| sym::prelude_import
|
||||
| sym::panic_handler
|
||||
| sym::allow_internal_unsafe
|
||||
| sym::lang
|
||||
| sym::needs_allocator
|
||||
| sym::default_lib_allocator
|
||||
|
|
@ -1155,8 +1157,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
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()
|
||||
.and_then(|trait_ref| trait_ref.path.segments.last())
|
||||
.and_then(|of_trait| of_trait.trait_ref.path.segments.last())
|
||||
.map(|last_segment| last_segment.args().args)
|
||||
{
|
||||
matches!(&ty.kind, hir::TyKind::Tup([_]))
|
||||
|
|
@ -1646,8 +1647,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
&& let parent_hir_id = self.tcx.parent_hir_id(hir_id)
|
||||
&& let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id)
|
||||
&& let hir::ItemKind::Impl(impl_) = item.kind
|
||||
&& let Some(trait_) = impl_.of_trait
|
||||
&& let Some(def_id) = trait_.trait_def_id()
|
||||
&& let Some(of_trait) = impl_.of_trait
|
||||
&& let Some(def_id) = of_trait.trait_ref.trait_def_id()
|
||||
&& self.tcx.is_lang_item(def_id, hir::LangItem::Drop)
|
||||
{
|
||||
return;
|
||||
|
|
@ -2212,7 +2213,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
|
||||
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
|
||||
/// (Allows proc_macro functions)
|
||||
// FIXME(jdonszelmann): if possible, move to attr parsing
|
||||
fn check_allow_internal_unstable(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
|
|
@ -2220,6 +2220,42 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
span: Span,
|
||||
target: Target,
|
||||
attrs: &[Attribute],
|
||||
) {
|
||||
self.check_macro_only_attr(
|
||||
hir_id,
|
||||
attr_span,
|
||||
span,
|
||||
target,
|
||||
attrs,
|
||||
"allow_internal_unstable",
|
||||
)
|
||||
}
|
||||
|
||||
/// Outputs an error for `#[allow_internal_unsafe]` which can only be applied to macros.
|
||||
/// (Allows proc_macro functions)
|
||||
fn check_allow_internal_unsafe(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
attr_span: Span,
|
||||
span: Span,
|
||||
target: Target,
|
||||
attrs: &[Attribute],
|
||||
) {
|
||||
self.check_macro_only_attr(hir_id, attr_span, span, target, attrs, "allow_internal_unsafe")
|
||||
}
|
||||
|
||||
/// Outputs an error for attributes that can only be applied to macros, such as
|
||||
/// `#[allow_internal_unsafe]` and `#[allow_internal_unstable]`.
|
||||
/// (Allows proc_macro functions)
|
||||
// FIXME(jdonszelmann): if possible, move to attr parsing
|
||||
fn check_macro_only_attr(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
attr_span: Span,
|
||||
span: Span,
|
||||
target: Target,
|
||||
attrs: &[Attribute],
|
||||
attr_name: &str,
|
||||
) {
|
||||
match target {
|
||||
Target::Fn => {
|
||||
|
|
@ -2238,18 +2274,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
// erroneously allowed it and some crates used it accidentally, to be compatible
|
||||
// with crates depending on them, we can't throw an error here.
|
||||
Target::Field | Target::Arm => {
|
||||
self.inline_attr_str_error_without_macro_def(
|
||||
hir_id,
|
||||
attr_span,
|
||||
"allow_internal_unstable",
|
||||
);
|
||||
self.inline_attr_str_error_without_macro_def(hir_id, attr_span, attr_name);
|
||||
return;
|
||||
}
|
||||
// otherwise continue out of the match
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.tcx.dcx().emit_err(errors::AllowInternalUnstable { attr_span, span });
|
||||
self.tcx.dcx().emit_err(errors::MacroOnlyAttribute { attr_span, span });
|
||||
}
|
||||
|
||||
/// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
|
||||
|
|
@ -2294,7 +2326,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
match target {
|
||||
// FIXME(staged_api): There's no reason we can't support more targets here. We're just
|
||||
// being conservative to begin with.
|
||||
Target::Fn | Target::Impl { .. } => {}
|
||||
Target::Fn | Target::Impl { .. } | Target::Trait => {}
|
||||
Target::ExternCrate
|
||||
| Target::Use
|
||||
| Target::Static
|
||||
|
|
@ -2309,7 +2341,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| Target::Struct
|
||||
| Target::Field
|
||||
| Target::Union
|
||||
| Target::Trait
|
||||
| Target::TraitAlias
|
||||
| Target::Expression
|
||||
| Target::Statement
|
||||
|
|
|
|||
|
|
@ -172,7 +172,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // FIXME(81658): should be used + lint reinstated after #83171 relands.
|
||||
fn handle_assign(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
if self
|
||||
.typeck_results()
|
||||
|
|
@ -189,7 +188,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // FIXME(81658): should be used + lint reinstated after #83171 relands.
|
||||
fn check_for_self_assign(&mut self, assign: &'tcx hir::Expr<'tcx>) {
|
||||
fn check_for_self_assign_helper<'tcx>(
|
||||
typeck_results: &'tcx ty::TypeckResults<'tcx>,
|
||||
|
|
@ -576,6 +574,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
|
|||
hir::ExprKind::OffsetOf(..) => {
|
||||
self.handle_offset_of(expr);
|
||||
}
|
||||
hir::ExprKind::Assign(ref lhs, ..) => {
|
||||
self.handle_assign(lhs);
|
||||
self.check_for_self_assign(expr);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -643,8 +643,8 @@ pub(crate) struct UsedStatic {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_allow_internal_unstable)]
|
||||
pub(crate) struct AllowInternalUnstable {
|
||||
#[diag(passes_macro_only_attribute)]
|
||||
pub(crate) struct MacroOnlyAttribute {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
|
|
|
|||
|
|
@ -590,9 +590,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
// 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(t), self_ty, items, constness, ..
|
||||
}) => {
|
||||
hir::ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), self_ty, items, .. }) => {
|
||||
let features = self.tcx.features();
|
||||
if features.staged_api() {
|
||||
let attrs = self.tcx.hir_attrs(item.hir_id());
|
||||
|
|
@ -628,7 +626,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
{
|
||||
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
|
||||
c.visit_ty_unambig(self_ty);
|
||||
c.visit_trait_ref(t);
|
||||
c.visit_trait_ref(&of_trait.trait_ref);
|
||||
|
||||
// Skip the lint if the impl is marked as unstable using
|
||||
// #[unstable_feature_bound(..)]
|
||||
|
|
@ -641,7 +639,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
|
||||
// do not lint when the trait isn't resolved, since resolution error should
|
||||
// be fixed first
|
||||
if t.path.res != Res::Err
|
||||
if of_trait.trait_ref.path.res != Res::Err
|
||||
&& c.fully_stable
|
||||
&& !unstable_feature_bound_in_effect
|
||||
{
|
||||
|
|
@ -655,7 +653,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
}
|
||||
|
||||
if features.const_trait_impl()
|
||||
&& let hir::Constness::Const = constness
|
||||
&& let hir::Constness::Const = of_trait.constness
|
||||
{
|
||||
let stable_or_implied_stable = match const_stab {
|
||||
None => true,
|
||||
|
|
@ -671,7 +669,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
Some(_) => false,
|
||||
};
|
||||
|
||||
if let Some(trait_id) = t.trait_def_id()
|
||||
if let Some(trait_id) = of_trait.trait_ref.trait_def_id()
|
||||
&& let Some(const_stab) = self.tcx.lookup_const_stability(trait_id)
|
||||
{
|
||||
// the const stability of a trait impl must match the const stability on the trait.
|
||||
|
|
@ -699,14 +697,18 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if let hir::Constness::Const = constness
|
||||
&& let Some(def_id) = t.trait_def_id()
|
||||
if let hir::Constness::Const = of_trait.constness
|
||||
&& let Some(def_id) = of_trait.trait_ref.trait_def_id()
|
||||
{
|
||||
// FIXME(const_trait_impl): Improve the span here.
|
||||
self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
|
||||
self.tcx.check_const_stability(
|
||||
def_id,
|
||||
of_trait.trait_ref.path.span,
|
||||
of_trait.trait_ref.path.span,
|
||||
);
|
||||
}
|
||||
|
||||
for impl_item_ref in *items {
|
||||
for impl_item_ref in items {
|
||||
let impl_item = self.tcx.associated_item(impl_item_ref.owner_id);
|
||||
|
||||
if let Some(def_id) = impl_item.trait_item_def_id {
|
||||
|
|
|
|||
|
|
@ -1779,7 +1779,8 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
|
|||
if let DefKind::Impl { of_trait: true } = tcx.def_kind(def_id) {
|
||||
let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
|
||||
let trait_ref = trait_ref.instantiate_identity();
|
||||
visitor.span = tcx.hir_expect_item(def_id).expect_impl().of_trait.unwrap().path.span;
|
||||
visitor.span =
|
||||
tcx.hir_expect_item(def_id).expect_impl().of_trait.unwrap().trait_ref.path.span;
|
||||
let _ =
|
||||
visitor.visit_def_id(trait_ref.def_id, "trait", &trait_ref.print_only_trait_path());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use std::sync::Arc;
|
|||
use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind};
|
||||
use rustc_ast::{
|
||||
self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem,
|
||||
ForeignItemKind, Impl, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias,
|
||||
ForeignItemKind, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias,
|
||||
};
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::AttributeParser;
|
||||
|
|
@ -906,10 +906,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
}
|
||||
|
||||
// These items do not add names to modules.
|
||||
ItemKind::Impl(box Impl { of_trait: Some(..), .. })
|
||||
| ItemKind::Impl { .. }
|
||||
| ItemKind::ForeignMod(..)
|
||||
| ItemKind::GlobalAsm(..) => {}
|
||||
ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
|
||||
|
||||
ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
|
||||
unreachable!()
|
||||
|
|
|
|||
|
|
@ -2620,7 +2620,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
self.resolve_adt(item, generics);
|
||||
}
|
||||
|
||||
ItemKind::Impl(box Impl {
|
||||
ItemKind::Impl(Impl {
|
||||
ref generics,
|
||||
ref of_trait,
|
||||
ref self_ty,
|
||||
|
|
@ -2631,7 +2631,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
self.resolve_implementation(
|
||||
&item.attrs,
|
||||
generics,
|
||||
of_trait,
|
||||
of_trait.as_deref(),
|
||||
self_ty,
|
||||
item.id,
|
||||
impl_items,
|
||||
|
|
@ -3177,7 +3177,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
&mut self,
|
||||
attrs: &[ast::Attribute],
|
||||
generics: &'ast Generics,
|
||||
opt_trait_reference: &'ast Option<TraitRef>,
|
||||
of_trait: Option<&'ast ast::TraitImplHeader>,
|
||||
self_type: &'ast Ty,
|
||||
item_id: NodeId,
|
||||
impl_items: &'ast [Box<AssocItem>],
|
||||
|
|
@ -3201,7 +3201,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
|this| {
|
||||
// Resolve the trait reference, if necessary.
|
||||
this.with_optional_trait_ref(
|
||||
opt_trait_reference.as_ref(),
|
||||
of_trait.map(|t| &t.trait_ref),
|
||||
self_type,
|
||||
|this, trait_id| {
|
||||
this.resolve_doc_links(attrs, MaybeExported::Impl(trait_id));
|
||||
|
|
@ -3224,9 +3224,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
is_trait_impl: trait_id.is_some()
|
||||
};
|
||||
this.with_self_rib(res, |this| {
|
||||
if let Some(trait_ref) = opt_trait_reference.as_ref() {
|
||||
if let Some(of_trait) = of_trait {
|
||||
// Resolve type arguments in the trait path.
|
||||
visit::walk_trait_ref(this, trait_ref);
|
||||
visit::walk_trait_ref(this, &of_trait.trait_ref);
|
||||
}
|
||||
// Resolve the self type.
|
||||
this.visit_ty(self_type);
|
||||
|
|
@ -5183,7 +5183,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
|
|||
| ItemKind::Enum(_, generics, _)
|
||||
| ItemKind::Struct(_, generics, _)
|
||||
| ItemKind::Union(_, generics, _)
|
||||
| ItemKind::Impl(box Impl { generics, .. })
|
||||
| ItemKind::Impl(Impl { generics, .. })
|
||||
| ItemKind::Trait(box Trait { generics, .. })
|
||||
| ItemKind::TraitAlias(_, generics, _) => {
|
||||
if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::fmt::{Display, from_fn};
|
||||
use std::num::ParseIntError;
|
||||
use std::str::FromStr;
|
||||
|
|
@ -209,29 +208,10 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> {
|
|||
// that's only applicable to cross-OS compilation. Always leave anything for the
|
||||
// host OS alone though.
|
||||
if os == "macos" {
|
||||
let mut env_remove = Vec::with_capacity(2);
|
||||
// Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which
|
||||
// may occur when we're linking a custom build script while targeting iOS for example.
|
||||
if let Ok(sdkroot) = env::var("SDKROOT") {
|
||||
if sdkroot.contains("iPhoneOS.platform")
|
||||
|| sdkroot.contains("iPhoneSimulator.platform")
|
||||
|| sdkroot.contains("AppleTVOS.platform")
|
||||
|| sdkroot.contains("AppleTVSimulator.platform")
|
||||
|| sdkroot.contains("WatchOS.platform")
|
||||
|| sdkroot.contains("WatchSimulator.platform")
|
||||
|| sdkroot.contains("XROS.platform")
|
||||
|| sdkroot.contains("XRSimulator.platform")
|
||||
{
|
||||
env_remove.push("SDKROOT".into())
|
||||
}
|
||||
}
|
||||
// Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
|
||||
// `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
|
||||
// "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld",
|
||||
// although this is apparently ignored when using the linker at "/usr/bin/ld".
|
||||
env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".into());
|
||||
env_remove.push("TVOS_DEPLOYMENT_TARGET".into());
|
||||
env_remove.push("XROS_DEPLOYMENT_TARGET".into());
|
||||
env_remove.into()
|
||||
cvs!["IPHONEOS_DEPLOYMENT_TARGET", "TVOS_DEPLOYMENT_TARGET", "XROS_DEPLOYMENT_TARGET"]
|
||||
} else {
|
||||
// Otherwise if cross-compiling for a different OS/SDK (including Mac Catalyst), remove any part
|
||||
// of the linking environment that's wrong and reversed.
|
||||
|
|
|
|||
|
|
@ -3471,8 +3471,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
..
|
||||
})) => {
|
||||
let mut spans = Vec::with_capacity(2);
|
||||
if let Some(trait_ref) = of_trait {
|
||||
spans.push(trait_ref.path.span);
|
||||
if let Some(of_trait) = of_trait {
|
||||
spans.push(of_trait.trait_ref.path.span);
|
||||
}
|
||||
spans.push(self_ty.span);
|
||||
let mut spans: MultiSpan = spans.into();
|
||||
|
|
@ -3480,7 +3480,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
self_ty.span.ctxt().outer_expn_data().kind,
|
||||
ExpnKind::Macro(MacroKind::Derive, _)
|
||||
) || matches!(
|
||||
of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
|
||||
of_trait.map(|t| t.trait_ref.path.span.ctxt().outer_expn_data().kind),
|
||||
Some(ExpnKind::Macro(MacroKind::Derive, _))
|
||||
) {
|
||||
spans.push_span_label(
|
||||
|
|
@ -3592,7 +3592,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
..
|
||||
})) => {
|
||||
let mut spans = vec![self_ty.span];
|
||||
spans.extend(of_trait.as_ref().map(|t| t.path.span));
|
||||
spans.extend(of_trait.map(|t| t.trait_ref.path.span));
|
||||
let mut spans: MultiSpan = spans.into();
|
||||
spans.push_span_label(data.span, "unsatisfied trait bound introduced here");
|
||||
err.span_note(spans, msg);
|
||||
|
|
|
|||
|
|
@ -174,10 +174,10 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>(
|
|||
})
|
||||
.collect(),
|
||||
ItemKind::Impl(impl_) => {
|
||||
let Some(trait_ref) = impl_.of_trait else {
|
||||
let Some(of_trait) = impl_.of_trait else {
|
||||
return Default::default();
|
||||
};
|
||||
let Some(trait_def_id) = trait_ref.trait_def_id() else {
|
||||
let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else {
|
||||
return Default::default();
|
||||
};
|
||||
let in_trait_def = tcx.associated_types_for_impl_traits_in_trait_or_impl(trait_def_id);
|
||||
|
|
|
|||
|
|
@ -172,10 +172,12 @@ fn impl_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span>
|
|||
let trait_args = impl_
|
||||
.of_trait
|
||||
.into_iter()
|
||||
.flat_map(|trait_ref| trait_ref.path.segments.last().unwrap().args().args)
|
||||
.flat_map(|of_trait| of_trait.trait_ref.path.segments.last().unwrap().args().args)
|
||||
.map(|arg| arg.span());
|
||||
let dummy_spans_for_default_args =
|
||||
impl_.of_trait.into_iter().flat_map(|trait_ref| iter::repeat(trait_ref.path.span));
|
||||
let dummy_spans_for_default_args = impl_
|
||||
.of_trait
|
||||
.into_iter()
|
||||
.flat_map(|of_trait| iter::repeat(of_trait.trait_ref.path.span));
|
||||
iter::once(impl_.self_ty.span).chain(trait_args).chain(dummy_spans_for_default_args)
|
||||
} else {
|
||||
bug!("unexpected item for impl {def_id:?}: {item:?}")
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
|
|||
DefKind::InlineConst | DefKind::Closure | DefKind::SyntheticCoroutineBody => {}
|
||||
DefKind::Impl { of_trait } => {
|
||||
if of_trait {
|
||||
let span = tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().path.span;
|
||||
let span = tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().trait_ref.path.span;
|
||||
let args = &tcx.impl_trait_ref(item).unwrap().instantiate_identity().args[1..];
|
||||
try_visit!(visitor.visit(span, args));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,11 @@ fn sizedness_constraint_for_ty<'tcx>(
|
|||
fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
|
||||
match tcx.hir_node_by_def_id(def_id) {
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { defaultness, of_trait: Some(_), .. }),
|
||||
kind:
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
of_trait: Some(hir::TraitImplHeader { defaultness, .. }),
|
||||
..
|
||||
}),
|
||||
..
|
||||
})
|
||||
| hir::Node::ImplItem(hir::ImplItem { defaultness, .. })
|
||||
|
|
|
|||
|
|
@ -49,7 +49,27 @@
|
|||
//! v[1] = v[1] + 5;
|
||||
//! ```
|
||||
//!
|
||||
//! # Memory layout
|
||||
//!
|
||||
//! When the type is non-zero-sized and the capacity is nonzero, [`Vec`] uses the [`Global`]
|
||||
//! allocator for its allocation. It is valid to convert both ways between such a [`Vec`] and a raw
|
||||
//! pointer allocated with the [`Global`] allocator, provided that the [`Layout`] used with the
|
||||
//! allocator is correct for a sequence of `capacity` elements of the type, and the first `len`
|
||||
//! values pointed to by the raw pointer are valid. More precisely, a `ptr: *mut T` that has been
|
||||
//! allocated with the [`Global`] allocator with [`Layout::array::<T>(capacity)`][Layout::array] may
|
||||
//! be converted into a vec using
|
||||
//! [`Vec::<T>::from_raw_parts(ptr, len, capacity)`](Vec::from_raw_parts). Conversely, the memory
|
||||
//! backing a `value: *mut T` obtained from [`Vec::<T>::as_mut_ptr`] may be deallocated using the
|
||||
//! [`Global`] allocator with the same layout.
|
||||
//!
|
||||
//! For zero-sized types (ZSTs), or when the capacity is zero, the `Vec` pointer must be non-null
|
||||
//! and sufficiently aligned. The recommended way to build a `Vec` of ZSTs if [`vec!`] cannot be
|
||||
//! used is to use [`ptr::NonNull::dangling`].
|
||||
//!
|
||||
//! [`push`]: Vec::push
|
||||
//! [`ptr::NonNull::dangling`]: NonNull::dangling
|
||||
//! [`Layout`]: crate::alloc::Layout
|
||||
//! [Layout::array]: crate::alloc::Layout::array
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
|
@ -523,18 +543,23 @@ impl<T> Vec<T> {
|
|||
/// This is highly unsafe, due to the number of invariants that aren't
|
||||
/// checked:
|
||||
///
|
||||
/// * `ptr` must have been allocated using the global allocator, such as via
|
||||
/// the [`alloc::alloc`] function.
|
||||
/// * `T` needs to have the same alignment as what `ptr` was allocated with.
|
||||
/// * If `T` is not a zero-sized type and the capacity is nonzero, `ptr` must have
|
||||
/// been allocated using the global allocator, such as via the [`alloc::alloc`]
|
||||
/// function. If `T` is a zero-sized type or the capacity is zero, `ptr` need
|
||||
/// only be non-null and aligned.
|
||||
/// * `T` needs to have the same alignment as what `ptr` was allocated with,
|
||||
/// if the pointer is required to be allocated.
|
||||
/// (`T` having a less strict alignment is not sufficient, the alignment really
|
||||
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
|
||||
/// allocated and deallocated with the same layout.)
|
||||
/// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs
|
||||
/// to be the same size as the pointer was allocated with. (Because similar to
|
||||
/// alignment, [`dealloc`] must be called with the same layout `size`.)
|
||||
/// * The size of `T` times the `capacity` (ie. the allocated size in bytes), if
|
||||
/// nonzero, needs to be the same size as the pointer was allocated with.
|
||||
/// (Because similar to alignment, [`dealloc`] must be called with the same
|
||||
/// layout `size`.)
|
||||
/// * `length` needs to be less than or equal to `capacity`.
|
||||
/// * The first `length` values must be properly initialized values of type `T`.
|
||||
/// * `capacity` needs to be the capacity that the pointer was allocated with.
|
||||
/// * `capacity` needs to be the capacity that the pointer was allocated with,
|
||||
/// if the pointer is required to be allocated.
|
||||
/// * The allocated size in bytes must be no larger than `isize::MAX`.
|
||||
/// See the safety documentation of [`pointer::offset`].
|
||||
///
|
||||
|
|
@ -770,12 +795,16 @@ impl<T> Vec<T> {
|
|||
/// order as the arguments to [`from_raw_parts`].
|
||||
///
|
||||
/// After calling this function, the caller is responsible for the
|
||||
/// memory previously managed by the `Vec`. The only way to do
|
||||
/// this is to convert the raw pointer, length, and capacity back
|
||||
/// into a `Vec` with the [`from_raw_parts`] function, allowing
|
||||
/// the destructor to perform the cleanup.
|
||||
/// memory previously managed by the `Vec`. Most often, one does
|
||||
/// this by converting the raw pointer, length, and capacity back
|
||||
/// into a `Vec` with the [`from_raw_parts`] function; more generally,
|
||||
/// if `T` is non-zero-sized and the capacity is nonzero, one may use
|
||||
/// any method that calls [`dealloc`] with a layout of
|
||||
/// `Layout::array::<T>(capacity)`; if `T` is zero-sized or the
|
||||
/// capacity is zero, nothing needs to be done.
|
||||
///
|
||||
/// [`from_raw_parts`]: Vec::from_raw_parts
|
||||
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1755,6 +1784,12 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
/// may still invalidate this pointer.
|
||||
/// See the second example below for how this guarantee can be used.
|
||||
///
|
||||
/// The method also guarantees that, as long as `T` is not zero-sized and the capacity is
|
||||
/// nonzero, the pointer may be passed into [`dealloc`] with a layout of
|
||||
/// `Layout::array::<T>(capacity)` in order to deallocate the backing memory. If this is done,
|
||||
/// be careful not to run the destructor of the `Vec`, as dropping it will result in
|
||||
/// double-frees. Wrapping the `Vec` in a [`ManuallyDrop`] is the typical way to achieve this.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -1787,9 +1822,24 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Deallocating a vector using [`Box`] (which uses [`dealloc`] internally):
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem::{ManuallyDrop, MaybeUninit};
|
||||
///
|
||||
/// let mut v = ManuallyDrop::new(vec![0, 1, 2]);
|
||||
/// let ptr = v.as_mut_ptr();
|
||||
/// let capacity = v.capacity();
|
||||
/// let slice_ptr: *mut [MaybeUninit<i32>] =
|
||||
/// std::ptr::slice_from_raw_parts_mut(ptr.cast(), capacity);
|
||||
/// drop(unsafe { Box::from_raw(slice_ptr) });
|
||||
/// ```
|
||||
///
|
||||
/// [`as_mut_ptr`]: Vec::as_mut_ptr
|
||||
/// [`as_ptr`]: Vec::as_ptr
|
||||
/// [`as_non_null`]: Vec::as_non_null
|
||||
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
|
||||
/// [`ManuallyDrop`]: core::mem::ManuallyDrop
|
||||
#[stable(feature = "vec_as_ptr", since = "1.37.0")]
|
||||
#[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")]
|
||||
#[rustc_never_returns_null_ptr]
|
||||
|
|
|
|||
|
|
@ -853,7 +853,7 @@ pub trait RangeBounds<T: ?Sized> {
|
|||
/// assert!( RangeBounds::is_empty(&(f32::NAN..5.0)));
|
||||
/// ```
|
||||
///
|
||||
/// But never empty is either side is unbounded:
|
||||
/// But never empty if either side is unbounded:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(range_bounds_is_empty)]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
//! These tests are not run automatically right now. Please run these tests manually by copying them
|
||||
//! to a separate project when modifying any related code.
|
||||
|
||||
use super::alloc::*;
|
||||
use super::time::*;
|
||||
use super::time::system_time_internal::{from_uefi, to_uefi};
|
||||
use crate::io::{IoSlice, IoSliceMut};
|
||||
use crate::time::Duration;
|
||||
|
||||
const SECS_IN_MINUTE: u64 = 60;
|
||||
|
||||
#[test]
|
||||
fn align() {
|
||||
// UEFI ABI specifies that allocation alignment minimum is always 8. So this can be
|
||||
|
|
@ -24,21 +29,61 @@ fn align() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn epoch() {
|
||||
let t = r_efi::system::Time {
|
||||
year: 1970,
|
||||
fn systemtime_start() {
|
||||
let t = r_efi::efi::Time {
|
||||
year: 1900,
|
||||
month: 1,
|
||||
day: 1,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
nanosecond: 0,
|
||||
timezone: r_efi::efi::UNSPECIFIED_TIMEZONE,
|
||||
timezone: -1440,
|
||||
daylight: 0,
|
||||
pad1: 0,
|
||||
pad2: 0,
|
||||
};
|
||||
assert_eq!(system_time_internal::uefi_time_to_duration(t), Duration::new(0, 0));
|
||||
assert_eq!(from_uefi(&t), Duration::new(0, 0));
|
||||
assert_eq!(t, to_uefi(&from_uefi(&t), -1440, 0).unwrap());
|
||||
assert!(to_uefi(&from_uefi(&t), 0, 0).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn systemtime_utc_start() {
|
||||
let t = r_efi::efi::Time {
|
||||
year: 1900,
|
||||
month: 1,
|
||||
day: 1,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
pad1: 0,
|
||||
nanosecond: 0,
|
||||
timezone: 0,
|
||||
daylight: 0,
|
||||
pad2: 0,
|
||||
};
|
||||
assert_eq!(from_uefi(&t), Duration::new(1440 * SECS_IN_MINUTE, 0));
|
||||
assert_eq!(t, to_uefi(&from_uefi(&t), 0, 0).unwrap());
|
||||
assert!(to_uefi(&from_uefi(&t), -1440, 0).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn systemtime_end() {
|
||||
let t = r_efi::efi::Time {
|
||||
year: 9999,
|
||||
month: 12,
|
||||
day: 31,
|
||||
hour: 23,
|
||||
minute: 59,
|
||||
second: 59,
|
||||
pad1: 0,
|
||||
nanosecond: 0,
|
||||
timezone: 1440,
|
||||
daylight: 0,
|
||||
pad2: 0,
|
||||
};
|
||||
assert!(to_uefi(&from_uefi(&t), 1440, 0).is_some());
|
||||
assert!(to_uefi(&from_uefi(&t), 1439, 0).is_none());
|
||||
}
|
||||
|
||||
// UEFI IoSlice and IoSliceMut Tests
|
||||
|
|
|
|||
|
|
@ -1,16 +1,42 @@
|
|||
use crate::time::Duration;
|
||||
|
||||
const SECS_IN_MINUTE: u64 = 60;
|
||||
const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60;
|
||||
const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct Instant(Duration);
|
||||
|
||||
/// When a Timezone is specified, the stored Duration is in UTC. If timezone is unspecified, then
|
||||
/// the timezone is assumed to be in UTC.
|
||||
///
|
||||
/// UEFI SystemTime is stored as Duration from 1900-01-01-00:00:00 with timezone -1440 as anchor
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct SystemTime(Duration);
|
||||
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
|
||||
year: 1970,
|
||||
month: 1,
|
||||
day: 1,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
nanosecond: 0,
|
||||
timezone: 0,
|
||||
daylight: 0,
|
||||
pad1: 0,
|
||||
pad2: 0,
|
||||
});
|
||||
|
||||
const MAX_UEFI_TIME: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
|
||||
year: 9999,
|
||||
month: 12,
|
||||
day: 31,
|
||||
hour: 23,
|
||||
minute: 59,
|
||||
second: 59,
|
||||
nanosecond: 999_999_999,
|
||||
timezone: 1440,
|
||||
daylight: 0,
|
||||
pad1: 0,
|
||||
pad2: 0,
|
||||
});
|
||||
|
||||
impl Instant {
|
||||
pub fn now() -> Instant {
|
||||
|
|
@ -40,6 +66,15 @@ impl Instant {
|
|||
}
|
||||
|
||||
impl SystemTime {
|
||||
pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Self {
|
||||
Self(system_time_internal::from_uefi(&t))
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub(crate) const fn to_uefi(self, timezone: i16, daylight: u8) -> Option<r_efi::efi::Time> {
|
||||
system_time_internal::to_uefi(&self.0, timezone, daylight)
|
||||
}
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
system_time_internal::now()
|
||||
.unwrap_or_else(|| panic!("time not implemented on this platform"))
|
||||
|
|
@ -50,11 +85,14 @@ impl SystemTime {
|
|||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime(self.0.checked_add(*other)?))
|
||||
let temp = Self(self.0.checked_add(*other)?);
|
||||
|
||||
// Check if can be represented in UEFI
|
||||
if temp <= MAX_UEFI_TIME { Some(temp) } else { None }
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime(self.0.checked_sub(*other)?))
|
||||
self.0.checked_sub(*other).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,51 +104,132 @@ pub(crate) mod system_time_internal {
|
|||
use crate::mem::MaybeUninit;
|
||||
use crate::ptr::NonNull;
|
||||
|
||||
const SECS_IN_MINUTE: u64 = 60;
|
||||
const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60;
|
||||
const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24;
|
||||
const TIMEZONE_DELTA: u64 = 1440 * SECS_IN_MINUTE;
|
||||
|
||||
pub fn now() -> Option<SystemTime> {
|
||||
let runtime_services: NonNull<RuntimeServices> = helpers::runtime_services()?;
|
||||
let mut t: MaybeUninit<Time> = MaybeUninit::uninit();
|
||||
let r = unsafe {
|
||||
((*runtime_services.as_ptr()).get_time)(t.as_mut_ptr(), crate::ptr::null_mut())
|
||||
};
|
||||
|
||||
if r.is_error() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let t = unsafe { t.assume_init() };
|
||||
|
||||
Some(SystemTime(uefi_time_to_duration(t)))
|
||||
Some(SystemTime::from_uefi(t))
|
||||
}
|
||||
|
||||
// This algorithm is based on the one described in the post
|
||||
// https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
|
||||
pub(crate) const fn uefi_time_to_duration(t: r_efi::system::Time) -> Duration {
|
||||
assert!(t.month <= 12);
|
||||
assert!(t.month != 0);
|
||||
/// This algorithm is a modified form of the one described in the post
|
||||
/// https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
|
||||
///
|
||||
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
|
||||
/// epoch used in the original algorithm.
|
||||
pub(crate) const fn from_uefi(t: &Time) -> Duration {
|
||||
assert!(t.month <= 12 && t.month != 0);
|
||||
assert!(t.year >= 1900 && t.year <= 9999);
|
||||
assert!(t.day <= 31 && t.day != 0);
|
||||
|
||||
assert!(t.second < 60);
|
||||
assert!(t.minute < 60);
|
||||
assert!(t.hour < 24);
|
||||
assert!(t.nanosecond < 1_000_000_000);
|
||||
|
||||
assert!(
|
||||
(t.timezone <= 1440 && t.timezone >= -1440)
|
||||
|| t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE
|
||||
);
|
||||
|
||||
const YEAR_BASE: u32 = 4800; /* Before min year, multiple of 400. */
|
||||
|
||||
// Calculate the number of days since 1/1/1970
|
||||
// Calculate the number of days since 1/1/1900. This is the earliest supported date in UEFI
|
||||
// time.
|
||||
// Use 1 March as the start
|
||||
let (m_adj, overflow): (u32, bool) = (t.month as u32).overflowing_sub(3);
|
||||
let (carry, adjust): (u32, u32) = if overflow { (1, 12) } else { (0, 0) };
|
||||
let y_adj: u32 = (t.year as u32) + YEAR_BASE - carry;
|
||||
let month_days: u32 = (m_adj.wrapping_add(adjust) * 62719 + 769) / 2048;
|
||||
let leap_days: u32 = y_adj / 4 - y_adj / 100 + y_adj / 400;
|
||||
let days: u32 = y_adj * 365 + leap_days + month_days + (t.day as u32 - 1) - 2472632;
|
||||
let days: u32 = y_adj * 365 + leap_days + month_days + (t.day as u32 - 1) - 2447065;
|
||||
|
||||
let localtime_epoch: u64 = (days as u64) * SECS_IN_DAY
|
||||
+ (t.second as u64)
|
||||
+ (t.minute as u64) * SECS_IN_MINUTE
|
||||
+ (t.hour as u64) * SECS_IN_HOUR;
|
||||
|
||||
let utc_epoch: u64 = if t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
|
||||
localtime_epoch
|
||||
// Calculate the offset from 1/1/1900 at timezone -1440 min
|
||||
let adjusted_localtime_epoc: u64 = localtime_epoch + TIMEZONE_DELTA;
|
||||
|
||||
let epoch: u64 = if t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
|
||||
adjusted_localtime_epoc
|
||||
} else {
|
||||
(localtime_epoch as i64 + (t.timezone as i64) * SECS_IN_MINUTE as i64) as u64
|
||||
adjusted_localtime_epoc
|
||||
.checked_add_signed((t.timezone as i64) * SECS_IN_MINUTE as i64)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
Duration::new(utc_epoch, t.nanosecond)
|
||||
Duration::new(epoch, t.nanosecond)
|
||||
}
|
||||
|
||||
/// This algorithm is a modifed version of the one described in the post:
|
||||
/// https://howardhinnant.github.io/date_algorithms.html#clive_from_days
|
||||
///
|
||||
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
|
||||
/// epoch used in the original algorithm.
|
||||
pub(crate) const fn to_uefi(dur: &Duration, timezone: i16, daylight: u8) -> Option<Time> {
|
||||
// Check timzone validity
|
||||
assert!(timezone <= 1440 && timezone >= -1440);
|
||||
|
||||
// FIXME(#126043): use checked_sub_signed once stablized
|
||||
let secs =
|
||||
dur.as_secs().checked_add_signed((-timezone as i64) * SECS_IN_MINUTE as i64).unwrap();
|
||||
|
||||
// Convert to seconds since 1900-01-01-00:00:00 in timezone.
|
||||
let Some(secs) = secs.checked_sub(TIMEZONE_DELTA) else { return None };
|
||||
|
||||
let days = secs / SECS_IN_DAY;
|
||||
let remaining_secs = secs % SECS_IN_DAY;
|
||||
|
||||
let z = days + 693901;
|
||||
let era = z / 146097;
|
||||
let doe = z - (era * 146097);
|
||||
let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
|
||||
let mut y = yoe + era * 400;
|
||||
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
|
||||
let mp = (5 * doy + 2) / 153;
|
||||
let d = doy - (153 * mp + 2) / 5 + 1;
|
||||
let m = if mp < 10 { mp + 3 } else { mp - 9 };
|
||||
|
||||
if m <= 2 {
|
||||
y += 1;
|
||||
}
|
||||
|
||||
let hour = (remaining_secs / SECS_IN_HOUR) as u8;
|
||||
let minute = ((remaining_secs % SECS_IN_HOUR) / SECS_IN_MINUTE) as u8;
|
||||
let second = (remaining_secs % SECS_IN_MINUTE) as u8;
|
||||
|
||||
// Check Bounds
|
||||
if y >= 1900 && y <= 9999 {
|
||||
Some(Time {
|
||||
year: y as u16,
|
||||
month: m as u8,
|
||||
day: d as u8,
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
nanosecond: dur.subsec_nanos(),
|
||||
timezone,
|
||||
daylight,
|
||||
pad1: 0,
|
||||
pad2: 0,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -955,7 +955,7 @@ impl Config {
|
|||
config.download_rustc_commit =
|
||||
download_ci_rustc_commit(dwn_ctx, rust_download_rustc, config.llvm_assertions);
|
||||
|
||||
if debug_assertions_requested {
|
||||
if debug_assertions_requested && config.download_rustc_commit.is_some() {
|
||||
eprintln!(
|
||||
"WARN: `rust.debug-assertions = true` will prevent downloading CI rustc as alt CI \
|
||||
rustc is not currently built with debug assertions."
|
||||
|
|
|
|||
|
|
@ -33,11 +33,11 @@ ENV SCRIPT \
|
|||
python3 ../x.py test --stage 1 src/tools/compiletest && \
|
||||
python3 ../x.py doc bootstrap && \
|
||||
# Build both public and internal documentation.
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc compiler --stage 2 && \
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc library --stage 2 && \
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc compiler --stage 1 && \
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc library --stage 1 && \
|
||||
mkdir -p /checkout/obj/staging/doc && \
|
||||
cp -r build/x86_64-unknown-linux-gnu/doc /checkout/obj/staging && \
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc library/test --stage 2 && \
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc library/test --stage 1 && \
|
||||
# The BOOTSTRAP_TRACING flag is added to verify whether the
|
||||
# bootstrap process compiles successfully with this flag enabled.
|
||||
BOOTSTRAP_TRACING=1 python3 ../x.py --help
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 1be151c051a082b542548c62cafbcb055fa8944f
|
||||
Subproject commit 59b8af811886313577615c2cf0e045f01faed88b
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit bd1279cdc9865bfff605e741fb76a0b2f07314a7
|
||||
Subproject commit adc1f3b9012ad3255eea2054ca30596a953d053d
|
||||
|
|
@ -182,6 +182,11 @@ of the standard library raises it to a warning with
|
|||
`#![warn(deprecated_in_future)]`.
|
||||
|
||||
## unstable_feature_bound
|
||||
The `#[unstable_feature_bound(foo)]` attribute can be used together with `#[unstable]` attribute to mark an `impl` of stable type and stable trait as unstable. In std/core, an item annotated with `#[unstable_feature_bound(foo)]` can only be used by another item that is also annotated with `#[unstable_feature_bound(foo)]`. Outside of std/core, using an item with `#[unstable_feature_bound(foo)]` requires the feature to be enabled with `#![feature(foo)]` attribute on the crate. Currently, only `impl`s and free functions can be annotated with `#[unstable_feature_bound]`.
|
||||
The `#[unstable_feature_bound(foo)]` attribute can be used together with `#[unstable]` attribute to mark an `impl` of stable type and stable trait as unstable. In std/core, an item annotated with `#[unstable_feature_bound(foo)]` can only be used by another item that is also annotated with `#[unstable_feature_bound(foo)]`. Outside of std/core, using an item with `#[unstable_feature_bound(foo)]` requires the feature to be enabled with `#![feature(foo)]` attribute on the crate.
|
||||
|
||||
Currently, the items that can be annotated with `#[unstable_feature_bound]` are:
|
||||
- `impl`
|
||||
- free function
|
||||
- trait
|
||||
|
||||
[blog]: https://www.ralfj.de/blog/2018/07/19/const.html
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# `SDKROOT`
|
||||
|
||||
This environment variable is used on Apple targets.
|
||||
It is passed through to the linker (currently either as `-isysroot` or `-syslibroot`).
|
||||
It is passed through to the linker (currently either directly or via the `-syslibroot` flag).
|
||||
|
||||
Note that this variable is not always respected. When the SDKROOT is clearly wrong (e.g. when the platform of the SDK does not match the `--target` used by rustc), this is ignored and rustc does its own detection.
|
||||
|
|
|
|||
|
|
@ -2768,7 +2768,7 @@ fn clean_maybe_renamed_item<'tcx>(
|
|||
// These kinds of item either don't need a `name` or accept a `None` one so we handle them
|
||||
// before.
|
||||
match item.kind {
|
||||
ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
|
||||
ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
|
||||
ItemKind::Use(path, kind) => {
|
||||
return clean_use_statement(
|
||||
item,
|
||||
|
|
@ -2896,7 +2896,7 @@ fn clean_impl<'tcx>(
|
|||
) -> Vec<Item> {
|
||||
let tcx = cx.tcx;
|
||||
let mut ret = Vec::new();
|
||||
let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx));
|
||||
let trait_ = impl_.of_trait.map(|t| clean_trait_ref(&t.trait_ref, cx));
|
||||
let items = impl_
|
||||
.items
|
||||
.iter()
|
||||
|
|
@ -2922,7 +2922,10 @@ fn clean_impl<'tcx>(
|
|||
});
|
||||
let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
|
||||
let kind = ImplItem(Box::new(Impl {
|
||||
safety: impl_.safety,
|
||||
safety: match impl_.of_trait {
|
||||
Some(of_trait) => of_trait.safety,
|
||||
None => hir::Safety::Safe,
|
||||
},
|
||||
generics: clean_generics(impl_.generics, cx),
|
||||
trait_,
|
||||
for_,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue