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:
bors 2025-08-12 12:37:26 +00:00
commit d9dba3a554
221 changed files with 2690 additions and 1192 deletions

View file

@ -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

View file

@ -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()
});

View file

@ -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,

View file

@ -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

View file

@ -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)

View file

@ -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 {

View file

@ -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");
}
}

View file

@ -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);

View file

@ -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

View file

@ -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>,

View file

@ -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>,

View file

@ -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>,

View file

@ -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);

View file

@ -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"
);

View file

@ -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 {

View file

@ -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)?;

View file

@ -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);
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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)?;

View file

@ -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,

View file

@ -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)

View file

@ -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;

View file

@ -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 {

View file

@ -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;

View file

@ -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 {

View file

@ -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>>,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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));
};

View file

@ -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(),
})),
}),
)
}

View file

@ -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

View file

@ -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)
}

View file

@ -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") => {}

View file

@ -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));

View file

@ -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",
"{}",

View file

@ -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::*;

View file

@ -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)?;

View file

@ -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,

View file

@ -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]

View file

@ -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:?}"

View file

@ -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())

View file

@ -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",
),

View file

@ -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),

View file

@ -16,6 +16,7 @@ impl AttributeKind {
Align { .. } => No,
AllowConstFnUnstable(..) => No,
AllowIncoherentImpl(..) => No,
AllowInternalUnsafe(..) => Yes,
AllowInternalUnstable(..) => Yes,
AsPtr(..) => Yes,
AutomaticallyDerived(..) => Yes,

View file

@ -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);

View file

@ -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) => {

View file

@ -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(),
);

View file

@ -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)
};

View file

@ -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);

View file

@ -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 {

View file

@ -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()));

View file

@ -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(

View file

@ -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);

View file

@ -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, .. },
..
}),
..
}),
..

View file

@ -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;

View file

@ -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,

View file

@ -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()

View file

@ -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);

View file

@ -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 {

View file

@ -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, ""));
}

View file

@ -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 ->

View file

@ -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);
}
}
_ => {}
}
}

View file

@ -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()

View file

@ -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)
}

View file

@ -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)
{

View file

@ -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)]

View file

@ -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

View file

@ -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 {

View file

@ -793,6 +793,7 @@ pub enum BuiltinLintDiag {
},
IllFormedAttributeInput {
suggestions: Vec<String>,
docs: Option<&'static str>,
},
InnerAttributeUnstable {
is_macro: bool,

View file

@ -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<...>`

View file

@ -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 {

View file

@ -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",

View file

@ -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();
}
}

View file

@ -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

View file

@ -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

View file

@ -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);
}
_ => (),
}

View file

@ -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]

View file

@ -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 {

View file

@ -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());
}

View file

@ -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!()

View file

@ -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 {

View file

@ -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.

View file

@ -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);

View file

@ -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);

View file

@ -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:?}")

View file

@ -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));
}

View file

@ -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, .. })

View file

@ -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]

View file

@ -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)]

View file

@ -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

View file

@ -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
}
}
}

View file

@ -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."

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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