diff options
| author | bors <bors@rust-lang.org> | 2017-10-28 13:34:12 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-10-28 13:34:12 +0000 |
| commit | dce604a8fe85c22beb53d99c609d88e3a0ca9320 (patch) | |
| tree | a90645a189471c19ec8f875685c12e9ee9c6224e /src/libsyntax | |
| parent | 7da9a5e178e28b2e387e6296aa1b0289acdf5781 (diff) | |
| parent | 1e9e3191ab01ad16e8a839efeea5cac2999140af (diff) | |
| download | rust-dce604a8fe85c22beb53d99c609d88e3a0ca9320.tar.gz rust-dce604a8fe85c22beb53d99c609d88e3a0ca9320.zip | |
Auto merge of #44295 - plietar:extern-types, r=arielb1
Implement RFC 1861: Extern types
A few notes :
- Type parameters are not supported. This was an unresolved question from the RFC. It is not clear how useful this feature is, and how variance should be treated. This can be added in a future PR.
- `size_of_val` / `align_of_val` can be called with extern types, and respectively return 0 and 1. This differs from the RFC, which specified that they should panic, but after discussion with @eddyb on IRC this seems like a better solution.
If/when a `DynSized` trait is added, this will be disallowed statically.
- Auto traits are not implemented by default, since the contents of extern types is unknown. This means extern types are `!Sync`, `!Send` and `!Freeze`. This seems like the correct behaviour to me.
Manual `unsafe impl Sync for Foo` is still possible.
- This PR allows extern type to be used as the tail of a struct, as described by the RFC :
```rust
extern {
type OpaqueTail;
}
#[repr(C)]
struct FfiStruct {
data: u8,
more_data: u32,
tail: OpaqueTail,
}
```
However this is undesirable, as the alignment of `tail` is unknown (the current PR assumes an alignment of 1). Unfortunately we can't prevent it in the general case as the tail could be a type parameter :
```rust
#[repr(C)]
struct FfiStruct<T: ?Sized> {
data: u8,
more_data: u32,
tail: T,
}
```
Adding a `DynSized` trait would solve this as well, by requiring tail fields to be bound by it.
- Despite being unsized, pointers to extern types are thin and can be casted from/to integers. However it is not possible to write a `null<T>() -> *const T` function which works with extern types, as I've explained here : https://github.com/rust-lang/rust/issues/43467#issuecomment-321678621
- Trait objects cannot be built from extern types. I intend to support it eventually, although how this interacts with `DynSized`/`size_of_val` is still unclear.
- The definition of `c_void` is unmodified
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 27 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 22 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 1 |
6 files changed, 55 insertions, 8 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 090fc193b38..d3995d95792 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2007,13 +2007,16 @@ pub enum ForeignItemKind { /// A foreign static item (`static ext: u8`), with optional mutability /// (the boolean is true when mutable) Static(P<Ty>, bool), + /// A foreign type + Ty, } impl ForeignItemKind { pub fn descriptive_variant(&self) -> &str { match *self { ForeignItemKind::Fn(..) => "foreign function", - ForeignItemKind::Static(..) => "foreign static item" + ForeignItemKind::Static(..) => "foreign static item", + ForeignItemKind::Ty => "foreign type", } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 02aba8a3612..30451ec757a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -404,6 +404,9 @@ declare_features! ( // `crate` as visibility modifier, synonymous to `pub(crate)` (active, crate_visibility_modifier, "1.23.0", Some(45388)), + + // extern types + (active, extern_types, "1.23.0", Some(43467)), ); declare_features! ( @@ -1398,13 +1401,23 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { - let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") { - Some(val) => val.as_str().starts_with("llvm."), - _ => false - }; - if links_to_llvm { - gate_feature_post!(&self, link_llvm_intrinsics, i.span, - "linking to LLVM intrinsics is experimental"); + match i.node { + ast::ForeignItemKind::Fn(..) | + ast::ForeignItemKind::Static(..) => { + let link_name = attr::first_attr_value_str_by_name(&i.attrs, "link_name"); + let links_to_llvm = match link_name { + Some(val) => val.as_str().starts_with("llvm."), + _ => false + }; + if links_to_llvm { + gate_feature_post!(&self, link_llvm_intrinsics, i.span, + "linking to LLVM intrinsics is experimental"); + } + } + ast::ForeignItemKind::Ty => { + gate_feature_post!(&self, extern_types, i.span, + "extern types are experimental"); + } } visit::walk_foreign_item(self, i) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 518386a2ad2..fea49424dc8 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1069,6 +1069,7 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> For ForeignItemKind::Static(t, m) => { ForeignItemKind::Static(folder.fold_ty(t), m) } + ForeignItemKind::Ty => ForeignItemKind::Ty, }, span: folder.new_span(ni.span) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e96a5417aff..a3a265450ab 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5687,6 +5687,24 @@ impl<'a> Parser<'a> { }) } + /// Parse a type from a foreign module + fn parse_item_foreign_type(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>) + -> PResult<'a, ForeignItem> { + self.expect_keyword(keywords::Type)?; + + let ident = self.parse_ident()?; + let hi = self.span; + self.expect(&token::Semi)?; + Ok(ast::ForeignItem { + ident: ident, + attrs: attrs, + node: ForeignItemKind::Ty, + id: ast::DUMMY_NODE_ID, + span: lo.to(hi), + vis: vis + }) + } + /// Parse extern crate links /// /// # Examples @@ -6161,6 +6179,10 @@ impl<'a> Parser<'a> { if self.check_keyword(keywords::Fn) { return Ok(Some(self.parse_item_foreign_fn(visibility, lo, attrs)?)); } + // FOREIGN TYPE ITEM + if self.check_keyword(keywords::Type) { + return Ok(Some(self.parse_item_foreign_type(visibility, lo, attrs)?)); + } // FIXME #5668: this will occur for a macro invocation: match self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)? { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 656a51c6637..8a970fd4098 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1112,6 +1112,13 @@ impl<'a> State<'a> { self.end()?; // end the head-ibox self.end() // end the outer cbox } + ast::ForeignItemKind::Ty => { + self.head(&visibility_qualified(&item.vis, "type"))?; + self.print_ident(item.ident)?; + self.s.word(";")?; + self.end()?; // end the head-ibox + self.end() // end the outer cbox + } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 4198055f670..96e47a6cc0f 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -477,6 +477,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a visitor.visit_generics(generics) } ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ), + ForeignItemKind::Ty => (), } walk_list!(visitor, visit_attribute, &foreign_item.attrs); |
