@@ -23,6 +23,7 @@ use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext};
2323
2424use syntax:: ast;
2525use syntax:: symbol:: Symbol ;
26+ use syntax:: feature_gate:: { emit_feature_err, GateIssue } ;
2627
2728use std:: ops:: Bound ;
2829
@@ -96,7 +97,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
9697 if let hir:: Unsafety :: Unsafe = sig. unsafety ( ) {
9798 self . require_unsafe ( "call to unsafe function" ,
9899 "consult the function's documentation for information on how to avoid \
99- undefined behavior", UnsafetyViolationKind :: MinConstFn )
100+ undefined behavior", UnsafetyViolationKind :: GatedConstFnCall )
100101 }
101102 }
102103 }
@@ -146,7 +147,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
146147 "initializing type with `rustc_layout_scalar_valid_range` attr" ,
147148 "initializing a layout restricted type's field with a value outside \
148149 the valid range is undefined behavior",
149- UnsafetyViolationKind :: MinConstFn ,
150+ UnsafetyViolationKind :: GeneralAndConstFn ,
150151 ) ,
151152 }
152153 }
@@ -319,12 +320,21 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
319320 ( Safety :: Safe , _) => {
320321 for violation in violations {
321322 let mut violation = violation. clone ( ) ;
322- if self . min_const_fn {
323- // overwrite unsafety violation in const fn with a single hard error kind
324- violation. kind = UnsafetyViolationKind :: MinConstFn ;
325- } else if let UnsafetyViolationKind :: MinConstFn = violation. kind {
326- // outside of const fns we treat `MinConstFn` and `General` the same
327- violation. kind = UnsafetyViolationKind :: General ;
323+ match violation. kind {
324+ UnsafetyViolationKind :: GeneralAndConstFn |
325+ UnsafetyViolationKind :: General => { } ,
326+ UnsafetyViolationKind :: BorrowPacked ( _) |
327+ UnsafetyViolationKind :: ExternStatic ( _) => if self . min_const_fn {
328+ // const fns don't need to be backwards compatible and can
329+ // emit these violations as a hard error instead of a backwards
330+ // compat lint
331+ violation. kind = UnsafetyViolationKind :: General ;
332+ } ,
333+ UnsafetyViolationKind :: GatedConstFnCall => {
334+ // safe code can't call unsafe const fns, this `UnsafetyViolationKind`
335+ // is only relevant for `Safety::ExplicitUnsafe` in `unsafe const fn`s
336+ violation. kind = UnsafetyViolationKind :: General ;
337+ }
328338 }
329339 if !self . violations . contains ( & violation) {
330340 self . violations . push ( violation)
@@ -344,13 +354,24 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
344354 for violation in violations {
345355 match violation. kind {
346356 // these are allowed
347- UnsafetyViolationKind :: MinConstFn
357+ UnsafetyViolationKind :: GatedConstFnCall => {
348358 // if `#![feature(min_const_unsafe_fn)]` is active
349- if self . tcx . sess . features_untracked ( ) . min_const_unsafe_fn => { } ,
350- _ => {
359+ if !self . tcx . sess . features_untracked ( ) . min_const_unsafe_fn {
360+ if !self . violations . contains ( & violation) {
361+ self . violations . push ( violation. clone ( ) )
362+ }
363+ }
364+ }
365+ // these unsafe things are stable in const fn
366+ UnsafetyViolationKind :: GeneralAndConstFn => { } ,
367+ UnsafetyViolationKind :: General |
368+ UnsafetyViolationKind :: BorrowPacked ( _) |
369+ UnsafetyViolationKind :: ExternStatic ( _) => {
351370 let mut violation = violation. clone ( ) ;
352- // overwrite unsafety violation in const fn with a hard error
353- violation. kind = UnsafetyViolationKind :: MinConstFn ;
371+ // const fns don't need to be backwards compatible and can
372+ // emit these violations as a hard error instead of a backwards
373+ // compat lint
374+ violation. kind = UnsafetyViolationKind :: General ;
354375 if !self . violations . contains ( & violation) {
355376 self . violations . push ( violation)
356377 }
@@ -400,7 +421,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
400421 source_info,
401422 description : Symbol :: intern ( description) . as_interned_str ( ) ,
402423 details : Symbol :: intern ( details) . as_interned_str ( ) ,
403- kind : UnsafetyViolationKind :: MinConstFn ,
424+ kind : UnsafetyViolationKind :: GeneralAndConstFn ,
404425 } ] , & [ ] ) ;
405426 }
406427 } ,
@@ -592,6 +613,16 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
592613 } in violations. iter ( ) {
593614 // Report an error.
594615 match kind {
616+ UnsafetyViolationKind :: General if tcx. is_min_const_fn ( def_id) => {
617+ tcx. sess . struct_span_err (
618+ source_info. span ,
619+ & format ! ( "{} is unsafe and unsafe operations \
620+ are not allowed in const fn", description) )
621+ . span_label ( source_info. span , & description. as_str ( ) [ ..] )
622+ . note ( & details. as_str ( ) [ ..] )
623+ . emit ( ) ;
624+ }
625+ UnsafetyViolationKind :: GeneralAndConstFn |
595626 UnsafetyViolationKind :: General => {
596627 struct_span_err ! (
597628 tcx. sess, source_info. span, E0133 ,
@@ -600,14 +631,15 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
600631 . note ( & details. as_str ( ) [ ..] )
601632 . emit ( ) ;
602633 }
603- UnsafetyViolationKind :: MinConstFn => {
604- tcx. sess . struct_span_err (
634+ UnsafetyViolationKind :: GatedConstFnCall => {
635+ emit_feature_err (
636+ & tcx. sess . parse_sess ,
637+ "min_const_unsafe_fn" ,
605638 source_info. span ,
606- & format ! ( "{} is unsafe and unsafe operations \
607- are not allowed in const fn", description) )
608- . span_label ( source_info. span , & description. as_str ( ) [ ..] )
609- . note ( & details. as_str ( ) [ ..] )
610- . emit ( ) ;
639+ GateIssue :: Language ,
640+ "calls to `const unsafe fn` in const fns are unstable" ,
641+ ) ;
642+
611643 }
612644 UnsafetyViolationKind :: ExternStatic ( lint_node_id) => {
613645 tcx. lint_node_note ( SAFE_EXTERN_STATICS ,
0 commit comments