1#![allow(incomplete_features)]
2#![feature(rustc_private, specialization, if_let_guard)]
3
4extern crate rustc_ast;
5extern crate rustc_data_structures;
6extern crate rustc_errors;
7extern crate rustc_hir;
8extern crate rustc_macros;
9extern crate rustc_metadata;
10extern crate rustc_middle;
11extern crate rustc_serialize;
12extern crate rustc_session;
13extern crate rustc_span;
14
15mod decoder;
16mod encoder;
17
18const TAG_FULL_SPAN: u8 = 0;
20const TAG_PARTIAL_SPAN: u8 = 1;
21
22use std::{hash::Hash, path::PathBuf, rc::Rc};
23
24use decoder::decode_crate_metadata;
25use derive_where::derive_where;
26use flux_errors::FluxSession;
27use flux_macros::fluent_messages;
28use flux_middle::{
29 PanicSpec,
30 call_graph::NodeKey,
31 cstore::{CrateStore, OptResult},
32 def_id::{FluxDefId, FluxId},
33 fhir,
34 global_env::GlobalEnv,
35 queries::QueryResult,
36 rty,
37};
38use rustc_data_structures::{
39 fx::FxHashMap,
40 unord::{ExtendUnord, UnordMap, UnordSet},
41};
42use rustc_hir::{
43 def::{CtorKind, DefKind},
44 def_id::{LOCAL_CRATE, LocalDefId},
45};
46use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
47use rustc_middle::ty::TyCtxt;
48use rustc_session::config::OutFileName;
49use rustc_span::{
50 SourceFile, Span, StableSourceFileId,
51 def_id::{CrateNum, DefId, DefIndex, StableCrateId},
52};
53
54pub use crate::encoder::encode_metadata;
55
56fluent_messages! { "../locales/en-US.ftl" }
57
58const METADATA_VERSION: u8 = 0;
59const METADATA_HEADER: &[u8] = &[b'f', b'l', b'u', b'x', 0, 0, 0, METADATA_VERSION];
60
61#[derive(Default)]
62pub struct CStore<'tcx> {
63 local_tables: UnordMap<CrateNum, Tables<'tcx, DefIndex>>,
64 extern_tables: Tables<'tcx, DefId>,
65}
66
67#[derive(Encodable, Decodable, Clone, Debug)]
74struct EncodedSourceFileId {
75 stable_source_file_id: StableSourceFileId,
76 stable_crate_id: StableCrateId,
77}
78
79impl EncodedSourceFileId {
80 #[inline]
81 fn new(tcx: TyCtxt<'_>, file: &SourceFile) -> EncodedSourceFileId {
82 EncodedSourceFileId {
83 stable_source_file_id: file.stable_id,
84 stable_crate_id: tcx.stable_crate_id(file.cnum),
85 }
86 }
87}
88
89#[derive(Default, Decodable, Encodable)]
91pub struct Footer {
92 file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
93 syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
94 expn_data: FxHashMap<(StableCrateId, u32), AbsoluteBytePos>,
95}
96#[derive(Encodable, Decodable, Eq, PartialEq, Hash, Clone, Copy, Debug)]
97struct SourceFileIndex(u32);
98
99#[derive(Encodable, Decodable, Clone, Copy)]
100pub struct AbsoluteBytePos(u64);
101
102impl AbsoluteBytePos {
103 fn new(pos: usize) -> AbsoluteBytePos {
104 AbsoluteBytePos(pos.try_into().unwrap())
105 }
106
107 fn to_usize(self) -> usize {
108 self.0 as usize
109 }
110}
111
112#[derive(Default, TyEncodable, TyDecodable)]
113pub struct CrateMetadata<'tcx> {
114 local_tables: Tables<'tcx, DefIndex>,
115 extern_tables: Tables<'tcx, DefId>,
116}
117
118trait Key {
121 type KeyIndex;
122 fn crate_num(self) -> CrateNum;
123 fn to_index(self) -> Self::KeyIndex;
124 fn name(self, tcx: TyCtxt) -> String;
125}
126
127impl Key for DefId {
128 type KeyIndex = DefIndex;
129
130 fn crate_num(self) -> CrateNum {
131 self.krate
132 }
133
134 fn to_index(self) -> Self::KeyIndex {
135 self.index
136 }
137
138 fn name(self, tcx: TyCtxt) -> String {
139 tcx.def_path_str(self)
140 }
141}
142
143impl Key for FluxDefId {
144 type KeyIndex = FluxId<DefIndex>;
145
146 fn crate_num(self) -> CrateNum {
147 self.parent().krate
148 }
149
150 fn to_index(self) -> Self::KeyIndex {
151 self.index()
152 }
153
154 fn name(self, tcx: TyCtxt) -> String {
155 format!("{}::{}", tcx.def_path_str(self.parent()), self.name())
156 }
157}
158
159#[derive_where(Default)]
160#[derive(TyEncodable, TyDecodable)]
161pub struct Tables<'tcx, K: Eq + Hash> {
162 generics_of: UnordMap<K, QueryResult<rty::Generics>>,
163 refinement_generics_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::RefinementGenerics>>>,
164 predicates_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::GenericPredicates>>>,
165 item_bounds: UnordMap<K, QueryResult<rty::EarlyBinder<rty::Clauses>>>,
166 assoc_refinements_of: UnordMap<K, QueryResult<rty::AssocRefinements>>,
167 assoc_refinements_def: UnordMap<FluxId<K>, QueryResult<rty::EarlyBinder<rty::Lambda>>>,
168 default_assoc_refinements_def:
169 UnordMap<FluxId<K>, QueryResult<Option<rty::EarlyBinder<rty::Lambda>>>>,
170 sort_of_assoc_reft: UnordMap<FluxId<K>, QueryResult<rty::EarlyBinder<rty::FuncSort>>>,
171 fn_sig: UnordMap<K, QueryResult<rty::EarlyBinder<rty::PolyFnSig>>>,
172 adt_def: UnordMap<K, QueryResult<rty::AdtDef>>,
173 constant_info: UnordMap<K, QueryResult<rty::ConstantInfo>>,
174 static_info: UnordMap<K, QueryResult<rty::StaticInfo>>,
175 adt_sort_def: UnordMap<K, QueryResult<rty::AdtSortDef>>,
176 variants_of: UnordMap<K, QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>>>,
177 type_of: UnordMap<K, QueryResult<rty::EarlyBinder<rty::TyOrCtor>>>,
178 normalized_defns: Rc<rty::NormalizedDefns>,
179 flux_module_children: UnordMap<K, Vec<fhir::FluxModChild>>,
180 func_sort: UnordMap<FluxId<K>, rty::PolyFuncSort>,
181 func_span: UnordMap<FluxId<K>, Span>,
182 sort_decl_param_count: UnordMap<FluxId<K>, usize>,
183 no_panic: UnordMap<K, bool>,
184 assume_parametric_params: UnordMap<K, UnordSet<u32>>,
185 spec_attr_span: UnordMap<K, Span>,
186 no_panic_specs: UnordMap<NodeKey<'tcx>, PanicSpec>,
187}
188
189impl<'tcx> CStore<'tcx> {
190 pub fn load(tcx: TyCtxt<'tcx>, sess: &FluxSession) -> Self {
191 let mut cstore = CStore::default();
192 for crate_num in tcx.used_crates(()) {
193 let Some(path) = flux_metadata_extern_location(tcx, *crate_num) else { continue };
194 let Some(meta) = decode_crate_metadata(tcx, sess, path.as_path()) else { continue };
195 cstore.local_tables.insert(*crate_num, meta.local_tables);
196 cstore.merge_extern_tables(tcx, sess, meta.extern_tables);
197 }
198 cstore
199 }
200
201 fn merge_extern_tables(
202 &mut self,
203 tcx: TyCtxt,
204 sess: &FluxSession,
205 extern_tables: Tables<'tcx, DefId>,
206 ) {
207 macro_rules! merge_extern_table {
208 ($self:expr, $tcx:expr, $table:ident, $extern_tables:expr) => {{
209 $extern_tables.$table.keys().map(|k| {
212 if self.$table(*k).is_some() {
213 sess.emit_fatal(errors::DuplicateSpec::new($tcx, *k));
214 }
215 });
216 $self
217 .extern_tables
218 .$table
219 .extend_unord(extern_tables.$table.into_items());
220 }};
221 }
222 merge_extern_table!(self, tcx, generics_of, extern_tables);
223 merge_extern_table!(self, tcx, refinement_generics_of, extern_tables);
224 merge_extern_table!(self, tcx, predicates_of, extern_tables);
225 merge_extern_table!(self, tcx, item_bounds, extern_tables);
226 merge_extern_table!(self, tcx, assoc_refinements_of, extern_tables);
227 merge_extern_table!(self, tcx, default_assoc_refinements_def, extern_tables);
228 merge_extern_table!(self, tcx, assoc_refinements_def, extern_tables);
229 merge_extern_table!(self, tcx, sort_of_assoc_reft, extern_tables);
230 merge_extern_table!(self, tcx, fn_sig, extern_tables);
231 merge_extern_table!(self, tcx, adt_def, extern_tables);
232 merge_extern_table!(self, tcx, adt_sort_def, extern_tables);
233 merge_extern_table!(self, tcx, variants_of, extern_tables);
234 merge_extern_table!(self, tcx, type_of, extern_tables);
235 merge_extern_table!(self, tcx, no_panic, extern_tables);
236 merge_extern_table!(self, tcx, assume_parametric_params, extern_tables);
237 merge_extern_table!(self, tcx, spec_attr_span, extern_tables);
238 merge_extern_table!(self, tcx, static_info, extern_tables);
239 }
240}
241
242macro_rules! get {
243 ($self:expr, $table:ident, $key:expr) => {{
244 let key = $key;
245 let this = $self;
246 if let Some(tables) = this.local_tables.get(&key.crate_num()) {
247 tables.$table.get(&key.to_index()).cloned()
248 } else {
249 this.extern_tables.$table.get(&key).cloned()
250 }
251 }};
252}
253
254macro_rules! get_ref {
256 ($self:expr, $table:ident, $key:expr) => {{
257 let key = $key;
258 let this = $self;
259 if let Some(tables) = this.local_tables.get(&key.crate_num()) {
260 tables.$table.get(&key.to_index())
261 } else {
262 this.extern_tables.$table.get(&key)
263 }
264 }};
265}
266
267impl<'tcx> CrateStore<'tcx> for CStore<'tcx> {
268 fn fn_sig(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::PolyFnSig>> {
269 get!(self, fn_sig, def_id)
270 }
271
272 fn adt_def(&self, def_id: DefId) -> OptResult<rty::AdtDef> {
273 get!(self, adt_def, def_id)
274 }
275
276 fn adt_sort_def(&self, def_id: DefId) -> OptResult<rty::AdtSortDef> {
277 get!(self, adt_sort_def, def_id)
278 }
279
280 fn no_panic(&self, def_id: DefId) -> Option<bool> {
281 get!(self, no_panic, def_id)
282 }
283
284 fn assume_parametric_params(&self, def_id: DefId) -> Option<UnordSet<u32>> {
285 get!(self, assume_parametric_params, def_id)
286 }
287
288 fn variants_of(
289 &self,
290 def_id: DefId,
291 ) -> OptResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
292 get!(self, variants_of, def_id)
293 }
294
295 fn type_of(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::TyOrCtor>> {
296 get!(self, type_of, def_id)
297 }
298
299 fn generics_of(&self, def_id: DefId) -> OptResult<rty::Generics> {
300 get!(self, generics_of, def_id)
301 }
302
303 fn refinement_generics_of(
304 &self,
305 def_id: DefId,
306 ) -> OptResult<rty::EarlyBinder<rty::RefinementGenerics>> {
307 get!(self, refinement_generics_of, def_id)
308 }
309
310 fn item_bounds(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::Clauses>> {
311 get!(self, item_bounds, def_id)
312 }
313
314 fn predicates_of(&self, def_id: DefId) -> OptResult<rty::EarlyBinder<rty::GenericPredicates>> {
315 get!(self, predicates_of, def_id)
316 }
317
318 fn assoc_refinements_of(&self, def_id: DefId) -> OptResult<rty::AssocRefinements> {
319 get!(self, assoc_refinements_of, def_id)
320 }
321
322 fn assoc_refinements_def(&self, key: FluxDefId) -> OptResult<rty::EarlyBinder<rty::Lambda>> {
323 get!(self, assoc_refinements_def, key)
324 }
325
326 fn default_assoc_refinements_def(
327 &self,
328 key: FluxDefId,
329 ) -> OptResult<Option<rty::EarlyBinder<rty::Lambda>>> {
330 get!(self, default_assoc_refinements_def, key)
331 }
332
333 fn sort_of_assoc_reft(&self, key: FluxDefId) -> OptResult<rty::EarlyBinder<rty::FuncSort>> {
334 get!(self, sort_of_assoc_reft, key)
335 }
336
337 fn constant_info(&self, key: DefId) -> OptResult<rty::ConstantInfo> {
338 get!(self, constant_info, key)
339 }
340
341 fn static_info(&self, key: DefId) -> OptResult<rty::StaticInfo> {
342 get!(self, static_info, key)
343 }
344
345 fn normalized_defns(&self, krate: CrateNum) -> std::rc::Rc<rty::NormalizedDefns> {
346 self.local_tables[&krate].normalized_defns.clone()
347 }
348
349 fn flux_module_children(&self, def_id: DefId) -> Option<&[fhir::FluxModChild]> {
350 get_ref!(self, flux_module_children, def_id).map(Vec::as_slice)
351 }
352
353 fn inferred_no_panic(&self, krate: CrateNum) -> Rc<UnordMap<NodeKey<'tcx>, PanicSpec>> {
354 Rc::new(
358 self.local_tables
359 .get(&krate)
360 .map(|t| t.no_panic_specs.clone())
361 .unwrap_or_default(),
362 )
363 }
364
365 fn has_crate(&self, krate: CrateNum) -> bool {
366 self.local_tables.contains_key(&krate)
367 }
368
369 fn func_sort(&self, key: FluxDefId) -> Option<rty::PolyFuncSort> {
370 get!(self, func_sort, key)
371 }
372
373 fn func_span(&self, key: FluxDefId) -> Option<Span> {
374 get!(self, func_span, key)
375 }
376
377 fn sort_decl_param_count(&self, key: FluxDefId) -> Option<usize> {
378 get!(self, sort_decl_param_count, key)
379 }
380
381 fn spec_attr_span(&self, def_id: DefId) -> Option<Span> {
382 get!(self, spec_attr_span, def_id)
383 }
384}
385
386impl<'tcx> CrateMetadata<'tcx> {
387 #[allow(
388 clippy::disallowed_methods,
389 reason = "we seed the call graph with non-dummy local def ids, so the traversal should never reach dummy extern spec items."
390 )]
391 fn new(genv: GlobalEnv<'_, 'tcx>) -> Self {
392 let mut local_tables = Tables::default();
393 encode_def_ids(
394 genv,
395 genv.iter_local_def_id().map(LocalDefId::to_def_id),
396 &mut local_tables,
397 DefId::to_index,
398 FluxDefId::to_index,
399 );
400 encode_flux_defs(genv, &mut local_tables);
401 local_tables.no_panic_specs = genv
406 .inferred_no_panic_local()
407 .items()
408 .filter(|(key, _)| key.is_local_item())
409 .map(|(key, spec)| (*key, *spec))
410 .collect();
411
412 let mut extern_tables = Tables::default();
413 encode_def_ids(
414 genv,
415 genv.iter_extern_def_id(),
416 &mut extern_tables,
417 |def_id| def_id,
418 |flux_id| flux_id,
419 );
420
421 CrateMetadata { local_tables, extern_tables }
422 }
423}
424
425fn encode_flux_defs<'tcx>(genv: GlobalEnv<'_, 'tcx>, tables: &mut Tables<'tcx, DefIndex>) {
426 tables.normalized_defns = genv.normalized_defns(LOCAL_CRATE);
427
428 encode_flux_module_children(genv, tables);
429 for (def_id, item) in genv.fhir_iter_flux_items() {
430 match item {
431 fhir::FluxItem::Func(spec_func) => {
432 tables
433 .func_sort
434 .insert(def_id.local_def_index(), genv.func_sort(def_id));
435 tables
436 .func_span
437 .insert(def_id.local_def_index(), spec_func.ident_span);
438 }
439 fhir::FluxItem::SortDecl(_sort_decl) => {
440 tables
441 .sort_decl_param_count
442 .insert(def_id.local_def_index(), genv.sort_decl_param_count(def_id));
443 }
444 fhir::FluxItem::PrimOpProp(_) | fhir::FluxItem::Qualifier(_) => {}
445 }
446 }
447}
448
449#[allow(clippy::disallowed_methods, reason = "`flux_items_by_parent` is the source of truth")]
450fn encode_flux_module_children<'tcx>(
451 genv: GlobalEnv<'_, 'tcx>,
452 tables: &mut Tables<'tcx, DefIndex>,
453) {
454 let specs = genv.collect_specs();
455 for parent in specs.flux_items_by_parent.keys() {
456 let children = genv.flux_module_children(parent.def_id.to_def_id());
457 tables
458 .flux_module_children
459 .insert(parent.def_id.local_def_index, children.to_vec());
460 }
461}
462
463fn encode_def_ids<'tcx, K: Eq + Hash + Copy>(
464 genv: GlobalEnv<'_, 'tcx>,
465 def_ids: impl IntoIterator<Item = DefId>,
466 tables: &mut Tables<'tcx, K>,
467 did_to_key: fn(DefId) -> K,
468 assoc_id_to_key: fn(FluxDefId) -> FluxId<K>,
469) {
470 for def_id in def_ids {
471 let def_kind = genv.def_kind(def_id);
472 let key = did_to_key(def_id);
473
474 match def_kind {
475 DefKind::Trait => {
476 tables
477 .generics_of
478 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
479 tables
480 .predicates_of
481 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
482 tables.refinement_generics_of.insert(
483 key,
484 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
485 );
486 let assocs = genv.run_query_if_reached(def_id, GlobalEnv::assoc_refinements_of);
487 if let Ok(assocs) = &assocs {
488 for assoc_reft in &assocs.items {
489 let def_id = assoc_reft.def_id();
490 let key = assoc_id_to_key(def_id);
491 tables.default_assoc_refinements_def.insert(
492 key,
493 genv.run_query_if_reached(
494 def_id,
495 GlobalEnv::default_assoc_refinement_body,
496 ),
497 );
498 tables.sort_of_assoc_reft.insert(
499 key,
500 genv.run_query_if_reached(def_id, GlobalEnv::sort_of_assoc_reft),
501 );
502 }
503 }
504 tables.assoc_refinements_of.insert(key, assocs);
505 }
506 DefKind::Impl { of_trait } => {
507 tables
508 .generics_of
509 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
510 tables
511 .predicates_of
512 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
513 tables.refinement_generics_of.insert(
514 key,
515 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
516 );
517
518 if of_trait {
519 let assocs = genv.run_query_if_reached(def_id, GlobalEnv::assoc_refinements_of);
520 if let Ok(assocs) = &assocs {
521 for assoc_reft in &assocs.items {
522 let def_id = assoc_reft.def_id();
523 let key = assoc_id_to_key(def_id);
524 tables.assoc_refinements_def.insert(
525 key,
526 genv.run_query_if_reached(def_id, GlobalEnv::assoc_refinement_body),
527 );
528 tables.sort_of_assoc_reft.insert(
529 key,
530 genv.run_query_if_reached(def_id, GlobalEnv::sort_of_assoc_reft),
531 );
532 }
533 }
534 tables.assoc_refinements_of.insert(key, assocs);
535 }
536 }
537 DefKind::Fn | DefKind::AssocFn => {
538 tables
539 .generics_of
540 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
541 tables
542 .predicates_of
543 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
544 tables.refinement_generics_of.insert(
545 key,
546 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
547 );
548 tables
549 .fn_sig
550 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::fn_sig));
551 tables.no_panic.insert(key, genv.no_panic(def_id));
552 tables
553 .assume_parametric_params
554 .insert(key, genv.assume_parametric_params(def_id));
555 if let Some(span) = genv.spec_attr_span(def_id) {
556 tables.spec_attr_span.insert(key, span);
557 }
558 }
559 DefKind::Ctor(_, CtorKind::Fn) => {
560 tables
561 .generics_of
562 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
563 tables.refinement_generics_of.insert(
564 key,
565 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
566 );
567 tables
568 .fn_sig
569 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::fn_sig));
570 }
571 DefKind::Enum | DefKind::Struct => {
572 tables
573 .generics_of
574 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
575 tables
576 .predicates_of
577 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
578 tables.refinement_generics_of.insert(
579 key,
580 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
581 );
582 tables
583 .adt_def
584 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::adt_def));
585 tables
586 .adt_sort_def
587 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::adt_sort_def_of));
588 tables
589 .variants_of
590 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::variants_of));
591 tables
592 .type_of
593 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::type_of));
594 }
595 DefKind::TyAlias => {
596 tables
597 .generics_of
598 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
599 tables
600 .predicates_of
601 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
602 tables.refinement_generics_of.insert(
603 key,
604 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
605 );
606 tables
607 .type_of
608 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::type_of));
609 }
610 DefKind::OpaqueTy => {
611 tables
612 .generics_of
613 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::generics_of));
614 tables
615 .predicates_of
616 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::predicates_of));
617 tables
618 .item_bounds
619 .insert(key, genv.run_query_if_reached(def_id, GlobalEnv::item_bounds));
620 tables.refinement_generics_of.insert(
621 key,
622 genv.run_query_if_reached(def_id, GlobalEnv::refinement_generics_of),
623 );
624 }
625 DefKind::Static { .. } => {
626 tables.static_info.insert(key, genv.static_info(def_id));
627 }
628 _ => {}
629 }
630 }
631}
632
633pub fn filename_for_metadata(tcx: TyCtxt) -> OutFileName {
634 match rustc_session::output::filename_for_metadata(tcx.sess, tcx.output_filenames(())) {
635 OutFileName::Real(path) => OutFileName::Real(path.with_extension("fluxmeta")),
636 OutFileName::Stdout => OutFileName::Stdout,
637 }
638}
639
640fn flux_metadata_extern_location(tcx: TyCtxt, crate_num: CrateNum) -> Option<PathBuf> {
641 tcx.used_crate_source(crate_num)
644 .rmeta
645 .as_ref()
646 .map(|path| path.with_extension("fluxmeta"))
647}
648
649const SYMBOL_STR: u8 = 0;
651const SYMBOL_OFFSET: u8 = 1;
652const SYMBOL_PREDEFINED: u8 = 2;
653
654mod errors {
655 use flux_errors::E0999;
656 use flux_macros::Diagnostic;
657 use rustc_middle::ty::TyCtxt;
658
659 use crate::Key;
660
661 #[derive(Diagnostic)]
662 #[diag(metadata_duplicate_spec, code = E0999)]
663 pub(super) struct DuplicateSpec {
664 def_name: String,
665 }
666
667 impl DuplicateSpec {
668 pub(super) fn new(tcx: TyCtxt, key: impl Key) -> Self {
669 Self { def_name: key.name(tcx) }
670 }
671 }
672}