Skip to content

Commit

Permalink
Implement #[defines] attribute for consts and functions.
Browse files Browse the repository at this point in the history
statics still need work
  • Loading branch information
oli-obk committed Dec 4, 2024
1 parent 2e3f62c commit cb85e75
Show file tree
Hide file tree
Showing 601 changed files with 2,395 additions and 2,596 deletions.
11 changes: 11 additions & 0 deletions compiler/rustc_ast/src/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::token::{self, CommentKind, Delimiter, Token};
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenTree};
use crate::util::comments;
use crate::util::literal::escape_string_symbol;
use crate::NodeId;

pub struct MarkedAttrs(GrowableBitSet<AttrId>);

Expand Down Expand Up @@ -506,6 +507,16 @@ impl MetaItemKind {
}
}
}

pub fn defines(&self) -> Vec<NodeId> {
match self {
MetaItemKind::Word => vec![],
MetaItemKind::List(things) => {
things.iter().filter_map(|i| Some(i.meta_item()?.path.segments[0].id)).collect()
}
MetaItemKind::NameValue(_) => vec![],
}
}
}

impl MetaItemInner {
Expand Down
21 changes: 19 additions & 2 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ struct LoweringContext<'a, 'hir> {

/// Bodies inside the owner being lowered.
bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
/// Bodies inside the owner being lowered.
defines: SortedMap<hir::ItemLocalId, &'hir [LocalDefId]>,
/// Attributes inside the owner being lowered.
attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
/// Collect items that were created by lowering the current owner.
Expand Down Expand Up @@ -146,6 +148,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {

// HirId handling.
bodies: Vec::new(),
defines: SortedMap::default(),
attrs: SortedMap::default(),
children: Vec::default(),
current_hir_id_owner: hir::CRATE_OWNER_ID,
Expand Down Expand Up @@ -528,6 +531,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {

let current_attrs = std::mem::take(&mut self.attrs);
let current_bodies = std::mem::take(&mut self.bodies);
let current_defines = std::mem::take(&mut self.defines);
let current_ident_and_label_to_local_id =
std::mem::take(&mut self.ident_and_label_to_local_id);

Expand Down Expand Up @@ -560,6 +564,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let info = self.make_owner_info(item);

self.attrs = current_attrs;
self.defines = current_defines;
self.bodies = current_bodies;
self.ident_and_label_to_local_id = current_ident_and_label_to_local_id;

Expand All @@ -578,6 +583,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}

fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
let defines = std::mem::take(&mut self.defines);
let attrs = std::mem::take(&mut self.attrs);
let mut bodies = std::mem::take(&mut self.bodies);
let trait_map = std::mem::take(&mut self.trait_map);
Expand All @@ -595,11 +601,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {

// Don't hash unless necessary, because it's expensive.
let (opt_hash_including_bodies, attrs_hash) =
self.tcx.hash_owner_nodes(node, &bodies, &attrs);
self.tcx.hash_owner_nodes(node, &bodies, &attrs, &defines);
let num_nodes = self.item_local_id_counter.as_usize();
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash };
let attrs = hir::AttributeMap { map: attrs, defines, opt_hash: attrs_hash };

self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
}
Expand Down Expand Up @@ -847,6 +853,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
debug_assert_eq!(id.owner, self.current_hir_id_owner);
let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)));
debug_assert!(!ret.is_empty());

let defines = &*self.arena.alloc_from_iter(
ret.iter()
.filter(|attr| attr.has_name(sym::defines))
.filter_map(|attr| self.resolver.defines.get(&attr.id))
// TODO: error reporting for non-local items being mentioned and tests that go through these code paths
.flat_map(|defines| defines.into_iter().map(|did| did.expect_local())),
);
trace!(?id, ?ret, ?defines, "lower_attrs");

self.defines.insert(id.local_id, defines);
self.attrs.insert(id.local_id, ret);
ret
}
Expand Down
9 changes: 7 additions & 2 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -941,13 +941,18 @@ pub struct ParentedNode<'tcx> {
#[derive(Debug)]
pub struct AttributeMap<'tcx> {
pub map: SortedMap<ItemLocalId, &'tcx [Attribute]>,
/// Preprocessed `#[defines]` attribute.
pub defines: SortedMap<ItemLocalId, &'tcx [LocalDefId]>,
// Only present when the crate hash is needed.
pub opt_hash: Option<Fingerprint>,
}

impl<'tcx> AttributeMap<'tcx> {
pub const EMPTY: &'static AttributeMap<'static> =
&AttributeMap { map: SortedMap::new(), opt_hash: Some(Fingerprint::ZERO) };
pub const EMPTY: &'static AttributeMap<'static> = &AttributeMap {
map: SortedMap::new(),
defines: SortedMap::new(),
opt_hash: Some(Fingerprint::ZERO),
};

#[inline]
pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir/src/stable_hash_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'

impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
// We ignore the `map` since it refers to information included in `opt_hash` which is
// We ignore the `map` and `defines` since they refer to information included in `opt_hash` which is
// hashed in the collector and used for the crate hash.
let AttributeMap { opt_hash, map: _ } = *self;
let AttributeMap { opt_hash, map: _, defines: _ } = *self;
opt_hash.unwrap().hash_stable(hcx, hasher);
}
}
Expand Down
15 changes: 7 additions & 8 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,19 +518,18 @@ fn best_definition_site_of_opaque<'tcx>(
None
}
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
let scope = tcx.hir().get_defining_scope(tcx.local_def_id_to_hir_id(opaque_def_id));
let found = if scope == hir::CRATE_HIR_ID {
tcx.hir().walk_toplevel_module(&mut locator)
} else {
match tcx.hir_node(scope) {
for (_id, node) in tcx.hir().parent_iter(tcx.local_def_id_to_hir_id(opaque_def_id)) {
return match node {
Node::Item(it) => locator.visit_item(it),
Node::ImplItem(it) => locator.visit_impl_item(it),
Node::TraitItem(it) => locator.visit_trait_item(it),
Node::ForeignItem(it) => locator.visit_foreign_item(it),
other => bug!("{:?} is not a valid scope for an opaque type item", other),
Node::Crate(_) => tcx.hir().walk_toplevel_module(&mut locator),
_ => continue,
}
};
found.break_value()
.break_value();
}
unreachable!()
}
}
}
Expand Down
86 changes: 22 additions & 64 deletions compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
use rustc_errors::StashKey;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def};
use rustc_middle::bug;
use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def, intravisit};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::{bug, span_bug};
use rustc_span::DUMMY_SP;
use tracing::{debug, instrument, trace};

use crate::errors::{TaitForwardCompat, TaitForwardCompat2, UnconstrainedOpaqueType};
use crate::errors::{TaitForwardCompat2, UnconstrainedOpaqueType};

/// Checks "defining uses" of opaque `impl Trait` in associated types.
/// These can only be defined by associated items of the same trait.
Expand Down Expand Up @@ -83,38 +82,9 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
/// ```
#[instrument(skip(tcx), level = "debug")]
pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
let hir_id = tcx.local_def_id_to_hir_id(def_id);
let scope = tcx.hir().get_defining_scope(hir_id);
let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };

debug!(?scope);

if scope == hir::CRATE_HIR_ID {
tcx.hir().walk_toplevel_module(&mut locator);
} else {
trace!("scope={:#?}", tcx.hir_node(scope));
match tcx.hir_node(scope) {
// We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
// This allows our visitor to process the defining item itself, causing
// it to pick up any 'sibling' defining uses.
//
// For example, this code:
// ```
// fn foo() {
// type Blah = impl Debug;
// let my_closure = || -> Blah { true };
// }
// ```
//
// requires us to explicitly process `foo()` in order
// to notice the defining usage of `Blah`.
Node::Item(it) => locator.visit_item(it),
Node::ImplItem(it) => locator.visit_impl_item(it),
Node::TraitItem(it) => locator.visit_trait_item(it),
Node::ForeignItem(it) => locator.visit_foreign_item(it),
other => bug!("{:?} is not a valid scope for an opaque type item", other),
}
}
tcx.hir().walk_toplevel_module(&mut locator);

if let Some(hidden) = locator.found {
// Only check against typeck if we didn't already error
Expand All @@ -138,12 +108,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
span: tcx.def_span(def_id),
name: tcx.item_name(parent_def_id.to_def_id()),
what: match tcx.hir_node(scope) {
_ if scope == hir::CRATE_HIR_ID => "module",
Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl",
_ => "item",
},
what: "crate",
});
Ty::new_error(tcx, reported)
}
Expand Down Expand Up @@ -177,6 +142,13 @@ impl TaitConstraintLocator<'_> {
return;
}

let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
// Don't try to check items that cannot possibly constrain the type.
if opaque_types_defined_by.is_empty() {
debug!("no constraint: no opaque types defined");
return;
}

// Function items with `_` in their return type already emit an error, skip any
// "non-defining use" errors for them.
// Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former
Expand Down Expand Up @@ -216,8 +188,6 @@ impl TaitConstraintLocator<'_> {
return;
}

let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);

let mut constrained = false;
for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
if opaque_type_key.def_id != self.def_id {
Expand All @@ -226,18 +196,12 @@ impl TaitConstraintLocator<'_> {
constrained = true;

if !opaque_types_defined_by.contains(&self.def_id) {
let guar = self.tcx.dcx().emit_err(TaitForwardCompat {
span: hidden_type.span,
item_span: self
.tcx
.def_ident_span(item_def_id)
.unwrap_or_else(|| self.tcx.def_span(item_def_id)),
});
// Avoid "opaque type not constrained" errors on the opaque itself.
self.found = Some(ty::OpaqueHiddenType {
span: DUMMY_SP,
ty: Ty::new_error(self.tcx, guar),
});
span_bug!(
hidden_type.span,
"item registered hidden type {} for {:?}, even though it does not define it",
hidden_type.ty,
opaque_type_key
);
}
let concrete_type =
self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params(
Expand Down Expand Up @@ -311,19 +275,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
if it.owner_id.def_id != self.def_id {
self.check(it.owner_id.def_id);
intravisit::walk_item(self, it);
}
self.check(it.owner_id.def_id);
intravisit::walk_item(self, it);
}
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
if it.owner_id.def_id != self.def_id {
self.check(it.owner_id.def_id);
intravisit::walk_impl_item(self, it);
}
self.check(it.owner_id.def_id);
intravisit::walk_impl_item(self, it);
}
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
trace!(?it.owner_id);
Expand Down
10 changes: 0 additions & 10 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,16 +423,6 @@ pub(crate) struct UnconstrainedOpaqueType {
pub what: &'static str,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_tait_forward_compat)]
#[note]
pub(crate) struct TaitForwardCompat {
#[primary_span]
pub span: Span,
#[note]
pub item_span: Span,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_tait_forward_compat2)]
#[note]
Expand Down
11 changes: 0 additions & 11 deletions compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,17 +657,6 @@ impl<'hir> Map<'hir> {
None
}

/// Returns the defining scope for an opaque type definition.
pub fn get_defining_scope(self, id: HirId) -> HirId {
let mut scope = id;
loop {
scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID);
if scope == CRATE_HIR_ID || !matches!(self.tcx.hir_node(scope), Node::Block(_)) {
return scope;
}
}
}

pub fn get_foreign_abi(self, hir_id: HirId) -> ExternAbi {
let parent = self.get_parent_item(hir_id);
if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) =
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ impl<'tcx> TyCtxt<'tcx> {
node: OwnerNode<'_>,
bodies: &SortedMap<ItemLocalId, &Body<'_>>,
attrs: &SortedMap<ItemLocalId, &[rustc_ast::Attribute]>,
defines: &SortedMap<ItemLocalId, &[LocalDefId]>,
) -> (Option<Fingerprint>, Option<Fingerprint>) {
if self.needs_crate_hash() {
self.with_stable_hashing_context(|mut hcx| {
Expand All @@ -163,6 +164,7 @@ impl<'tcx> TyCtxt<'tcx> {

let mut stable_hasher = StableHasher::new();
attrs.hash_stable(&mut hcx, &mut stable_hasher);
defines.hash_stable(&mut hcx, &mut stable_hasher);
let h2 = stable_hasher.finish();
(Some(h1), Some(h2))
})
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1228,7 +1228,8 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> {
let bodies = Default::default();
let attrs = hir::AttributeMap::EMPTY;

let (opt_hash_including_bodies, _) = self.tcx.hash_owner_nodes(node, &bodies, &attrs.map);
let (opt_hash_including_bodies, _) =
self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, &attrs.defines);
let node = node.into();
self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes {
opt_hash_including_bodies,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ pub struct ResolverAstLowering {

/// Information about functions signatures for delegation items expansion
pub delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,

/// List of resolved `#[defines]` attribute arguments.
pub defines: FxHashMap<ast::AttrId, Vec<DefId>>,
}

#[derive(Debug)]
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ passes_debug_visualizer_placement =
passes_debug_visualizer_unreadable =
couldn't read {$file}: {$error}
passes_defines_not_fn_or_const =
attribute should be applied to a function definition, a closure, a static, or a const
.label = cannot define hidden types
passes_deprecated =
attribute is ignored here
Expand Down
Loading

0 comments on commit cb85e75

Please sign in to comment.