1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
use crate::structured_errors::StructuredDiagnostic;
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
use rustc_middle::ty::{Ty, TypeFoldable};
use rustc_session::Session;
use rustc_span::Span;

pub struct MissingCastForVariadicArg<'tcx> {
    pub sess: &'tcx Session,
    pub span: Span,
    pub ty: Ty<'tcx>,
    pub cast_ty: &'tcx str,
}

impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx> {
    fn session(&self) -> &Session {
        self.sess
    }

    fn code(&self) -> DiagnosticId {
        rustc_errors::error_code!(E0617)
    }

    fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> {
        let mut err = if self.ty.references_error() {
            self.sess.diagnostic().struct_dummy()
        } else {
            self.sess.struct_span_fatal_with_code(
                self.span,
                &format!("can't pass `{}` to variadic function", self.ty),
                self.code(),
            )
        };

        if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.span) {
            err.span_suggestion(
                self.span,
                &format!("cast the value to `{}`", self.cast_ty),
                format!("{} as {}", snippet, self.cast_ty),
                Applicability::MachineApplicable,
            );
        } else {
            err.help(&format!("cast the value to `{}`", self.cast_ty));
        }

        err
    }

    fn diagnostic_extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
        err.note(&format!(
            "certain types, like `{}`, must be casted before passing them to a \
                variadic function, because of arcane ABI rules dictated by the C \
                standard",
            self.ty
        ));

        err
    }
}