rustc: Add a debug_assertions #[cfg] directive
This commit is an implementation of [RFC 563][rfc] which adds a new `cfg(debug_assertions)` directive which is specially recognized and calculated by the compiler. The flag is turned off at any optimization level greater than 1 and may also be explicitly controlled through the `-C debug-assertions` flag. [rfc]: https://github.com/rust-lang/rfcs/pull/563 The `debug_assert!` and `debug_assert_eq!` macros now respect this instead of the `ndebug` variable and `ndebug` no longer holds any meaning to the standard library. Code which was previously relying on `not(ndebug)` to gate expensive code should be updated to rely on `debug_assertions` instead. Closes #22492 [breaking-change]
This commit is contained in:
parent
68740b4054
commit
d5d834551c
|
@ -590,7 +590,7 @@ TEST_SREQ$(1)_T_$(2)_H_$(3) = \
|
||||||
|
|
||||||
# The tests select when to use debug configuration on their own;
|
# The tests select when to use debug configuration on their own;
|
||||||
# remove directive, if present, from CFG_RUSTC_FLAGS (issue #7898).
|
# remove directive, if present, from CFG_RUSTC_FLAGS (issue #7898).
|
||||||
CTEST_RUSTC_FLAGS := $$(subst --cfg ndebug,,$$(CFG_RUSTC_FLAGS))
|
CTEST_RUSTC_FLAGS := $$(subst -C debug-assertions,,$$(CFG_RUSTC_FLAGS))
|
||||||
|
|
||||||
# The tests cannot be optimized while the rest of the compiler is optimized, so
|
# The tests cannot be optimized while the rest of the compiler is optimized, so
|
||||||
# filter out the optimization (if any) from rustc and then figure out if we need
|
# filter out the optimization (if any) from rustc and then figure out if we need
|
||||||
|
|
|
@ -100,10 +100,12 @@ macro_rules! assert_eq {
|
||||||
/// This will invoke the `panic!` macro if the provided expression cannot be
|
/// This will invoke the `panic!` macro if the provided expression cannot be
|
||||||
/// evaluated to `true` at runtime.
|
/// evaluated to `true` at runtime.
|
||||||
///
|
///
|
||||||
/// Unlike `assert!`, `debug_assert!` statements can be disabled by passing
|
/// Unlike `assert!`, `debug_assert!` statements are only enabled in non
|
||||||
/// `--cfg ndebug` to the compiler. This makes `debug_assert!` useful for
|
/// optimized builds by default. An optimized build will omit all
|
||||||
/// checks that are too expensive to be present in a release build but may be
|
/// `debug_assert!` statements unless `-C debug-assertions` is passed to the
|
||||||
/// helpful during development.
|
/// compiler. This makes `debug_assert!` useful for checks that are too
|
||||||
|
/// expensive to be present in a release build but may be helpful during
|
||||||
|
/// development.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
|
@ -125,7 +127,7 @@ macro_rules! assert_eq {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
macro_rules! debug_assert {
|
macro_rules! debug_assert {
|
||||||
($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
|
($($arg:tt)*) => (if cfg!(debug_assertions) { assert!($($arg)*); })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asserts that two expressions are equal to each other, testing equality in
|
/// Asserts that two expressions are equal to each other, testing equality in
|
||||||
|
@ -133,10 +135,12 @@ macro_rules! debug_assert {
|
||||||
///
|
///
|
||||||
/// On panic, this macro will print the values of the expressions.
|
/// On panic, this macro will print the values of the expressions.
|
||||||
///
|
///
|
||||||
/// Unlike `assert_eq!`, `debug_assert_eq!` statements can be disabled by
|
/// Unlike `assert_eq!`, `debug_assert_eq!` statements are only enabled in non
|
||||||
/// passing `--cfg ndebug` to the compiler. This makes `debug_assert_eq!`
|
/// optimized builds by default. An optimized build will omit all
|
||||||
/// useful for checks that are too expensive to be present in a release build
|
/// `debug_assert_eq!` statements unless `-C debug-assertions` is passed to the
|
||||||
/// but may be helpful during development.
|
/// compiler. This makes `debug_assert_eq!` useful for checks that are too
|
||||||
|
/// expensive to be present in a release build but may be helpful during
|
||||||
|
/// development.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
|
@ -147,7 +151,7 @@ macro_rules! debug_assert {
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! debug_assert_eq {
|
macro_rules! debug_assert_eq {
|
||||||
($($arg:tt)*) => (if cfg!(not(ndebug)) { assert_eq!($($arg)*); })
|
($($arg:tt)*) => (if cfg!(debug_assertions) { assert_eq!($($arg)*); })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Short circuiting evaluation on Err
|
/// Short circuiting evaluation on Err
|
||||||
|
|
|
@ -157,7 +157,7 @@ macro_rules! info {
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! debug {
|
macro_rules! debug {
|
||||||
($($arg:tt)*) => (if cfg!(not(ndebug)) { log!(::log::DEBUG, $($arg)*) })
|
($($arg:tt)*) => (if cfg!(debug_assertions) { log!(::log::DEBUG, $($arg)*) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A macro to test whether a log level is enabled for the current module.
|
/// A macro to test whether a log level is enabled for the current module.
|
||||||
|
@ -192,7 +192,7 @@ macro_rules! debug {
|
||||||
macro_rules! log_enabled {
|
macro_rules! log_enabled {
|
||||||
($lvl:expr) => ({
|
($lvl:expr) => ({
|
||||||
let lvl = $lvl;
|
let lvl = $lvl;
|
||||||
(lvl != ::log::DEBUG || cfg!(not(ndebug))) &&
|
(lvl != ::log::DEBUG || cfg!(debug_assertions)) &&
|
||||||
lvl <= ::log::log_level() &&
|
lvl <= ::log::log_level() &&
|
||||||
::log::mod_enabled(lvl, module_path!())
|
::log::mod_enabled(lvl, module_path!())
|
||||||
})
|
})
|
||||||
|
|
|
@ -81,6 +81,7 @@ pub struct Options {
|
||||||
|
|
||||||
pub gc: bool,
|
pub gc: bool,
|
||||||
pub optimize: OptLevel,
|
pub optimize: OptLevel,
|
||||||
|
pub debug_assertions: bool,
|
||||||
pub debuginfo: DebugInfoLevel,
|
pub debuginfo: DebugInfoLevel,
|
||||||
pub lint_opts: Vec<(String, lint::Level)>,
|
pub lint_opts: Vec<(String, lint::Level)>,
|
||||||
pub describe_lints: bool,
|
pub describe_lints: bool,
|
||||||
|
@ -238,7 +239,8 @@ pub fn basic_options() -> Options {
|
||||||
crate_name: None,
|
crate_name: None,
|
||||||
alt_std_name: None,
|
alt_std_name: None,
|
||||||
libs: Vec::new(),
|
libs: Vec::new(),
|
||||||
unstable_features: UnstableFeatures::Disallow
|
unstable_features: UnstableFeatures::Disallow,
|
||||||
|
debug_assertions: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,6 +530,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
|
||||||
2 = full debug info with variable and type information"),
|
2 = full debug info with variable and type information"),
|
||||||
opt_level: Option<uint> = (None, parse_opt_uint,
|
opt_level: Option<uint> = (None, parse_opt_uint,
|
||||||
"Optimize with possible levels 0-3"),
|
"Optimize with possible levels 0-3"),
|
||||||
|
debug_assertions: Option<bool> = (None, parse_opt_bool,
|
||||||
|
"explicitly enable the cfg(debug_assertions) directive"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -621,7 +625,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mk = attr::mk_name_value_item_str;
|
let mk = attr::mk_name_value_item_str;
|
||||||
return vec!(// Target bindings.
|
let mut ret = vec![ // Target bindings.
|
||||||
attr::mk_word_item(fam.clone()),
|
attr::mk_word_item(fam.clone()),
|
||||||
mk(InternedString::new("target_os"), intern(os)),
|
mk(InternedString::new("target_os"), intern(os)),
|
||||||
mk(InternedString::new("target_family"), fam),
|
mk(InternedString::new("target_family"), fam),
|
||||||
|
@ -629,7 +633,11 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
|
||||||
mk(InternedString::new("target_endian"), intern(end)),
|
mk(InternedString::new("target_endian"), intern(end)),
|
||||||
mk(InternedString::new("target_pointer_width"),
|
mk(InternedString::new("target_pointer_width"),
|
||||||
intern(wordsz))
|
intern(wordsz))
|
||||||
);
|
];
|
||||||
|
if sess.opts.debug_assertions {
|
||||||
|
ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append_configuration(cfg: &mut ast::CrateConfig,
|
pub fn append_configuration(cfg: &mut ast::CrateConfig,
|
||||||
|
@ -923,6 +931,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == No);
|
||||||
let gc = debugging_opts.gc;
|
let gc = debugging_opts.gc;
|
||||||
let debuginfo = if matches.opt_present("g") {
|
let debuginfo = if matches.opt_present("g") {
|
||||||
if cg.debuginfo.is_some() {
|
if cg.debuginfo.is_some() {
|
||||||
|
@ -1064,6 +1073,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||||
alt_std_name: None,
|
alt_std_name: None,
|
||||||
libs: libs,
|
libs: libs,
|
||||||
unstable_features: get_unstable_features_setting(),
|
unstable_features: get_unstable_features_setting(),
|
||||||
|
debug_assertions: debug_assertions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3089,7 +3089,7 @@ pub fn trans_crate<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
|
||||||
let check_overflow = if let Some(v) = tcx.sess.opts.debugging_opts.force_overflow_checks {
|
let check_overflow = if let Some(v) = tcx.sess.opts.debugging_opts.force_overflow_checks {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
!attr::contains_name(&krate.config, "ndebug")
|
tcx.sess.opts.debug_assertions
|
||||||
};
|
};
|
||||||
|
|
||||||
// Before we touch LLVM, make sure that multithreading is enabled.
|
// Before we touch LLVM, make sure that multithreading is enabled.
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
|
// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
|
||||||
|
// compile-flags: -C debug-assertions
|
||||||
|
|
||||||
// (Work around constant-evaluation)
|
// (Work around constant-evaluation)
|
||||||
fn value() -> u8 { 200 }
|
fn value() -> u8 { 200 }
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
|
// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
|
||||||
|
// compile-flags: -C debug-assertions
|
||||||
|
|
||||||
// (Work around constant-evaluation)
|
// (Work around constant-evaluation)
|
||||||
fn value() -> u8 { 200 }
|
fn value() -> u8 { 200 }
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
|
// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
|
||||||
|
// compile-flags: -C debug-assertions
|
||||||
|
|
||||||
// (Work around constant-evaluation)
|
// (Work around constant-evaluation)
|
||||||
fn value() -> u8 { 42 }
|
fn value() -> u8 { 42 }
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
-include ../tools.mk
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(RUSTC) debug.rs -C debug-assertions=no
|
||||||
|
$(call RUN,debug) good
|
||||||
|
$(RUSTC) debug.rs -C opt-level=0
|
||||||
|
$(call RUN,debug) bad
|
||||||
|
$(RUSTC) debug.rs -C opt-level=1
|
||||||
|
$(call RUN,debug) good
|
||||||
|
$(RUSTC) debug.rs -C opt-level=2
|
||||||
|
$(call RUN,debug) good
|
||||||
|
$(RUSTC) debug.rs -C opt-level=3
|
||||||
|
$(call RUN,debug) good
|
||||||
|
$(RUSTC) debug.rs -O
|
||||||
|
$(call RUN,debug) good
|
||||||
|
$(RUSTC) debug.rs
|
||||||
|
$(call RUN,debug) bad
|
||||||
|
$(RUSTC) debug.rs -C debug-assertions=yes -O
|
||||||
|
$(call RUN,debug) bad
|
||||||
|
$(RUSTC) debug.rs -C debug-assertions=yes -C opt-level=1
|
||||||
|
$(call RUN,debug) bad
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![deny(warnings)]
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let should_fail = env::args().nth(1) == Some("bad".to_string());
|
||||||
|
|
||||||
|
assert_eq!(thread::spawn(debug_assert_eq).join().is_err(), should_fail);
|
||||||
|
assert_eq!(thread::spawn(debug_assert).join().is_err(), should_fail);
|
||||||
|
assert_eq!(thread::spawn(overflow).join().is_err(), should_fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn debug_assert_eq() {
|
||||||
|
let mut hit1 = false;
|
||||||
|
let mut hit2 = false;
|
||||||
|
debug_assert_eq!({ hit1 = true; 1 }, { hit2 = true; 2 });
|
||||||
|
assert!(!hit1);
|
||||||
|
assert!(!hit2);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn debug_assert() {
|
||||||
|
let mut hit = false;
|
||||||
|
debug_assert!({ hit = true; false });
|
||||||
|
assert!(!hit);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn overflow() {
|
||||||
|
fn add(a: u8, b: u8) -> u8 { a + b }
|
||||||
|
|
||||||
|
add(200u8, 200u8);
|
||||||
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: --cfg ndebug
|
// compile-flags: -C debug-assertions=no
|
||||||
// exec-env:RUST_LOG=conditional-debug-macro-off=4
|
// exec-env:RUST_LOG=conditional-debug-macro-off=4
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags:--cfg ndebug
|
// compile-flags:-C debug-assertions=no
|
||||||
// exec-env:RUST_LOG=logging-enabled-debug=debug
|
// exec-env:RUST_LOG=logging-enabled-debug=debug
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
// ignore-windows
|
// ignore-windows
|
||||||
// exec-env:RUST_LOG=debug
|
// exec-env:RUST_LOG=debug
|
||||||
|
// compile-flags:-C debug-assertions=y
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
Loading…
Reference in New Issue