1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Representation of a `#[doc(cfg(...))]` attribute.
13 // FIXME: Once RFC #1868 is implemented, switch to use those structures instead.
16 use std::fmt::{self, Write};
19 use syntax::symbol::Symbol;
20 use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind, LitKind};
21 use syntax::parse::ParseSess;
22 use syntax::feature_gate::Features;
26 use html::escape::Escape;
28 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq, Hash)]
30 /// Accepts all configurations.
32 /// Denies all configurations.
34 /// A generic configration option, e.g. `test` or `target_os = "linux"`.
35 Cfg(Symbol, Option<Symbol>),
36 /// Negate a configuration requirement, i.e. `not(x)`.
38 /// Union of a list of configuration requirements, i.e. `any(...)`.
40 /// Intersection of a list of configuration requirements, i.e. `all(...)`.
44 #[derive(PartialEq, Debug)]
45 pub struct InvalidCfgError {
46 pub msg: &'static str,
51 /// Parses a `NestedMetaItem` into a `Cfg`.
52 fn parse_nested(nested_cfg: &NestedMetaItem) -> Result<Cfg, InvalidCfgError> {
53 match nested_cfg.node {
54 NestedMetaItemKind::MetaItem(ref cfg) => Cfg::parse(cfg),
55 NestedMetaItemKind::Literal(ref lit) => Err(InvalidCfgError {
56 msg: "unexpected literal",
62 /// Parses a `MetaItem` into a `Cfg`.
64 /// The `MetaItem` should be the content of the `#[cfg(...)]`, e.g. `unix` or
65 /// `target_os = "redox"`.
67 /// If the content is not properly formatted, it will return an error indicating what and where
69 pub fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> {
70 let name = cfg.name();
72 MetaItemKind::Word => Ok(Cfg::Cfg(name, None)),
73 MetaItemKind::NameValue(ref lit) => match lit.node {
74 LitKind::Str(value, _) => Ok(Cfg::Cfg(name, Some(value))),
75 _ => Err(InvalidCfgError {
76 // FIXME: if the main #[cfg] syntax decided to support non-string literals,
77 // this should be changed as well.
78 msg: "value of cfg option should be a string literal",
82 MetaItemKind::List(ref items) => {
83 let mut sub_cfgs = items.iter().map(Cfg::parse_nested);
84 match &*name.as_str() {
85 "all" => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)),
86 "any" => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)),
87 "not" => if sub_cfgs.len() == 1 {
88 Ok(!sub_cfgs.next().unwrap()?)
91 msg: "expected 1 cfg-pattern",
95 _ => Err(InvalidCfgError {
96 msg: "invalid predicate",
104 /// Checks whether the given configuration can be matched in the current session.
106 /// Equivalent to `attr::cfg_matches`.
107 // FIXME: Actually make use of `features`.
108 pub fn matches(&self, parse_sess: &ParseSess, features: Option<&Features>) -> bool {
112 Cfg::Not(ref child) => !child.matches(parse_sess, features),
113 Cfg::All(ref sub_cfgs) => {
114 sub_cfgs.iter().all(|sub_cfg| sub_cfg.matches(parse_sess, features))
116 Cfg::Any(ref sub_cfgs) => {
117 sub_cfgs.iter().any(|sub_cfg| sub_cfg.matches(parse_sess, features))
119 Cfg::Cfg(name, value) => parse_sess.config.contains(&(name, value)),
123 /// Whether the configuration consists of just `Cfg` or `Not`.
124 fn is_simple(&self) -> bool {
126 Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) => true,
127 Cfg::All(..) | Cfg::Any(..) => false,
131 /// Whether the configuration consists of just `Cfg`, `Not` or `All`.
132 fn is_all(&self) -> bool {
134 Cfg::False | Cfg::True | Cfg::Cfg(..) | Cfg::Not(..) | Cfg::All(..) => true,
135 Cfg::Any(..) => false,
139 /// Renders the configuration for human display, as a short HTML description.
140 pub(crate) fn render_short_html(&self) -> String {
141 let mut msg = ShortHtml(self).to_string();
142 if self.should_capitalize_first_letter() {
143 if let Some(i) = msg.find(|c: char| c.is_ascii_alphanumeric()) {
144 msg[i .. i+1].make_ascii_uppercase();
150 /// Renders the configuration for long display, as a long HTML description.
151 pub(crate) fn render_long_html(&self) -> String {
152 let on = if self.should_use_with_in_description() {
158 let mut msg = format!("This is supported {} <strong>{}</strong>", on, Html(self));
159 if self.should_append_only_to_description() {
160 msg.push_str(" only");
166 fn should_capitalize_first_letter(&self) -> bool {
168 Cfg::False | Cfg::True | Cfg::Not(..) => true,
169 Cfg::Any(ref sub_cfgs) | Cfg::All(ref sub_cfgs) => {
170 sub_cfgs.first().map(Cfg::should_capitalize_first_letter).unwrap_or(false)
172 Cfg::Cfg(name, _) => match &*name.as_str() {
173 "debug_assertions" | "target_endian" => true,
179 fn should_append_only_to_description(&self) -> bool {
181 Cfg::False | Cfg::True => false,
182 Cfg::Any(..) | Cfg::All(..) | Cfg::Cfg(..) => true,
183 Cfg::Not(ref child) => match **child {
184 Cfg::Cfg(..) => true,
190 fn should_use_with_in_description(&self) -> bool {
192 Cfg::Cfg(ref name, _) if name == &"target_feature" => true,
198 impl ops::Not for Cfg {
200 fn not(self) -> Cfg {
202 Cfg::False => Cfg::True,
203 Cfg::True => Cfg::False,
204 Cfg::Not(cfg) => *cfg,
205 s => Cfg::Not(Box::new(s)),
210 impl ops::BitAndAssign for Cfg {
211 fn bitand_assign(&mut self, other: Cfg) {
212 match (self, other) {
213 (&mut Cfg::False, _) | (_, Cfg::True) => {},
214 (s, Cfg::False) => *s = Cfg::False,
215 (s @ &mut Cfg::True, b) => *s = b,
216 (&mut Cfg::All(ref mut a), Cfg::All(ref mut b)) => a.append(b),
217 (&mut Cfg::All(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)),
218 (s, Cfg::All(mut a)) => {
219 let b = mem::replace(s, Cfg::True);
224 let a = mem::replace(s, Cfg::True);
225 *s = Cfg::All(vec![a, b]);
231 impl ops::BitAnd for Cfg {
233 fn bitand(mut self, other: Cfg) -> Cfg {
239 impl ops::BitOrAssign for Cfg {
240 fn bitor_assign(&mut self, other: Cfg) {
241 match (self, other) {
242 (&mut Cfg::True, _) | (_, Cfg::False) => {},
243 (s, Cfg::True) => *s = Cfg::True,
244 (s @ &mut Cfg::False, b) => *s = b,
245 (&mut Cfg::Any(ref mut a), Cfg::Any(ref mut b)) => a.append(b),
246 (&mut Cfg::Any(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)),
247 (s, Cfg::Any(mut a)) => {
248 let b = mem::replace(s, Cfg::True);
253 let a = mem::replace(s, Cfg::True);
254 *s = Cfg::Any(vec![a, b]);
260 impl ops::BitOr for Cfg {
262 fn bitor(mut self, other: Cfg) -> Cfg {
268 struct Html<'a>(&'a Cfg);
270 fn write_with_opt_paren<T: fmt::Display>(
271 fmt: &mut fmt::Formatter,
276 fmt.write_char('(')?;
280 fmt.write_char(')')?;
286 impl<'a> fmt::Display for Html<'a> {
287 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
289 Cfg::Not(ref child) => match **child {
290 Cfg::Any(ref sub_cfgs) => {
291 let separator = if sub_cfgs.iter().all(Cfg::is_simple) {
296 for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
297 fmt.write_str(if i == 0 { "neither " } else { separator })?;
298 write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg))?;
302 ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Html(simple)),
303 ref c => write!(fmt, "not ({})", Html(c)),
306 Cfg::Any(ref sub_cfgs) => {
307 let separator = if sub_cfgs.iter().all(Cfg::is_simple) {
312 for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
314 fmt.write_str(separator)?;
316 write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg))?;
321 Cfg::All(ref sub_cfgs) => {
322 for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
324 fmt.write_str(" and ")?;
326 write_with_opt_paren(fmt, !sub_cfg.is_simple(), Html(sub_cfg))?;
331 Cfg::True => fmt.write_str("everywhere"),
332 Cfg::False => fmt.write_str("nowhere"),
334 Cfg::Cfg(name, value) => {
335 let n = &*name.as_str();
336 let human_readable = match (n, value) {
337 ("unix", None) => "Unix",
338 ("windows", None) => "Windows",
339 ("debug_assertions", None) => "debug-assertions enabled",
340 ("target_os", Some(os)) => match &*os.as_str() {
341 "android" => "Android",
342 "bitrig" => "Bitrig",
343 "dragonfly" => "DragonFly BSD",
344 "emscripten" => "Emscripten",
345 "freebsd" => "FreeBSD",
346 "fuchsia" => "Fuchsia",
352 "netbsd" => "NetBSD",
353 "openbsd" => "OpenBSD",
355 "solaris" => "Solaris",
356 "windows" => "Windows",
359 ("target_arch", Some(arch)) => match &*arch.as_str() {
360 "aarch64" => "AArch64",
364 "mips64" => "MIPS-64",
365 "msp430" => "MSP430",
366 "powerpc" => "PowerPC",
367 "powerpc64" => "PowerPC-64",
369 "sparc64" => "SPARC64",
370 "wasm32" => "WebAssembly",
372 "x86_64" => "x86-64",
375 ("target_vendor", Some(vendor)) => match &*vendor.as_str() {
378 "rumprun" => "Rumprun",
382 ("target_env", Some(env)) => match &*env.as_str() {
386 "newlib" => "Newlib",
387 "uclibc" => "uClibc",
390 ("target_endian", Some(endian)) => return write!(fmt, "{}-endian", endian),
391 ("target_pointer_width", Some(bits)) => return write!(fmt, "{}-bit", bits),
392 ("target_feature", Some(feat)) =>
393 return write!(fmt, "target feature <code>{}</code>", feat),
396 if !human_readable.is_empty() {
397 fmt.write_str(human_readable)
398 } else if let Some(v) = value {
399 write!(fmt, "<code>{}=\"{}\"</code>", Escape(n), Escape(&*v.as_str()))
401 write!(fmt, "<code>{}</code>", Escape(n))
408 struct ShortHtml<'a>(&'a Cfg);
410 impl<'a> fmt::Display for ShortHtml<'a> {
411 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
413 Cfg::Cfg(ref name, Some(ref vendor)) if name == &"target_feature" => {
414 write!(fmt, "<code>{}</code>", vendor)
416 ref cfg => write!(fmt, "{}", Html(cfg)),
425 use syntax::symbol::Symbol;
427 use syntax::codemap::dummy_spanned;
428 use syntax_pos::DUMMY_SP;
429 use syntax::with_globals;
431 fn word_cfg(s: &str) -> Cfg {
432 Cfg::Cfg(Symbol::intern(s), None)
435 fn name_value_cfg(name: &str, value: &str) -> Cfg {
436 Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value)))
442 assert_eq!(!Cfg::False, Cfg::True);
443 assert_eq!(!Cfg::True, Cfg::False);
444 assert_eq!(!word_cfg("test"), Cfg::Not(Box::new(word_cfg("test"))));
446 !Cfg::All(vec![word_cfg("a"), word_cfg("b")]),
447 Cfg::Not(Box::new(Cfg::All(vec![word_cfg("a"), word_cfg("b")])))
450 !Cfg::Any(vec![word_cfg("a"), word_cfg("b")]),
451 Cfg::Not(Box::new(Cfg::Any(vec![word_cfg("a"), word_cfg("b")])))
453 assert_eq!(!Cfg::Not(Box::new(word_cfg("test"))), word_cfg("test"));
460 let mut x = Cfg::False;
462 assert_eq!(x, Cfg::False);
464 x = word_cfg("test");
466 assert_eq!(x, Cfg::False);
468 x = word_cfg("test2");
470 assert_eq!(x, word_cfg("test2"));
473 x &= word_cfg("test3");
474 assert_eq!(x, word_cfg("test3"));
476 x &= word_cfg("test4");
477 assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")]));
479 x &= word_cfg("test5");
480 assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")]));
482 x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]);
483 assert_eq!(x, Cfg::All(vec![
491 let mut y = Cfg::Any(vec![word_cfg("a"), word_cfg("b")]);
493 assert_eq!(y, Cfg::All(vec![
499 Cfg::Any(vec![word_cfg("a"), word_cfg("b")]),
503 word_cfg("a") & word_cfg("b") & word_cfg("c"),
504 Cfg::All(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
512 let mut x = Cfg::True;
514 assert_eq!(x, Cfg::True);
516 x = word_cfg("test");
518 assert_eq!(x, Cfg::True);
520 x = word_cfg("test2");
522 assert_eq!(x, word_cfg("test2"));
525 x |= word_cfg("test3");
526 assert_eq!(x, word_cfg("test3"));
528 x |= word_cfg("test4");
529 assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")]));
531 x |= word_cfg("test5");
532 assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4"), word_cfg("test5")]));
534 x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]);
535 assert_eq!(x, Cfg::Any(vec![
543 let mut y = Cfg::All(vec![word_cfg("a"), word_cfg("b")]);
545 assert_eq!(y, Cfg::Any(vec![
551 Cfg::All(vec![word_cfg("a"), word_cfg("b")]),
555 word_cfg("a") | word_cfg("b") | word_cfg("c"),
556 Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
565 name: Symbol::intern("all"),
566 node: MetaItemKind::Word,
569 assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));
572 name: Symbol::intern("all"),
573 node: MetaItemKind::NameValue(dummy_spanned(LitKind::Str(
574 Symbol::intern("done"),
579 assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done")));
582 name: Symbol::intern("all"),
583 node: MetaItemKind::List(vec![
584 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
585 name: Symbol::intern("a"),
586 node: MetaItemKind::Word,
589 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
590 name: Symbol::intern("b"),
591 node: MetaItemKind::Word,
597 assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b")));
600 name: Symbol::intern("any"),
601 node: MetaItemKind::List(vec![
602 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
603 name: Symbol::intern("a"),
604 node: MetaItemKind::Word,
607 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
608 name: Symbol::intern("b"),
609 node: MetaItemKind::Word,
615 assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") | word_cfg("b")));
618 name: Symbol::intern("not"),
619 node: MetaItemKind::List(vec![
620 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
621 name: Symbol::intern("a"),
622 node: MetaItemKind::Word,
628 assert_eq!(Cfg::parse(&mi), Ok(!word_cfg("a")));
631 name: Symbol::intern("not"),
632 node: MetaItemKind::List(vec![
633 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
634 name: Symbol::intern("any"),
635 node: MetaItemKind::List(vec![
636 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
637 name: Symbol::intern("a"),
638 node: MetaItemKind::Word,
641 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
642 name: Symbol::intern("all"),
643 node: MetaItemKind::List(vec![
644 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
645 name: Symbol::intern("b"),
646 node: MetaItemKind::Word,
649 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
650 name: Symbol::intern("c"),
651 node: MetaItemKind::Word,
663 assert_eq!(Cfg::parse(&mi), Ok(!(word_cfg("a") | (word_cfg("b") & word_cfg("c")))));
666 name: Symbol::intern("all"),
667 node: MetaItemKind::List(vec![
668 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
669 name: Symbol::intern("a"),
670 node: MetaItemKind::Word,
673 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
674 name: Symbol::intern("b"),
675 node: MetaItemKind::Word,
678 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
679 name: Symbol::intern("c"),
680 node: MetaItemKind::Word,
686 assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b") & word_cfg("c")));
691 fn test_parse_err() {
694 name: Symbol::intern("foo"),
695 node: MetaItemKind::NameValue(dummy_spanned(LitKind::Bool(false))),
698 assert!(Cfg::parse(&mi).is_err());
701 name: Symbol::intern("not"),
702 node: MetaItemKind::List(vec![
703 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
704 name: Symbol::intern("a"),
705 node: MetaItemKind::Word,
708 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
709 name: Symbol::intern("b"),
710 node: MetaItemKind::Word,
716 assert!(Cfg::parse(&mi).is_err());
719 name: Symbol::intern("not"),
720 node: MetaItemKind::List(vec![]),
723 assert!(Cfg::parse(&mi).is_err());
726 name: Symbol::intern("foo"),
727 node: MetaItemKind::List(vec![
728 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
729 name: Symbol::intern("a"),
730 node: MetaItemKind::Word,
736 assert!(Cfg::parse(&mi).is_err());
739 name: Symbol::intern("all"),
740 node: MetaItemKind::List(vec![
741 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
742 name: Symbol::intern("foo"),
743 node: MetaItemKind::List(vec![]),
746 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
747 name: Symbol::intern("b"),
748 node: MetaItemKind::Word,
754 assert!(Cfg::parse(&mi).is_err());
757 name: Symbol::intern("any"),
758 node: MetaItemKind::List(vec![
759 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
760 name: Symbol::intern("a"),
761 node: MetaItemKind::Word,
764 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
765 name: Symbol::intern("foo"),
766 node: MetaItemKind::List(vec![]),
772 assert!(Cfg::parse(&mi).is_err());
775 name: Symbol::intern("not"),
776 node: MetaItemKind::List(vec![
777 dummy_spanned(NestedMetaItemKind::MetaItem(MetaItem {
778 name: Symbol::intern("foo"),
779 node: MetaItemKind::List(vec![]),
785 assert!(Cfg::parse(&mi).is_err());
790 fn test_render_short_html() {
793 word_cfg("unix").render_short_html(),
797 name_value_cfg("target_os", "macos").render_short_html(),
801 name_value_cfg("target_pointer_width", "16").render_short_html(),
805 name_value_cfg("target_endian", "little").render_short_html(),
809 (!word_cfg("windows")).render_short_html(),
813 (word_cfg("unix") & word_cfg("windows")).render_short_html(),
817 (word_cfg("unix") | word_cfg("windows")).render_short_html(),
822 word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions")
823 ).render_short_html(),
824 "Unix and Windows and debug-assertions enabled"
828 word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")
829 ).render_short_html(),
830 "Unix or Windows or debug-assertions enabled"
834 !(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions"))
835 ).render_short_html(),
836 "Neither Unix nor Windows nor debug-assertions enabled"
840 (word_cfg("unix") & name_value_cfg("target_arch", "x86_64")) |
841 (word_cfg("windows") & name_value_cfg("target_pointer_width", "64"))
842 ).render_short_html(),
843 "Unix and x86-64, or Windows and 64-bit"
846 (!(word_cfg("unix") & word_cfg("windows"))).render_short_html(),
847 "Not (Unix and Windows)"
851 (word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix")
852 ).render_short_html(),
853 "(Debug-assertions enabled or Windows) and Unix"
856 name_value_cfg("target_feature", "sse2").render_short_html(),
863 fn test_render_long_html() {
866 word_cfg("unix").render_long_html(),
867 "This is supported on <strong>Unix</strong> only."
870 name_value_cfg("target_os", "macos").render_long_html(),
871 "This is supported on <strong>macOS</strong> only."
874 name_value_cfg("target_pointer_width", "16").render_long_html(),
875 "This is supported on <strong>16-bit</strong> only."
878 name_value_cfg("target_endian", "little").render_long_html(),
879 "This is supported on <strong>little-endian</strong> only."
882 (!word_cfg("windows")).render_long_html(),
883 "This is supported on <strong>non-Windows</strong> only."
886 (word_cfg("unix") & word_cfg("windows")).render_long_html(),
887 "This is supported on <strong>Unix and Windows</strong> only."
890 (word_cfg("unix") | word_cfg("windows")).render_long_html(),
891 "This is supported on <strong>Unix or Windows</strong> only."
895 word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions")
896 ).render_long_html(),
897 "This is supported on <strong>Unix and Windows and debug-assertions enabled\
902 word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")
903 ).render_long_html(),
904 "This is supported on <strong>Unix or Windows or debug-assertions enabled\
909 !(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions"))
910 ).render_long_html(),
911 "This is supported on <strong>neither Unix nor Windows nor debug-assertions \
916 (word_cfg("unix") & name_value_cfg("target_arch", "x86_64")) |
917 (word_cfg("windows") & name_value_cfg("target_pointer_width", "64"))
918 ).render_long_html(),
919 "This is supported on <strong>Unix and x86-64, or Windows and 64-bit</strong> \
923 (!(word_cfg("unix") & word_cfg("windows"))).render_long_html(),
924 "This is supported on <strong>not (Unix and Windows)</strong>."
928 (word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix")
929 ).render_long_html(),
930 "This is supported on <strong>(debug-assertions enabled or Windows) and Unix\
934 name_value_cfg("target_feature", "sse2").render_long_html(),
935 "This is supported with <strong>target feature <code>sse2</code></strong> only."