use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext};
use std::collections::HashSet;
+use rustc::util::nodemap::FxHashSet;
use syntax::tokenstream::{TokenTree, TokenStream};
use syntax::ast;
}
}
+fn validate_const<'a, 'tcx>(
+ tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+ constant: &ty::Const<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ gid: ::rustc::mir::interpret::GlobalId<'tcx>,
+ what: &str,
+) {
+ let mut ecx = ::rustc_mir::interpret::mk_eval_cx(tcx, gid.instance, param_env).unwrap();
+ let result = (|| {
+ let val = ecx.const_to_value(constant.val)?;
+ use rustc_target::abi::LayoutOf;
+ let layout = ecx.layout_of(constant.ty)?;
+ let place = ecx.allocate_place_for_value(val, layout, None)?;
+ let ptr = place.to_ptr()?;
+ let mut todo = vec![(ptr, layout.ty, String::new())];
+ let mut seen = FxHashSet();
+ seen.insert((ptr, layout.ty));
+ while let Some((ptr, ty, path)) = todo.pop() {
+ let layout = ecx.layout_of(ty)?;
+ ecx.validate_ptr_target(
+ ptr,
+ layout.align,
+ layout,
+ path,
+ &mut seen,
+ &mut todo,
+ )?;
+ }
+ Ok(())
+ })();
+ if let Err(err) = result {
+ let (trace, span) = ecx.generate_stacktrace(None);
+ let err = ::rustc::mir::interpret::ConstEvalErr {
+ error: err,
+ stacktrace: trace,
+ span,
+ };
+ let err = err.struct_error(
+ tcx.at(span),
+ &format!("this {} likely exhibits undefined behavior", what),
+ );
+ if let Some(mut err) = err {
+ err.note("The rules on what exactly is undefined behavior aren't clear, \
+ so this check might be overzealous. Please open an issue on the rust compiler \
+ repository if you believe it should not be considered undefined behavior",
+ );
+ err.emit();
+ }
+ }
+}
+
fn check_const(cx: &LateContext, body_id: hir::BodyId, what: &str) {
let def_id = cx.tcx.hir.body_owner_def_id(body_id);
let param_env = cx.tcx.param_env(def_id);
instance: ty::Instance::mono(cx.tcx, def_id),
promoted: None
};
- if let Err(err) = cx.tcx.const_eval(param_env.and(cid)) {
- let span = cx.tcx.def_span(def_id);
- err.report_as_lint(
- cx.tcx.at(span),
- &format!("this {} cannot be used", what),
- cx.current_lint_root(),
- );
+ match cx.tcx.const_eval(param_env.and(cid)) {
+ Ok(val) => validate_const(cx.tcx, val, param_env, cid, what),
+ Err(err) => {
+ // errors for statics are already reported directly in the query
+ if cx.tcx.is_static(def_id).is_none() {
+ let span = cx.tcx.def_span(def_id);
+ err.report_as_lint(
+ cx.tcx.at(span),
+ &format!("this {} cannot be used", what),
+ cx.current_lint_root(),
+ );
+ }
+ },
}
}
hir::ItemKind::Const(_, body_id) => {
check_const(cx, body_id, "constant");
},
+ hir::ItemKind::Static(_, _, body_id) => {
+ check_const(cx, body_id, "static");
+ },
hir::ItemKind::Ty(ref ty, _) => hir::intravisit::walk_ty(
&mut UnusedBrokenConstVisitor(cx),
ty