Skip to content

Commit cb85e75

Browse files
committed
Implement #[defines] attribute for consts and functions.
statics still need work
1 parent 2e3f62c commit cb85e75

File tree

601 files changed

+2395
-2596
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

601 files changed

+2395
-2596
lines changed

compiler/rustc_ast/src/attr/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::token::{self, CommentKind, Delimiter, Token};
1919
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenTree};
2020
use crate::util::comments;
2121
use crate::util::literal::escape_string_symbol;
22+
use crate::NodeId;
2223

2324
pub struct MarkedAttrs(GrowableBitSet<AttrId>);
2425

@@ -506,6 +507,16 @@ impl MetaItemKind {
506507
}
507508
}
508509
}
510+
511+
pub fn defines(&self) -> Vec<NodeId> {
512+
match self {
513+
MetaItemKind::Word => vec![],
514+
MetaItemKind::List(things) => {
515+
things.iter().filter_map(|i| Some(i.meta_item()?.path.segments[0].id)).collect()
516+
}
517+
MetaItemKind::NameValue(_) => vec![],
518+
}
519+
}
509520
}
510521

511522
impl MetaItemInner {

compiler/rustc_ast_lowering/src/lib.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ struct LoweringContext<'a, 'hir> {
9595

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

147149
// HirId handling.
148150
bodies: Vec::new(),
151+
defines: SortedMap::default(),
149152
attrs: SortedMap::default(),
150153
children: Vec::default(),
151154
current_hir_id_owner: hir::CRATE_OWNER_ID,
@@ -528,6 +531,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
528531

529532
let current_attrs = std::mem::take(&mut self.attrs);
530533
let current_bodies = std::mem::take(&mut self.bodies);
534+
let current_defines = std::mem::take(&mut self.defines);
531535
let current_ident_and_label_to_local_id =
532536
std::mem::take(&mut self.ident_and_label_to_local_id);
533537

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

562566
self.attrs = current_attrs;
567+
self.defines = current_defines;
563568
self.bodies = current_bodies;
564569
self.ident_and_label_to_local_id = current_ident_and_label_to_local_id;
565570

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

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

596602
// Don't hash unless necessary, because it's expensive.
597603
let (opt_hash_including_bodies, attrs_hash) =
598-
self.tcx.hash_owner_nodes(node, &bodies, &attrs);
604+
self.tcx.hash_owner_nodes(node, &bodies, &attrs, &defines);
599605
let num_nodes = self.item_local_id_counter.as_usize();
600606
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
601607
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
602-
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash };
608+
let attrs = hir::AttributeMap { map: attrs, defines, opt_hash: attrs_hash };
603609

604610
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
605611
}
@@ -847,6 +853,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
847853
debug_assert_eq!(id.owner, self.current_hir_id_owner);
848854
let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)));
849855
debug_assert!(!ret.is_empty());
856+
857+
let defines = &*self.arena.alloc_from_iter(
858+
ret.iter()
859+
.filter(|attr| attr.has_name(sym::defines))
860+
.filter_map(|attr| self.resolver.defines.get(&attr.id))
861+
// TODO: error reporting for non-local items being mentioned and tests that go through these code paths
862+
.flat_map(|defines| defines.into_iter().map(|did| did.expect_local())),
863+
);
864+
trace!(?id, ?ret, ?defines, "lower_attrs");
865+
866+
self.defines.insert(id.local_id, defines);
850867
self.attrs.insert(id.local_id, ret);
851868
ret
852869
}

compiler/rustc_hir/src/hir.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -941,13 +941,18 @@ pub struct ParentedNode<'tcx> {
941941
#[derive(Debug)]
942942
pub struct AttributeMap<'tcx> {
943943
pub map: SortedMap<ItemLocalId, &'tcx [Attribute]>,
944+
/// Preprocessed `#[defines]` attribute.
945+
pub defines: SortedMap<ItemLocalId, &'tcx [LocalDefId]>,
944946
// Only present when the crate hash is needed.
945947
pub opt_hash: Option<Fingerprint>,
946948
}
947949

948950
impl<'tcx> AttributeMap<'tcx> {
949-
pub const EMPTY: &'static AttributeMap<'static> =
950-
&AttributeMap { map: SortedMap::new(), opt_hash: Some(Fingerprint::ZERO) };
951+
pub const EMPTY: &'static AttributeMap<'static> = &AttributeMap {
952+
map: SortedMap::new(),
953+
defines: SortedMap::new(),
954+
opt_hash: Some(Fingerprint::ZERO),
955+
};
951956

952957
#[inline]
953958
pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {

compiler/rustc_hir/src/stable_hash_impls.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'
100100

101101
impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> {
102102
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
103-
// We ignore the `map` since it refers to information included in `opt_hash` which is
103+
// We ignore the `map` and `defines` since they refer to information included in `opt_hash` which is
104104
// hashed in the collector and used for the crate hash.
105-
let AttributeMap { opt_hash, map: _ } = *self;
105+
let AttributeMap { opt_hash, map: _, defines: _ } = *self;
106106
opt_hash.unwrap().hash_stable(hcx, hasher);
107107
}
108108
}

compiler/rustc_hir_analysis/src/check/check.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -518,19 +518,18 @@ fn best_definition_site_of_opaque<'tcx>(
518518
None
519519
}
520520
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
521-
let scope = tcx.hir().get_defining_scope(tcx.local_def_id_to_hir_id(opaque_def_id));
522-
let found = if scope == hir::CRATE_HIR_ID {
523-
tcx.hir().walk_toplevel_module(&mut locator)
524-
} else {
525-
match tcx.hir_node(scope) {
521+
for (_id, node) in tcx.hir().parent_iter(tcx.local_def_id_to_hir_id(opaque_def_id)) {
522+
return match node {
526523
Node::Item(it) => locator.visit_item(it),
527524
Node::ImplItem(it) => locator.visit_impl_item(it),
528525
Node::TraitItem(it) => locator.visit_trait_item(it),
529526
Node::ForeignItem(it) => locator.visit_foreign_item(it),
530-
other => bug!("{:?} is not a valid scope for an opaque type item", other),
527+
Node::Crate(_) => tcx.hir().walk_toplevel_module(&mut locator),
528+
_ => continue,
531529
}
532-
};
533-
found.break_value()
530+
.break_value();
531+
}
532+
unreachable!()
534533
}
535534
}
536535
}

compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs

+22-64
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
use rustc_errors::StashKey;
22
use rustc_hir::def::DefKind;
33
use rustc_hir::def_id::LocalDefId;
4-
use rustc_hir::intravisit::{self, Visitor};
5-
use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def};
6-
use rustc_middle::bug;
4+
use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def, intravisit};
75
use rustc_middle::hir::nested_filter;
86
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
7+
use rustc_middle::{bug, span_bug};
98
use rustc_span::DUMMY_SP;
109
use tracing::{debug, instrument, trace};
1110

12-
use crate::errors::{TaitForwardCompat, TaitForwardCompat2, UnconstrainedOpaqueType};
11+
use crate::errors::{TaitForwardCompat2, UnconstrainedOpaqueType};
1312

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

90-
debug!(?scope);
91-
92-
if scope == hir::CRATE_HIR_ID {
93-
tcx.hir().walk_toplevel_module(&mut locator);
94-
} else {
95-
trace!("scope={:#?}", tcx.hir_node(scope));
96-
match tcx.hir_node(scope) {
97-
// We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
98-
// This allows our visitor to process the defining item itself, causing
99-
// it to pick up any 'sibling' defining uses.
100-
//
101-
// For example, this code:
102-
// ```
103-
// fn foo() {
104-
// type Blah = impl Debug;
105-
// let my_closure = || -> Blah { true };
106-
// }
107-
// ```
108-
//
109-
// requires us to explicitly process `foo()` in order
110-
// to notice the defining usage of `Blah`.
111-
Node::Item(it) => locator.visit_item(it),
112-
Node::ImplItem(it) => locator.visit_impl_item(it),
113-
Node::TraitItem(it) => locator.visit_trait_item(it),
114-
Node::ForeignItem(it) => locator.visit_foreign_item(it),
115-
other => bug!("{:?} is not a valid scope for an opaque type item", other),
116-
}
117-
}
87+
tcx.hir().walk_toplevel_module(&mut locator);
11888

11989
if let Some(hidden) = locator.found {
12090
// Only check against typeck if we didn't already error
@@ -138,12 +108,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
138108
let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
139109
span: tcx.def_span(def_id),
140110
name: tcx.item_name(parent_def_id.to_def_id()),
141-
what: match tcx.hir_node(scope) {
142-
_ if scope == hir::CRATE_HIR_ID => "module",
143-
Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
144-
Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl",
145-
_ => "item",
146-
},
111+
what: "crate",
147112
});
148113
Ty::new_error(tcx, reported)
149114
}
@@ -177,6 +142,13 @@ impl TaitConstraintLocator<'_> {
177142
return;
178143
}
179144

145+
let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
146+
// Don't try to check items that cannot possibly constrain the type.
147+
if opaque_types_defined_by.is_empty() {
148+
debug!("no constraint: no opaque types defined");
149+
return;
150+
}
151+
180152
// Function items with `_` in their return type already emit an error, skip any
181153
// "non-defining use" errors for them.
182154
// Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former
@@ -216,8 +188,6 @@ impl TaitConstraintLocator<'_> {
216188
return;
217189
}
218190

219-
let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
220-
221191
let mut constrained = false;
222192
for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
223193
if opaque_type_key.def_id != self.def_id {
@@ -226,18 +196,12 @@ impl TaitConstraintLocator<'_> {
226196
constrained = true;
227197

228198
if !opaque_types_defined_by.contains(&self.def_id) {
229-
let guar = self.tcx.dcx().emit_err(TaitForwardCompat {
230-
span: hidden_type.span,
231-
item_span: self
232-
.tcx
233-
.def_ident_span(item_def_id)
234-
.unwrap_or_else(|| self.tcx.def_span(item_def_id)),
235-
});
236-
// Avoid "opaque type not constrained" errors on the opaque itself.
237-
self.found = Some(ty::OpaqueHiddenType {
238-
span: DUMMY_SP,
239-
ty: Ty::new_error(self.tcx, guar),
240-
});
199+
span_bug!(
200+
hidden_type.span,
201+
"item registered hidden type {} for {:?}, even though it does not define it",
202+
hidden_type.ty,
203+
opaque_type_key
204+
);
241205
}
242206
let concrete_type =
243207
self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params(
@@ -311,19 +275,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
311275
}
312276
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
313277
trace!(?it.owner_id);
314-
// The opaque type itself or its children are not within its reveal scope.
315-
if it.owner_id.def_id != self.def_id {
316-
self.check(it.owner_id.def_id);
317-
intravisit::walk_item(self, it);
318-
}
278+
self.check(it.owner_id.def_id);
279+
intravisit::walk_item(self, it);
319280
}
320281
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
321282
trace!(?it.owner_id);
322-
// The opaque type itself or its children are not within its reveal scope.
323-
if it.owner_id.def_id != self.def_id {
324-
self.check(it.owner_id.def_id);
325-
intravisit::walk_impl_item(self, it);
326-
}
283+
self.check(it.owner_id.def_id);
284+
intravisit::walk_impl_item(self, it);
327285
}
328286
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
329287
trace!(?it.owner_id);

compiler/rustc_hir_analysis/src/errors.rs

-10
Original file line numberDiff line numberDiff line change
@@ -423,16 +423,6 @@ pub(crate) struct UnconstrainedOpaqueType {
423423
pub what: &'static str,
424424
}
425425

426-
#[derive(Diagnostic)]
427-
#[diag(hir_analysis_tait_forward_compat)]
428-
#[note]
429-
pub(crate) struct TaitForwardCompat {
430-
#[primary_span]
431-
pub span: Span,
432-
#[note]
433-
pub item_span: Span,
434-
}
435-
436426
#[derive(Diagnostic)]
437427
#[diag(hir_analysis_tait_forward_compat2)]
438428
#[note]

compiler/rustc_middle/src/hir/map/mod.rs

-11
Original file line numberDiff line numberDiff line change
@@ -657,17 +657,6 @@ impl<'hir> Map<'hir> {
657657
None
658658
}
659659

660-
/// Returns the defining scope for an opaque type definition.
661-
pub fn get_defining_scope(self, id: HirId) -> HirId {
662-
let mut scope = id;
663-
loop {
664-
scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID);
665-
if scope == CRATE_HIR_ID || !matches!(self.tcx.hir_node(scope), Node::Block(_)) {
666-
return scope;
667-
}
668-
}
669-
}
670-
671660
pub fn get_foreign_abi(self, hir_id: HirId) -> ExternAbi {
672661
let parent = self.get_parent_item(hir_id);
673662
if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) =

compiler/rustc_middle/src/hir/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ impl<'tcx> TyCtxt<'tcx> {
152152
node: OwnerNode<'_>,
153153
bodies: &SortedMap<ItemLocalId, &Body<'_>>,
154154
attrs: &SortedMap<ItemLocalId, &[rustc_ast::Attribute]>,
155+
defines: &SortedMap<ItemLocalId, &[LocalDefId]>,
155156
) -> (Option<Fingerprint>, Option<Fingerprint>) {
156157
if self.needs_crate_hash() {
157158
self.with_stable_hashing_context(|mut hcx| {
@@ -163,6 +164,7 @@ impl<'tcx> TyCtxt<'tcx> {
163164

164165
let mut stable_hasher = StableHasher::new();
165166
attrs.hash_stable(&mut hcx, &mut stable_hasher);
167+
defines.hash_stable(&mut hcx, &mut stable_hasher);
166168
let h2 = stable_hasher.finish();
167169
(Some(h1), Some(h2))
168170
})

compiler/rustc_middle/src/ty/context.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1228,7 +1228,8 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> {
12281228
let bodies = Default::default();
12291229
let attrs = hir::AttributeMap::EMPTY;
12301230

1231-
let (opt_hash_including_bodies, _) = self.tcx.hash_owner_nodes(node, &bodies, &attrs.map);
1231+
let (opt_hash_including_bodies, _) =
1232+
self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, &attrs.defines);
12321233
let node = node.into();
12331234
self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes {
12341235
opt_hash_including_bodies,

compiler/rustc_middle/src/ty/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ pub struct ResolverAstLowering {
213213

214214
/// Information about functions signatures for delegation items expansion
215215
pub delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
216+
217+
/// List of resolved `#[defines]` attribute arguments.
218+
pub defines: FxHashMap<ast::AttrId, Vec<DefId>>,
216219
}
217220

218221
#[derive(Debug)]

compiler/rustc_passes/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ passes_debug_visualizer_placement =
137137
passes_debug_visualizer_unreadable =
138138
couldn't read {$file}: {$error}
139139
140+
passes_defines_not_fn_or_const =
141+
attribute should be applied to a function definition, a closure, a static, or a const
142+
.label = cannot define hidden types
143+
140144
passes_deprecated =
141145
attribute is ignored here
142146

0 commit comments

Comments
 (0)