1 //! Contains `ParseSess` which holds state living beyond what one `Parser` might.
2 //! It also serves as an input to the parser itself.
4 use crate::config::CheckCfg;
5 use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId};
6 use crate::SessionDiagnostic;
7 use rustc_ast::node_id::NodeId;
8 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
9 use rustc_data_structures::sync::{Lock, Lrc};
10 use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
12 error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder,
13 DiagnosticMessage, ErrorGuaranteed, MultiSpan,
15 use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
16 use rustc_span::edition::Edition;
17 use rustc_span::hygiene::ExpnId;
18 use rustc_span::source_map::{FilePathMapping, SourceMap};
19 use rustc_span::{Span, Symbol};
23 /// The set of keys (and, optionally, values) that define the compilation
24 /// environment of the crate, used to drive conditional compilation.
25 pub type CrateConfig = FxHashSet<(Symbol, Option<Symbol>)>;
26 pub type CrateCheckConfig = CheckCfg<Symbol>;
28 /// Collected spans during parsing for places where a certain feature was
29 /// used and should be feature gated accordingly in `check_crate`.
31 pub struct GatedSpans {
32 pub spans: Lock<FxHashMap<Symbol, Vec<Span>>>,
36 /// Feature gate the given `span` under the given `feature`
37 /// which is same `Symbol` used in `active.rs`.
38 pub fn gate(&self, feature: Symbol, span: Span) {
39 self.spans.borrow_mut().entry(feature).or_default().push(span);
42 /// Ungate the last span under the given `feature`.
43 /// Panics if the given `span` wasn't the last one.
45 /// Using this is discouraged unless you have a really good reason to.
46 pub fn ungate_last(&self, feature: Symbol, span: Span) {
47 let removed_span = self.spans.borrow_mut().entry(feature).or_default().pop().unwrap();
48 debug_assert_eq!(span, removed_span);
51 /// Is the provided `feature` gate ungated currently?
53 /// Using this is discouraged unless you have a really good reason to.
54 pub fn is_ungated(&self, feature: Symbol) -> bool {
55 self.spans.borrow().get(&feature).map_or(true, |spans| spans.is_empty())
58 /// Prepend the given set of `spans` onto the set in `self`.
59 pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) {
60 let mut inner = self.spans.borrow_mut();
61 for (gate, mut gate_spans) in inner.drain() {
62 spans.entry(gate).or_default().append(&mut gate_spans);
69 pub struct SymbolGallery {
70 /// All symbols occurred and their first occurrence span.
71 pub symbols: Lock<FxHashMap<Symbol, Span>>,
75 /// Insert a symbol and its span into symbol gallery.
76 /// If the symbol has occurred before, ignore the new occurrence.
77 pub fn insert(&self, symbol: Symbol, span: Span) {
78 self.symbols.lock().entry(symbol).or_insert(span);
82 /// Construct a diagnostic for a language feature error due to the given `span`.
83 /// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`.
84 pub fn feature_err<'a>(
87 span: impl Into<MultiSpan>,
89 ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
90 feature_err_issue(sess, feature, span, GateIssue::Language, explain)
93 /// Construct a diagnostic for a feature gate error.
95 /// This variant allows you to control whether it is a library or language feature.
96 /// Almost always, you want to use this for a language feature. If so, prefer `feature_err`.
97 pub fn feature_err_issue<'a>(
100 span: impl Into<MultiSpan>,
103 ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
104 let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658));
105 add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
109 /// Adds the diagnostics for a feature to an existing error.
110 pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) {
111 add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language);
114 /// Adds the diagnostics for a feature to an existing error.
116 /// This variant allows you to control whether it is a library or language feature.
117 /// Almost always, you want to use this for a language feature. If so, prefer
118 /// `add_feature_diagnostics`.
119 pub fn add_feature_diagnostics_for_issue<'a>(
120 err: &mut Diagnostic,
125 if let Some(n) = find_feature_issue(feature, issue) {
127 "see issue #{n} <https://github.com/rust-lang/rust/issues/{n}> for more information"
131 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
132 if sess.unstable_features.is_nightly_build() {
133 err.help(&format!("add `#![feature({feature})]` to the crate attributes to enable"));
137 /// Info about a parsing session.
138 pub struct ParseSess {
139 pub span_diagnostic: Handler,
140 pub unstable_features: UnstableFeatures,
141 pub config: CrateConfig,
142 pub check_config: CrateCheckConfig,
143 pub edition: Edition,
144 /// Places where raw identifiers were used. This is used to avoid complaining about idents
145 /// clashing with keywords in new editions.
146 pub raw_identifier_spans: Lock<Vec<Span>>,
147 /// Places where identifiers that contain invalid Unicode codepoints but that look like they
148 /// should be. Useful to avoid bad tokenization when encountering emoji. We group them to
149 /// provide a single error per unique incorrect identifier.
150 pub bad_unicode_identifiers: Lock<FxHashMap<Symbol, Vec<Span>>>,
151 source_map: Lrc<SourceMap>,
152 pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
153 /// Contains the spans of block expressions that could have been incomplete based on the
154 /// operation token that followed it, but that the parser cannot identify without further
156 pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
157 pub gated_spans: GatedSpans,
158 pub symbol_gallery: SymbolGallery,
159 /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
160 pub reached_eof: Lock<bool>,
161 /// Environment variables accessed during the build and their values when they exist.
162 pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>,
163 /// File paths accessed during the build.
164 pub file_depinfo: Lock<FxHashSet<Symbol>>,
165 /// All the type ascriptions expressions that have had a suggestion for likely path typo.
166 pub type_ascription_path_suggestions: Lock<FxHashSet<Span>>,
167 /// Whether cfg(version) should treat the current release as incomplete
168 pub assume_incomplete_release: bool,
169 /// Spans passed to `proc_macro::quote_span`. Each span has a numerical
170 /// identifier represented by its position in the vector.
171 pub proc_macro_quoted_spans: Lock<Vec<Span>>,
175 /// Used for testing.
176 pub fn new(file_path_mapping: FilePathMapping) -> Self {
177 let fallback_bundle = fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
178 let sm = Lrc::new(SourceMap::new(file_path_mapping));
179 let handler = Handler::with_tty_emitter(
187 ParseSess::with_span_handler(handler, sm)
190 pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self {
192 span_diagnostic: handler,
193 unstable_features: UnstableFeatures::from_environment(None),
194 config: FxHashSet::default(),
195 check_config: CrateCheckConfig::default(),
196 edition: ExpnId::root().expn_data().edition,
197 raw_identifier_spans: Lock::new(Vec::new()),
198 bad_unicode_identifiers: Lock::new(Default::default()),
200 buffered_lints: Lock::new(vec![]),
201 ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
202 gated_spans: GatedSpans::default(),
203 symbol_gallery: SymbolGallery::default(),
204 reached_eof: Lock::new(false),
205 env_depinfo: Default::default(),
206 file_depinfo: Default::default(),
207 type_ascription_path_suggestions: Default::default(),
208 assume_incomplete_release: false,
209 proc_macro_quoted_spans: Default::default(),
213 pub fn with_silent_emitter(fatal_note: Option<String>) -> Self {
214 let fallback_bundle = fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
215 let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
217 Handler::with_tty_emitter(ColorConfig::Auto, false, None, None, None, fallback_bundle);
218 let handler = Handler::with_emitter(
221 Box::new(SilentEmitter { fatal_handler, fatal_note }),
223 ParseSess::with_span_handler(handler, sm)
227 pub fn source_map(&self) -> &SourceMap {
231 pub fn clone_source_map(&self) -> Lrc<SourceMap> {
232 self.source_map.clone()
238 span: impl Into<MultiSpan>,
242 self.buffered_lints.with_lock(|buffered_lints| {
243 buffered_lints.push(BufferedEarlyLint {
247 lint_id: LintId::of(lint),
248 diagnostic: BuiltinLintDiagnostics::Normal,
253 pub fn buffer_lint_with_diagnostic(
256 span: impl Into<MultiSpan>,
259 diagnostic: BuiltinLintDiagnostics,
261 self.buffered_lints.with_lock(|buffered_lints| {
262 buffered_lints.push(BufferedEarlyLint {
266 lint_id: LintId::of(lint),
272 /// Extend an error with a suggestion to wrap an expression with parentheses to allow the
273 /// parser to continue parsing the following operation as part of the same expression.
274 pub fn expr_parentheses_needed(&self, err: &mut Diagnostic, span: Span) {
275 err.multipart_suggestion(
276 "parentheses are required to parse this as an expression",
277 vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), ")".to_string())],
278 Applicability::MachineApplicable,
282 pub fn save_proc_macro_span(&self, span: Span) -> usize {
283 let mut spans = self.proc_macro_quoted_spans.lock();
285 return spans.len() - 1;
288 pub fn proc_macro_quoted_spans(&self) -> Vec<Span> {
289 self.proc_macro_quoted_spans.lock().clone()
292 pub fn create_err<'a>(
294 err: impl SessionDiagnostic<'a>,
295 ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
296 err.into_diagnostic(self)
299 pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed {
300 self.create_err(err).emit()
303 pub fn create_warning<'a>(
305 warning: impl SessionDiagnostic<'a, ()>,
306 ) -> DiagnosticBuilder<'a, ()> {
307 warning.into_diagnostic(self)
310 pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) {
311 self.create_warning(warning).emit()
316 msg: impl Into<DiagnosticMessage>,
317 ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
318 self.span_diagnostic.struct_err(msg)
321 pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
322 self.span_diagnostic.struct_warn(msg)