]>
Commit | Line | Data |
---|---|---|
e74abb32 XL |
1 | //! Contains `ParseSess` which holds state living beyond what one `Parser` might. |
2 | //! It also serves as an input to the parser itself. | |
3 | ||
5099ac24 | 4 | use crate::config::CheckCfg; |
f2b60f7d FG |
5 | use crate::errors::{FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError}; |
6 | use crate::lint::{ | |
7 | builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId, | |
8 | }; | |
74b04a01 | 9 | use rustc_ast::node_id::NodeId; |
f2b60f7d | 10 | use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; |
353b0b11 | 11 | use rustc_data_structures::sync::{AppendOnlyVec, AtomicBool, Lock, Lrc}; |
dfeec247 | 12 | use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; |
04454e1e | 13 | use rustc_errors::{ |
2b03887a FG |
14 | fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, |
15 | EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey, | |
04454e1e | 16 | }; |
dfeec247 XL |
17 | use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; |
18 | use rustc_span::edition::Edition; | |
19 | use rustc_span::hygiene::ExpnId; | |
20 | use rustc_span::source_map::{FilePathMapping, SourceMap}; | |
04454e1e | 21 | use rustc_span::{Span, Symbol}; |
e74abb32 | 22 | |
f2b60f7d | 23 | use rustc_ast::attr::AttrIdGenerator; |
e74abb32 XL |
24 | use std::str; |
25 | ||
60c5eb7d XL |
26 | /// The set of keys (and, optionally, values) that define the compilation |
27 | /// environment of the crate, used to drive conditional compilation. | |
f2b60f7d | 28 | pub type CrateConfig = FxIndexSet<(Symbol, Option<Symbol>)>; |
5099ac24 | 29 | pub type CrateCheckConfig = CheckCfg<Symbol>; |
60c5eb7d | 30 | |
e74abb32 XL |
31 | /// Collected spans during parsing for places where a certain feature was |
32 | /// used and should be feature gated accordingly in `check_crate`. | |
33 | #[derive(Default)] | |
60c5eb7d XL |
34 | pub struct GatedSpans { |
35 | pub spans: Lock<FxHashMap<Symbol, Vec<Span>>>, | |
36 | } | |
37 | ||
38 | impl GatedSpans { | |
39 | /// Feature gate the given `span` under the given `feature` | |
40 | /// which is same `Symbol` used in `active.rs`. | |
41 | pub fn gate(&self, feature: Symbol, span: Span) { | |
dfeec247 | 42 | self.spans.borrow_mut().entry(feature).or_default().push(span); |
60c5eb7d XL |
43 | } |
44 | ||
45 | /// Ungate the last span under the given `feature`. | |
46 | /// Panics if the given `span` wasn't the last one. | |
47 | /// | |
48 | /// Using this is discouraged unless you have a really good reason to. | |
49 | pub fn ungate_last(&self, feature: Symbol, span: Span) { | |
dfeec247 | 50 | let removed_span = self.spans.borrow_mut().entry(feature).or_default().pop().unwrap(); |
60c5eb7d XL |
51 | debug_assert_eq!(span, removed_span); |
52 | } | |
53 | ||
54 | /// Is the provided `feature` gate ungated currently? | |
55 | /// | |
56 | /// Using this is discouraged unless you have a really good reason to. | |
57 | pub fn is_ungated(&self, feature: Symbol) -> bool { | |
dfeec247 | 58 | self.spans.borrow().get(&feature).map_or(true, |spans| spans.is_empty()) |
60c5eb7d XL |
59 | } |
60 | ||
61 | /// Prepend the given set of `spans` onto the set in `self`. | |
62 | pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) { | |
63 | let mut inner = self.spans.borrow_mut(); | |
64 | for (gate, mut gate_spans) in inner.drain() { | |
65 | spans.entry(gate).or_default().append(&mut gate_spans); | |
66 | } | |
67 | *inner = spans; | |
68 | } | |
e74abb32 XL |
69 | } |
70 | ||
f9f354fc XL |
71 | #[derive(Default)] |
72 | pub struct SymbolGallery { | |
3dfed10e XL |
73 | /// All symbols occurred and their first occurrence span. |
74 | pub symbols: Lock<FxHashMap<Symbol, Span>>, | |
f9f354fc XL |
75 | } |
76 | ||
77 | impl SymbolGallery { | |
78 | /// Insert a symbol and its span into symbol gallery. | |
5e7ed085 | 79 | /// If the symbol has occurred before, ignore the new occurrence. |
f9f354fc XL |
80 | pub fn insert(&self, symbol: Symbol, span: Span) { |
81 | self.symbols.lock().entry(symbol).or_insert(span); | |
82 | } | |
83 | } | |
84 | ||
dfeec247 XL |
85 | /// Construct a diagnostic for a language feature error due to the given `span`. |
86 | /// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`. | |
353b0b11 FG |
87 | pub fn feature_err( |
88 | sess: &ParseSess, | |
dfeec247 XL |
89 | feature: Symbol, |
90 | span: impl Into<MultiSpan>, | |
9ffffee4 | 91 | explain: impl Into<DiagnosticMessage>, |
353b0b11 | 92 | ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { |
dfeec247 XL |
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`. | |
487cf647 | 100 | #[track_caller] |
353b0b11 FG |
101 | pub fn feature_err_issue( |
102 | sess: &ParseSess, | |
dfeec247 XL |
103 | feature: Symbol, |
104 | span: impl Into<MultiSpan>, | |
105 | issue: GateIssue, | |
9ffffee4 | 106 | explain: impl Into<DiagnosticMessage>, |
353b0b11 | 107 | ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { |
f2b60f7d FG |
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() { | |
353b0b11 FG |
112 | if let Some(err) = sess.span_diagnostic.steal_diagnostic(span, StashKey::EarlySyntaxWarning) |
113 | { | |
114 | err.cancel() | |
115 | } | |
f2b60f7d FG |
116 | } |
117 | ||
9ffffee4 | 118 | let mut err = sess.create_err(FeatureGateError { span, explain: explain.into() }); |
5e7ed085 FG |
119 | add_feature_diagnostics_for_issue(&mut err, sess, feature, issue); |
120 | err | |
121 | } | |
122 | ||
f2b60f7d FG |
123 | /// Construct a future incompatibility diagnostic for a feature gate. |
124 | /// | |
125 | /// This diagnostic is only a warning and *does not cause compilation to fail*. | |
9c376795 | 126 | pub fn feature_warn(sess: &ParseSess, feature: Symbol, span: Span, explain: &str) { |
f2b60f7d FG |
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 | #[allow(rustc::diagnostic_outside_of_impl)] | |
137 | #[allow(rustc::untranslatable_diagnostic)] | |
9c376795 FG |
138 | pub fn feature_warn_issue( |
139 | sess: &ParseSess, | |
f2b60f7d FG |
140 | feature: Symbol, |
141 | span: Span, | |
142 | issue: GateIssue, | |
143 | explain: &str, | |
144 | ) { | |
145 | let mut err = sess.span_diagnostic.struct_span_warn(span, explain); | |
146 | add_feature_diagnostics_for_issue(&mut err, sess, feature, issue); | |
147 | ||
148 | // Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level | |
149 | let lint = UNSTABLE_SYNTAX_PRE_EXPANSION; | |
150 | let future_incompatible = lint.future_incompatible.as_ref().unwrap(); | |
151 | err.code(DiagnosticId::Lint { | |
152 | name: lint.name_lower(), | |
153 | has_future_breakage: false, | |
154 | is_force_warn: false, | |
155 | }); | |
156 | err.warn(lint.desc); | |
157 | err.note(format!("for more information, see {}", future_incompatible.reference)); | |
158 | ||
159 | // A later feature_err call can steal and cancel this warning. | |
160 | err.stash(span, StashKey::EarlySyntaxWarning); | |
161 | } | |
162 | ||
5e7ed085 | 163 | /// Adds the diagnostics for a feature to an existing error. |
9c376795 | 164 | pub fn add_feature_diagnostics(err: &mut Diagnostic, sess: &ParseSess, feature: Symbol) { |
5e7ed085 FG |
165 | add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language); |
166 | } | |
dfeec247 | 167 | |
5e7ed085 FG |
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`. | |
9c376795 | 173 | pub fn add_feature_diagnostics_for_issue( |
5e7ed085 | 174 | err: &mut Diagnostic, |
9c376795 | 175 | sess: &ParseSess, |
5e7ed085 FG |
176 | feature: Symbol, |
177 | issue: GateIssue, | |
178 | ) { | |
dfeec247 | 179 | if let Some(n) = find_feature_issue(feature, issue) { |
f2b60f7d | 180 | err.subdiagnostic(FeatureDiagnosticForIssue { n }); |
dfeec247 XL |
181 | } |
182 | ||
183 | // #23973: do not suggest `#![feature(...)]` if we are in beta/stable | |
184 | if sess.unstable_features.is_nightly_build() { | |
f2b60f7d | 185 | err.subdiagnostic(FeatureDiagnosticHelp { feature }); |
dfeec247 | 186 | } |
dfeec247 XL |
187 | } |
188 | ||
e74abb32 XL |
189 | /// Info about a parsing session. |
190 | pub struct ParseSess { | |
191 | pub span_diagnostic: Handler, | |
60c5eb7d | 192 | pub unstable_features: UnstableFeatures, |
e74abb32 | 193 | pub config: CrateConfig, |
5099ac24 | 194 | pub check_config: CrateCheckConfig, |
e74abb32 | 195 | pub edition: Edition, |
3c0e092e XL |
196 | /// Places where raw identifiers were used. This is used to avoid complaining about idents |
197 | /// clashing with keywords in new editions. | |
353b0b11 | 198 | pub raw_identifier_spans: AppendOnlyVec<Span>, |
3c0e092e XL |
199 | /// Places where identifiers that contain invalid Unicode codepoints but that look like they |
200 | /// should be. Useful to avoid bad tokenization when encountering emoji. We group them to | |
201 | /// provide a single error per unique incorrect identifier. | |
202 | pub bad_unicode_identifiers: Lock<FxHashMap<Symbol, Vec<Span>>>, | |
e74abb32 XL |
203 | source_map: Lrc<SourceMap>, |
204 | pub buffered_lints: Lock<Vec<BufferedEarlyLint>>, | |
205 | /// Contains the spans of block expressions that could have been incomplete based on the | |
206 | /// operation token that followed it, but that the parser cannot identify without further | |
207 | /// analysis. | |
208 | pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>, | |
60c5eb7d | 209 | pub gated_spans: GatedSpans, |
f9f354fc | 210 | pub symbol_gallery: SymbolGallery, |
e74abb32 | 211 | /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors. |
353b0b11 | 212 | pub reached_eof: AtomicBool, |
f035d41b XL |
213 | /// Environment variables accessed during the build and their values when they exist. |
214 | pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>, | |
136023e0 XL |
215 | /// File paths accessed during the build. |
216 | pub file_depinfo: Lock<FxHashSet<Symbol>>, | |
3dfed10e XL |
217 | /// All the type ascriptions expressions that have had a suggestion for likely path typo. |
218 | pub type_ascription_path_suggestions: Lock<FxHashSet<Span>>, | |
5869c6ff XL |
219 | /// Whether cfg(version) should treat the current release as incomplete |
220 | pub assume_incomplete_release: bool, | |
17df50a5 XL |
221 | /// Spans passed to `proc_macro::quote_span`. Each span has a numerical |
222 | /// identifier represented by its position in the vector. | |
353b0b11 | 223 | pub proc_macro_quoted_spans: AppendOnlyVec<Span>, |
f2b60f7d FG |
224 | /// Used to generate new `AttrId`s. Every `AttrId` is unique. |
225 | pub attr_id_generator: AttrIdGenerator, | |
e74abb32 XL |
226 | } |
227 | ||
228 | impl ParseSess { | |
cdc7bbd5 | 229 | /// Used for testing. |
9ffffee4 FG |
230 | pub fn new(locale_resources: Vec<&'static str>, file_path_mapping: FilePathMapping) -> Self { |
231 | let fallback_bundle = fallback_fluent_bundle(locale_resources, false); | |
74b04a01 | 232 | let sm = Lrc::new(SourceMap::new(file_path_mapping)); |
04454e1e FG |
233 | let handler = Handler::with_tty_emitter( |
234 | ColorConfig::Auto, | |
235 | true, | |
236 | None, | |
237 | Some(sm.clone()), | |
238 | None, | |
239 | fallback_bundle, | |
240 | ); | |
74b04a01 | 241 | ParseSess::with_span_handler(handler, sm) |
e74abb32 XL |
242 | } |
243 | ||
dfeec247 | 244 | pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self { |
e74abb32 XL |
245 | Self { |
246 | span_diagnostic: handler, | |
fc512014 | 247 | unstable_features: UnstableFeatures::from_environment(None), |
f2b60f7d | 248 | config: FxIndexSet::default(), |
5099ac24 | 249 | check_config: CrateCheckConfig::default(), |
e74abb32 | 250 | edition: ExpnId::root().expn_data().edition, |
353b0b11 | 251 | raw_identifier_spans: Default::default(), |
3c0e092e | 252 | bad_unicode_identifiers: Lock::new(Default::default()), |
e74abb32 XL |
253 | source_map, |
254 | buffered_lints: Lock::new(vec![]), | |
255 | ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), | |
e74abb32 | 256 | gated_spans: GatedSpans::default(), |
f9f354fc | 257 | symbol_gallery: SymbolGallery::default(), |
353b0b11 | 258 | reached_eof: AtomicBool::new(false), |
f035d41b | 259 | env_depinfo: Default::default(), |
136023e0 | 260 | file_depinfo: Default::default(), |
3dfed10e | 261 | type_ascription_path_suggestions: Default::default(), |
5869c6ff | 262 | assume_incomplete_release: false, |
17df50a5 | 263 | proc_macro_quoted_spans: Default::default(), |
f2b60f7d | 264 | attr_id_generator: AttrIdGenerator::new(), |
e74abb32 XL |
265 | } |
266 | } | |
267 | ||
3c0e092e | 268 | pub fn with_silent_emitter(fatal_note: Option<String>) -> Self { |
9ffffee4 | 269 | let fallback_bundle = fallback_fluent_bundle(Vec::new(), false); |
74b04a01 | 270 | let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); |
04454e1e FG |
271 | let fatal_handler = |
272 | Handler::with_tty_emitter(ColorConfig::Auto, false, None, None, None, fallback_bundle); | |
3c0e092e XL |
273 | let handler = Handler::with_emitter( |
274 | false, | |
275 | None, | |
276 | Box::new(SilentEmitter { fatal_handler, fatal_note }), | |
277 | ); | |
74b04a01 | 278 | ParseSess::with_span_handler(handler, sm) |
60c5eb7d XL |
279 | } |
280 | ||
e74abb32 XL |
281 | #[inline] |
282 | pub fn source_map(&self) -> &SourceMap { | |
283 | &self.source_map | |
284 | } | |
285 | ||
f9f354fc XL |
286 | pub fn clone_source_map(&self) -> Lrc<SourceMap> { |
287 | self.source_map.clone() | |
288 | } | |
289 | ||
e74abb32 XL |
290 | pub fn buffer_lint( |
291 | &self, | |
dfeec247 | 292 | lint: &'static Lint, |
e74abb32 | 293 | span: impl Into<MultiSpan>, |
dfeec247 | 294 | node_id: NodeId, |
e74abb32 XL |
295 | msg: &str, |
296 | ) { | |
297 | self.buffered_lints.with_lock(|buffered_lints| { | |
dfeec247 | 298 | buffered_lints.push(BufferedEarlyLint { |
e74abb32 | 299 | span: span.into(), |
dfeec247 | 300 | node_id, |
e74abb32 | 301 | msg: msg.into(), |
dfeec247 XL |
302 | lint_id: LintId::of(lint), |
303 | diagnostic: BuiltinLintDiagnostics::Normal, | |
e74abb32 XL |
304 | }); |
305 | }); | |
306 | } | |
307 | ||
74b04a01 XL |
308 | pub fn buffer_lint_with_diagnostic( |
309 | &self, | |
310 | lint: &'static Lint, | |
311 | span: impl Into<MultiSpan>, | |
312 | node_id: NodeId, | |
313 | msg: &str, | |
314 | diagnostic: BuiltinLintDiagnostics, | |
315 | ) { | |
316 | self.buffered_lints.with_lock(|buffered_lints| { | |
317 | buffered_lints.push(BufferedEarlyLint { | |
318 | span: span.into(), | |
319 | node_id, | |
320 | msg: msg.into(), | |
321 | lint_id: LintId::of(lint), | |
322 | diagnostic, | |
323 | }); | |
324 | }); | |
325 | } | |
326 | ||
17df50a5 | 327 | pub fn save_proc_macro_span(&self, span: Span) -> usize { |
353b0b11 | 328 | self.proc_macro_quoted_spans.push(span) |
17df50a5 XL |
329 | } |
330 | ||
353b0b11 FG |
331 | pub fn proc_macro_quoted_spans(&self) -> impl Iterator<Item = (usize, Span)> + '_ { |
332 | // This is equivalent to `.iter().copied().enumerate()`, but that isn't possible for | |
333 | // AppendOnlyVec, so we resort to this scheme. | |
334 | self.proc_macro_quoted_spans.iter_enumerated() | |
17df50a5 | 335 | } |
04454e1e | 336 | |
487cf647 | 337 | #[track_caller] |
04454e1e FG |
338 | pub fn create_err<'a>( |
339 | &'a self, | |
2b03887a | 340 | err: impl IntoDiagnostic<'a>, |
04454e1e | 341 | ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { |
f2b60f7d | 342 | err.into_diagnostic(&self.span_diagnostic) |
04454e1e FG |
343 | } |
344 | ||
487cf647 | 345 | #[track_caller] |
2b03887a | 346 | pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed { |
04454e1e FG |
347 | self.create_err(err).emit() |
348 | } | |
349 | ||
487cf647 | 350 | #[track_caller] |
04454e1e FG |
351 | pub fn create_warning<'a>( |
352 | &'a self, | |
2b03887a | 353 | warning: impl IntoDiagnostic<'a, ()>, |
04454e1e | 354 | ) -> DiagnosticBuilder<'a, ()> { |
f2b60f7d | 355 | warning.into_diagnostic(&self.span_diagnostic) |
04454e1e FG |
356 | } |
357 | ||
487cf647 | 358 | #[track_caller] |
2b03887a | 359 | pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { |
04454e1e FG |
360 | self.create_warning(warning).emit() |
361 | } | |
362 | ||
2b03887a FG |
363 | pub fn create_note<'a>( |
364 | &'a self, | |
365 | note: impl IntoDiagnostic<'a, Noted>, | |
366 | ) -> DiagnosticBuilder<'a, Noted> { | |
367 | note.into_diagnostic(&self.span_diagnostic) | |
368 | } | |
369 | ||
370 | pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted { | |
371 | self.create_note(note).emit() | |
372 | } | |
373 | ||
f2b60f7d FG |
374 | pub fn create_fatal<'a>( |
375 | &'a self, | |
2b03887a | 376 | fatal: impl IntoDiagnostic<'a, !>, |
f2b60f7d FG |
377 | ) -> DiagnosticBuilder<'a, !> { |
378 | fatal.into_diagnostic(&self.span_diagnostic) | |
379 | } | |
380 | ||
2b03887a | 381 | pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! { |
f2b60f7d FG |
382 | self.create_fatal(fatal).emit() |
383 | } | |
384 | ||
064997fb | 385 | #[rustc_lint_diagnostics] |
487cf647 | 386 | #[track_caller] |
04454e1e FG |
387 | pub fn struct_err( |
388 | &self, | |
389 | msg: impl Into<DiagnosticMessage>, | |
390 | ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { | |
391 | self.span_diagnostic.struct_err(msg) | |
392 | } | |
393 | ||
064997fb | 394 | #[rustc_lint_diagnostics] |
04454e1e FG |
395 | pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { |
396 | self.span_diagnostic.struct_warn(msg) | |
397 | } | |
f2b60f7d FG |
398 | |
399 | #[rustc_lint_diagnostics] | |
f2b60f7d FG |
400 | pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> { |
401 | self.span_diagnostic.struct_fatal(msg) | |
402 | } | |
403 | ||
404 | #[rustc_lint_diagnostics] | |
f2b60f7d FG |
405 | pub fn struct_diagnostic<G: EmissionGuarantee>( |
406 | &self, | |
407 | msg: impl Into<DiagnosticMessage>, | |
408 | ) -> DiagnosticBuilder<'_, G> { | |
409 | self.span_diagnostic.struct_diagnostic(msg) | |
410 | } | |
e74abb32 | 411 | } |