@@ -25,11 +25,13 @@ use syntax::feature_gate::{emit_feature_err, GateIssue};
25
25
use syntax:: symbol:: sym;
26
26
use syntax_pos:: { Span , DUMMY_SP } ;
27
27
28
+ use std:: borrow:: Cow ;
28
29
use std:: cell:: Cell ;
29
30
use std:: fmt;
30
31
use std:: ops:: { Deref , Index , IndexMut } ;
31
32
use std:: usize;
32
33
34
+ use rustc:: hir:: HirId ;
33
35
use crate :: transform:: { MirPass , MirSource } ;
34
36
use super :: promote_consts:: { self , Candidate , TempState } ;
35
37
@@ -1596,51 +1598,24 @@ impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants<'tcx> {
1596
1598
}
1597
1599
1598
1600
let def_id = src. def_id ( ) ;
1599
- let id = tcx. hir ( ) . as_local_hir_id ( def_id) . unwrap ( ) ;
1600
- let mut const_promoted_temps = None ;
1601
- let mode = match tcx. hir ( ) . body_owner_kind ( id) {
1602
- hir:: BodyOwnerKind :: Closure => Mode :: NonConstFn ,
1603
- hir:: BodyOwnerKind :: Fn => {
1604
- if tcx. is_const_fn ( def_id) {
1605
- Mode :: ConstFn
1606
- } else {
1607
- Mode :: NonConstFn
1608
- }
1609
- }
1610
- hir:: BodyOwnerKind :: Const => {
1611
- const_promoted_temps = Some ( tcx. mir_const_qualif ( def_id) . 1 ) ;
1612
- Mode :: Const
1613
- }
1614
- hir:: BodyOwnerKind :: Static ( hir:: MutImmutable ) => Mode :: Static ,
1615
- hir:: BodyOwnerKind :: Static ( hir:: MutMutable ) => Mode :: StaticMut ,
1616
- } ;
1601
+ let hir_id = tcx. hir ( ) . as_local_hir_id ( def_id) . unwrap ( ) ;
1602
+
1603
+ let mode = determine_mode ( tcx, hir_id, def_id) ;
1617
1604
1618
1605
debug ! ( "run_pass: mode={:?}" , mode) ;
1619
- if mode == Mode :: NonConstFn || mode == Mode :: ConstFn {
1606
+ if let Mode :: NonConstFn | Mode :: ConstFn = mode {
1620
1607
// This is ugly because Checker holds onto mir,
1621
1608
// which can't be mutated until its scope ends.
1622
1609
let ( temps, candidates) = {
1623
1610
let mut checker = Checker :: new ( tcx, def_id, body, mode) ;
1624
- if mode == Mode :: ConstFn {
1611
+ if let Mode :: ConstFn = mode {
1625
1612
if tcx. sess . opts . debugging_opts . unleash_the_miri_inside_of_you {
1626
1613
checker. check_const ( ) ;
1627
1614
} else if tcx. is_min_const_fn ( def_id) {
1628
- // enforce `min_const_fn` for stable const fns
1615
+ // Enforce `min_const_fn` for stable ` const fn`s.
1629
1616
use super :: qualify_min_const_fn:: is_min_const_fn;
1630
1617
if let Err ( ( span, err) ) = is_min_const_fn ( tcx, def_id, body) {
1631
- let mut diag = struct_span_err ! (
1632
- tcx. sess,
1633
- span,
1634
- E0723 ,
1635
- "{}" ,
1636
- err,
1637
- ) ;
1638
- diag. note ( "for more information, see issue \
1639
- https://github.com/rust-lang/rust/issues/57563") ;
1640
- diag. help (
1641
- "add `#![feature(const_fn)]` to the crate attributes to enable" ,
1642
- ) ;
1643
- diag. emit ( ) ;
1618
+ error_min_const_fn_violation ( tcx, span, err) ;
1644
1619
} else {
1645
1620
// this should not produce any errors, but better safe than sorry
1646
1621
// FIXME(#53819)
@@ -1664,107 +1639,119 @@ impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants<'tcx> {
1664
1639
promote_consts:: promote_candidates ( def_id, body, tcx, temps, candidates)
1665
1640
) ;
1666
1641
} else {
1667
- if !body. control_flow_destroyed . is_empty ( ) {
1668
- let mut locals = body. vars_iter ( ) ;
1669
- if let Some ( local) = locals. next ( ) {
1670
- let span = body. local_decls [ local] . source_info . span ;
1671
- let mut error = tcx. sess . struct_span_err (
1672
- span,
1673
- & format ! (
1674
- "new features like let bindings are not permitted in {}s \
1675
- which also use short circuiting operators",
1676
- mode,
1677
- ) ,
1678
- ) ;
1679
- for ( span, kind) in body. control_flow_destroyed . iter ( ) {
1680
- error. span_note (
1681
- * span,
1682
- & format ! ( "use of {} here does not actually short circuit due to \
1683
- the const evaluator presently not being able to do control flow. \
1684
- See https://github.com/rust-lang/rust/issues/49146 for more \
1685
- information.", kind) ,
1686
- ) ;
1687
- }
1688
- for local in locals {
1689
- let span = body. local_decls [ local] . source_info . span ;
1690
- error. span_note (
1691
- span,
1692
- "more locals defined here" ,
1693
- ) ;
1694
- }
1695
- error. emit ( ) ;
1696
- }
1697
- }
1698
- let promoted_temps = if mode == Mode :: Const {
1699
- // Already computed by `mir_const_qualif`.
1700
- const_promoted_temps. unwrap ( )
1701
- } else {
1702
- Checker :: new ( tcx, def_id, body, mode) . check_const ( ) . 1
1642
+ check_short_circuiting_in_const_local ( tcx, body, mode) ;
1643
+
1644
+ let promoted_temps = match mode {
1645
+ Mode :: Const => tcx. mir_const_qualif ( def_id) . 1 ,
1646
+ _ => Checker :: new ( tcx, def_id, body, mode) . check_const ( ) . 1 ,
1703
1647
} ;
1648
+ remove_drop_and_storage_dead_on_promoted_locals ( body, promoted_temps) ;
1649
+ }
1704
1650
1705
- // In `const` and `static` everything without `StorageDead`
1706
- // is `'static`, we don't have to create promoted MIR fragments,
1707
- // just remove `Drop` and `StorageDead` on "promoted" locals.
1708
- debug ! ( "run_pass: promoted_temps={:?}" , promoted_temps) ;
1709
- for block in body. basic_blocks_mut ( ) {
1710
- block. statements . retain ( |statement| {
1711
- match statement. kind {
1712
- StatementKind :: StorageDead ( index) => {
1713
- !promoted_temps. contains ( index)
1714
- }
1715
- _ => true
1716
- }
1717
- } ) ;
1718
- let terminator = block. terminator_mut ( ) ;
1719
- match terminator. kind {
1720
- TerminatorKind :: Drop {
1721
- location : Place {
1722
- base : PlaceBase :: Local ( index) ,
1723
- projection : None ,
1724
- } ,
1725
- target,
1726
- ..
1727
- } => {
1728
- if promoted_temps. contains ( index) {
1729
- terminator. kind = TerminatorKind :: Goto {
1730
- target,
1731
- } ;
1732
- }
1733
- }
1734
- _ => { }
1735
- }
1736
- }
1651
+ if mode == Mode :: Static && !tcx. has_attr ( def_id, sym:: thread_local) {
1652
+ // `static`s (not `static mut`s) which are not `#[thread_local]` must be `Sync`.
1653
+ check_static_is_sync ( tcx, body, hir_id) ;
1737
1654
}
1655
+ }
1656
+ }
1738
1657
1739
- // Statics must be Sync.
1740
- if mode == Mode :: Static {
1741
- // `#[thread_local]` statics don't have to be `Sync`.
1742
- for attr in & tcx. get_attrs ( def_id) [ ..] {
1743
- if attr. check_name ( sym:: thread_local) {
1744
- return ;
1745
- }
1658
+ fn determine_mode ( tcx : TyCtxt < ' _ > , hir_id : HirId , def_id : DefId ) -> Mode {
1659
+ match tcx. hir ( ) . body_owner_kind ( hir_id) {
1660
+ hir:: BodyOwnerKind :: Closure => Mode :: NonConstFn ,
1661
+ hir:: BodyOwnerKind :: Fn if tcx. is_const_fn ( def_id) => Mode :: ConstFn ,
1662
+ hir:: BodyOwnerKind :: Fn => Mode :: NonConstFn ,
1663
+ hir:: BodyOwnerKind :: Const => Mode :: Const ,
1664
+ hir:: BodyOwnerKind :: Static ( hir:: MutImmutable ) => Mode :: Static ,
1665
+ hir:: BodyOwnerKind :: Static ( hir:: MutMutable ) => Mode :: StaticMut ,
1666
+ }
1667
+ }
1668
+
1669
+ fn error_min_const_fn_violation ( tcx : TyCtxt < ' _ > , span : Span , msg : Cow < ' _ , str > ) {
1670
+ struct_span_err ! ( tcx. sess, span, E0723 , "{}" , msg)
1671
+ . note ( "for more information, see issue https://github.com/rust-lang/rust/issues/57563" )
1672
+ . help ( "add `#![feature(const_fn)]` to the crate attributes to enable" )
1673
+ . emit ( ) ;
1674
+ }
1675
+
1676
+ fn check_short_circuiting_in_const_local ( tcx : TyCtxt < ' _ > , body : & mut Body < ' tcx > , mode : Mode ) {
1677
+ if body. control_flow_destroyed . is_empty ( ) {
1678
+ return ;
1679
+ }
1680
+
1681
+ let mut locals = body. vars_iter ( ) ;
1682
+ if let Some ( local) = locals. next ( ) {
1683
+ let span = body. local_decls [ local] . source_info . span ;
1684
+ let mut error = tcx. sess . struct_span_err (
1685
+ span,
1686
+ & format ! (
1687
+ "new features like let bindings are not permitted in {}s \
1688
+ which also use short circuiting operators",
1689
+ mode,
1690
+ ) ,
1691
+ ) ;
1692
+ for ( span, kind) in body. control_flow_destroyed . iter ( ) {
1693
+ error. span_note (
1694
+ * span,
1695
+ & format ! ( "use of {} here does not actually short circuit due to \
1696
+ the const evaluator presently not being able to do control flow. \
1697
+ See https://github.com/rust-lang/rust/issues/49146 for more \
1698
+ information.", kind) ,
1699
+ ) ;
1700
+ }
1701
+ for local in locals {
1702
+ let span = body. local_decls [ local] . source_info . span ;
1703
+ error. span_note ( span, "more locals defined here" ) ;
1704
+ }
1705
+ error. emit ( ) ;
1706
+ }
1707
+ }
1708
+
1709
+ /// In `const` and `static` everything without `StorageDead`
1710
+ /// is `'static`, we don't have to create promoted MIR fragments,
1711
+ /// just remove `Drop` and `StorageDead` on "promoted" locals.
1712
+ fn remove_drop_and_storage_dead_on_promoted_locals (
1713
+ body : & mut Body < ' tcx > ,
1714
+ promoted_temps : & BitSet < Local > ,
1715
+ ) {
1716
+ debug ! ( "run_pass: promoted_temps={:?}" , promoted_temps) ;
1717
+
1718
+ for block in body. basic_blocks_mut ( ) {
1719
+ block. statements . retain ( |statement| {
1720
+ match statement. kind {
1721
+ StatementKind :: StorageDead ( index) => !promoted_temps. contains ( index) ,
1722
+ _ => true
1746
1723
}
1747
- let ty = body. return_ty ( ) ;
1748
- tcx. infer_ctxt ( ) . enter ( |infcx| {
1749
- let param_env = ty:: ParamEnv :: empty ( ) ;
1750
- let cause = traits:: ObligationCause :: new ( body. span , id, traits:: SharedStatic ) ;
1751
- let mut fulfillment_cx = traits:: FulfillmentContext :: new ( ) ;
1752
- fulfillment_cx. register_bound ( & infcx,
1753
- param_env,
1754
- ty,
1755
- tcx. require_lang_item (
1756
- lang_items:: SyncTraitLangItem ,
1757
- Some ( body. span )
1758
- ) ,
1759
- cause) ;
1760
- if let Err ( err) = fulfillment_cx. select_all_or_error ( & infcx) {
1761
- infcx. report_fulfillment_errors ( & err, None , false ) ;
1762
- }
1763
- } ) ;
1724
+ } ) ;
1725
+ let terminator = block. terminator_mut ( ) ;
1726
+ match terminator. kind {
1727
+ TerminatorKind :: Drop {
1728
+ location : Place {
1729
+ base : PlaceBase :: Local ( index) ,
1730
+ projection : None ,
1731
+ } ,
1732
+ target,
1733
+ ..
1734
+ } if promoted_temps. contains ( index) => {
1735
+ terminator. kind = TerminatorKind :: Goto { target } ;
1736
+ }
1737
+ _ => { }
1764
1738
}
1765
1739
}
1766
1740
}
1767
1741
1742
+ fn check_static_is_sync ( tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > , hir_id : HirId ) {
1743
+ let ty = body. return_ty ( ) ;
1744
+ tcx. infer_ctxt ( ) . enter ( |infcx| {
1745
+ let cause = traits:: ObligationCause :: new ( body. span , hir_id, traits:: SharedStatic ) ;
1746
+ let mut fulfillment_cx = traits:: FulfillmentContext :: new ( ) ;
1747
+ let sync_def_id = tcx. require_lang_item ( lang_items:: SyncTraitLangItem , Some ( body. span ) ) ;
1748
+ fulfillment_cx. register_bound ( & infcx, ty:: ParamEnv :: empty ( ) , ty, sync_def_id, cause) ;
1749
+ if let Err ( err) = fulfillment_cx. select_all_or_error ( & infcx) {
1750
+ infcx. report_fulfillment_errors ( & err, None , false ) ;
1751
+ }
1752
+ } ) ;
1753
+ }
1754
+
1768
1755
fn args_required_const ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> Option < FxHashSet < usize > > {
1769
1756
let attrs = tcx. get_attrs ( def_id) ;
1770
1757
let attr = attrs. iter ( ) . find ( |a| a. check_name ( sym:: rustc_args_required_const) ) ?;
0 commit comments