Skip to content

Commit 1907ecc

Browse files
committed
Implement #[defines] attribute for consts and functions.
statics still need work
1 parent 17d35ca commit 1907ecc

File tree

606 files changed

+2209
-1942
lines changed

Some content is hidden

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

606 files changed

+2209
-1942
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

@@ -501,6 +502,16 @@ impl MetaItemKind {
501502
},
502503
}
503504
}
505+
506+
pub fn defines(&self) -> Vec<NodeId> {
507+
match self {
508+
MetaItemKind::Word => vec![],
509+
MetaItemKind::List(things) => {
510+
things.iter().filter_map(|i| Some(i.meta_item()?.path.segments[0].id)).collect()
511+
}
512+
MetaItemKind::NameValue(_) => vec![],
513+
}
514+
}
504515
}
505516

506517
impl MetaItemInner {

compiler/rustc_ast_lowering/src/lib.rs

+31-2
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ struct LoweringContext<'a, 'hir> {
9393

9494
/// Bodies inside the owner being lowered.
9595
bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
96+
/// Bodies inside the owner being lowered.
97+
defines: SortedMap<hir::ItemLocalId, &'hir [LocalDefId]>,
9698
/// Attributes inside the owner being lowered.
9799
attrs: SortedMap<hir::ItemLocalId, &'hir [hir::Attribute]>,
98100
/// Collect items that were created by lowering the current owner.
@@ -144,6 +146,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
144146

145147
// HirId handling.
146148
bodies: Vec::new(),
149+
defines: SortedMap::default(),
147150
attrs: SortedMap::default(),
148151
children: Vec::default(),
149152
current_hir_id_owner: hir::CRATE_OWNER_ID,
@@ -533,6 +536,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
533536

534537
let current_attrs = std::mem::take(&mut self.attrs);
535538
let current_bodies = std::mem::take(&mut self.bodies);
539+
let current_defines = std::mem::take(&mut self.defines);
536540
let current_ident_and_label_to_local_id =
537541
std::mem::take(&mut self.ident_and_label_to_local_id);
538542

@@ -565,6 +569,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
565569
let info = self.make_owner_info(item);
566570

567571
self.attrs = current_attrs;
572+
self.defines = current_defines;
568573
self.bodies = current_bodies;
569574
self.ident_and_label_to_local_id = current_ident_and_label_to_local_id;
570575

@@ -583,6 +588,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
583588
}
584589

585590
fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
591+
let defines = std::mem::take(&mut self.defines);
586592
let attrs = std::mem::take(&mut self.attrs);
587593
let mut bodies = std::mem::take(&mut self.bodies);
588594
let trait_map = std::mem::take(&mut self.trait_map);
@@ -600,11 +606,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
600606

601607
// Don't hash unless necessary, because it's expensive.
602608
let (opt_hash_including_bodies, attrs_hash) =
603-
self.tcx.hash_owner_nodes(node, &bodies, &attrs);
609+
self.tcx.hash_owner_nodes(node, &bodies, &attrs, &defines);
604610
let num_nodes = self.item_local_id_counter.as_usize();
605611
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
606612
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
607-
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash };
613+
let attrs = hir::AttributeMap { map: attrs, defines, opt_hash: attrs_hash };
608614

609615
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
610616
}
@@ -852,6 +858,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
852858
debug_assert_eq!(id.owner, self.current_hir_id_owner);
853859
let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)));
854860
debug_assert!(!ret.is_empty());
861+
862+
let mut defines = None;
863+
for attr in ret.iter() {
864+
if !attr.has_name(sym::defines) {
865+
continue;
866+
}
867+
let defines = defines.get_or_insert_with(Vec::new);
868+
869+
// TODO: error reporting for non-local items being mentioned and tests that go through these code paths
870+
defines.extend(
871+
self.resolver
872+
.defines
873+
.get(&attr.id)
874+
.into_iter()
875+
.flatten()
876+
.map(|did| did.expect_local()),
877+
);
878+
}
879+
trace!(?id, ?ret, ?defines, "lower_attrs");
880+
881+
if let Some(defines) = defines {
882+
self.defines.insert(id.local_id, &*self.arena.alloc_from_iter(defines));
883+
}
855884
self.attrs.insert(id.local_id, ret);
856885
ret
857886
}

compiler/rustc_hir/src/hir.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1188,13 +1188,18 @@ impl Attribute {
11881188
#[derive(Debug)]
11891189
pub struct AttributeMap<'tcx> {
11901190
pub map: SortedMap<ItemLocalId, &'tcx [Attribute]>,
1191+
/// Preprocessed `#[defines]` attribute.
1192+
pub defines: SortedMap<ItemLocalId, &'tcx [LocalDefId]>,
11911193
// Only present when the crate hash is needed.
11921194
pub opt_hash: Option<Fingerprint>,
11931195
}
11941196

11951197
impl<'tcx> AttributeMap<'tcx> {
1196-
pub const EMPTY: &'static AttributeMap<'static> =
1197-
&AttributeMap { map: SortedMap::new(), opt_hash: Some(Fingerprint::ZERO) };
1198+
pub const EMPTY: &'static AttributeMap<'static> = &AttributeMap {
1199+
map: SortedMap::new(),
1200+
defines: SortedMap::new(),
1201+
opt_hash: Some(Fingerprint::ZERO),
1202+
};
11981203

11991204
#[inline]
12001205
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
@@ -102,9 +102,9 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'
102102

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

compiler/rustc_hir_analysis/src/check/check.rs

+7-13
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,12 @@ fn best_definition_site_of_opaque<'tcx>(
459459
return ControlFlow::Continue(());
460460
}
461461

462+
let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
463+
// Don't try to check items that cannot possibly constrain the type.
464+
if !opaque_types_defined_by.contains(&self.opaque_def_id) {
465+
return ControlFlow::Continue(());
466+
}
467+
462468
if let Some(hidden_ty) =
463469
self.tcx.mir_borrowck(item_def_id).concrete_opaque_types.get(&self.opaque_def_id)
464470
{
@@ -518,19 +524,7 @@ fn best_definition_site_of_opaque<'tcx>(
518524
None
519525
}
520526
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) {
526-
Node::Item(it) => locator.visit_item(it),
527-
Node::ImplItem(it) => locator.visit_impl_item(it),
528-
Node::TraitItem(it) => locator.visit_trait_item(it),
529-
Node::ForeignItem(it) => locator.visit_foreign_item(it),
530-
other => bug!("{:?} is not a valid scope for an opaque type item", other),
531-
}
532-
};
533-
found.break_value()
527+
tcx.hir().walk_toplevel_module(&mut locator).break_value()
534528
}
535529
}
536530
}

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

+15-65
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};
4+
use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def, intravisit};
65
use rustc_middle::bug;
76
use rustc_middle::hir::nested_filter;
87
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
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.contains(&self.def_id) {
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,29 +188,13 @@ 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 {
224194
continue;
225195
}
226196
constrained = true;
227197

228-
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-
});
241-
}
242198
let concrete_type =
243199
self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params(
244200
opaque_type_key,
@@ -311,19 +267,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
311267
}
312268
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
313269
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-
}
270+
self.check(it.owner_id.def_id);
271+
intravisit::walk_item(self, it);
319272
}
320273
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
321274
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-
}
275+
self.check(it.owner_id.def_id);
276+
intravisit::walk_impl_item(self, it);
327277
}
328278
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
329279
trace!(?it.owner_id);

compiler/rustc_hir_analysis/src/errors.rs

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

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

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

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

659-
/// Returns the defining scope for an opaque type definition.
660-
pub fn get_defining_scope(self, id: HirId) -> HirId {
661-
let mut scope = id;
662-
loop {
663-
scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID);
664-
if scope == CRATE_HIR_ID || !matches!(self.tcx.hir_node(scope), Node::Block(_)) {
665-
return scope;
666-
}
667-
}
668-
}
669-
670659
pub fn get_foreign_abi(self, hir_id: HirId) -> ExternAbi {
671660
let parent = self.get_parent_item(hir_id);
672661
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, &[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
@@ -1231,7 +1231,8 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> {
12311231
let bodies = Default::default();
12321232
let attrs = hir::AttributeMap::EMPTY;
12331233

1234-
let (opt_hash_including_bodies, _) = self.tcx.hash_owner_nodes(node, &bodies, &attrs.map);
1234+
let (opt_hash_including_bodies, _) =
1235+
self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, &attrs.defines);
12351236
let node = node.into();
12361237
self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes {
12371238
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)