rustc_hir_typeck/
naked_functions.rs1use rustc_hir as hir;
4use rustc_hir::def_id::LocalDefId;
5use rustc_hir::intravisit::Visitor;
6use rustc_hir::{ExprKind, HirIdSet, StmtKind, find_attr};
7use rustc_middle::ty::TyCtxt;
8use rustc_span::{Span, span_bug};
9
10use crate::diagnostics::{
11 NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, ParamsNotAllowed,
12};
13
14pub(crate) fn typeck_naked_fn<'tcx>(
18 tcx: TyCtxt<'tcx>,
19 def_id: LocalDefId,
20 body: &'tcx hir::Body<'tcx>,
21) {
22 if true {
if !{
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &tcx)
{
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(Naked(..)) => {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some() {
::core::panicking::panic("assertion failed: find_attr!(tcx, def_id, Naked(..))")
};
};debug_assert!(find_attr!(tcx, def_id, Naked(..)));
23 check_no_patterns(tcx, body.params);
24 check_no_parameters_use(tcx, body);
25 check_asm(tcx, def_id, body);
26}
27
28fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
30 for param in params {
31 match param.pat.kind {
32 hir::PatKind::Wild | hir::PatKind::Binding(hir::BindingMode::NONE, _, _, None) => {}
33 _ => {
34 tcx.dcx().emit_err(NoPatterns { span: param.pat.span });
35 }
36 }
37 }
38}
39
40fn check_no_parameters_use<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) {
42 let mut params = HirIdSet::default();
43 for param in body.params {
44 param.pat.each_binding(|_binding_mode, hir_id, _span, _ident| {
45 params.insert(hir_id);
46 });
47 }
48 CheckParameters { tcx, params }.visit_body(body);
49}
50
51struct CheckParameters<'tcx> {
52 tcx: TyCtxt<'tcx>,
53 params: HirIdSet,
54}
55
56impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
57 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
58 if let hir::ExprKind::Path(hir::QPath::Resolved(
59 _,
60 hir::Path { res: hir::def::Res::Local(var_hir_id), .. },
61 )) = expr.kind
62 {
63 if self.params.contains(var_hir_id) {
64 self.tcx.dcx().emit_err(ParamsNotAllowed { span: expr.span });
65 return;
66 }
67 }
68 hir::intravisit::walk_expr(self, expr);
69 }
70}
71
72fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) {
74 let mut this = CheckInlineAssembly { items: Vec::new() };
75 this.visit_body(body);
76 if let [(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..] {
77 } else {
79 let mut must_show_error = false;
80 let mut has_naked_asm = false;
81 let mut has_err = false;
82 let mut multiple_asms = ::alloc::vec::Vec::new()vec![];
83 let mut non_asms = ::alloc::vec::Vec::new()vec![];
84 for &(kind, span) in &this.items {
85 match kind {
86 ItemKind::NakedAsm if has_naked_asm => {
87 must_show_error = true;
88 multiple_asms.push(span);
89 }
90 ItemKind::NakedAsm => has_naked_asm = true,
91 ItemKind::InlineAsm => {
92 has_err = true;
93
94 tcx.dcx().emit_err(NakedFunctionsMustNakedAsm { span });
95 }
96 ItemKind::NonAsm => {
97 must_show_error = true;
98 non_asms.push(span);
99 }
100 ItemKind::Err => has_err = true,
101 }
102 }
103
104 if must_show_error || !has_err {
108 tcx.dcx().emit_err(NakedFunctionsAsmBlock {
109 span: tcx.def_span(def_id),
110 multiple_asms,
111 non_asms,
112 });
113 }
114 }
115}
116
117struct CheckInlineAssembly {
118 items: Vec<(ItemKind, Span)>,
119}
120
121#[derive(#[automatically_derived]
impl ::core::marker::Copy for ItemKind { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ItemKind { }
#[automatically_derived]
impl ::core::clone::Clone for ItemKind {
#[inline]
fn clone(&self) -> ItemKind { *self }
}Clone)]
122enum ItemKind {
123 NakedAsm,
124 InlineAsm,
125 NonAsm,
126 Err,
127}
128
129impl CheckInlineAssembly {
130 fn check_expr<'tcx>(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) {
131 match expr.kind {
132 ExprKind::ConstBlock(..)
133 | ExprKind::Array(..)
134 | ExprKind::Call(..)
135 | ExprKind::MethodCall(..)
136 | ExprKind::Use(..)
137 | ExprKind::Tup(..)
138 | ExprKind::Binary(..)
139 | ExprKind::Unary(..)
140 | ExprKind::Lit(..)
141 | ExprKind::Cast(..)
142 | ExprKind::Type(..)
143 | ExprKind::UnsafeBinderCast(..)
144 | ExprKind::Loop(..)
145 | ExprKind::Match(..)
146 | ExprKind::If(..)
147 | ExprKind::Closure { .. }
148 | ExprKind::Assign(..)
149 | ExprKind::AssignOp(..)
150 | ExprKind::Field(..)
151 | ExprKind::Index(..)
152 | ExprKind::Path(..)
153 | ExprKind::AddrOf(..)
154 | ExprKind::Let(..)
155 | ExprKind::Break(..)
156 | ExprKind::Continue(..)
157 | ExprKind::Ret(..)
158 | ExprKind::OffsetOf(..)
159 | ExprKind::Become(..)
160 | ExprKind::Struct(..)
161 | ExprKind::Repeat(..)
162 | ExprKind::Yield(..) => {
163 self.items.push((ItemKind::NonAsm, span));
164 }
165
166 ExprKind::InlineAsm(asm) => match asm.asm_macro {
167 rustc_ast::AsmMacro::Asm => {
168 self.items.push((ItemKind::InlineAsm, span));
169 }
170 rustc_ast::AsmMacro::NakedAsm => {
171 self.items.push((ItemKind::NakedAsm, span));
172 }
173 rustc_ast::AsmMacro::GlobalAsm => {
174 bug_impl(Some(span),
format_args!("`global_asm!` is not allowed in this position"),
Location::caller())span_bug!(span, "`global_asm!` is not allowed in this position")
175 }
176 },
177
178 ExprKind::DropTemps(..) | ExprKind::Block(..) => {
179 hir::intravisit::walk_expr(self, expr);
180 }
181
182 ExprKind::Err(_) => {
183 self.items.push((ItemKind::Err, span));
184 }
185 }
186 }
187}
188
189impl<'tcx> Visitor<'tcx> for CheckInlineAssembly {
190 fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
191 match stmt.kind {
192 StmtKind::Item(..) => {}
193 StmtKind::Let(..) => {
194 self.items.push((ItemKind::NonAsm, stmt.span));
195 }
196 StmtKind::Expr(expr) | StmtKind::Semi(expr) => {
197 self.check_expr(expr, stmt.span);
198 }
199 }
200 }
201
202 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
203 self.check_expr(expr, expr.span);
204 }
205}