1use 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};
10use rustc_data_structures::sync::{AppendOnlyVec, DynSend, DynSync, Lock};
11use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
12use rustc_errors::emitter::{EmitterWithNote, stderr_destination};
13use rustc_errors::{
14 BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle,
15 DiagMessage, EmissionGuarantee, Level, MultiSpan, StashKey,
16};
17use rustc_feature::{GateIssue, find_feature_issue};
18use rustc_span::edition::Edition;
19use rustc_span::hygiene::ExpnId;
20use rustc_span::source_map::{FilePathMapping, SourceMap};
21use rustc_span::{Span, Symbol, sym};
22
23use crate::Session;
24use crate::errors::{
25 CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp,
26 FeatureDiagnosticSuggestion, FeatureGateError, SuggestUpgradeCompiler,
27};
28use crate::lint::builtin::UNSTABLE_SYNTAX_PRE_EXPANSION;
29use crate::lint::{Lint, LintId};
30
31#[derive(#[automatically_derived]
impl ::core::default::Default for GatedSpans {
#[inline]
fn default() -> GatedSpans {
GatedSpans { spans: ::core::default::Default::default() }
}
}Default)]
34pub struct GatedSpans {
35 pub spans: Lock<FxHashMap<Symbol, Vec<Span>>>,
36}
37
38impl GatedSpans {
39 pub fn gate(&self, feature: Symbol, span: Span) {
42 self.spans.borrow_mut().entry(feature).or_default().push(span);
43 }
44
45 pub fn ungate_last(&self, feature: Symbol, span: Span) {
50 let removed_span = self.spans.borrow_mut().entry(feature).or_default().pop().unwrap();
51 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);
52 }
53
54 pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) {
56 let mut inner = self.spans.borrow_mut();
57 #[allow(rustc::potential_query_instability)]
60 for (gate, mut gate_spans) in inner.drain() {
61 spans.entry(gate).or_default().append(&mut gate_spans);
62 }
63 *inner = spans;
64 }
65}
66
67#[derive(#[automatically_derived]
impl ::core::default::Default for SymbolGallery {
#[inline]
fn default() -> SymbolGallery {
SymbolGallery { symbols: ::core::default::Default::default() }
}
}Default)]
68pub struct SymbolGallery {
69 pub symbols: Lock<FxIndexMap<Symbol, Span>>,
71}
72
73impl SymbolGallery {
74 pub fn insert(&self, symbol: Symbol, span: Span) {
77 self.symbols.lock().entry(symbol).or_insert(span);
78 }
79}
80
81#[track_caller]
85pub fn feature_err(
86 sess: &Session,
87 feature: Symbol,
88 span: impl Into<MultiSpan>,
89 explain: impl Into<DiagMessage>,
90) -> Diag<'_> {
91 feature_err_issue(sess, feature, span, GateIssue::Language, explain)
92}
93
94#[track_caller]
99pub fn feature_err_issue(
100 sess: &Session,
101 feature: Symbol,
102 span: impl Into<MultiSpan>,
103 issue: GateIssue,
104 explain: impl Into<DiagMessage>,
105) -> Diag<'_> {
106 let span = span.into();
107
108 if let Some(span) = span.primary_span()
110 && let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning)
111 {
112 err.cancel()
113 }
114
115 let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() });
116 add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None);
117 err
118}
119
120#[track_caller]
124pub fn feature_warn(sess: &Session, feature: Symbol, span: Span, explain: &'static str) {
125 feature_warn_issue(sess, feature, span, GateIssue::Language, explain);
126}
127
128#[track_caller]
135pub fn feature_warn_issue(
136 sess: &Session,
137 feature: Symbol,
138 span: Span,
139 issue: GateIssue,
140 explain: &'static str,
141) {
142 let mut err = sess.dcx().struct_span_warn(span, explain);
143 add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None);
144
145 let lint = UNSTABLE_SYNTAX_PRE_EXPANSION;
147 let future_incompatible = lint.future_incompatible.as_ref().unwrap();
148 err.is_lint(lint.name_lower(), false);
149 err.warn(lint.desc);
150 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()));
151
152 err.stash(span, StashKey::EarlySyntaxWarning);
154}
155
156pub fn add_feature_diagnostics<G: EmissionGuarantee>(
159 err: &mut Diag<'_, G>,
160 sess: &Session,
161 feature: Symbol,
162) {
163 add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false, None);
164}
165
166pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
172 err: &mut Diag<'_, G>,
173 sess: &Session,
174 feature: Symbol,
175 issue: GateIssue,
176 feature_from_cli: bool,
177 inject_span: Option<Span>,
178) {
179 if let Some(n) = find_feature_issue(feature, issue) {
180 err.subdiagnostic(FeatureDiagnosticForIssue { n });
181 }
182
183 if sess.unstable_features.is_nightly_build() {
185 if feature_from_cli {
186 err.subdiagnostic(CliFeatureDiagnosticHelp { feature });
187 } else if let Some(span) = inject_span {
188 err.subdiagnostic(FeatureDiagnosticSuggestion { feature, span });
189 } else {
190 err.subdiagnostic(FeatureDiagnosticHelp { feature });
191 }
192 if feature == sym::rustc_attrs {
193 } else if sess.opts.unstable_opts.ui_testing {
197 err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
198 } else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
199 err.subdiagnostic(suggestion);
200 }
201 }
202}
203
204#[track_caller]
210pub fn feature_err_unstable_feature_bound(
211 sess: &Session,
212 feature: Symbol,
213 span: impl Into<MultiSpan>,
214 explain: impl Into<DiagMessage>,
215) -> Diag<'_> {
216 let span = span.into();
217
218 if let Some(span) = span.primary_span() {
220 if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) {
221 err.cancel()
222 }
223 }
224
225 let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() });
226
227 if sess.unstable_features.is_nightly_build() {
229 err.subdiagnostic(FeatureDiagnosticHelp { feature });
230
231 if feature == sym::rustc_attrs {
232 } else if sess.opts.unstable_opts.ui_testing {
236 err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
237 } else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
238 err.subdiagnostic(suggestion);
239 }
240 }
241 err
242}
243
244pub struct ParseSess {
246 dcx: DiagCtxt,
247 pub edition: Edition,
248 pub raw_identifier_spans: AppendOnlyVec<Span>,
251 pub bad_unicode_identifiers: Lock<FxIndexMap<Symbol, Vec<Span>>>,
255 source_map: Arc<SourceMap>,
256 pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
257 pub ambiguous_block_expr_parse: Lock<FxIndexMap<Span, Span>>,
261 pub gated_spans: GatedSpans,
262 pub symbol_gallery: SymbolGallery,
263 pub attr_id_generator: AttrIdGenerator,
265}
266
267impl ParseSess {
268 pub fn new() -> Self {
270 let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
271 let emitter = Box::new(
272 AnnotateSnippetEmitter::new(stderr_destination(ColorConfig::Auto))
273 .sm(Some(Arc::clone(&sm))),
274 );
275 let dcx = DiagCtxt::new(emitter);
276 ParseSess::with_dcx(dcx, sm)
277 }
278
279 pub fn with_dcx(dcx: DiagCtxt, source_map: Arc<SourceMap>) -> Self {
280 Self {
281 dcx,
282 edition: ExpnId::root().expn_data().edition,
283 raw_identifier_spans: Default::default(),
284 bad_unicode_identifiers: Lock::new(Default::default()),
285 source_map,
286 buffered_lints: Lock::new(::alloc::vec::Vec::new()vec![]),
287 ambiguous_block_expr_parse: Lock::new(Default::default()),
288 gated_spans: GatedSpans::default(),
289 symbol_gallery: SymbolGallery::default(),
290 attr_id_generator: AttrIdGenerator::new(),
291 }
292 }
293
294 pub fn emitter_with_note(note: String) -> Self {
295 let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
296 let emitter = Box::new(AnnotateSnippetEmitter::new(stderr_destination(ColorConfig::Auto)));
297 let dcx = DiagCtxt::new(Box::new(EmitterWithNote { emitter, note }));
298 ParseSess::with_dcx(dcx, sm)
299 }
300
301 #[inline]
302 pub fn source_map(&self) -> &SourceMap {
303 &self.source_map
304 }
305
306 pub fn clone_source_map(&self) -> Arc<SourceMap> {
307 Arc::clone(&self.source_map)
308 }
309
310 pub fn buffer_lint(
311 &self,
312 lint: &'static Lint,
313 span: impl Into<MultiSpan>,
314 node_id: NodeId,
315 diagnostic: impl Into<DecorateDiagCompat>,
316 ) {
317 self.opt_span_buffer_lint(lint, Some(span.into()), node_id, diagnostic.into())
318 }
319
320 pub fn dyn_buffer_lint<
321 F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSync + DynSend + 'static,
322 >(
323 &self,
324 lint: &'static Lint,
325 span: impl Into<MultiSpan>,
326 node_id: NodeId,
327 callback: F,
328 ) {
329 self.opt_span_buffer_lint(
330 lint,
331 Some(span.into()),
332 node_id,
333 DecorateDiagCompat(Box::new(|dcx, level, _| callback(dcx, level))),
334 )
335 }
336
337 pub fn dyn_buffer_lint_sess<
338 F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &Session) -> Diag<'a, ()>
339 + DynSync
340 + DynSend
341 + 'static,
342 >(
343 &self,
344 lint: &'static Lint,
345 span: impl Into<MultiSpan>,
346 node_id: NodeId,
347 callback: F,
348 ) {
349 self.opt_span_buffer_lint(
350 lint,
351 Some(span.into()),
352 node_id,
353 DecorateDiagCompat(Box::new(|dcx, level, sess| {
354 let sess = sess.downcast_ref::<Session>().expect("expected a `Session`");
355 callback(dcx, level, sess)
356 })),
357 )
358 }
359
360 pub(crate) fn opt_span_buffer_lint(
361 &self,
362 lint: &'static Lint,
363 span: Option<MultiSpan>,
364 node_id: NodeId,
365 diagnostic: DecorateDiagCompat,
366 ) {
367 self.buffered_lints.with_lock(|buffered_lints| {
368 buffered_lints.push(BufferedEarlyLint {
369 span,
370 node_id,
371 lint_id: LintId::of(lint),
372 diagnostic,
373 });
374 });
375 }
376
377 pub fn dcx(&self) -> DiagCtxtHandle<'_> {
378 self.dcx.handle()
379 }
380}