Skip to main content

rustc_session/
parse.rs

1//! Contains `ParseSess` which holds state living beyond what one `Parser` might.
2//! It also serves as an input to the parser itself.
3
4use std::str;
5use std::sync::Arc;
6
7use rustc_ast::attr::AttrIdGenerator;
8use rustc_ast::node_id::NodeId;
9use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
10use rustc_data_structures::sync::{AppendOnlyVec, Lock};
11use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
12use rustc_errors::emitter::{EmitterWithNote, stderr_destination};
13use rustc_errors::translation::Translator;
14use rustc_errors::{
15    BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle,
16    DiagMessage, EmissionGuarantee, MultiSpan, StashKey,
17};
18use rustc_feature::{GateIssue, UnstableFeatures, find_feature_issue};
19use rustc_span::edition::Edition;
20use rustc_span::hygiene::ExpnId;
21use rustc_span::source_map::{FilePathMapping, SourceMap};
22use rustc_span::{Span, Symbol, sym};
23
24use crate::Session;
25use crate::config::{Cfg, CheckCfg};
26use crate::errors::{
27    CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp,
28    FeatureDiagnosticSuggestion, FeatureGateError, SuggestUpgradeCompiler,
29};
30use crate::lint::builtin::UNSTABLE_SYNTAX_PRE_EXPANSION;
31use crate::lint::{Lint, LintId};
32
33/// Collected spans during parsing for places where a certain feature was
34/// used and should be feature gated accordingly in `check_crate`.
35#[derive(#[automatically_derived]
impl ::core::default::Default for GatedSpans {
    #[inline]
    fn default() -> GatedSpans {
        GatedSpans { spans: ::core::default::Default::default() }
    }
}Default)]
36pub struct GatedSpans {
37    pub spans: Lock<FxHashMap<Symbol, Vec<Span>>>,
38}
39
40impl GatedSpans {
41    /// Feature gate the given `span` under the given `feature`
42    /// which is same `Symbol` used in `unstable.rs`.
43    pub fn gate(&self, feature: Symbol, span: Span) {
44        self.spans.borrow_mut().entry(feature).or_default().push(span);
45    }
46
47    /// Ungate the last span under the given `feature`.
48    /// Panics if the given `span` wasn't the last one.
49    ///
50    /// Using this is discouraged unless you have a really good reason to.
51    pub fn ungate_last(&self, feature: Symbol, span: Span) {
52        let removed_span = self.spans.borrow_mut().entry(feature).or_default().pop().unwrap();
53        if true {
    match (&span, &removed_span) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    };
};debug_assert_eq!(span, removed_span);
54    }
55
56    /// Prepend the given set of `spans` onto the set in `self`.
57    pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) {
58        let mut inner = self.spans.borrow_mut();
59        // The entries will be moved to another map so the drain order does not
60        // matter.
61        #[allow(rustc::potential_query_instability)]
62        for (gate, mut gate_spans) in inner.drain() {
63            spans.entry(gate).or_default().append(&mut gate_spans);
64        }
65        *inner = spans;
66    }
67}
68
69#[derive(#[automatically_derived]
impl ::core::default::Default for SymbolGallery {
    #[inline]
    fn default() -> SymbolGallery {
        SymbolGallery { symbols: ::core::default::Default::default() }
    }
}Default)]
70pub struct SymbolGallery {
71    /// All symbols occurred and their first occurrence span.
72    pub symbols: Lock<FxIndexMap<Symbol, Span>>,
73}
74
75impl SymbolGallery {
76    /// Insert a symbol and its span into symbol gallery.
77    /// If the symbol has occurred before, ignore the new occurrence.
78    pub fn insert(&self, symbol: Symbol, span: Span) {
79        self.symbols.lock().entry(symbol).or_insert(span);
80    }
81}
82
83// todo: this function now accepts `Session` instead of `ParseSess` and should be relocated
84/// Construct a diagnostic for a language feature error due to the given `span`.
85/// The `feature`'s `Symbol` is the one you used in `unstable.rs` and `rustc_span::symbol`.
86#[track_caller]
87pub fn feature_err(
88    sess: &Session,
89    feature: Symbol,
90    span: impl Into<MultiSpan>,
91    explain: impl Into<DiagMessage>,
92) -> Diag<'_> {
93    feature_err_issue(sess, feature, span, GateIssue::Language, explain)
94}
95
96/// Construct a diagnostic for a feature gate error.
97///
98/// This variant allows you to control whether it is a library or language feature.
99/// Almost always, you want to use this for a language feature. If so, prefer `feature_err`.
100#[track_caller]
101pub fn feature_err_issue(
102    sess: &Session,
103    feature: Symbol,
104    span: impl Into<MultiSpan>,
105    issue: GateIssue,
106    explain: impl Into<DiagMessage>,
107) -> Diag<'_> {
108    let span = span.into();
109
110    // Cancel an earlier warning for this same error, if it exists.
111    if let Some(span) = span.primary_span()
112        && let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning)
113    {
114        err.cancel()
115    }
116
117    let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() });
118    add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None);
119    err
120}
121
122/// Construct a future incompatibility diagnostic for a feature gate.
123///
124/// This diagnostic is only a warning and *does not cause compilation to fail*.
125#[track_caller]
126pub fn feature_warn(sess: &Session, feature: Symbol, span: Span, explain: &'static str) {
127    feature_warn_issue(sess, feature, span, GateIssue::Language, explain);
128}
129
130/// Construct a future incompatibility diagnostic for a feature gate.
131///
132/// This diagnostic is only a warning and *does not cause compilation to fail*.
133///
134/// This variant allows you to control whether it is a library or language feature.
135/// Almost always, you want to use this for a language feature. If so, prefer `feature_warn`.
136#[track_caller]
137pub fn feature_warn_issue(
138    sess: &Session,
139    feature: Symbol,
140    span: Span,
141    issue: GateIssue,
142    explain: &'static str,
143) {
144    let mut err = sess.dcx().struct_span_warn(span, explain);
145    add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None);
146
147    // Decorate this as a future-incompatibility lint as in rustc_middle::lint::lint_level
148    let lint = UNSTABLE_SYNTAX_PRE_EXPANSION;
149    let future_incompatible = lint.future_incompatible.as_ref().unwrap();
150    err.is_lint(lint.name_lower(), /* has_future_breakage */ false);
151    err.warn(lint.desc);
152    err.note(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("for more information, see {0}",
                future_incompatible.reason.reference()))
    })format!("for more information, see {}", future_incompatible.reason.reference()));
153
154    // A later feature_err call can steal and cancel this warning.
155    err.stash(span, StashKey::EarlySyntaxWarning);
156}
157
158/// Adds the diagnostics for a feature to an existing error.
159/// Must be a language feature!
160pub fn add_feature_diagnostics<G: EmissionGuarantee>(
161    err: &mut Diag<'_, G>,
162    sess: &Session,
163    feature: Symbol,
164) {
165    add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false, None);
166}
167
168/// Adds the diagnostics for a feature to an existing error.
169///
170/// This variant allows you to control whether it is a library or language feature.
171/// Almost always, you want to use this for a language feature. If so, prefer
172/// `add_feature_diagnostics`.
173pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
174    err: &mut Diag<'_, G>,
175    sess: &Session,
176    feature: Symbol,
177    issue: GateIssue,
178    feature_from_cli: bool,
179    inject_span: Option<Span>,
180) {
181    if let Some(n) = find_feature_issue(feature, issue) {
182        err.subdiagnostic(FeatureDiagnosticForIssue { n });
183    }
184
185    // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
186    if sess.psess.unstable_features.is_nightly_build() {
187        if feature_from_cli {
188            err.subdiagnostic(CliFeatureDiagnosticHelp { feature });
189        } else if let Some(span) = inject_span {
190            err.subdiagnostic(FeatureDiagnosticSuggestion { feature, span });
191        } else {
192            err.subdiagnostic(FeatureDiagnosticHelp { feature });
193        }
194        if feature == sym::rustc_attrs {
195            // We're unlikely to stabilize something out of `rustc_attrs`
196            // without at least renaming it, so pointing out how old
197            // the compiler is will do little good.
198        } else if sess.opts.unstable_opts.ui_testing {
199            err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
200        } else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
201            err.subdiagnostic(suggestion);
202        }
203    }
204}
205
206/// This is only used by unstable_feature_bound as it does not have issue number information for now.
207/// This is basically the same as `feature_err_issue`
208/// but without the feature issue note. If we can do a lookup for issue number from feature name,
209/// then we should directly use `feature_err_issue` for ambiguity error of
210/// `#[unstable_feature_bound]`.
211#[track_caller]
212pub fn feature_err_unstable_feature_bound(
213    sess: &Session,
214    feature: Symbol,
215    span: impl Into<MultiSpan>,
216    explain: impl Into<DiagMessage>,
217) -> Diag<'_> {
218    let span = span.into();
219
220    // Cancel an earlier warning for this same error, if it exists.
221    if let Some(span) = span.primary_span() {
222        if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) {
223            err.cancel()
224        }
225    }
226
227    let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() });
228
229    // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
230    if sess.psess.unstable_features.is_nightly_build() {
231        err.subdiagnostic(FeatureDiagnosticHelp { feature });
232
233        if feature == sym::rustc_attrs {
234            // We're unlikely to stabilize something out of `rustc_attrs`
235            // without at least renaming it, so pointing out how old
236            // the compiler is will do little good.
237        } else if sess.opts.unstable_opts.ui_testing {
238            err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
239        } else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
240            err.subdiagnostic(suggestion);
241        }
242    }
243    err
244}
245
246/// Info about a parsing session.
247pub struct ParseSess {
248    dcx: DiagCtxt,
249    pub unstable_features: UnstableFeatures,
250    pub config: Cfg,
251    pub check_config: CheckCfg,
252    pub edition: Edition,
253    /// Places where raw identifiers were used. This is used to avoid complaining about idents
254    /// clashing with keywords in new editions.
255    pub raw_identifier_spans: AppendOnlyVec<Span>,
256    /// Places where identifiers that contain invalid Unicode codepoints but that look like they
257    /// should be. Useful to avoid bad tokenization when encountering emoji. We group them to
258    /// provide a single error per unique incorrect identifier.
259    pub bad_unicode_identifiers: Lock<FxIndexMap<Symbol, Vec<Span>>>,
260    source_map: Arc<SourceMap>,
261    pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
262    /// Contains the spans of block expressions that could have been incomplete based on the
263    /// operation token that followed it, but that the parser cannot identify without further
264    /// analysis.
265    pub ambiguous_block_expr_parse: Lock<FxIndexMap<Span, Span>>,
266    pub gated_spans: GatedSpans,
267    pub symbol_gallery: SymbolGallery,
268    /// Environment variables accessed during the build and their values when they exist.
269    pub env_depinfo: Lock<FxIndexSet<(Symbol, Option<Symbol>)>>,
270    /// File paths accessed during the build.
271    pub file_depinfo: Lock<FxIndexSet<Symbol>>,
272    /// Whether cfg(version) should treat the current release as incomplete
273    pub assume_incomplete_release: bool,
274    /// Spans passed to `proc_macro::quote_span`. Each span has a numerical
275    /// identifier represented by its position in the vector.
276    proc_macro_quoted_spans: AppendOnlyVec<Span>,
277    /// Used to generate new `AttrId`s. Every `AttrId` is unique.
278    pub attr_id_generator: AttrIdGenerator,
279}
280
281impl ParseSess {
282    /// Used for testing.
283    pub fn new(locale_resources: Vec<&'static str>) -> Self {
284        let translator = Translator::with_fallback_bundle(locale_resources, false);
285        let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
286        let emitter = Box::new(
287            AnnotateSnippetEmitter::new(stderr_destination(ColorConfig::Auto), translator)
288                .sm(Some(Arc::clone(&sm))),
289        );
290        let dcx = DiagCtxt::new(emitter);
291        ParseSess::with_dcx(dcx, sm)
292    }
293
294    pub fn with_dcx(dcx: DiagCtxt, source_map: Arc<SourceMap>) -> Self {
295        Self {
296            dcx,
297            unstable_features: UnstableFeatures::from_environment(None),
298            config: Cfg::default(),
299            check_config: CheckCfg::default(),
300            edition: ExpnId::root().expn_data().edition,
301            raw_identifier_spans: Default::default(),
302            bad_unicode_identifiers: Lock::new(Default::default()),
303            source_map,
304            buffered_lints: Lock::new(::alloc::vec::Vec::new()vec![]),
305            ambiguous_block_expr_parse: Lock::new(Default::default()),
306            gated_spans: GatedSpans::default(),
307            symbol_gallery: SymbolGallery::default(),
308            env_depinfo: Default::default(),
309            file_depinfo: Default::default(),
310            assume_incomplete_release: false,
311            proc_macro_quoted_spans: Default::default(),
312            attr_id_generator: AttrIdGenerator::new(),
313        }
314    }
315
316    pub fn emitter_with_note(locale_resources: Vec<&'static str>, note: String) -> Self {
317        let translator = Translator::with_fallback_bundle(locale_resources, false);
318        let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
319        let emitter = Box::new(AnnotateSnippetEmitter::new(
320            stderr_destination(ColorConfig::Auto),
321            translator,
322        ));
323        let dcx = DiagCtxt::new(Box::new(EmitterWithNote { emitter, note }));
324        ParseSess::with_dcx(dcx, sm)
325    }
326
327    #[inline]
328    pub fn source_map(&self) -> &SourceMap {
329        &self.source_map
330    }
331
332    pub fn clone_source_map(&self) -> Arc<SourceMap> {
333        Arc::clone(&self.source_map)
334    }
335
336    pub fn buffer_lint(
337        &self,
338        lint: &'static Lint,
339        span: impl Into<MultiSpan>,
340        node_id: NodeId,
341        diagnostic: impl Into<DecorateDiagCompat>,
342    ) {
343        self.opt_span_buffer_lint(lint, Some(span.into()), node_id, diagnostic.into())
344    }
345
346    pub(crate) fn opt_span_buffer_lint(
347        &self,
348        lint: &'static Lint,
349        span: Option<MultiSpan>,
350        node_id: NodeId,
351        diagnostic: DecorateDiagCompat,
352    ) {
353        self.buffered_lints.with_lock(|buffered_lints| {
354            buffered_lints.push(BufferedEarlyLint {
355                span,
356                node_id,
357                lint_id: LintId::of(lint),
358                diagnostic,
359            });
360        });
361    }
362
363    pub fn save_proc_macro_span(&self, span: Span) -> usize {
364        self.proc_macro_quoted_spans.push(span)
365    }
366
367    pub fn proc_macro_quoted_spans(&self) -> impl Iterator<Item = (usize, Span)> {
368        // This is equivalent to `.iter().copied().enumerate()`, but that isn't possible for
369        // AppendOnlyVec, so we resort to this scheme.
370        self.proc_macro_quoted_spans.iter_enumerated()
371    }
372
373    pub fn dcx(&self) -> DiagCtxtHandle<'_> {
374        self.dcx.handle()
375    }
376}