diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 92d0fb1aec8..afa0f6fcb80 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -296,20 +296,24 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Lints: ungated!( - warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk + warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), ungated!( - allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk + allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), gated!( expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk, lint_reasons, experimental!(expect) ), ungated!( - forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk + forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), ungated!( - deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk + deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), + DuplicatesOk, @only_local: true, ), ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing), gated!( @@ -340,7 +344,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(no_link, Normal, template!(Word), WarnFollowing), - ungated!(repr, Normal, template!(List: "C"), DuplicatesOk), + ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true), ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true), @@ -382,7 +386,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, @only_local: true), ungated!(cold, Normal, template!(Word), WarnFollowing, @only_local: true), ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing), - ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk), + ungated!( + target_feature, Normal, template!(List: r#"enable = "name""#), + DuplicatesOk, @only_local: true, + ), ungated!(track_caller, Normal, template!(Word), WarnFollowing), gated!( no_sanitize, Normal, @@ -488,18 +495,24 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== - ungated!(feature, CrateLevel, template!(List: "name1, name2, ..."), DuplicatesOk), + ungated!( + feature, CrateLevel, + template!(List: "name1, name2, ..."), DuplicatesOk, @only_local: true, + ), // DuplicatesOk since it has its own validation ungated!( - stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, + stable, Normal, + template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, @only_local: true, ), ungated!( unstable, Normal, template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk, ), ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), - ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), - ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk), + ungated!( + rustc_const_stable, Normal, + template!(List: r#"feature = "name""#), DuplicatesOk, @only_local: true, + ), ungated!( rustc_default_body_unstable, Normal, template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk @@ -517,6 +530,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ allow_internal_unsafe, Normal, template!(Word), WarnFollowing, "allow_internal_unsafe side-steps the unsafe_code lint", ), + ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk), rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing, "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \ through unstable paths"), @@ -823,6 +837,8 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() } +/// Whether this builtin attribute is only used in the local crate. +/// If so, it is not encoded in the crate metadata. pub fn is_builtin_only_local(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 68119598285..377e3f013be 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -3,6 +3,7 @@ use crate::rmeta::def_path_hash_map::DefPathHashMapRef; use crate::rmeta::table::TableBuilder; use crate::rmeta::*; +use rustc_ast::Attribute; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; @@ -764,6 +765,40 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } +/// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and +/// useful in downstream crates. Local-only attributes are an obvious example, but some +/// rustdoc-specific attributes can equally be of use while documenting the current crate only. +/// +/// Removing these superfluous attributes speeds up compilation by making the metadata smaller. +/// +/// Note: the `is_def_id_public` parameter is used to cache whether the given `DefId` has a public +/// visibility: this is a piece of data that can be computed once per defid, and not once per +/// attribute. Some attributes would only be usable downstream if they are public. +#[inline] +fn should_encode_attr( + tcx: TyCtxt<'_>, + attr: &Attribute, + def_id: LocalDefId, + is_def_id_public: &mut Option, +) -> bool { + if rustc_feature::is_builtin_only_local(attr.name_or_empty()) { + // Attributes marked local-only don't need to be encoded for downstream crates. + false + } else if attr.doc_str().is_some() { + // We keep all public doc comments because they might be "imported" into downstream crates + // if they use `#[doc(inline)]` to copy an item's documentation into their own. + *is_def_id_public.get_or_insert_with(|| { + tcx.privacy_access_levels(()).get_effective_vis(def_id).is_some() + }) + } else if attr.has_name(sym::doc) { + // If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can + // remove it. It won't be inlinable in downstream crates. + attr.meta_item_list().map(|l| l.iter().any(|l| !l.has_name(sym::inline))).unwrap_or(false) + } else { + true + } +} + fn should_encode_visibility(def_kind: DefKind) -> bool { match def_kind { DefKind::Mod @@ -1126,12 +1161,14 @@ fn should_encode_trait_impl_trait_tys<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_attrs(&mut self, def_id: LocalDefId) { - let mut attrs = self - .tcx + let tcx = self.tcx; + let mut is_public: Option = None; + + let mut attrs = tcx .hir() - .attrs(self.tcx.hir().local_def_id_to_hir_id(def_id)) + .attrs(tcx.hir().local_def_id_to_hir_id(def_id)) .iter() - .filter(|attr| !rustc_feature::is_builtin_only_local(attr.name_or_empty())); + .filter(move |attr| should_encode_attr(tcx, attr, def_id, &mut is_public)); record_array!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone()); if attrs.any(|attr| attr.may_have_doc_links()) { diff --git a/src/test/ui/attr-from-macro.rs b/src/test/ui/attr-from-macro.rs new file mode 100644 index 00000000000..bb3a5c94d41 --- /dev/null +++ b/src/test/ui/attr-from-macro.rs @@ -0,0 +1,20 @@ +// aux-build:attr-from-macro.rs +// run-pass + +extern crate attr_from_macro; + +attr_from_macro::creator! { + struct Foo; + enum Bar; + enum FooBar; +} + +fn main() { + // Checking the `repr(u32)` on the enum. + assert_eq!(4, std::mem::size_of::()); + // Checking the `repr(u16)` on the enum. + assert_eq!(2, std::mem::size_of::()); + + // Checking the Debug impl on the types. + eprintln!("{:?} {:?} {:?}", Foo, Bar::A, FooBar::A); +} diff --git a/src/test/ui/auxiliary/attr-from-macro.rs b/src/test/ui/auxiliary/attr-from-macro.rs new file mode 100644 index 00000000000..9b388675c80 --- /dev/null +++ b/src/test/ui/auxiliary/attr-from-macro.rs @@ -0,0 +1,15 @@ +#[macro_export] +macro_rules! creator { + (struct $name1:ident; enum $name2:ident; enum $name3:ident;) => { + #[derive(Debug)] + pub struct $name1; + + #[derive(Debug)] + #[repr(u32)] + pub enum $name2 { A } + + #[derive(Debug)] + #[repr(u16)] + pub enum $name3 { A } + } +} diff --git a/src/test/ui/query-visibility.rs b/src/test/ui/query-visibility.rs new file mode 100644 index 00000000000..09a289d85da --- /dev/null +++ b/src/test/ui/query-visibility.rs @@ -0,0 +1,9 @@ +// check-pass +// Check that it doesn't panic when `Input` gets its visibility checked. + +#![crate_type = "lib"] + +pub trait Layer< + /// Hello. + Input, +> {}