From 092d04a40a3db44af2dd50e43a77449a7e56dd13 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 9 Dec 2014 10:36:46 -0500 Subject: Rename FnStyle trait to Unsafety. --- src/libsyntax/parse/parser.rs | 48 +++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 29 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 381942a3e62..cc96d45a1c8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -16,7 +16,7 @@ use self::ItemOrViewItem::*; use abi; use ast::{AssociatedType, BareFnTy, ClosureTy}; use ast::{RegionTyParamBound, TraitTyParamBound}; -use ast::{ProvidedMethod, Public, FnStyle}; +use ast::{ProvidedMethod, Public, Unsafety}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, Block}; use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause}; @@ -34,7 +34,7 @@ use ast::{Many}; use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind}; use ast::{FnOnceUnboxedClosureKind}; use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy}; -use ast::{Ident, NormalFn, Inherited, ImplItem, Item, Item_, ItemStatic}; +use ast::{Ident, Inherited, ImplItem, Item, Item_, ItemStatic}; use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemConst}; use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy}; use ast::{LifetimeDef, Lit, Lit_}; @@ -60,7 +60,7 @@ use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq}; use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind}; use ast::{UnnamedField, UnsafeBlock}; -use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse}; +use ast::{ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause}; use ast; @@ -1121,7 +1121,7 @@ impl<'a> Parser<'a> { Function Style */ - let fn_style = self.parse_unsafety(); + let unsafety = self.parse_unsafety(); let abi = if self.eat_keyword(keywords::Extern) { self.parse_opt_abi().unwrap_or(abi::C) } else { @@ -1139,7 +1139,7 @@ impl<'a> Parser<'a> { }); TyBareFn(P(BareFnTy { abi: abi, - fn_style: fn_style, + unsafety: unsafety, lifetimes: lifetime_defs, decl: decl })) @@ -1240,7 +1240,7 @@ impl<'a> Parser<'a> { */ - let fn_style = self.parse_unsafety(); + let unsafety = self.parse_unsafety(); let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs); @@ -1266,7 +1266,7 @@ impl<'a> Parser<'a> { }); TyClosure(P(ClosureTy { - fn_style: fn_style, + unsafety: unsafety, onceness: Many, bounds: bounds, decl: decl, @@ -1274,11 +1274,11 @@ impl<'a> Parser<'a> { })) } - pub fn parse_unsafety(&mut self) -> FnStyle { + pub fn parse_unsafety(&mut self) -> Unsafety { if self.eat_keyword(keywords::Unsafe) { - return UnsafeFn; + return Unsafety::Unsafe; } else { - return NormalFn; + return Unsafety::Normal; } } @@ -1351,7 +1351,7 @@ impl<'a> Parser<'a> { let lo = p.span.lo; let vis = p.parse_visibility(); - let style = p.parse_fn_style(); + let style = p.parse_unsafety(); let abi = if p.eat_keyword(keywords::Extern) { p.parse_opt_abi().unwrap_or(abi::C) } else { @@ -1379,7 +1379,7 @@ impl<'a> Parser<'a> { RequiredMethod(TypeMethod { ident: ident, attrs: attrs, - fn_style: style, + unsafety: style, decl: d, generics: generics, abi: abi, @@ -4548,12 +4548,12 @@ impl<'a> Parser<'a> { } /// Parse an item-position function declaration. - fn parse_item_fn(&mut self, fn_style: FnStyle, abi: abi::Abi) -> ItemInfo { + fn parse_item_fn(&mut self, unsafety: Unsafety, abi: abi::Abi) -> ItemInfo { let (ident, mut generics) = self.parse_fn_header(); let decl = self.parse_fn_decl(false); self.parse_where_clause(&mut generics); let (inner_attrs, body) = self.parse_inner_attrs_and_block(); - (ident, ItemFn(decl, fn_style, abi, generics, body), Some(inner_attrs)) + (ident, ItemFn(decl, unsafety, abi, generics, body), Some(inner_attrs)) } /// Parse a method in a trait impl @@ -4591,7 +4591,7 @@ impl<'a> Parser<'a> { self.span.hi) }; (ast::MethMac(m), self.span.hi, attrs) } else { - let fn_style = self.parse_fn_style(); + let unsafety = self.parse_unsafety(); let abi = if self.eat_keyword(keywords::Extern) { self.parse_opt_abi().unwrap_or(abi::C) } else { @@ -4612,7 +4612,7 @@ impl<'a> Parser<'a> { generics, abi, explicit_self, - fn_style, + unsafety, decl, body, visa), @@ -5143,16 +5143,6 @@ impl<'a> Parser<'a> { }) } - /// Parse unsafe or not - fn parse_fn_style(&mut self) -> FnStyle { - if self.eat_keyword(keywords::Unsafe) { - UnsafeFn - } else { - NormalFn - } - } - - /// At this point, this is essentially a wrapper for /// parse_foreign_items. fn parse_foreign_mod_items(&mut self, @@ -5491,7 +5481,7 @@ impl<'a> Parser<'a> { // EXTERN FUNCTION ITEM let abi = opt_abi.unwrap_or(abi::C); let (ident, item_, extra_attrs) = - self.parse_item_fn(NormalFn, abi); + self.parse_item_fn(Unsafety::Normal, abi); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5554,7 +5544,7 @@ impl<'a> Parser<'a> { // FUNCTION ITEM self.bump(); let (ident, item_, extra_attrs) = - self.parse_item_fn(NormalFn, abi::Rust); + self.parse_item_fn(Unsafety::Normal, abi::Rust); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5575,7 +5565,7 @@ impl<'a> Parser<'a> { }; self.expect_keyword(keywords::Fn); let (ident, item_, extra_attrs) = - self.parse_item_fn(UnsafeFn, abi); + self.parse_item_fn(Unsafety::Unsafe, abi); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, -- cgit 1.4.1-3-g733a5 From 5686a91914ac678ccb78220367daefe585a0d66a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 9 Dec 2014 19:59:20 -0500 Subject: Parse `unsafe trait` but do not do anything with it beyond parsing and integrating into rustdoc etc. --- src/librustc/lint/builtin.rs | 2 +- src/librustc/metadata/common.rs | 2 ++ src/librustc/metadata/decoder.rs | 5 +++++ src/librustc/metadata/encoder.rs | 11 ++++++++++- src/librustc/middle/privacy.rs | 10 +++++----- src/librustc/middle/resolve.rs | 4 ++-- src/librustc/middle/resolve_lifetime.rs | 2 +- src/librustc/middle/ty.rs | 4 +++- src/librustc_trans/save/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/collect.rs | 12 +++++++----- src/librustc_typeck/variance.rs | 2 +- src/librustdoc/clean/inline.rs | 1 + src/librustdoc/clean/mod.rs | 2 ++ src/librustdoc/doctree.rs | 1 + src/librustdoc/html/render.rs | 3 ++- src/librustdoc/visit_ast.rs | 3 ++- src/libsyntax/ast.rs | 3 ++- src/libsyntax/ast_map/mod.rs | 2 +- src/libsyntax/config.rs | 4 ++-- src/libsyntax/fold.rs | 5 +++-- src/libsyntax/parse/parser.rs | 24 +++++++++++++++++++++--- src/libsyntax/print/pprust.rs | 8 +++++--- src/libsyntax/visit.rs | 2 +- src/test/pretty/trait-safety.rs | 21 +++++++++++++++++++++ 25 files changed, 103 insertions(+), 34 deletions(-) create mode 100644 src/test/pretty/trait-safety.rs (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index e19fa01b2e4..5af7fec4181 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1721,7 +1721,7 @@ impl LintPass for Stability { if self.is_internal(cx, item.span) { return } match item.node { - ast::ItemTrait(_, _, ref supertraits, _) => { + ast::ItemTrait(_, _, _, ref supertraits, _) => { for t in supertraits.iter() { if let ast::TraitTyParamBound(ref t) = *t { let id = ty::trait_ref_to_def_id(cx.tcx, &t.trait_ref); diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 99e7966b66f..b698e4fcc7f 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -255,3 +255,5 @@ pub const tag_method_ty_generics: uint = 0xa7; pub const tag_predicate: uint = 0xa8; pub const tag_predicate_space: uint = 0xa9; pub const tag_predicate_data: uint = 0xb0; + +pub const tag_unsafety: uint = 0xb1; diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 4e892f53186..37124286398 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -368,8 +368,13 @@ pub fn get_trait_def<'tcx>(cdata: Cmd, let item_doc = lookup_item(item_id, cdata.data()); let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); let bounds = trait_def_bounds(item_doc, tcx, cdata); + let unsafety = match reader::maybe_get_doc(item_doc, tag_unsafety) { + Some(_) => ast::Unsafety::Unsafe, + None => ast::Unsafety::Normal, + }; ty::TraitDef { + unsafety: unsafety, generics: generics, bounds: bounds, trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata)) diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 9804e3c20aa..cb8de256448 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1308,13 +1308,22 @@ fn encode_info_for_item(ecx: &EncodeContext, } } } - ast::ItemTrait(_, _, _, ref ms) => { + ast::ItemTrait(_, _, _, _, ref ms) => { add_to_index(item, rbml_w, index); rbml_w.start_tag(tag_items_data_item); encode_def_id(rbml_w, def_id); encode_family(rbml_w, 'I'); encode_item_variances(rbml_w, ecx, item.id); let trait_def = ty::lookup_trait_def(tcx, def_id); + + match trait_def.unsafety { + ast::Unsafety::Unsafe => { + rbml_w.start_tag(tag_unsafety); + rbml_w.end_tag(); + } + ast::Unsafety::Normal => { } + } + encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics); encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref); encode_name(rbml_w, item.ident.name); diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 79bb19a1e53..352c2add000 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -76,7 +76,7 @@ impl<'v> Visitor<'v> for ParentVisitor { // method to the root. In this case, if the trait is private, then // parent all the methods to the trait to indicate that they're // private. - ast::ItemTrait(_, _, _, ref methods) if item.vis != ast::Public => { + ast::ItemTrait(_, _, _, _, ref methods) if item.vis != ast::Public => { for m in methods.iter() { match *m { ast::ProvidedMethod(ref m) => { @@ -282,7 +282,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { // Default methods on traits are all public so long as the trait // is public - ast::ItemTrait(_, _, _, ref methods) if public_first => { + ast::ItemTrait(_, _, _, _, ref methods) if public_first => { for method in methods.iter() { match *method { ast::ProvidedMethod(ref m) => { @@ -1134,7 +1134,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { } } - ast::ItemTrait(_, _, _, ref methods) => { + ast::ItemTrait(_, _, _, _, ref methods) => { for m in methods.iter() { match *m { ast::ProvidedMethod(ref m) => { @@ -1198,7 +1198,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { ast::ItemStruct(ref def, _) => check_struct(&**def), - ast::ItemTrait(_, _, _, ref methods) => { + ast::ItemTrait(_, _, _, _, ref methods) => { for m in methods.iter() { match *m { ast::RequiredMethod(..) => {} @@ -1305,7 +1305,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { // namespace (the contents have their own privacies). ast::ItemForeignMod(_) => {} - ast::ItemTrait(_, _, ref bounds, _) => { + ast::ItemTrait(_, _, _, ref bounds, _) => { if !self.trait_is_public(item.id) { return } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index f2c83291b79..2e52bab2ae3 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1583,7 +1583,7 @@ impl<'a> Resolver<'a> { ItemImpl(_, Some(_), _, _) => parent, - ItemTrait(_, _, _, ref items) => { + ItemTrait(_, _, _, _, ref items) => { let name_bindings = self.add_child(name, parent.clone(), @@ -4241,7 +4241,7 @@ impl<'a> Resolver<'a> { impl_items.as_slice()); } - ItemTrait(ref generics, ref unbound, ref bounds, ref trait_items) => { + ItemTrait(_, ref generics, ref unbound, ref bounds, ref trait_items) => { // Create a new rib for the self type. let mut self_type_rib = Rib::new(ItemRibKind); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index ee0fc327020..683948cd2e7 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -106,7 +106,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { ast::ItemTy(_, ref generics) | ast::ItemEnum(_, ref generics) | ast::ItemStruct(_, ref generics) | - ast::ItemTrait(ref generics, _, _, _) => { + ast::ItemTrait(_, ref generics, _, _, _) => { // These kinds of items have only early bound lifetime parameters. let lifetimes = &generics.lifetimes; self.with(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE), |this| { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9673b9ab586..4c4df698f33 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1915,6 +1915,8 @@ pub struct Polytype<'tcx> { /// As `Polytype` but for a trait ref. pub struct TraitDef<'tcx> { + pub unsafety: ast::Unsafety, + /// Generic type definitions. Note that `Self` is listed in here /// as having a single bound, the trait itself (e.g., in the trait /// `Eq`, there is a single bound `Self : Eq`). This is so that @@ -4572,7 +4574,7 @@ pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) match cx.map.find(id.node) { Some(ast_map::NodeItem(item)) => { match item.node { - ItemTrait(_, _, _, ref ms) => { + ItemTrait(_, _, _, _, ref ms) => { let (_, p) = ast_util::split_trait_methods(ms.as_slice()); p.iter() diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 329241b24e6..779fcd70864 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -1050,7 +1050,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { &**typ, impl_items) } - ast::ItemTrait(ref generics, _, ref trait_refs, ref methods) => + ast::ItemTrait(_, ref generics, _, ref trait_refs, ref methods) => self.process_trait(item, generics, trait_refs, methods), ast::ItemMod(ref m) => self.process_mod(item, m), ast::ItemTy(ref ty, ref ty_params) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5b1ca8fc1c0..c64519c96dd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -625,7 +625,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { } } - ast::ItemTrait(_, _, _, ref trait_methods) => { + ast::ItemTrait(_, _, _, _, ref trait_methods) => { let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id)); for trait_method in trait_methods.iter() { match *trait_method { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 0bb0f95a66b..643d8eb60ce 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -258,7 +258,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_def: &ty::TraitDef<'tcx>) { let tcx = ccx.tcx; if let ast_map::NodeItem(item) = tcx.map.get(trait_id) { - if let ast::ItemTrait(_, _, _, ref trait_items) = item.node { + if let ast::ItemTrait(_, _, _, _, ref trait_items) = item.node { // For each method, construct a suitable ty::Method and // store it into the `tcx.impl_or_trait_items` table: for trait_item in trait_items.iter() { @@ -1144,7 +1144,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { AllowEqConstraints::DontAllow); } }, - ast::ItemTrait(_, _, _, ref trait_methods) => { + ast::ItemTrait(_, _, _, _, ref trait_methods) => { let trait_def = trait_def_of_item(ccx, it); debug!("trait_def: ident={} trait_def={}", @@ -1335,12 +1335,13 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return def.clone(); } - let (generics, unbound, bounds, items) = match it.node { - ast::ItemTrait(ref generics, + let (unsafety, generics, unbound, bounds, items) = match it.node { + ast::ItemTrait(unsafety, + ref generics, ref unbound, ref supertraits, ref items) => { - (generics, unbound, supertraits, items.as_slice()) + (unsafety, generics, unbound, supertraits, items.as_slice()) } ref s => { tcx.sess.span_bug( @@ -1369,6 +1370,7 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let substs = mk_item_substs(ccx, &ty_generics); let trait_def = Rc::new(ty::TraitDef { + unsafety: unsafety, generics: ty_generics, bounds: bounds, trait_ref: Rc::new(ty::TraitRef { diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index bd7db560d9e..8fe14bae0f5 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -358,7 +358,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> { match item.node { ast::ItemEnum(_, ref generics) | ast::ItemStruct(_, ref generics) | - ast::ItemTrait(ref generics, _, _, _) => { + ast::ItemTrait(_, ref generics, _, _, _) => { for (i, p) in generics.lifetimes.iter().enumerate() { let id = p.lifetime.id; self.add_inferred(item.id, RegionParam, TypeSpace, i, id); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 75cf0c7a26b..a7d7c520755 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -161,6 +161,7 @@ pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt, let trait_def = ty::lookup_trait_def(tcx, did); let (bounds, default_unbound) = trait_def.bounds.clean(cx); clean::Trait { + unsafety: def.unsafety, generics: (&def.generics, subst::TypeSpace).clean(cx), items: items.collect(), bounds: bounds, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1d0929746c2..92184ce93de 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -974,6 +974,7 @@ impl Clean for ast::FunctionRetTy { #[deriving(Clone, Encodable, Decodable)] pub struct Trait { + pub unsafety: ast::Unsafety, pub items: Vec, pub generics: Generics, pub bounds: Vec, @@ -991,6 +992,7 @@ impl Clean for doctree::Trait { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), inner: TraitItem(Trait { + unsafety: self.unsafety, items: self.items.clean(cx), generics: self.generics.clean(cx), bounds: self.bounds.clean(cx), diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index a25d4352430..79f04e91260 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -170,6 +170,7 @@ pub struct Constant { } pub struct Trait { + pub unsafety: ast::Unsafety, pub name: Ident, pub items: Vec, //should be TraitItem pub generics: ast::Generics, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 54b7ead5469..1977b6320d0 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1693,8 +1693,9 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } // Output the trait definition - try!(write!(w, "
{}trait {}{}{}{} ",
+    try!(write!(w, "
{}{}trait {}{}{}{} ",
                   VisSpace(it.visibility),
+                  UnsafetySpace(t.unsafety),
                   it.name.as_ref().unwrap().as_slice(),
                   t.generics,
                   bounds,
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 1706df10d9a..f94e647b1cf 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -322,8 +322,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 };
                 om.constants.push(s);
             },
-            ast::ItemTrait(ref gen, ref def_ub, ref b, ref items) => {
+            ast::ItemTrait(unsafety, ref gen, ref def_ub, ref b, ref items) => {
                 let t = Trait {
+                    unsafety: unsafety,
                     name: name,
                     items: items.clone(),
                     generics: gen.clone(),
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 812b1baa8f7..1cc6b6feee8 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1611,7 +1611,8 @@ pub enum Item_ {
     ItemEnum(EnumDef, Generics),
     ItemStruct(P, Generics),
     /// Represents a Trait Declaration
-    ItemTrait(Generics,
+    ItemTrait(Unsafety,
+              Generics,
               Option, // (optional) default bound not required for Self.
                                 // Currently, only Sized makes sense here.
               TyParamBounds,
diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs
index 6f1d2d39b30..a2cdc4d2fbc 100644
--- a/src/libsyntax/ast_map/mod.rs
+++ b/src/libsyntax/ast_map/mod.rs
@@ -786,7 +786,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
                     None => {}
                 }
             }
-            ItemTrait(_, _, ref bounds, ref trait_items) => {
+            ItemTrait(_, _, _, ref bounds, ref trait_items) => {
                 for b in bounds.iter() {
                     if let TraitTyParamBound(ref t) = *b {
                         self.insert(t.trait_ref.ref_id, NodeItem(i));
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 87426dce918..ee651592117 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -139,11 +139,11 @@ fn fold_item_underscore(cx: &mut Context, item: ast::Item_) -> ast::Item_
                                        .collect();
             ast::ItemImpl(a, b, c, impl_items)
         }
-        ast::ItemTrait(a, b, c, methods) => {
+        ast::ItemTrait(u, a, b, c, methods) => {
             let methods = methods.into_iter()
                                  .filter(|m| trait_method_in_cfg(cx, m))
                                  .collect();
-            ast::ItemTrait(a, b, c, methods)
+            ast::ItemTrait(u, a, b, c, methods)
         }
         ast::ItemStruct(def, generics) => {
             ast::ItemStruct(fold_struct(cx, def), generics)
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index c2c77e5a16c..daed014f4eb 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1035,7 +1035,7 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ {
                      folder.fold_ty(ty),
                      new_impl_items)
         }
-        ItemTrait(generics, unbound, bounds, methods) => {
+        ItemTrait(unsafety, generics, unbound, bounds, methods) => {
             let bounds = folder.fold_bounds(bounds);
             let methods = methods.into_iter().flat_map(|method| {
                 let r = match method {
@@ -1063,7 +1063,8 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ {
                 };
                 r
             }).collect();
-            ItemTrait(folder.fold_generics(generics),
+            ItemTrait(unsafety,
+                      folder.fold_generics(generics),
                       unbound,
                       bounds,
                       methods)
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index cc96d45a1c8..b2c30797cac 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -4628,7 +4628,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse trait Foo { ... }
-    fn parse_item_trait(&mut self) -> ItemInfo {
+    fn parse_item_trait(&mut self, unsafety: Unsafety) -> ItemInfo {
         let ident = self.parse_ident();
         let mut tps = self.parse_generics();
         let sized = self.parse_for_sized();
@@ -4639,7 +4639,7 @@ impl<'a> Parser<'a> {
         self.parse_where_clause(&mut tps);
 
         let meths = self.parse_trait_items();
-        (ident, ItemTrait(tps, sized, bounds, meths), None)
+        (ident, ItemTrait(unsafety, tps, sized, bounds, meths), None)
     }
 
     fn parse_impl_items(&mut self) -> (Vec, Vec) {
@@ -5539,6 +5539,23 @@ impl<'a> Parser<'a> {
                                     maybe_append(attrs, extra_attrs));
             return IoviItem(item);
         }
+        if self.token.is_keyword(keywords::Unsafe) &&
+            self.look_ahead(1u, |t| t.is_keyword(keywords::Trait))
+        {
+            // UNSAFE TRAIT ITEM
+            self.expect_keyword(keywords::Unsafe);
+            self.expect_keyword(keywords::Trait);
+            let (ident, item_, extra_attrs) =
+                self.parse_item_trait(ast::Unsafety::Unsafe);
+            let last_span = self.last_span;
+            let item = self.mk_item(lo,
+                                    last_span.hi,
+                                    ident,
+                                    item_,
+                                    visibility,
+                                    maybe_append(attrs, extra_attrs));
+            return IoviItem(item);
+        }
         if self.token.is_keyword(keywords::Fn) &&
                 self.look_ahead(1, |f| !Parser::fn_expr_lookahead(f)) {
             // FUNCTION ITEM
@@ -5614,7 +5631,8 @@ impl<'a> Parser<'a> {
         }
         if self.eat_keyword(keywords::Trait) {
             // TRAIT ITEM
-            let (ident, item_, extra_attrs) = self.parse_item_trait();
+            let (ident, item_, extra_attrs) =
+                self.parse_item_trait(ast::Unsafety::Normal);
             let last_span = self.last_span;
             let item = self.mk_item(lo,
                                     last_span.hi,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 53399aba99a..037118b145f 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -955,9 +955,11 @@ impl<'a> State<'a> {
                 }
                 try!(self.bclose(item.span));
             }
-            ast::ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => {
-                try!(self.head(visibility_qualified(item.vis,
-                                                    "trait").as_slice()));
+            ast::ItemTrait(unsafety, ref generics, ref unbound, ref bounds, ref methods) => {
+                try!(self.head(""));
+                try!(self.print_visibility(item.vis));
+                try!(self.print_unsafety(unsafety));
+                try!(self.word_nbsp("trait"));
                 try!(self.print_ident(item.ident));
                 try!(self.print_generics(generics));
                 if let &Some(ref tref) = unbound {
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 6eedb77889a..7bb79a15f45 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -311,7 +311,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
                                      generics,
                                      item.id)
         }
-        ItemTrait(ref generics, _, ref bounds, ref methods) => {
+        ItemTrait(_, ref generics, _, ref bounds, ref methods) => {
             visitor.visit_generics(generics);
             walk_ty_param_bounds_helper(visitor, bounds);
             for method in methods.iter() {
diff --git a/src/test/pretty/trait-safety.rs b/src/test/pretty/trait-safety.rs
new file mode 100644
index 00000000000..42e578482e6
--- /dev/null
+++ b/src/test/pretty/trait-safety.rs
@@ -0,0 +1,21 @@
+// Copyright 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  or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// pp-exact
+
+unsafe trait UnsafeTrait {
+    fn foo(&self);
+}
+
+pub unsafe trait PubUnsafeTrait {
+    fn foo(&self);
+}
+
+fn main() { }
-- 
cgit 1.4.1-3-g733a5


From 22f777ba2ecfcd8d914d37db310a6feb4ad5219e Mon Sep 17 00:00:00 2001
From: Niko Matsakis 
Date: Wed, 10 Dec 2014 06:15:06 -0500
Subject: Parse `unsafe impl` but don't do anything particularly interesting
 with the results.

---
 src/librustc/lint/builtin.rs                 |  2 +-
 src/librustc/metadata/decoder.rs             | 14 ++++++++++----
 src/librustc/metadata/encoder.rs             | 23 ++++++++++++-----------
 src/librustc/middle/dead.rs                  |  2 +-
 src/librustc/middle/infer/error_reporting.rs |  2 +-
 src/librustc/middle/privacy.rs               | 10 +++++-----
 src/librustc/middle/reachable.rs             |  4 ++--
 src/librustc/middle/resolve.rs               |  7 ++++---
 src/librustc/middle/resolve_lifetime.rs      |  2 +-
 src/librustc/middle/ty.rs                    |  4 ++--
 src/librustc_trans/save/mod.rs               |  5 +++--
 src/librustc_trans/trans/base.rs             |  2 +-
 src/librustc_typeck/check/mod.rs             |  2 +-
 src/librustc_typeck/coherence/mod.rs         |  4 ++--
 src/librustc_typeck/coherence/orphan.rs      |  4 ++--
 src/librustc_typeck/collect.rs               |  3 ++-
 src/librustdoc/doctree.rs                    |  1 +
 src/librustdoc/visit_ast.rs                  |  3 ++-
 src/libsyntax/ast.rs                         |  3 ++-
 src/libsyntax/ast_map/mod.rs                 |  2 +-
 src/libsyntax/config.rs                      |  4 ++--
 src/libsyntax/ext/deriving/generic/mod.rs    |  3 ++-
 src/libsyntax/feature_gate.rs                |  2 +-
 src/libsyntax/fold.rs                        |  7 ++++---
 src/libsyntax/parse/parser.rs                | 22 +++++++++++++++++++---
 src/libsyntax/print/pprust.rs                | 10 +++++++---
 src/libsyntax/visit.rs                       |  3 ++-
 src/test/pretty/trait-safety.rs              |  4 ++++
 28 files changed, 97 insertions(+), 57 deletions(-)

(limited to 'src/libsyntax/parse/parser.rs')

diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 5af7fec4181..3040125d97e 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -1729,7 +1729,7 @@ impl LintPass for Stability {
                     }
                 }
             }
-            ast::ItemImpl(_, Some(ref t), _, _) => {
+            ast::ItemImpl(_, _, Some(ref t), _, _) => {
                 let id = ty::trait_ref_to_def_id(cx.tcx, t);
                 self.lint(cx, id, t.path.span);
             }
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 37124286398..b78112f1f78 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -361,6 +361,15 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
     }
 }
 
+fn parse_unsafety(item_doc: rbml::Doc) -> ast::Unsafety {
+    let unsafety_doc = reader::get_doc(item_doc, tag_unsafety);
+    if reader::doc_as_u8(unsafety_doc) != 0 {
+        ast::Unsafety::Unsafe
+    } else {
+        ast::Unsafety::Normal
+    }
+}
+
 pub fn get_trait_def<'tcx>(cdata: Cmd,
                            item_id: ast::NodeId,
                            tcx: &ty::ctxt<'tcx>) -> ty::TraitDef<'tcx>
@@ -368,10 +377,7 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
     let item_doc = lookup_item(item_id, cdata.data());
     let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
     let bounds = trait_def_bounds(item_doc, tcx, cdata);
-    let unsafety = match reader::maybe_get_doc(item_doc, tag_unsafety) {
-        Some(_) => ast::Unsafety::Unsafe,
-        None => ast::Unsafety::Normal,
-    };
+    let unsafety = parse_unsafety(item_doc);
 
     ty::TraitDef {
         unsafety: unsafety,
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index cb8de256448..a1f04b7412b 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -1205,7 +1205,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
             None => {}
         }
       }
-      ast::ItemImpl(_, ref opt_trait, ref ty, ref ast_items) => {
+      ast::ItemImpl(unsafety, _, ref opt_trait, ref ty, ref ast_items) => {
         // We need to encode information about the default methods we
         // have inherited, so we drive this based on the impl structure.
         let impl_items = tcx.impl_items.borrow();
@@ -1218,6 +1218,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
         encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
         encode_name(rbml_w, item.ident.name);
         encode_attributes(rbml_w, item.attrs.as_slice());
+        encode_unsafety(rbml_w, unsafety);
         match ty.node {
             ast::TyPath(ref path, _) if path.segments
                                                         .len() == 1 => {
@@ -1315,15 +1316,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
         encode_family(rbml_w, 'I');
         encode_item_variances(rbml_w, ecx, item.id);
         let trait_def = ty::lookup_trait_def(tcx, def_id);
-
-        match trait_def.unsafety {
-            ast::Unsafety::Unsafe => {
-                rbml_w.start_tag(tag_unsafety);
-                rbml_w.end_tag();
-            }
-            ast::Unsafety::Normal => { }
-        }
-
+        encode_unsafety(rbml_w, trait_def.unsafety);
         encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics);
         encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
         encode_name(rbml_w, item.ident.name);
@@ -1683,6 +1676,14 @@ fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) {
     rbml_w.end_tag();
 }
 
+fn encode_unsafety(rbml_w: &mut Encoder, unsafety: ast::Unsafety) {
+    let byte: u8 = match unsafety {
+        ast::Unsafety::Normal => 0,
+        ast::Unsafety::Unsafe => 1,
+    };
+    rbml_w.wr_tagged_u8(tag_unsafety, byte);
+}
+
 fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) {
     fn get_ordered_deps(cstore: &cstore::CStore) -> Vec {
         // Pull the cnums and name,vers,hash out of cstore
@@ -1864,7 +1865,7 @@ struct ImplVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> {
 
 impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> {
     fn visit_item(&mut self, item: &ast::Item) {
-        if let ast::ItemImpl(_, Some(ref trait_ref), _, _) = item.node {
+        if let ast::ItemImpl(_, _, Some(ref trait_ref), _, _) = item.node {
             let def_map = &self.ecx.tcx.def_map;
             let trait_def = def_map.borrow()[trait_ref.ref_id].clone();
             let def_id = trait_def.def_id();
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index d2f43faa003..939775e7507 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -355,7 +355,7 @@ impl<'v> Visitor<'v> for LifeSeeder {
             ast::ItemEnum(ref enum_def, _) if allow_dead_code => {
                 self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id));
             }
-            ast::ItemImpl(_, Some(ref _trait_ref), _, ref impl_items) => {
+            ast::ItemImpl(_, _, Some(ref _trait_ref), _, ref impl_items) => {
                 for impl_item in impl_items.iter() {
                     match *impl_item {
                         ast::MethodImplItem(ref method) => {
diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs
index c638182d7f3..5c2944f898e 100644
--- a/src/librustc/middle/infer/error_reporting.rs
+++ b/src/librustc/middle/infer/error_reporting.rs
@@ -1690,7 +1690,7 @@ fn lifetimes_in_scope(tcx: &ty::ctxt,
         match tcx.map.find(parent) {
             Some(node) => match node {
                 ast_map::NodeItem(item) => match item.node {
-                    ast::ItemImpl(ref gen, _, _, _) => {
+                    ast::ItemImpl(_, ref gen, _, _, _) => {
                         taken.push_all(gen.lifetimes.as_slice());
                     }
                     _ => ()
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 352c2add000..8cce1321d72 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -241,7 +241,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
             //   undefined symbols at linkage time if this case is not handled.
             //
             // * Private trait impls for private types can be completely ignored
-            ast::ItemImpl(_, _, ref ty, ref impl_items) => {
+            ast::ItemImpl(_, _, _, ref ty, ref impl_items) => {
                 let public_ty = match ty.node {
                     ast::TyPath(_, id) => {
                         match self.tcx.def_map.borrow()[id].clone() {
@@ -611,7 +611,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
                     // invoked, and the struct/enum itself is private. Crawl
                     // back up the chains to find the relevant struct/enum that
                     // was private.
-                    ast::ItemImpl(_, _, ref ty, _) => {
+                    ast::ItemImpl(_, _, _, ref ty, _) => {
                         let id = match ty.node {
                             ast::TyPath(_, id) => id,
                             _ => return Some((err_span, err_msg, None)),
@@ -1096,7 +1096,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> {
         match item.node {
             // implementations of traits don't need visibility qualifiers because
             // that's controlled by having the trait in scope.
-            ast::ItemImpl(_, Some(..), _, ref impl_items) => {
+            ast::ItemImpl(_, _, Some(..), _, ref impl_items) => {
                 check_inherited(item.span, item.vis,
                                 "visibility qualifiers have no effect on trait \
                                  impls");
@@ -1175,7 +1175,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> {
         };
         check_inherited(tcx, item.span, item.vis);
         match item.node {
-            ast::ItemImpl(_, _, _, ref impl_items) => {
+            ast::ItemImpl(_, _, _, _, ref impl_items) => {
                 for impl_item in impl_items.iter() {
                     match *impl_item {
                         ast::MethodImplItem(ref m) => {
@@ -1320,7 +1320,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
             // (i.e. we could just return here to not check them at
             // all, or some worse estimation of whether an impl is
             // publicly visible.
-            ast::ItemImpl(ref g, ref trait_ref, ref self_, ref impl_items) => {
+            ast::ItemImpl(_, ref g, ref trait_ref, ref self_, ref impl_items) => {
                 // `impl [... for] Private` is never visible.
                 let self_contains_private;
                 // impl [... for] Public<...>, but not `impl [... for]
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index fa02c940aa7..38d3b859c9d 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -55,7 +55,7 @@ fn item_might_be_inlined(item: &ast::Item) -> bool {
     }
 
     match item.node {
-        ast::ItemImpl(ref generics, _, _, _) |
+        ast::ItemImpl(_, ref generics, _, _, _) |
         ast::ItemFn(_, _, _, ref generics, _) => {
             generics_require_inlining(generics)
         }
@@ -216,7 +216,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                                       .map
                                       .expect_item(impl_did.node)
                                       .node {
-                                ast::ItemImpl(ref generics, _, _, _) => {
+                                ast::ItemImpl(_, ref generics, _, _, _) => {
                                     generics_require_inlining(generics)
                                 }
                                 _ => false
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 2e52bab2ae3..c6fdd845ea7 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -1432,7 +1432,7 @@ impl<'a> Resolver<'a> {
                 parent
             }
 
-            ItemImpl(_, None, ref ty, ref impl_items) => {
+            ItemImpl(_, _, None, ref ty, ref impl_items) => {
                 // If this implements an anonymous trait, then add all the
                 // methods within to a new module, if the type was defined
                 // within this module.
@@ -1581,7 +1581,7 @@ impl<'a> Resolver<'a> {
                 parent
             }
 
-            ItemImpl(_, Some(_), _, _) => parent,
+            ItemImpl(_, _, Some(_), _, _) => parent,
 
             ItemTrait(_, _, _, _, ref items) => {
                 let name_bindings =
@@ -4230,7 +4230,8 @@ impl<'a> Resolver<'a> {
                 });
             }
 
-            ItemImpl(ref generics,
+            ItemImpl(_,
+                     ref generics,
                      ref implemented_traits,
                      ref self_type,
                      ref impl_items) => {
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 683948cd2e7..48d6ac847d8 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -114,7 +114,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
                     visit::walk_item(this, item);
                 });
             }
-            ast::ItemImpl(ref generics, _, _, _) => {
+            ast::ItemImpl(_, ref generics, _, _, _) => {
                 // Impls have both early- and late-bound lifetimes.
                 self.visit_early_late(subst::TypeSpace, generics, |this| {
                     this.check_lifetime_defs(&generics.lifetimes);
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 4c4df698f33..d6fd3d9a943 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -4741,7 +4741,7 @@ pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
             match cx.map.find(id.node) {
                 Some(ast_map::NodeItem(item)) => {
                     match item.node {
-                        ast::ItemImpl(_, ref opt_trait, _, _) => {
+                        ast::ItemImpl(_, _, ref opt_trait, _, _) => {
                             match opt_trait {
                                 &Some(ref t) => {
                                     Some(ty::node_id_to_trait_ref(cx, t.ref_id))
@@ -5722,7 +5722,7 @@ pub fn trait_id_of_impl(tcx: &ctxt,
     match node {
         ast_map::NodeItem(item) => {
             match item.node {
-                ast::ItemImpl(_, Some(ref trait_ref), _, _) => {
+                ast::ItemImpl(_, _, Some(ref trait_ref), _, _) => {
                     Some(node_id_to_trait_ref(tcx, trait_ref.ref_id).def_id)
                 }
                 _ => None
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 779fcd70864..712d6217dde 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -282,7 +282,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
                 NodeItem(item) => {
                     scope_id = item.id;
                     match item.node {
-                        ast::ItemImpl(_, _, ref ty, _) => {
+                        ast::ItemImpl(_, _, _, ref ty, _) => {
                             let mut result = String::from_str("<");
                             result.push_str(ty_to_string(&**ty).as_slice());
 
@@ -1040,7 +1040,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
                 self.process_const(item, &**typ, &**expr),
             ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params),
             ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
-            ast::ItemImpl(ref ty_params,
+            ast::ItemImpl(_,
+                          ref ty_params,
                           ref trait_ref,
                           ref typ,
                           ref impl_items) => {
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index b2578fdbc05..83779ffbe16 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -2304,7 +2304,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
         let mut v = TransItemVisitor{ ccx: ccx };
         v.visit_block(&**body);
       }
-      ast::ItemImpl(ref generics, _, _, ref impl_items) => {
+      ast::ItemImpl(_, ref generics, _, _, ref impl_items) => {
         meth::trans_impl(ccx,
                          item.ident,
                          impl_items.as_slice(),
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c64519c96dd..e0df94745d6 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -595,7 +595,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
         let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id);
         check_bare_fn(ccx, &**decl, &**body, it.id, fn_pty.ty, param_env);
       }
-      ast::ItemImpl(_, ref opt_trait_ref, _, ref impl_items) => {
+      ast::ItemImpl(_, _, ref opt_trait_ref, _, ref impl_items) => {
         debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
 
         let impl_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index defad95f749..7bc79d6e4a4 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -145,7 +145,7 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for CoherenceCheckVisitor<'a, 'tcx> {
         //debug!("(checking coherence) item '{}'", token::get_ident(item.ident));
 
         match item.node {
-            ItemImpl(_, ref opt_trait, _, _) => {
+            ItemImpl(_, _, ref opt_trait, _, _) => {
                 match opt_trait.clone() {
                     Some(opt_trait) => {
                         self.cc.check_implementation(item, &[opt_trait]);
@@ -325,7 +325,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
     // Converts an implementation in the AST to a vector of items.
     fn create_impl_from_item(&self, item: &Item) -> Vec {
         match item.node {
-            ItemImpl(_, ref trait_refs, _, ref ast_items) => {
+            ItemImpl(_, _, ref trait_refs, _, ref ast_items) => {
                 let mut items: Vec =
                         ast_items.iter()
                                  .map(|ast_item| {
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index dc3afaae35f..1803bf766dd 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -44,7 +44,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v ast::Item) {
         let def_id = ast_util::local_def(item.id);
         match item.node {
-            ast::ItemImpl(_, None, _, _) => {
+            ast::ItemImpl(_, _, None, _, _) => {
                 // For inherent impls, self type must be a nominal type
                 // defined in this crate.
                 debug!("coherence2::orphan check: inherent impl {}", item.repr(self.tcx));
@@ -64,7 +64,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
                     }
                 }
             }
-            ast::ItemImpl(_, Some(_), _, _) => {
+            ast::ItemImpl(_, _, Some(_), _, _) => {
                 // "Trait" impl
                 debug!("coherence2::orphan check: trait impl {}", item.repr(self.tcx));
                 if traits::is_orphan_impl(self.tcx, def_id) {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 643d8eb60ce..61b8e6c956c 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1045,7 +1045,8 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
                                    enum_definition.variants.as_slice(),
                                    generics);
         },
-        ast::ItemImpl(ref generics,
+        ast::ItemImpl(_,
+                      ref generics,
                       ref opt_trait_ref,
                       ref selfty,
                       ref impl_items) => {
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 79f04e91260..6592ca498dc 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -184,6 +184,7 @@ pub struct Trait {
 }
 
 pub struct Impl {
+    pub unsafety: ast::Unsafety,
     pub generics: ast::Generics,
     pub trait_: Option,
     pub for_: P,
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index f94e647b1cf..4374ce5deef 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -338,8 +338,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 };
                 om.traits.push(t);
             },
-            ast::ItemImpl(ref gen, ref tr, ref ty, ref items) => {
+            ast::ItemImpl(unsafety, ref gen, ref tr, ref ty, ref items) => {
                 let i = Impl {
+                    unsafety: unsafety,
                     generics: gen.clone(),
                     trait_: tr.clone(),
                     for_: ty.clone(),
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 1cc6b6feee8..206fb26eb55 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1617,7 +1617,8 @@ pub enum Item_ {
                                 // Currently, only Sized makes sense here.
               TyParamBounds,
               Vec),
-    ItemImpl(Generics,
+    ItemImpl(Unsafety,
+             Generics,
              Option, // (optional) trait this impl implements
              P, // self
              Vec),
diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs
index a2cdc4d2fbc..6089f39e828 100644
--- a/src/libsyntax/ast_map/mod.rs
+++ b/src/libsyntax/ast_map/mod.rs
@@ -755,7 +755,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
         let parent = self.parent;
         self.parent = i.id;
         match i.node {
-            ItemImpl(_, _, _, ref impl_items) => {
+            ItemImpl(_, _, _, _, ref impl_items) => {
                 for impl_item in impl_items.iter() {
                     match *impl_item {
                         MethodImplItem(ref m) => {
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index ee651592117..d2185a00876 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -133,11 +133,11 @@ fn fold_item_underscore(cx: &mut Context, item: ast::Item_) -> ast::Item_
     F: FnMut(&[ast::Attribute]) -> bool
 {
     let item = match item {
-        ast::ItemImpl(a, b, c, impl_items) => {
+        ast::ItemImpl(u, a, b, c, impl_items) => {
             let impl_items = impl_items.into_iter()
                                        .filter(|ii| impl_item_in_cfg(cx, ii))
                                        .collect();
-            ast::ItemImpl(a, b, c, impl_items)
+            ast::ItemImpl(u, a, b, c, impl_items)
         }
         ast::ItemTrait(u, a, b, c, methods) => {
             let methods = methods.into_iter()
diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs
index 820ff08a255..f40be823a1a 100644
--- a/src/libsyntax/ext/deriving/generic/mod.rs
+++ b/src/libsyntax/ext/deriving/generic/mod.rs
@@ -462,7 +462,8 @@ impl<'a> TraitDef<'a> {
             self.span,
             ident,
             a,
-            ast::ItemImpl(trait_generics,
+            ast::ItemImpl(ast::Unsafety::Normal,
+                          trait_generics,
                           opt_trait_ref,
                           self_type,
                           methods.into_iter()
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 66fe672c3e5..9656629e14d 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -215,7 +215,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
                 }
             }
 
-            ast::ItemImpl(_, _, _, ref items) => {
+            ast::ItemImpl(_, _, _, _, ref items) => {
                 if attr::contains_name(i.attrs.as_slice(),
                                        "unsafe_destructor") {
                     self.gate_feature("unsafe_destructor",
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index daed014f4eb..8a578c2cb05 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1008,7 +1008,7 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ {
             let struct_def = folder.fold_struct_def(struct_def);
             ItemStruct(struct_def, folder.fold_generics(generics))
         }
-        ItemImpl(generics, ifce, ty, impl_items) => {
+        ItemImpl(unsafety, generics, ifce, ty, impl_items) => {
             let mut new_impl_items = Vec::new();
             for impl_item in impl_items.iter() {
                 match *impl_item {
@@ -1030,7 +1030,8 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ {
                     Some(folder.fold_trait_ref((*trait_ref).clone()))
                 }
             };
-            ItemImpl(folder.fold_generics(generics),
+            ItemImpl(unsafety,
+                     folder.fold_generics(generics),
                      ifce,
                      folder.fold_ty(ty),
                      new_impl_items)
@@ -1160,7 +1161,7 @@ pub fn noop_fold_item_simple(Item {id, ident, attrs, node, vis, span}
     let node = folder.fold_item_underscore(node);
     let ident = match node {
         // The node may have changed, recompute the "pretty" impl name.
-        ItemImpl(_, ref maybe_trait, ref ty, _) => {
+        ItemImpl(_, _, ref maybe_trait, ref ty, _) => {
             ast_util::impl_pretty_name(maybe_trait, &**ty)
         }
         _ => ident
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index b2c30797cac..d1991c0463f 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -4667,7 +4667,7 @@ impl<'a> Parser<'a> {
     /// Parses two variants (with the region/type params always optional):
     ///    impl Foo { ... }
     ///    impl ToString for ~[T] { ... }
-    fn parse_item_impl(&mut self) -> ItemInfo {
+    fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> ItemInfo {
         // First, parse type parameters if necessary.
         let mut generics = self.parse_generics();
 
@@ -4706,7 +4706,7 @@ impl<'a> Parser<'a> {
         let ident = ast_util::impl_pretty_name(&opt_trait, &*ty);
 
         (ident,
-         ItemImpl(generics, opt_trait, ty, impl_items),
+         ItemImpl(unsafety, generics, opt_trait, ty, impl_items),
          Some(attrs))
     }
 
@@ -5556,6 +5556,22 @@ impl<'a> Parser<'a> {
                                     maybe_append(attrs, extra_attrs));
             return IoviItem(item);
         }
+        if self.token.is_keyword(keywords::Unsafe) &&
+            self.look_ahead(1u, |t| t.is_keyword(keywords::Impl))
+        {
+            // IMPL ITEM
+            self.expect_keyword(keywords::Unsafe);
+            self.expect_keyword(keywords::Impl);
+            let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe);
+            let last_span = self.last_span;
+            let item = self.mk_item(lo,
+                                    last_span.hi,
+                                    ident,
+                                    item_,
+                                    visibility,
+                                    maybe_append(attrs, extra_attrs));
+            return IoviItem(item);
+        }
         if self.token.is_keyword(keywords::Fn) &&
                 self.look_ahead(1, |f| !Parser::fn_expr_lookahead(f)) {
             // FUNCTION ITEM
@@ -5644,7 +5660,7 @@ impl<'a> Parser<'a> {
         }
         if self.eat_keyword(keywords::Impl) {
             // IMPL ITEM
-            let (ident, item_, extra_attrs) = self.parse_item_impl();
+            let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal);
             let last_span = self.last_span;
             let item = self.mk_item(lo,
                                     last_span.hi,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 037118b145f..db122f271a9 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -917,12 +917,16 @@ impl<'a> State<'a> {
                 try!(self.print_struct(&**struct_def, generics, item.ident, item.span));
             }
 
-            ast::ItemImpl(ref generics,
+            ast::ItemImpl(unsafety,
+                          ref generics,
                           ref opt_trait,
                           ref ty,
                           ref impl_items) => {
-                try!(self.head(visibility_qualified(item.vis,
-                                                    "impl").as_slice()));
+                try!(self.head(""));
+                try!(self.print_visibility(item.vis));
+                try!(self.print_unsafety(unsafety));
+                try!(self.word_nbsp("impl"));
+
                 if generics.is_parameterized() {
                     try!(self.print_generics(generics));
                     try!(space(&mut self.s));
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 7bb79a15f45..3535c6e267e 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -282,7 +282,8 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             visitor.visit_generics(type_parameters);
             walk_enum_def(visitor, enum_definition, type_parameters)
         }
-        ItemImpl(ref type_parameters,
+        ItemImpl(_,
+                 ref type_parameters,
                  ref trait_reference,
                  ref typ,
                  ref impl_items) => {
diff --git a/src/test/pretty/trait-safety.rs b/src/test/pretty/trait-safety.rs
index 42e578482e6..b96dbbf3cc9 100644
--- a/src/test/pretty/trait-safety.rs
+++ b/src/test/pretty/trait-safety.rs
@@ -14,6 +14,10 @@ unsafe trait UnsafeTrait {
     fn foo(&self);
 }
 
+unsafe impl UnsafeTrait for int {
+    fn foo(&self) { }
+}
+
 pub unsafe trait PubUnsafeTrait {
     fn foo(&self);
 }
-- 
cgit 1.4.1-3-g733a5