Skip to content

Commit 8957c75

Browse files
committed
syntax: #[allow_internal_unsafe] bypasses the unsafe_code lint in macros.
1 parent 59675d2 commit 8957c75

File tree

18 files changed

+155
-31
lines changed

18 files changed

+155
-31
lines changed

src/librustc/hir/lowering.rs

+1
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ impl<'a> LoweringContext<'a> {
404404
format: codemap::CompilerDesugaring(Symbol::intern(reason)),
405405
span: Some(span),
406406
allow_internal_unstable: true,
407+
allow_internal_unsafe: false,
407408
},
408409
});
409410
span.ctxt = SyntaxContext::empty().apply_mark(mark);

src/librustc_allocator/expand.rs

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
7979
format: MacroAttribute(Symbol::intern(name)),
8080
span: None,
8181
allow_internal_unstable: true,
82+
allow_internal_unsafe: false,
8283
}
8384
});
8485
let span = Span {

src/librustc_lint/builtin.rs

+17-8
Original file line numberDiff line numberDiff line change
@@ -195,24 +195,35 @@ impl LintPass for UnsafeCode {
195195
}
196196
}
197197

198+
impl UnsafeCode {
199+
fn report_unsafe(&self, cx: &LateContext, span: Span, desc: &'static str) {
200+
// This comes from a macro that has #[allow_internal_unsafe].
201+
if span.allows_unsafe() {
202+
return;
203+
}
204+
205+
cx.span_lint(UNSAFE_CODE, span, desc);
206+
}
207+
}
208+
198209
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
199210
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
200211
if let hir::ExprBlock(ref blk) = e.node {
201212
// Don't warn about generated blocks, that'll just pollute the output.
202213
if blk.rules == hir::UnsafeBlock(hir::UserProvided) {
203-
cx.span_lint(UNSAFE_CODE, blk.span, "usage of an `unsafe` block");
214+
self.report_unsafe(cx, blk.span, "usage of an `unsafe` block");
204215
}
205216
}
206217
}
207218

208219
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
209220
match it.node {
210221
hir::ItemTrait(hir::Unsafety::Unsafe, ..) => {
211-
cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait")
222+
self.report_unsafe(cx, it.span, "declaration of an `unsafe` trait")
212223
}
213224

214225
hir::ItemImpl(hir::Unsafety::Unsafe, ..) => {
215-
cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait")
226+
self.report_unsafe(cx, it.span, "implementation of an `unsafe` trait")
216227
}
217228

218229
_ => return,
@@ -228,12 +239,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
228239
_: ast::NodeId) {
229240
match fk {
230241
FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => {
231-
cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function")
242+
self.report_unsafe(cx, span, "declaration of an `unsafe` function")
232243
}
233244

234245
FnKind::Method(_, sig, ..) => {
235246
if sig.unsafety == hir::Unsafety::Unsafe {
236-
cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method")
247+
self.report_unsafe(cx, span, "implementation of an `unsafe` method")
237248
}
238249
}
239250

@@ -244,9 +255,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
244255
fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
245256
if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = item.node {
246257
if sig.unsafety == hir::Unsafety::Unsafe {
247-
cx.span_lint(UNSAFE_CODE,
248-
item.span,
249-
"declaration of an `unsafe` method")
258+
self.report_unsafe(cx, item.span, "declaration of an `unsafe` method")
250259
}
251260
}
252261
}

src/librustc_plugin/registry.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,19 @@ impl<'a> Registry<'a> {
102102
panic!("user-defined macros may not be named `macro_rules`");
103103
}
104104
self.syntax_exts.push((name, match extension {
105-
NormalTT(ext, _, allow_internal_unstable) => {
105+
NormalTT {
106+
expander,
107+
def_info: _,
108+
allow_internal_unstable,
109+
allow_internal_unsafe
110+
} => {
106111
let nid = ast::CRATE_NODE_ID;
107-
NormalTT(ext, Some((nid, self.krate_span)), allow_internal_unstable)
112+
NormalTT {
113+
expander,
114+
def_info: Some((nid, self.krate_span)),
115+
allow_internal_unstable,
116+
allow_internal_unsafe
117+
}
108118
}
109119
IdentTT(ext, _, allow_internal_unstable) => {
110120
IdentTT(ext, Some(self.krate_span), allow_internal_unstable)
@@ -134,8 +144,12 @@ impl<'a> Registry<'a> {
134144
/// It builds for you a `NormalTT` that calls `expander`,
135145
/// and also takes care of interning the macro's name.
136146
pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) {
137-
self.register_syntax_extension(Symbol::intern(name),
138-
NormalTT(Box::new(expander), None, false));
147+
self.register_syntax_extension(Symbol::intern(name), NormalTT {
148+
expander: Box::new(expander),
149+
def_info: None,
150+
allow_internal_unstable: false,
151+
allow_internal_unsafe: false,
152+
});
139153
}
140154

141155
/// Register a compiler lint pass.

src/librustc_resolve/macros.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ impl<'a> base::Resolver for Resolver<'a> {
313313
fn check_unused_macros(&self) {
314314
for did in self.unused_macros.iter() {
315315
let id_span = match *self.macro_map[did] {
316-
SyntaxExtension::NormalTT(_, isp, _) => isp,
316+
SyntaxExtension::NormalTT { def_info, .. } => def_info,
317317
SyntaxExtension::DeclMacro(.., osp) => osp,
318318
_ => None,
319319
};

src/libsyntax/ext/base.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -532,10 +532,16 @@ pub enum SyntaxExtension {
532532
/// A normal, function-like syntax extension.
533533
///
534534
/// `bytes!` is a `NormalTT`.
535-
///
536-
/// The `bool` dictates whether the contents of the macro can
537-
/// directly use `#[unstable]` things (true == yes).
538-
NormalTT(Box<TTMacroExpander>, Option<(ast::NodeId, Span)>, bool),
535+
NormalTT {
536+
expander: Box<TTMacroExpander>,
537+
def_info: Option<(ast::NodeId, Span)>,
538+
/// Whether the contents of the macro can
539+
/// directly use `#[unstable]` things (true == yes).
540+
allow_internal_unstable: bool,
541+
/// Whether the contents of the macro can use `unsafe`
542+
/// without triggering the `unsafe_code` lint.
543+
allow_internal_unsafe: bool,
544+
},
539545

540546
/// A function-like syntax extension that has an extra ident before
541547
/// the block.
@@ -562,7 +568,7 @@ impl SyntaxExtension {
562568
pub fn kind(&self) -> MacroKind {
563569
match *self {
564570
SyntaxExtension::DeclMacro(..) |
565-
SyntaxExtension::NormalTT(..) |
571+
SyntaxExtension::NormalTT { .. } |
566572
SyntaxExtension::IdentTT(..) |
567573
SyntaxExtension::ProcMacro(..) =>
568574
MacroKind::Bang,

src/libsyntax/ext/derive.rs

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path]
6464
format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
6565
span: None,
6666
allow_internal_unstable: true,
67+
allow_internal_unsafe: false,
6768
},
6869
});
6970

src/libsyntax/ext/expand.rs

+20-7
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
411411
format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
412412
span: None,
413413
allow_internal_unstable: false,
414+
allow_internal_unsafe: false,
414415
}
415416
});
416417

@@ -458,7 +459,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
458459
let path = &mac.node.path;
459460

460461
let ident = ident.unwrap_or_else(|| keywords::Invalid.ident());
461-
let validate_and_set_expn_info = |def_site_span, allow_internal_unstable| {
462+
let validate_and_set_expn_info = |def_site_span,
463+
allow_internal_unstable,
464+
allow_internal_unsafe| {
462465
if ident.name != keywords::Invalid.name() {
463466
return Err(format!("macro {}! expects no ident argument, given '{}'", path, ident));
464467
}
@@ -467,7 +470,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
467470
callee: NameAndSpan {
468471
format: MacroBang(Symbol::intern(&format!("{}", path))),
469472
span: def_site_span,
470-
allow_internal_unstable: allow_internal_unstable,
473+
allow_internal_unstable,
474+
allow_internal_unsafe,
471475
},
472476
});
473477
Ok(())
@@ -476,20 +480,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
476480
let opt_expanded = match *ext {
477481
DeclMacro(ref expand, def_span) => {
478482
if let Err(msg) = validate_and_set_expn_info(def_span.map(|(_, s)| s),
479-
false) {
483+
false, false) {
480484
self.cx.span_err(path.span, &msg);
481485
return kind.dummy(span);
482486
}
483487
kind.make_from(expand.expand(self.cx, span, mac.node.stream()))
484488
}
485489

486-
NormalTT(ref expandfun, def_info, allow_internal_unstable) => {
490+
NormalTT {
491+
ref expander,
492+
def_info,
493+
allow_internal_unstable,
494+
allow_internal_unsafe
495+
} => {
487496
if let Err(msg) = validate_and_set_expn_info(def_info.map(|(_, s)| s),
488-
allow_internal_unstable) {
497+
allow_internal_unstable,
498+
allow_internal_unsafe) {
489499
self.cx.span_err(path.span, &msg);
490500
return kind.dummy(span);
491501
}
492-
kind.make_from(expandfun.expand(self.cx, span, mac.node.stream()))
502+
kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
493503
}
494504

495505
IdentTT(ref expander, tt_span, allow_internal_unstable) => {
@@ -504,7 +514,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
504514
callee: NameAndSpan {
505515
format: MacroBang(Symbol::intern(&format!("{}", path))),
506516
span: tt_span,
507-
allow_internal_unstable: allow_internal_unstable,
517+
allow_internal_unstable,
518+
allow_internal_unsafe: false,
508519
}
509520
});
510521

@@ -540,6 +551,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
540551
span: None,
541552
// FIXME probably want to follow macro_rules macros here.
542553
allow_internal_unstable: false,
554+
allow_internal_unsafe: false,
543555
},
544556
});
545557

@@ -578,6 +590,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
578590
format: MacroAttribute(pretty_name),
579591
span: None,
580592
allow_internal_unstable: false,
593+
allow_internal_unsafe: false,
581594
}
582595
};
583596

src/libsyntax/ext/tt/macro_rules.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
269269
valid &= check_lhs_no_empty_seq(sess, &[lhs.clone()])
270270
}
271271

272-
let exp: Box<_> = Box::new(MacroRulesMacroExpander {
272+
let expander: Box<_> = Box::new(MacroRulesMacroExpander {
273273
name: def.ident,
274274
lhses: lhses,
275275
rhses: rhses,
@@ -278,9 +278,15 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
278278

279279
if body.legacy {
280280
let allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable");
281-
NormalTT(exp, Some((def.id, def.span)), allow_internal_unstable)
281+
let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe");
282+
NormalTT {
283+
expander,
284+
def_info: Some((def.id, def.span)),
285+
allow_internal_unstable,
286+
allow_internal_unsafe
287+
}
282288
} else {
283-
SyntaxExtension::DeclMacro(exp, Some((def.id, def.span)))
289+
SyntaxExtension::DeclMacro(expander, Some((def.id, def.span)))
284290
}
285291
}
286292

src/libsyntax/feature_gate.rs

+15
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,14 @@ declare_features! (
194194
// rustc internal
195195
(active, allow_internal_unstable, "1.0.0", None),
196196

197+
// Allows the use of #[allow_internal_unsafe]. This is an
198+
// attribute on macro_rules! and can't use the attribute handling
199+
// below (it has to be checked before expansion possibly makes
200+
// macros disappear).
201+
//
202+
// rustc internal
203+
(active, allow_internal_unsafe, "1.0.0", None),
204+
197205
// #23121. Array patterns have some hazards yet.
198206
(active, slice_patterns, "1.0.0", Some(23121)),
199207

@@ -735,6 +743,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
735743
EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
736744
cfg_fn!(allow_internal_unstable))),
737745

746+
("allow_internal_unsafe", Normal, Gated(Stability::Unstable,
747+
"allow_internal_unsafe",
748+
EXPLAIN_ALLOW_INTERNAL_UNSAFE,
749+
cfg_fn!(allow_internal_unsafe))),
750+
738751
("fundamental", Whitelisted, Gated(Stability::Unstable,
739752
"fundamental",
740753
"the `#[fundamental]` attribute \
@@ -1045,6 +1058,8 @@ pub const EXPLAIN_TRACE_MACROS: &'static str =
10451058
"`trace_macros` is not stable enough for use and is subject to change";
10461059
pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
10471060
"allow_internal_unstable side-steps feature gating and stability checks";
1061+
pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &'static str =
1062+
"allow_internal_unsafe side-steps the unsafe_code lint";
10481063

10491064
pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
10501065
"`#[derive]` for custom traits is deprecated and will be removed in the future.";

src/libsyntax/std_inject.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ fn ignored_span(sp: Span) -> Span {
2828
format: MacroAttribute(Symbol::intern("std_inject")),
2929
span: None,
3030
allow_internal_unstable: true,
31+
allow_internal_unsafe: false,
3132
}
3233
});
3334
Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..sp }

src/libsyntax/test.rs

+1
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ fn generate_test_harness(sess: &ParseSess,
291291
format: MacroAttribute(Symbol::intern("test")),
292292
span: None,
293293
allow_internal_unstable: true,
294+
allow_internal_unsafe: false,
294295
}
295296
});
296297

src/libsyntax_ext/lib.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,12 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
6464
macro_rules! register {
6565
($( $name:ident: $f:expr, )*) => { $(
6666
register(Symbol::intern(stringify!($name)),
67-
NormalTT(Box::new($f as MacroExpanderFn), None, false));
67+
NormalTT {
68+
expander: Box::new($f as MacroExpanderFn),
69+
def_info: None,
70+
allow_internal_unstable: false,
71+
allow_internal_unsafe: false,
72+
});
6873
)* }
6974
}
7075

@@ -112,7 +117,12 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
112117

113118
// format_args uses `unstable` things internally.
114119
register(Symbol::intern("format_args"),
115-
NormalTT(Box::new(format::expand_format_args), None, true));
120+
NormalTT {
121+
expander: Box::new(format::expand_format_args),
122+
def_info: None,
123+
allow_internal_unstable: true,
124+
allow_internal_unsafe: false,
125+
});
116126

117127
for (name, ext) in user_exts {
118128
register(name, ext);

src/libsyntax_ext/proc_macro_registrar.rs

+1
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
368368
format: MacroAttribute(Symbol::intern("proc_macro")),
369369
span: None,
370370
allow_internal_unstable: true,
371+
allow_internal_unsafe: false,
371372
}
372373
});
373374
let span = Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..DUMMY_SP };

src/libsyntax_pos/hygiene.rs

+3
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ pub struct NameAndSpan {
310310
/// features internally without forcing the whole crate to opt-in
311311
/// to them.
312312
pub allow_internal_unstable: bool,
313+
/// Whether the macro is allowed to use `unsafe` internally
314+
/// even if the user crate has `#![forbid(unsafe_code)]`.
315+
pub allow_internal_unsafe: bool,
313316
/// The span of the macro definition itself. The macro may not
314317
/// have a sensible definition span (e.g. something defined
315318
/// completely inside libsyntax) in which case this is None.

src/libsyntax_pos/lib.rs

+10
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,16 @@ impl Span {
153153
}
154154
}
155155

156+
/// Check if a span is "internal" to a macro in which `unsafe`
157+
/// can be used without triggering the `unsafe_code` lint
158+
// (that is, a macro marked with `#[allow_internal_unsafe]`).
159+
pub fn allows_unsafe(&self) -> bool {
160+
match self.ctxt.outer().expn_info() {
161+
Some(info) => info.callee.allow_internal_unsafe,
162+
None => false,
163+
}
164+
}
165+
156166
pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
157167
let mut prev_span = DUMMY_SP;
158168
let mut result = vec![];

0 commit comments

Comments
 (0)