Auto merge of #33965 - Manishearth:rollup, r=Manishearth

Rollup of 5 pull requests

- Successful merges: #33867, #33926, #33942, #33958, #33964
- Failed merges:
This commit is contained in:
bors 2016-05-30 08:13:08 -07:00
commit f3bfa313ec
13 changed files with 196 additions and 165 deletions

View File

@ -117,6 +117,7 @@ from xml.etree import cElementTree as ET
from htmlentitydefs import entitydefs
entitydefs['larrb'] = u'\u21e4'
entitydefs['rarrb'] = u'\u21e5'
entitydefs['nbsp'] = ' '
# "void elements" (no closing tag) from the HTML Standard section 12.1.2
VOID_ELEMENTS = set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen',

View File

@ -63,7 +63,7 @@
#[derive(Clone)]
pub struct Resolutions {
pub def_map: RefCell<DefMap>,
pub def_map: DefMap,
pub freevars: FreevarMap,
pub trait_map: TraitMap,
pub maybe_unused_trait_imports: NodeSet,
@ -818,7 +818,7 @@ pub fn lower_and_resolve<'a>(sess: &Session,
name: &id,
glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None },
}, Resolutions {
def_map: RefCell::new(resolver.def_map),
def_map: resolver.def_map,
freevars: resolver.freevars,
trait_map: resolver.trait_map,
maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
@ -866,7 +866,7 @@ macro_rules! try_with_f {
"lifetime resolution",
|| middle::resolve_lifetime::krate(sess,
&hir_map,
&resolutions.def_map.borrow()))?;
&resolutions.def_map))?;
time(time_passes,
"looking for entry point",
@ -886,14 +886,14 @@ macro_rules! try_with_f {
time(time_passes,
"static item recursion checking",
|| static_recursion::check_crate(sess, &resolutions.def_map.borrow(), &hir_map))?;
|| static_recursion::check_crate(sess, &resolutions.def_map, &hir_map))?;
let index = stability::Index::new(&hir_map);
let trait_map = resolutions.trait_map;
TyCtxt::create_and_enter(sess,
arenas,
resolutions.def_map,
RefCell::new(resolutions.def_map),
named_region_map,
hir_map,
resolutions.freevars,

View File

@ -29,6 +29,7 @@
use rustc_metadata::creader::read_local_crates;
use rustc::hir::map as hir_map;
use rustc::session::{self, config};
use std::cell::RefCell;
use std::rc::Rc;
use syntax::ast;
use syntax::abi::Abi;
@ -134,12 +135,12 @@ fn test_env<F>(source_string: &str,
// run just enough stuff to build a tcx:
let lang_items = lang_items::collect_language_items(&sess, &ast_map);
let named_region_map = resolve_lifetime::krate(&sess, &ast_map, &resolutions.def_map.borrow());
let named_region_map = resolve_lifetime::krate(&sess, &ast_map, &resolutions.def_map);
let region_map = region::resolve_crate(&sess, &ast_map);
let index = stability::Index::new(&ast_map);
TyCtxt::create_and_enter(&sess,
&arenas,
resolutions.def_map,
RefCell::new(resolutions.def_map),
named_region_map.unwrap(),
ast_map,
resolutions.freevars,

View File

@ -18,7 +18,9 @@
use std::slice;
use std::str;
pub struct ArchiveRO { ptr: ArchiveRef }
pub struct ArchiveRO {
ptr: ArchiveRef,
}
pub struct Iter<'a> {
archive: &'a ArchiveRO,
@ -61,11 +63,16 @@ fn path2cstr(p: &Path) -> CString {
}
}
pub fn raw(&self) -> ArchiveRef { self.ptr }
pub fn raw(&self) -> ArchiveRef {
self.ptr
}
pub fn iter(&self) -> Iter {
unsafe {
Iter { ptr: ::LLVMRustArchiveIteratorNew(self.ptr), archive: self }
Iter {
ptr: ::LLVMRustArchiveIteratorNew(self.ptr),
archive: self,
}
}
}
}
@ -86,7 +93,10 @@ fn next(&mut self) -> Option<Result<Child<'a>, String>> {
if ptr.is_null() {
::last_error().map(Err)
} else {
Some(Ok(Child { ptr: ptr, _data: marker::PhantomData }))
Some(Ok(Child {
ptr: ptr,
_data: marker::PhantomData,
}))
}
}
}
@ -107,8 +117,7 @@ pub fn name(&self) -> Option<&'a str> {
if name_ptr.is_null() {
None
} else {
let name = slice::from_raw_parts(name_ptr as *const u8,
name_len as usize);
let name = slice::from_raw_parts(name_ptr as *const u8, name_len as usize);
str::from_utf8(name).ok().map(|s| s.trim())
}
}
@ -125,11 +134,15 @@ pub fn data(&self) -> &'a [u8] {
}
}
pub fn raw(&self) -> ::ArchiveChildRef { self.ptr }
pub fn raw(&self) -> ::ArchiveChildRef {
self.ptr
}
}
impl<'a> Drop for Child<'a> {
fn drop(&mut self) {
unsafe { ::LLVMRustArchiveChildFree(self.ptr); }
unsafe {
::LLVMRustArchiveChildFree(self.ptr);
}
}
}

View File

@ -21,20 +21,25 @@ fn main() {
println!("cargo:rustc-cfg=cargobuild");
let target = env::var("TARGET").unwrap();
let llvm_config = env::var_os("LLVM_CONFIG").map(PathBuf::from)
.unwrap_or_else(|| {
match env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
Some(dir) => {
let to_test = dir.parent().unwrap().parent().unwrap()
.join(&target).join("llvm/bin/llvm-config");
if Command::new(&to_test).output().is_ok() {
return to_test
}
}
None => {}
}
PathBuf::from("llvm-config")
});
let llvm_config = env::var_os("LLVM_CONFIG")
.map(PathBuf::from)
.unwrap_or_else(|| {
match env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
Some(dir) => {
let to_test = dir.parent()
.unwrap()
.parent()
.unwrap()
.join(&target)
.join("llvm/bin/llvm-config");
if Command::new(&to_test).output().is_ok() {
return to_test;
}
}
None => {}
}
PathBuf::from("llvm-config")
});
println!("cargo:rerun-if-changed={}", llvm_config.display());
@ -63,20 +68,22 @@ fn main() {
let host = env::var("HOST").unwrap();
let is_crossed = target != host;
let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc",
"pnacl"];
let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl"];
// FIXME: surely we don't need all these components, right? Stuff like mcjit
// or interpreter the compiler itself never uses.
let required_components = &["ipo", "bitreader", "bitwriter", "linker",
"asmparser", "mcjit", "interpreter",
let required_components = &["ipo",
"bitreader",
"bitwriter",
"linker",
"asmparser",
"mcjit",
"interpreter",
"instrumentation"];
let components = output(Command::new(&llvm_config).arg("--components"));
let mut components = components.split_whitespace().collect::<Vec<_>>();
components.retain(|c| {
optional_components.contains(c) || required_components.contains(c)
});
components.retain(|c| optional_components.contains(c) || required_components.contains(c));
for component in required_components {
if !components.contains(component) {
@ -96,7 +103,7 @@ fn main() {
for flag in cxxflags.split_whitespace() {
// Ignore flags like `-m64` when we're doing a cross build
if is_crossed && flag.starts_with("-m") {
continue
continue;
}
cfg.flag(flag);
}
@ -131,7 +138,7 @@ fn main() {
} else if lib.starts_with("-") {
&lib[1..]
} else {
continue
continue;
};
// Don't need or want this library, but LLVM's CMake build system
@ -140,10 +147,14 @@ fn main() {
// library and it otherwise may just pull in extra dependencies on
// libedit which we don't want
if name == "LLVMLineEditor" {
continue
continue;
}
let kind = if name.starts_with("LLVM") {"static"} else {"dylib"};
let kind = if name.starts_with("LLVM") {
"static"
} else {
"dylib"
};
println!("cargo:rustc-link-lib={}={}", kind, name);
}

View File

@ -16,7 +16,7 @@
use libc::{c_char, c_uint};
use std::ptr;
use {ValueRef, TwineRef, DebugLocRef, DiagnosticInfoRef};
use {DebugLocRef, DiagnosticInfoRef, TwineRef, ValueRef};
#[derive(Copy, Clone)]
pub enum OptimizationDiagnosticKind {
@ -46,8 +46,9 @@ pub struct OptimizationDiagnostic {
}
impl OptimizationDiagnostic {
unsafe fn unpack(kind: OptimizationDiagnosticKind, di: DiagnosticInfoRef)
-> OptimizationDiagnostic {
unsafe fn unpack(kind: OptimizationDiagnosticKind,
di: DiagnosticInfoRef)
-> OptimizationDiagnostic {
let mut opt = OptimizationDiagnostic {
kind: kind,
@ -58,10 +59,10 @@ unsafe fn unpack(kind: OptimizationDiagnosticKind, di: DiagnosticInfoRef)
};
super::LLVMUnpackOptimizationDiagnostic(di,
&mut opt.pass_name,
&mut opt.function,
&mut opt.debug_loc,
&mut opt.message);
&mut opt.pass_name,
&mut opt.function,
&mut opt.debug_loc,
&mut opt.message);
opt
}
@ -75,8 +76,7 @@ pub struct InlineAsmDiagnostic {
}
impl InlineAsmDiagnostic {
unsafe fn unpack(di: DiagnosticInfoRef)
-> InlineAsmDiagnostic {
unsafe fn unpack(di: DiagnosticInfoRef) -> InlineAsmDiagnostic {
let mut opt = InlineAsmDiagnostic {
cookie: 0,
@ -85,9 +85,9 @@ unsafe fn unpack(di: DiagnosticInfoRef)
};
super::LLVMUnpackInlineAsmDiagnostic(di,
&mut opt.cookie,
&mut opt.message,
&mut opt.instruction);
&mut opt.cookie,
&mut opt.message,
&mut opt.instruction);
opt
}
@ -106,22 +106,25 @@ pub unsafe fn unpack(di: DiagnosticInfoRef) -> Diagnostic {
let kind = super::LLVMGetDiagInfoKind(di);
match kind {
super::DK_InlineAsm
=> InlineAsm(InlineAsmDiagnostic::unpack(di)),
super::DK_InlineAsm => InlineAsm(InlineAsmDiagnostic::unpack(di)),
super::DK_OptimizationRemark
=> Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di)),
super::DK_OptimizationRemark => {
Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di))
}
super::DK_OptimizationRemarkMissed
=> Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di)),
super::DK_OptimizationRemarkMissed => {
Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di))
}
super::DK_OptimizationRemarkAnalysis
=> Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di)),
super::DK_OptimizationRemarkAnalysis => {
Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di))
}
super::DK_OptimizationFailure
=> Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)),
super::DK_OptimizationFailure => {
Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di))
}
_ => UnknownDiagnostic(di)
_ => UnknownDiagnostic(di),
}
}
}

View File

@ -111,27 +111,27 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, life) in self.lifetimes.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
f.write_str(",&nbsp;")?;
}
write!(f, "{}", *life)?;
}
if !self.type_params.is_empty() {
if !self.lifetimes.is_empty() {
f.write_str(", ")?;
f.write_str(",&nbsp;")?;
}
for (i, tp) in self.type_params.iter().enumerate() {
if i > 0 {
f.write_str(", ")?
f.write_str(",&nbsp;")?
}
f.write_str(&tp.name)?;
if !tp.bounds.is_empty() {
write!(f, ": {}", TyParamBounds(&tp.bounds))?;
write!(f, ":&nbsp;{}", TyParamBounds(&tp.bounds))?;
}
match tp.default {
Some(ref ty) => { write!(f, " = {}", ty)?; },
Some(ref ty) => { write!(f, "&nbsp;=&nbsp;{}", ty)?; },
None => {}
};
}
@ -229,21 +229,21 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut comma = false;
for lifetime in lifetimes {
if comma {
f.write_str(", ")?;
f.write_str(",&nbsp;")?;
}
comma = true;
write!(f, "{}", *lifetime)?;
}
for ty in types {
if comma {
f.write_str(", ")?;
f.write_str(",&nbsp;")?;
}
comma = true;
write!(f, "{}", *ty)?;
}
for binding in bindings {
if comma {
f.write_str(", ")?;
f.write_str(",&nbsp;")?;
}
comma = true;
write!(f, "{}", *binding)?;

View File

@ -2243,26 +2243,24 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
write!(w, "</pre>")?;
document(w, cx, it)?;
let mut fields = s.fields.iter().filter(|f| {
let mut fields = s.fields.iter().filter_map(|f| {
match f.inner {
clean::StructFieldItem(..) => true,
_ => false,
clean::StructFieldItem(ref ty) => Some((f, ty)),
_ => None,
}
}).peekable();
if let doctree::Plain = s.struct_type {
if fields.peek().is_some() {
write!(w, "<h2 class='fields'>Fields</h2>\n<table>")?;
for field in fields {
write!(w, "<tr class='stab {stab}'>
<td id='{shortty}.{name}'>\
<code>{name}</code></td><td>",
write!(w, "<h2 class='fields'>Fields</h2>")?;
for (field, ty) in fields {
write!(w, "<span id='{shortty}.{name}'><code>{name}: {ty}</code></span>
<span class='stab {stab}'></span>",
shortty = ItemType::StructField,
stab = field.stability_class(),
name = field.name.as_ref().unwrap())?;
name = field.name.as_ref().unwrap(),
ty = ty)?;
document(w, cx, field)?;
write!(w, "</td></tr>")?;
}
write!(w, "</table>")?;
}
}
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
@ -2292,7 +2290,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
write!(w, "{}(", name)?;
for (i, ty) in tys.iter().enumerate() {
if i > 0 {
write!(w, ", ")?
write!(w, ",&nbsp;")?
}
write!(w, "{}", *ty)?;
}
@ -2324,40 +2322,47 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
document(w, cx, it)?;
if !e.variants.is_empty() {
write!(w, "<h2 class='variants'>Variants</h2>\n<table class='variants_table'>")?;
write!(w, "<h2 class='variants'>Variants</h2>\n")?;
for variant in &e.variants {
write!(w, "<tr><td id='{shortty}.{name}'><code>{name}</code></td><td>",
write!(w, "<span id='{shortty}.{name}' class='variant'><code>{name}",
shortty = ItemType::Variant,
name = variant.name.as_ref().unwrap())?;
if let clean::VariantItem(ref var) = variant.inner {
if let clean::TupleVariant(ref tys) = var.kind {
write!(w, "(")?;
for (i, ty) in tys.iter().enumerate() {
if i > 0 {
write!(w, ",&nbsp;")?;
}
write!(w, "{}", *ty)?;
}
write!(w, ")")?;
}
}
write!(w, "</code></span>")?;
document(w, cx, variant)?;
use clean::{Variant, StructVariant};
if let clean::VariantItem( Variant { kind: StructVariant(ref s) } ) = variant.inner {
let fields = s.fields.iter().filter(|f| {
match f.inner {
clean::StructFieldItem(..) => true,
_ => false,
}
});
write!(w, "<h3 class='fields'>Fields</h3>\n
<table>")?;
for field in fields {
write!(w, "<tr><td \
id='{shortty}.{v}.field.{f}'>\
<code>{f}</code></td><td>",
shortty = ItemType::Variant,
v = variant.name.as_ref().unwrap(),
f = field.name.as_ref().unwrap())?;
document(w, cx, field)?;
write!(w, "</td></tr>")?;
for field in &s.fields {
use clean::StructFieldItem;
if let StructFieldItem(ref ty) = field.inner {
write!(w, "<tr><td \
id='variant.{v}.field.{f}'>\
<code>{f}:&nbsp;{t}</code></td><td>",
v = variant.name.as_ref().unwrap(),
f = field.name.as_ref().unwrap(),
t = *ty)?;
document(w, cx, field)?;
write!(w, "</td></tr>")?;
}
}
write!(w, "</table>")?;
}
write!(w, "</td><td>")?;
render_stability_since(w, variant, it)?;
write!(w, "</td></tr>")?;
}
write!(w, "</table>")?;
}
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?;
Ok(())

View File

@ -265,6 +265,10 @@ nav.sub {
.docblock h2 { font-size: 1.15em; }
.docblock h3, .docblock h4, .docblock h5 { font-size: 1em; }
.docblock {
margin-left: 24px;
}
.content .out-of-band {
font-size: 23px;
margin: 0px;
@ -640,6 +644,21 @@ span.since {
margin-right: 5px;
}
.enum > .toggle-wrapper > .collapse-toggle, .struct > .toggle-wrapper > .collapse-toggle {
left: 0;
margin-top: 5px;
}
.enum > .toggle-wrapper + .docblock, .struct > .toggle-wrapper + .docblock {
margin-left: 30px;
margin-bottom: 20px;
margin-top: 5px;
}
.enum > .collapsed, .struct > .collapsed {
margin-bottom: 25px;
}
:target > code {
background: #FDFFD3;
}

View File

@ -1338,10 +1338,10 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
///
/// // one possible implementation of walking a directory only visiting files
/// fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
/// if try!(fs::metadata(dir)).is_dir() {
/// if dir.is_dir() {
/// for entry in try!(fs::read_dir(dir)) {
/// let entry = try!(entry);
/// if try!(fs::metadata(entry.path())).is_dir() {
/// if try!(entry.file_type()).is_dir() {
/// try!(visit_dirs(&entry.path(), cb));
/// } else {
/// cb(&entry);

View File

@ -201,7 +201,7 @@
use syntax::codemap::Span;
use syntax::errors::Handler;
use syntax::util::move_map::MoveMap;
use syntax::parse::token::{intern, keywords, InternedString};
use syntax::parse::token::{keywords, InternedString};
use syntax::ptr::P;
use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty};
@ -1420,31 +1420,13 @@ fn expand_static_enum_method_body(&self,
// general helper methods.
impl<'a> TraitDef<'a> {
fn set_expn_info(&self,
cx: &mut ExtCtxt,
mut to_set: Span) -> Span {
let trait_name = match self.path.path.last() {
None => cx.span_bug(self.span, "trait with empty path in generic `derive`"),
Some(name) => *name
};
to_set.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
call_site: to_set,
callee: codemap::NameAndSpan {
format: codemap::MacroAttribute(intern(&format!("derive({})", trait_name))),
span: Some(self.span),
allow_internal_unstable: false,
}
});
to_set
}
fn summarise_struct(&self,
cx: &mut ExtCtxt,
struct_def: &VariantData) -> StaticFields {
let mut named_idents = Vec::new();
let mut just_spans = Vec::new();
for field in struct_def.fields(){
let sp = self.set_expn_info(cx, field.span);
let sp = Span { expn_id: self.span.expn_id, ..field.span };
match field.ident {
Some(ident) => named_idents.push((ident, sp)),
_ => just_spans.push(sp),
@ -1486,7 +1468,7 @@ fn create_struct_pattern(&self,
let mut paths = Vec::new();
let mut ident_exprs = Vec::new();
for (i, struct_field) in struct_def.fields().iter().enumerate() {
let sp = self.set_expn_info(cx, struct_field.span);
let sp = Span { expn_id: self.span.expn_id, ..struct_field.span };
let ident = cx.ident_of(&format!("{}_{}", prefix, i));
paths.push(codemap::Spanned{span: sp, node: ident});
let val = cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)));

View File

@ -16,7 +16,7 @@
use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::codemap::Span;
use syntax::codemap::{self, Span};
use syntax::parse::token::{intern, intern_and_get_ident};
use syntax::ptr::P;
@ -94,37 +94,7 @@ fn expand_derive(cx: &mut ExtCtxt,
}
let mut found_partial_eq = false;
let mut found_eq = false;
// This span is **very** sensitive and crucial to
// getting the stability behavior we want. What we are
// doing is marking the generated `#[derive_*]` with the
// span of the `#[deriving(...)]` attribute (the
// entire attribute, not just the `PartialEq` or `Eq`
// part), but with the current backtrace. The current
// backtrace will contain a topmost entry that IS this
// `#[deriving(...)]` attribute and with the
// "allow-unstable" flag set to true.
//
// Note that we do NOT use the span of the `Eq`
// text itself. You might think this is
// equivalent, because the `Eq` appears within the
// `#[deriving(Eq)]` attribute, and hence we would
// inherit the "allows unstable" from the
// backtrace. But in fact this is not always the
// case. The actual source text that led to
// deriving can be `#[$attr]`, for example, where
// `$attr == deriving(Eq)`. In that case, the
// "#[derive_*]" would be considered to
// originate not from the deriving call but from
// text outside the deriving call, and hence would
// be forbidden from using unstable
// content.
//
// See tests src/run-pass/rfc1445 for
// examples. --nmatsakis
let span = Span { expn_id: cx.backtrace(), .. span };
assert!(cx.parse_sess.codemap().span_allows_unstable(span));
let mut eq_span = None;
for titem in traits.iter().rev() {
let tname = match titem.node {
@ -144,8 +114,19 @@ fn expand_derive(cx: &mut ExtCtxt,
continue;
}
let span = Span {
expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
call_site: titem.span,
callee: codemap::NameAndSpan {
format: codemap::MacroAttribute(intern(&format!("derive({})", tname))),
span: Some(titem.span),
allow_internal_unstable: true,
},
}), ..titem.span
};
if &tname[..] == "Eq" {
found_eq = true;
eq_span = Some(span);
} else if &tname[..] == "PartialEq" {
found_partial_eq = true;
}
@ -157,12 +138,13 @@ fn expand_derive(cx: &mut ExtCtxt,
// RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
// `#[structural_match]` attribute.
if found_partial_eq && found_eq {
debug!("inserting structural_match with span {:?}", span);
let structural_match = intern_and_get_ident("structural_match");
item.attrs.push(cx.attribute(span,
cx.meta_word(span,
structural_match)));
if let Some(eq_span) = eq_span {
if found_partial_eq {
let structural_match = intern_and_get_ident("structural_match");
item.attrs.push(cx.attribute(eq_span,
cx.meta_word(eq_span,
structural_match)));
}
}
item

View File

@ -0,0 +1,14 @@
// Copyright 2016 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.
#[derive(Clone,
Sync, //~ ERROR this unsafe trait should be implemented explicitly
Copy)]
enum Foo {}