]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #52011 - oli-obk:dont_you_hate_it_too_when_everything_panics_constantly...
authorbors <bors@rust-lang.org>
Wed, 22 Aug 2018 22:08:03 +0000 (22:08 +0000)
committerbors <bors@rust-lang.org>
Wed, 22 Aug 2018 22:08:03 +0000 (22:08 +0000)
Allow panicking with string literal messages inside constants

r? @eddyb

cc https://github.com/rust-lang/rust/issues/51999

we can't implement things like `panic!("foo: {}", x)` right now because we can't call trait methods (most notably `Display::fmt`) inside constants. Also most of these impls probably have loops and conditions, so it's messy anyway.

But hey `panic!("foo")` works at least.

cc @japaric got any test ideas for `#![no_std]`?

1  2 
src/librustc/ich/impls_ty.rs
src/librustc/ty/structural_impls.rs
src/librustc_mir/transform/qualify_consts.rs

index 709b53f248dd1cd768bd05db9ee78b011c7a78da,54829058f44fa0186991401591a783a956c0b840..1c331d53a2a3c889c7cc421e2539d7cf9bafbe7c
@@@ -25,7 -25,7 +25,7 @@@ use ty
  use mir;
  
  impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
 -for &'gcx ty::Slice<T>
 +for &'gcx ty::List<T>
      where T: HashStable<StableHashingContext<'a>> {
      fn hash_stable<W: StableHasherResult>(&self,
                                            hcx: &mut StableHashingContext<'a>,
@@@ -53,7 -53,7 +53,7 @@@
      }
  }
  
 -impl<'a, 'gcx, T> ToStableHashKey<StableHashingContext<'a>> for &'gcx ty::Slice<T>
 +impl<'a, 'gcx, T> ToStableHashKey<StableHashingContext<'a>> for &'gcx ty::List<T>
      where T: HashStable<StableHashingContext<'a>>
  {
      type KeyType = Fingerprint;
@@@ -536,7 -536,6 +536,6 @@@ for ::mir::interpret::EvalErrorKind<'gc
              DeallocateNonBasePtr |
              HeapAllocZeroBytes |
              Unreachable |
-             Panic |
              ReadFromReturnPointer |
              UnimplementedTraitSelection |
              TypeckError |
              GeneratorResumedAfterReturn |
              GeneratorResumedAfterPanic |
              InfiniteLoop => {}
+             Panic { ref msg, ref file, line, col } => {
+                 msg.hash_stable(hcx, hasher);
+                 file.hash_stable(hcx, hasher);
+                 line.hash_stable(hcx, hasher);
+                 col.hash_stable(hcx, hasher);
+             },
              ReferencedConstant(ref err) => err.hash_stable(hcx, hasher),
              MachineError(ref err) => err.hash_stable(hcx, hasher),
              FunctionPointerTyMismatch(a, b) => {
@@@ -797,90 -802,90 +802,90 @@@ impl_stable_hash_for!(enum ty::BoundReg
  });
  
  impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
 -for ty::TypeVariants<'gcx>
 +for ty::TyKind<'gcx>
  {
      fn hash_stable<W: StableHasherResult>(&self,
                                            hcx: &mut StableHashingContext<'a>,
                                            hasher: &mut StableHasher<W>) {
 -        use ty::TypeVariants::*;
 +        use ty::TyKind::*;
  
          mem::discriminant(self).hash_stable(hcx, hasher);
          match *self {
 -            TyBool  |
 -            TyChar  |
 -            TyStr   |
 -            TyError |
 -            TyNever => {
 +            Bool  |
 +            Char  |
 +            Str   |
 +            Error |
 +            Never => {
                  // Nothing more to hash.
              }
 -            TyInt(int_ty) => {
 +            Int(int_ty) => {
                  int_ty.hash_stable(hcx, hasher);
              }
 -            TyUint(uint_ty) => {
 +            Uint(uint_ty) => {
                  uint_ty.hash_stable(hcx, hasher);
              }
 -            TyFloat(float_ty)  => {
 +            Float(float_ty)  => {
                  float_ty.hash_stable(hcx, hasher);
              }
 -            TyAdt(adt_def, substs) => {
 +            Adt(adt_def, substs) => {
                  adt_def.hash_stable(hcx, hasher);
                  substs.hash_stable(hcx, hasher);
              }
 -            TyArray(inner_ty, len) => {
 +            Array(inner_ty, len) => {
                  inner_ty.hash_stable(hcx, hasher);
                  len.hash_stable(hcx, hasher);
              }
 -            TySlice(inner_ty) => {
 +            Slice(inner_ty) => {
                  inner_ty.hash_stable(hcx, hasher);
              }
 -            TyRawPtr(pointee_ty) => {
 +            RawPtr(pointee_ty) => {
                  pointee_ty.hash_stable(hcx, hasher);
              }
 -            TyRef(region, pointee_ty, mutbl) => {
 +            Ref(region, pointee_ty, mutbl) => {
                  region.hash_stable(hcx, hasher);
                  pointee_ty.hash_stable(hcx, hasher);
                  mutbl.hash_stable(hcx, hasher);
              }
 -            TyFnDef(def_id, substs) => {
 +            FnDef(def_id, substs) => {
                  def_id.hash_stable(hcx, hasher);
                  substs.hash_stable(hcx, hasher);
              }
 -            TyFnPtr(ref sig) => {
 +            FnPtr(ref sig) => {
                  sig.hash_stable(hcx, hasher);
              }
 -            TyDynamic(ref existential_predicates, region) => {
 +            Dynamic(ref existential_predicates, region) => {
                  existential_predicates.hash_stable(hcx, hasher);
                  region.hash_stable(hcx, hasher);
              }
 -            TyClosure(def_id, closure_substs) => {
 +            Closure(def_id, closure_substs) => {
                  def_id.hash_stable(hcx, hasher);
                  closure_substs.hash_stable(hcx, hasher);
              }
 -            TyGenerator(def_id, generator_substs, movability) => {
 +            Generator(def_id, generator_substs, movability) => {
                  def_id.hash_stable(hcx, hasher);
                  generator_substs.hash_stable(hcx, hasher);
                  movability.hash_stable(hcx, hasher);
              }
 -            TyGeneratorWitness(types) => {
 +            GeneratorWitness(types) => {
                  types.hash_stable(hcx, hasher)
              }
 -            TyTuple(inner_tys) => {
 +            Tuple(inner_tys) => {
                  inner_tys.hash_stable(hcx, hasher);
              }
 -            TyProjection(ref projection_ty) => {
 +            Projection(ref projection_ty) => {
                  projection_ty.hash_stable(hcx, hasher);
              }
 -            TyAnon(def_id, substs) => {
 +            Anon(def_id, substs) => {
                  def_id.hash_stable(hcx, hasher);
                  substs.hash_stable(hcx, hasher);
              }
 -            TyParam(param_ty) => {
 +            Param(param_ty) => {
                  param_ty.hash_stable(hcx, hasher);
              }
 -            TyForeign(def_id) => {
 +            Foreign(def_id) => {
                  def_id.hash_stable(hcx, hasher);
              }
 -            TyInfer(infer_ty) => {
 +            Infer(infer_ty) => {
                  infer_ty.hash_stable(hcx, hasher);
              }
          }
@@@ -905,7 -910,7 +910,7 @@@ for ty::TyVi
                                            _hasher: &mut StableHasher<W>) {
          // TyVid values are confined to an inference context and hence
          // should not be hashed.
 -        bug!("ty::TypeVariants::hash_stable() - can't hash a TyVid {:?}.", *self)
 +        bug!("ty::TyKind::hash_stable() - can't hash a TyVid {:?}.", *self)
      }
  }
  
@@@ -917,7 -922,7 +922,7 @@@ for ty::IntVi
                                            _hasher: &mut StableHasher<W>) {
          // IntVid values are confined to an inference context and hence
          // should not be hashed.
 -        bug!("ty::TypeVariants::hash_stable() - can't hash an IntVid {:?}.", *self)
 +        bug!("ty::TyKind::hash_stable() - can't hash an IntVid {:?}.", *self)
      }
  }
  
@@@ -929,7 -934,7 +934,7 @@@ for ty::FloatVi
                                            _hasher: &mut StableHasher<W>) {
          // FloatVid values are confined to an inference context and hence
          // should not be hashed.
 -        bug!("ty::TypeVariants::hash_stable() - can't hash a FloatVid {:?}.", *self)
 +        bug!("ty::TyKind::hash_stable() - can't hash a FloatVid {:?}.", *self)
      }
  }
  
index 09ec6c79139415aae83a84ed7d74e95325cf37fb,95e2cc6c3870d6d593d2118257faf20d3be837b8..e6c10358279b38cf03d049d53d4ff730977663f6
@@@ -574,7 -574,11 +574,11 @@@ impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx
              HeapAllocZeroBytes => HeapAllocZeroBytes,
              HeapAllocNonPowerOfTwoAlignment(n) => HeapAllocNonPowerOfTwoAlignment(n),
              Unreachable => Unreachable,
-             Panic => Panic,
+             Panic { ref msg, ref file, line, col } => Panic {
+                 msg: msg.clone(),
+                 file: file.clone(),
+                 line, col,
+             },
              ReadFromReturnPointer => ReadFromReturnPointer,
              PathNotFound(ref v) => PathNotFound(v.clone()),
              UnimplementedTraitSelection => UnimplementedTraitSelection,
@@@ -735,7 -739,7 +739,7 @@@ BraceStructTypeFoldableImpl! 
      impl<'tcx> TypeFoldable<'tcx> for ty::ParamEnv<'tcx> { reveal, caller_bounds }
  }
  
 -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
 +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
      fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
          let v = self.iter().map(|p| p.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
          folder.tcx().intern_existential_predicates(&v)
@@@ -754,7 -758,7 +758,7 @@@ EnumTypeFoldableImpl! 
      }
  }
  
 -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<Ty<'tcx>> {
 +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
      fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
          let v = self.iter().map(|t| t.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
          folder.tcx().intern_type_list(&v)
@@@ -836,33 -840,33 +840,33 @@@ impl<'tcx> TypeFoldable<'tcx> for inter
  impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
      fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
          let sty = match self.sty {
 -            ty::TyRawPtr(tm) => ty::TyRawPtr(tm.fold_with(folder)),
 -            ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz.fold_with(folder)),
 -            ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)),
 -            ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)),
 -            ty::TyDynamic(ref trait_ty, ref region) =>
 -                ty::TyDynamic(trait_ty.fold_with(folder), region.fold_with(folder)),
 -            ty::TyTuple(ts) => ty::TyTuple(ts.fold_with(folder)),
 -            ty::TyFnDef(def_id, substs) => {
 -                ty::TyFnDef(def_id, substs.fold_with(folder))
 +            ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)),
 +            ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)),
 +            ty::Slice(typ) => ty::Slice(typ.fold_with(folder)),
 +            ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)),
 +            ty::Dynamic(ref trait_ty, ref region) =>
 +                ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder)),
 +            ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)),
 +            ty::FnDef(def_id, substs) => {
 +                ty::FnDef(def_id, substs.fold_with(folder))
              }
 -            ty::TyFnPtr(f) => ty::TyFnPtr(f.fold_with(folder)),
 -            ty::TyRef(ref r, ty, mutbl) => {
 -                ty::TyRef(r.fold_with(folder), ty.fold_with(folder), mutbl)
 +            ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)),
 +            ty::Ref(ref r, ty, mutbl) => {
 +                ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl)
              }
 -            ty::TyGenerator(did, substs, movability) => {
 -                ty::TyGenerator(
 +            ty::Generator(did, substs, movability) => {
 +                ty::Generator(
                      did,
                      substs.fold_with(folder),
                      movability)
              }
 -            ty::TyGeneratorWitness(types) => ty::TyGeneratorWitness(types.fold_with(folder)),
 -            ty::TyClosure(did, substs) => ty::TyClosure(did, substs.fold_with(folder)),
 -            ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)),
 -            ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)),
 -            ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) |
 -            ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
 -            ty::TyParam(..) | ty::TyNever | ty::TyForeign(..) => return self
 +            ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)),
 +            ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)),
 +            ty::Projection(ref data) => ty::Projection(data.fold_with(folder)),
 +            ty::Anon(did, substs) => ty::Anon(did, substs.fold_with(folder)),
 +            ty::Bool | ty::Char | ty::Str | ty::Int(_) |
 +            ty::Uint(_) | ty::Float(_) | ty::Error | ty::Infer(_) |
 +            ty::Param(..) | ty::Never | ty::Foreign(..) => return self
          };
  
          if self.sty == sty {
  
      fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
          match self.sty {
 -            ty::TyRawPtr(ref tm) => tm.visit_with(visitor),
 -            ty::TyArray(typ, sz) => typ.visit_with(visitor) || sz.visit_with(visitor),
 -            ty::TySlice(typ) => typ.visit_with(visitor),
 -            ty::TyAdt(_, substs) => substs.visit_with(visitor),
 -            ty::TyDynamic(ref trait_ty, ref reg) =>
 +            ty::RawPtr(ref tm) => tm.visit_with(visitor),
 +            ty::Array(typ, sz) => typ.visit_with(visitor) || sz.visit_with(visitor),
 +            ty::Slice(typ) => typ.visit_with(visitor),
 +            ty::Adt(_, substs) => substs.visit_with(visitor),
 +            ty::Dynamic(ref trait_ty, ref reg) =>
                  trait_ty.visit_with(visitor) || reg.visit_with(visitor),
 -            ty::TyTuple(ts) => ts.visit_with(visitor),
 -            ty::TyFnDef(_, substs) => substs.visit_with(visitor),
 -            ty::TyFnPtr(ref f) => f.visit_with(visitor),
 -            ty::TyRef(r, ty, _) => r.visit_with(visitor) || ty.visit_with(visitor),
 -            ty::TyGenerator(_did, ref substs, _) => {
 +            ty::Tuple(ts) => ts.visit_with(visitor),
 +            ty::FnDef(_, substs) => substs.visit_with(visitor),
 +            ty::FnPtr(ref f) => f.visit_with(visitor),
 +            ty::Ref(r, ty, _) => r.visit_with(visitor) || ty.visit_with(visitor),
 +            ty::Generator(_did, ref substs, _) => {
                  substs.visit_with(visitor)
              }
 -            ty::TyGeneratorWitness(ref types) => types.visit_with(visitor),
 -            ty::TyClosure(_did, ref substs) => substs.visit_with(visitor),
 -            ty::TyProjection(ref data) => data.visit_with(visitor),
 -            ty::TyAnon(_, ref substs) => substs.visit_with(visitor),
 -            ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) |
 -            ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
 -            ty::TyParam(..) | ty::TyNever | ty::TyForeign(..) => false,
 +            ty::GeneratorWitness(ref types) => types.visit_with(visitor),
 +            ty::Closure(_did, ref substs) => substs.visit_with(visitor),
 +            ty::Projection(ref data) => data.visit_with(visitor),
 +            ty::Anon(_, ref substs) => substs.visit_with(visitor),
 +            ty::Bool | ty::Char | ty::Str | ty::Int(_) |
 +            ty::Uint(_) | ty::Float(_) | ty::Error | ty::Infer(_) |
 +            ty::Param(..) | ty::Never | ty::Foreign(..) => false,
          }
      }
  
@@@ -1010,7 -1014,7 +1014,7 @@@ BraceStructTypeFoldableImpl! 
      }
  }
  
 -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::Predicate<'tcx>> {
 +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
      fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
          let v = self.iter().map(|p| p.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
          folder.tcx().intern_predicates(&v)
index a56399eecd38ef057c2273bf2a5b357a52077c3c,20525b5f484bafe68983c0931034a5025dd398d2..740581b82995a3edac6da3213accfadbe76485df
@@@ -400,6 -400,11 +400,11 @@@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx
  
          (self.qualif, Lrc::new(promoted_temps))
      }
+     fn is_const_panic_fn(&self, def_id: DefId) -> bool {
+         Some(def_id) == self.tcx.lang_items().panic_fn() ||
+         Some(def_id) == self.tcx.lang_items().begin_panic_fn()
+     }
  }
  
  /// Accumulates an Rvalue or Call's effects in self.qualif.
@@@ -495,7 -500,7 +500,7 @@@ impl<'a, 'tcx> Visitor<'tcx> for Qualif
                                  this.add(Qualif::NOT_CONST);
                              } else {
                                  let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
 -                                if let ty::TyRawPtr(_) = base_ty.sty {
 +                                if let ty::RawPtr(_) = base_ty.sty {
                                      if !this.tcx.sess.features_untracked().const_raw_ptr_deref {
                                          emit_feature_err(
                                              &this.tcx.sess.parse_sess, "const_raw_ptr_deref",
              if let Place::Projection(ref proj) = *place {
                  if let ProjectionElem::Deref = proj.elem {
                      let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
 -                    if let ty::TyRef(..) = base_ty.sty {
 +                    if let ty::Ref(..) = base_ty.sty {
                          is_reborrow = true;
                      }
                  }
                      if self.mode == Mode::StaticMut {
                          // Inside a `static mut`, &mut [...] is also allowed.
                          match ty.sty {
 -                            ty::TyArray(..) | ty::TySlice(_) => forbidden_mut = false,
 +                            ty::Array(..) | ty::Slice(_) => forbidden_mut = false,
                              _ => {}
                          }
 -                    } else if let ty::TyArray(_, len) = ty.sty {
 +                    } else if let ty::Array(_, len) = ty.sty {
                          // FIXME(eddyb) the `self.mode == Mode::Fn` condition
                          // seems unnecessary, given that this is merely a ZST.
                          if len.unwrap_usize(self.tcx) == 0 && self.mode == Mode::Fn {
              }
  
              Rvalue::BinaryOp(op, ref lhs, _) => {
 -                if let ty::TyRawPtr(_) = lhs.ty(self.mir, self.tcx).sty {
 +                if let ty::RawPtr(_) = lhs.ty(self.mir, self.tcx).sty {
                      assert!(op == BinOp::Eq || op == BinOp::Ne ||
                              op == BinOp::Le || op == BinOp::Lt ||
                              op == BinOp::Ge || op == BinOp::Gt ||
              let fn_ty = func.ty(self.mir, self.tcx);
              let mut callee_def_id = None;
              let (mut is_shuffle, mut is_const_fn) = (false, None);
 -            if let ty::TyFnDef(def_id, _) = fn_ty.sty {
 +            if let ty::FnDef(def_id, _) = fn_ty.sty {
                  callee_def_id = Some(def_id);
                  match self.tcx.fn_sig(def_id).abi() {
                      Abi::RustIntrinsic |
                          }
                      }
                      _ => {
-                         if self.tcx.is_const_fn(def_id) {
+                         if self.tcx.is_const_fn(def_id) || self.is_const_panic_fn(def_id) {
                              is_const_fn = Some(def_id);
                          }
                      }
  
              // Const fn calls.
              if let Some(def_id) = is_const_fn {
+                 // check the const_panic feature gate or
                  // find corresponding rustc_const_unstable feature
-                 if let Some(&attr::Stability {
+                 // FIXME: cannot allow this inside `allow_internal_unstable` because that would make
+                 // `panic!` insta stable in constants, since the macro is marked with the attr
+                 if self.is_const_panic_fn(def_id) {
+                     if self.mode == Mode::Fn {
+                         // never promote panics
+                         self.qualif = Qualif::NOT_CONST;
+                     } else if !self.tcx.sess.features_untracked().const_panic {
+                         // don't allow panics in constants without the feature gate
+                         emit_feature_err(
+                             &self.tcx.sess.parse_sess,
+                             "const_panic",
+                             self.span,
+                             GateIssue::Language,
+                             &format!("panicking in {}s is unstable", self.mode),
+                         );
+                     }
+                 } else if let Some(&attr::Stability {
                      rustc_const_unstable: Some(attr::RustcConstUnstable {
                          feature: ref feature_name
                      }),