Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cfg for version based conditional compilation #14218

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mk/crates.mk
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ DEPS_std := core libc native:rustrt native:compiler-rt native:backtrace native:j
DEPS_green := std rand native:context_switch
DEPS_rustuv := std native:uv native:uv_support
DEPS_native := std
DEPS_syntax := std term serialize collections log fmt_macros
DEPS_syntax := std term serialize collections log fmt_macros semver
DEPS_rustc := syntax native:rustllvm flate arena serialize sync getopts \
collections time log
DEPS_rustdoc := rustc native:hoedown serialize sync getopts collections \
Expand Down
55 changes: 55 additions & 0 deletions src/libsyntax/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// except according to those terms.

// Functions dealing with attributes and meta items
extern crate semver;

use ast;
use ast::{Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList};
Expand All @@ -19,6 +20,7 @@ use parse::comments::{doc_comment_style, strip_doc_comment_decoration};
use parse::token::InternedString;
use parse::token;
use crateid::CrateId;
use self::semver::parse;

use collections::HashSet;

Expand Down Expand Up @@ -287,6 +289,41 @@ pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr {
})
}

fn cmp_version(curr: &str, cmp: &str ) -> bool {
let cmp_fn;
let idx;

let version = match parse(curr) {
Some(v) => v,
None => return false
};

if cmp.starts_with(">=") {
cmp_fn = |y| version.ge(y);
idx = 2;
} else if cmp.starts_with("<=") {
cmp_fn = |y| version.le(y);
idx = 2;
} else if cmp.starts_with(">") {
cmp_fn = |y| version.gt(y);
idx = 1;
} else if cmp.starts_with("<") {
cmp_fn =|y| version.lt(y);
idx = 1;
} else if cmp.starts_with("!=") {
cmp_fn = |y| version.ne(y);
idx = 2;
} else {
cmp_fn = |y| version.eq(y);
idx = 0;
}

match parse(cmp.slice_chars(idx, cmp.len())) {
Some(ref v) => cmp_fn(v),
None => false
}
}

/// Tests if any `cfg(...)` meta items in `metas` match `cfg`. e.g.
///
/// test_cfg(`[foo="a", bar]`, `[cfg(foo), cfg(bar)]`) == true
Expand Down Expand Up @@ -322,6 +359,24 @@ pub fn test_cfg<AM: AttrMetaMethods, It: Iterator<AM>>
contains(cfg, *mi)
})
}
ast::MetaNameValue(ref n, _)
if n.equiv(&("rust_version")) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is questionable to have this rust_version behaviour hardcoded into the cfg matcher here (since this matcher is fairly generic).

However, I'm not really sure of a better place for it to go.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't figure out a better place to put it, as the contains function doesn't cut it due to the need to parse and compare the versions. I did my best to make it follow the same style as the not() special case in the matcher.

debug!("rust_version!");
// Inside #[cfg(rust_version="...")]
// Need to get version and operator from the value
// and compare it to the current Rust version
match option_env!("CFG_VERSION") {
Some(s) => {
let v_opt = s.words().next();
match (v_opt, cfg_mi.value_str()) {
(None, _) => false,
(Some(v1), Some(v2)) => cmp_version(v1, v2.get()),
(_, None) => false
}
}
None => false
}
}
_ => contains(cfg, *cfg_mi)
}
})
Expand Down
19 changes: 19 additions & 0 deletions src/test/compile-fail/cfg-version-multiple-matches.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2012-2014 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.

#[cfg(rust_version=">0.1.0")]
fn foo() -> int { 1 }

#[cfg(rust_version=">=0.3.0")]
fn foo() -> int { 2 } //~ ERROR duplicate definition of value `foo`

fn main() {
foo();
}
16 changes: 16 additions & 0 deletions src/test/compile-fail/cfg-version-not-matched.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2012-2014 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.

#[cfg(rust_version="<0.1.0")]
fn foo() -> int { 1 }

fn main() {
foo(); //~ ERROR unresolved name `foo`
}
19 changes: 19 additions & 0 deletions src/test/run-pass/cfg-rust-version.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2012-2014 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.

#[cfg(rust_version=">0.2.0")]
fn foo() -> int { 1 }

#[cfg(rust_version="<0.2.0")]
fn foo() -> int { 0 }

fn main() {
assert_eq!(1, foo());
}