about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-01-14 14:26:50 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2016-01-15 19:57:53 +0300
commitccb4b35897c0356bb397fe045fa23ddbce9fc134 (patch)
tree395778e0f9f1e96f92593c4021d08b5c77bab9fe
parent1f4e317e45349eb2d3c853e96bfd24dd574b36d1 (diff)
downloadrust-ccb4b35897c0356bb397fe045fa23ddbce9fc134.tar.gz
rust-ccb4b35897c0356bb397fe045fa23ddbce9fc134.zip
Preserve struct/variant kinds in metadata
Add tests for use of empty structs in cross-crate scenarios
-rw-r--r--src/librustc/middle/ty/mod.rs11
-rw-r--r--src/librustc_metadata/decoder.rs32
-rw-r--r--src/librustc_metadata/encoder.rs11
-rw-r--r--src/librustc_typeck/collect.rs7
-rw-r--r--src/test/auxiliary/empty-struct.rs19
-rw-r--r--src/test/compile-fail/empty-struct-braces-expr.rs17
-rw-r--r--src/test/compile-fail/empty-struct-braces-pat-1.rs21
-rw-r--r--src/test/compile-fail/empty-struct-braces-pat-2.rs12
-rw-r--r--src/test/compile-fail/empty-struct-braces-pat-3.rs24
-rw-r--r--src/test/compile-fail/empty-struct-unit-expr.rs15
-rw-r--r--src/test/compile-fail/empty-struct-unit-pat.rs47
-rw-r--r--src/test/run-pass/empty-struct-braces.rs63
12 files changed, 229 insertions, 50 deletions
diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs
index 852d9d80a91..b902a46fea3 100644
--- a/src/librustc/middle/ty/mod.rs
+++ b/src/librustc/middle/ty/mod.rs
@@ -49,7 +49,7 @@ use std::collections::{HashMap, HashSet};
 use syntax::ast::{self, CrateNum, Name, NodeId};
 use syntax::attr::{self, AttrMetaMethods};
 use syntax::codemap::{DUMMY_SP, Span};
-use syntax::parse::token::{InternedString, special_idents};
+use syntax::parse::token::InternedString;
 
 use rustc_front::hir;
 use rustc_front::hir::{ItemImpl, ItemTrait};
@@ -1353,6 +1353,7 @@ pub struct VariantDefData<'tcx, 'container: 'tcx> {
     pub name: Name, // struct's name if this is a struct
     pub disr_val: Disr,
     pub fields: Vec<FieldDefData<'tcx, 'container>>,
+    pub kind: VariantKind,
 }
 
 pub struct FieldDefData<'tcx, 'container: 'tcx> {
@@ -1607,13 +1608,7 @@ impl<'tcx, 'container> VariantDefData<'tcx, 'container> {
     }
 
     pub fn kind(&self) -> VariantKind {
-        match self.fields.get(0) {
-            None => VariantKind::Unit,
-            Some(&FieldDefData { name, .. }) if name == special_idents::unnamed_field.name => {
-                VariantKind::Tuple
-            }
-            Some(_) => VariantKind::Struct
-        }
+        self.kind
     }
 
     pub fn is_tuple_struct(&self) -> bool {
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index b8dfb9f74c6..def5897e92d 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -101,12 +101,15 @@ enum Family {
     Mod,                   // m
     ForeignMod,            // n
     Enum,                  // t
-    TupleVariant,          // v
     StructVariant,         // V
+    TupleVariant,          // v
+    UnitVariant,           // w
     Impl,                  // i
-    DefaultImpl,              // d
+    DefaultImpl,           // d
     Trait,                 // I
     Struct,                // S
+    TupleStruct,           // s
+    UnitStruct,            // u
     PublicField,           // g
     InheritedField,        // N
     Constant,              // C
@@ -126,12 +129,15 @@ fn item_family(item: rbml::Doc) -> Family {
       'm' => Mod,
       'n' => ForeignMod,
       't' => Enum,
-      'v' => TupleVariant,
       'V' => StructVariant,
+      'v' => TupleVariant,
+      'w' => UnitVariant,
       'i' => Impl,
       'd' => DefaultImpl,
       'I' => Trait,
       'S' => Struct,
+      's' => TupleStruct,
+      'u' => UnitStruct,
       'g' => PublicField,
       'N' => InheritedField,
        c => panic!("unexpected family char: {}", c)
@@ -282,7 +288,7 @@ fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike {
         }
         ImmStatic => DlDef(def::DefStatic(did, false)),
         MutStatic => DlDef(def::DefStatic(did, true)),
-        Struct    => DlDef(def::DefStruct(did)),
+        Struct | TupleStruct | UnitStruct => DlDef(def::DefStruct(did)),
         Fn        => DlDef(def::DefFn(did, false)),
         CtorFn    => DlDef(def::DefFn(did, true)),
         Method | StaticMethod => {
@@ -302,7 +308,7 @@ fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike {
             let enum_did = item_require_parent_item(cdata, item);
             DlDef(def::DefVariant(enum_did, did, true))
         }
-        TupleVariant => {
+        TupleVariant | UnitVariant => {
             let enum_did = item_require_parent_item(cdata, item);
             DlDef(def::DefVariant(enum_did, did, false))
         }
@@ -365,6 +371,14 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
                          item_id: DefIndex,
                          tcx: &ty::ctxt<'tcx>) -> ty::AdtDefMaster<'tcx>
 {
+    fn family_to_variant_kind<'tcx>(family: Family, tcx: &ty::ctxt<'tcx>) -> ty::VariantKind {
+        match family {
+            Struct | StructVariant => ty::VariantKind::Struct,
+            TupleStruct | TupleVariant => ty::VariantKind::Tuple,
+            UnitStruct | UnitVariant => ty::VariantKind::Unit,
+            _ => tcx.sess.bug(&format!("unexpected family: {:?}", family)),
+        }
+    }
     fn get_enum_variants<'tcx>(intr: &IdentInterner,
                                cdata: Cmd,
                                doc: rbml::Doc,
@@ -384,7 +398,8 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
                 did: did,
                 name: item_name(intr, item),
                 fields: get_variant_fields(intr, cdata, item, tcx),
-                disr_val: disr
+                disr_val: disr,
+                kind: family_to_variant_kind(item_family(item), tcx),
             }
         }).collect()
     }
@@ -417,7 +432,8 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
             did: did,
             name: item_name(intr, doc),
             fields: get_variant_fields(intr, cdata, doc, tcx),
-            disr_val: 0
+            disr_val: 0,
+            kind: family_to_variant_kind(item_family(doc), tcx),
         }
     }
 
@@ -428,7 +444,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
             (ty::AdtKind::Enum,
              get_enum_variants(intr, cdata, doc, tcx))
         }
-        Struct => {
+        Struct | TupleStruct | UnitStruct => {
             let ctor_did =
                 reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).
                 map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc));
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 22da853dfed..ec70a610e0b 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -285,8 +285,9 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id_and_key(ecx, rbml_w, vid);
         encode_family(rbml_w, match variant.kind() {
-            ty::VariantKind::Unit | ty::VariantKind::Tuple => 'v',
-            ty::VariantKind::Struct => 'V'
+            ty::VariantKind::Struct => 'V',
+            ty::VariantKind::Tuple => 'v',
+            ty::VariantKind::Unit => 'w',
         });
         encode_name(rbml_w, variant.name);
         encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id));
@@ -1043,7 +1044,11 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         /* Now, make an item for the class itself */
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 'S');
+        encode_family(rbml_w, match *struct_def {
+            hir::VariantData::Struct(..) => 'S',
+            hir::VariantData::Tuple(..) => 's',
+            hir::VariantData::Unit(..) => 'u',
+        });
         encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
 
         encode_item_variances(rbml_w, ecx, item.id);
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index af2824d0930..eb204c56414 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1006,7 +1006,12 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>,
         did: did,
         name: name,
         disr_val: disr_val,
-        fields: fields
+        fields: fields,
+        kind: match *def {
+            hir::VariantData::Struct(..) => ty::VariantKind::Struct,
+            hir::VariantData::Tuple(..) => ty::VariantKind::Tuple,
+            hir::VariantData::Unit(..) => ty::VariantKind::Unit,
+        }
     }
 }
 
diff --git a/src/test/auxiliary/empty-struct.rs b/src/test/auxiliary/empty-struct.rs
new file mode 100644
index 00000000000..3b92bc31217
--- /dev/null
+++ b/src/test/auxiliary/empty-struct.rs
@@ -0,0 +1,19 @@
+// Copyright 2015 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.
+
+#![feature(braced_empty_structs)]
+
+pub struct XEmpty1 {}
+pub struct XEmpty2;
+
+pub enum XE {
+    XEmpty3 {},
+    XEmpty4,
+}
diff --git a/src/test/compile-fail/empty-struct-braces-expr.rs b/src/test/compile-fail/empty-struct-braces-expr.rs
index 67167086b9c..6ae0dad0e7b 100644
--- a/src/test/compile-fail/empty-struct-braces-expr.rs
+++ b/src/test/compile-fail/empty-struct-braces-expr.rs
@@ -10,17 +10,28 @@
 
 // Can't use empty braced struct as constant or constructor function
 
+// aux-build:empty-struct.rs
+
 #![feature(braced_empty_structs)]
 
+extern crate empty_struct;
+use empty_struct::*;
+
 struct Empty1 {}
 
 enum E {
-    Empty2 {}
+    Empty3 {}
 }
 
 fn main() {
     let e1 = Empty1; //~ ERROR `Empty1` is the name of a struct or struct variant
     let e1 = Empty1(); //~ ERROR `Empty1` is the name of a struct or struct variant
-    let e2 = E::Empty2; //~ ERROR `E::Empty2` is the name of a struct or struct variant
-    let e2 = E::Empty2(); //~ ERROR `E::Empty2` is the name of a struct or struct variant
+    let e3 = E::Empty3; //~ ERROR `E::Empty3` is the name of a struct or struct variant
+    let e3 = E::Empty3(); //~ ERROR `E::Empty3` is the name of a struct or struct variant
+
+    // FIXME: non-local struct kind should be known early (e.g. kept in `DefStruct`)
+    // let xe1 = XEmpty1; // ERROR `XEmpty1` is the name of a struct or struct variant
+    let xe1 = XEmpty1(); //~ ERROR expected function, found `empty_struct::XEmpty1`
+    let xe3 = XE::Empty3; //~ ERROR no associated item named `Empty3` found for type
+    let xe3 = XE::Empty3(); //~ ERROR no associated item named `Empty3` found for type
 }
diff --git a/src/test/compile-fail/empty-struct-braces-pat-1.rs b/src/test/compile-fail/empty-struct-braces-pat-1.rs
index 6a6c3f16c04..27c97a3a550 100644
--- a/src/test/compile-fail/empty-struct-braces-pat-1.rs
+++ b/src/test/compile-fail/empty-struct-braces-pat-1.rs
@@ -10,22 +10,35 @@
 
 // Can't use empty braced struct as constant pattern
 
+// aux-build:empty-struct.rs
+
 #![feature(braced_empty_structs)]
 
+extern crate empty_struct;
+use empty_struct::*;
+
 struct Empty1 {}
 
 enum E {
-    Empty2 {}
+    Empty3 {}
 }
 
 fn main() {
     let e1 = Empty1 {};
-    let e2 = E::Empty2 {};
+    let e3 = E::Empty3 {};
+    let xe1 = XEmpty1 {};
+    let xe3 = XE::XEmpty3 {};
 
     match e1 {
         Empty1 => () // Not an error, `Empty1` is interpreted as a new binding
     }
-    match e2 {
-        E::Empty2 => () //~ ERROR `E::Empty2` does not name a tuple variant or a tuple struct
+    match e3 {
+        E::Empty3 => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
+    }
+    match xe1 {
+        XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding
+    }
+    match xe3 {
+        XE::XEmpty3 => () //~ ERROR no associated item named `XEmpty3` found for type
     }
 }
diff --git a/src/test/compile-fail/empty-struct-braces-pat-2.rs b/src/test/compile-fail/empty-struct-braces-pat-2.rs
index d98d64b712a..3436e2a2cd7 100644
--- a/src/test/compile-fail/empty-struct-braces-pat-2.rs
+++ b/src/test/compile-fail/empty-struct-braces-pat-2.rs
@@ -10,18 +10,30 @@
 
 // Can't use empty braced struct as enum pattern
 
+// aux-build:empty-struct.rs
+
 #![feature(braced_empty_structs)]
 
+extern crate empty_struct;
+use empty_struct::*;
+
 struct Empty1 {}
 
 fn main() {
     let e1 = Empty1 {};
+    let xe1 = XEmpty1 {};
 
     // Rejected by parser as yet
     // match e1 {
     //     Empty1() => () // ERROR unresolved enum variant, struct or const `Empty1`
     // }
+    // match xe1 {
+    //     XEmpty1() => () // ERROR unresolved enum variant, struct or const `XEmpty1`
+    // }
     match e1 {
         Empty1(..) => () //~ ERROR unresolved enum variant, struct or const `Empty1`
     }
+    match xe1 {
+        XEmpty1(..) => () //~ ERROR `XEmpty1` does not name a tuple variant or a tuple struct
+    }
 }
diff --git a/src/test/compile-fail/empty-struct-braces-pat-3.rs b/src/test/compile-fail/empty-struct-braces-pat-3.rs
index 9fae203f389..ca51a1cfc21 100644
--- a/src/test/compile-fail/empty-struct-braces-pat-3.rs
+++ b/src/test/compile-fail/empty-struct-braces-pat-3.rs
@@ -10,20 +10,32 @@
 
 // Can't use empty braced struct as enum pattern
 
+// aux-build:empty-struct.rs
+
 #![feature(braced_empty_structs)]
 
+extern crate empty_struct;
+use empty_struct::*;
+
 enum E {
-    Empty2 {}
+    Empty3 {}
 }
 
 fn main() {
-    let e2 = E::Empty2 {};
+    let e3 = E::Empty3 {};
+    let xe3 = XE::XEmpty3 {};
 
     // Rejected by parser as yet
-    // match e2 {
-    //     E::Empty2() => () // ERROR `E::Empty2` does not name a tuple variant or a tuple struct
+    // match e3 {
+    //     E::Empty3() => () // ERROR `E::Empty3` does not name a tuple variant or a tuple struct
     // }
-    match e2 {
-        E::Empty2(..) => () //~ ERROR `E::Empty2` does not name a tuple variant or a tuple struct
+    // match xe3 {
+    //     E::Empty3() => () // ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
+    // }
+    match e3 {
+        E::Empty3(..) => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
+    }
+    match xe3 {
+        XE::XEmpty3(..) => () //~ ERROR no associated item named `XEmpty3` found for type
     }
 }
diff --git a/src/test/compile-fail/empty-struct-unit-expr.rs b/src/test/compile-fail/empty-struct-unit-expr.rs
index 199065665b9..822ee9e0dbc 100644
--- a/src/test/compile-fail/empty-struct-unit-expr.rs
+++ b/src/test/compile-fail/empty-struct-unit-expr.rs
@@ -10,15 +10,22 @@
 
 // Can't use unit struct as constructor function
 
+// aux-build:empty-struct.rs
+
 #![feature(braced_empty_structs)]
 
-struct Empty1;
+extern crate empty_struct;
+use empty_struct::*;
+
+struct Empty2;
 
 enum E {
-    Empty2
+    Empty4
 }
 
 fn main() {
-    let e1 = Empty1(); //~ ERROR expected function, found `Empty1`
-    let e2 = E::Empty2(); //~ ERROR expected function, found `E`
+    let e2 = Empty2(); //~ ERROR expected function, found `Empty2`
+    let e4 = E::Empty4(); //~ ERROR expected function, found `E`
+    let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2`
+    let xe4 = XE::XEmpty4(); //~ ERROR  expected function, found `empty_struct::XE`
 }
diff --git a/src/test/compile-fail/empty-struct-unit-pat.rs b/src/test/compile-fail/empty-struct-unit-pat.rs
index cffd9fd9b49..0f54d1b7365 100644
--- a/src/test/compile-fail/empty-struct-unit-pat.rs
+++ b/src/test/compile-fail/empty-struct-unit-pat.rs
@@ -10,36 +10,59 @@
 
 // Can't use unit struct as enum pattern
 
+// aux-build:empty-struct.rs
+
 #![feature(rustc_attrs)]
 // remove prior feature after warning cycle and promoting warnings to errors
 #![feature(braced_empty_structs)]
 
-struct Empty1;
+extern crate empty_struct;
+use empty_struct::*;
+
+struct Empty2;
 
 enum E {
-    Empty2
+    Empty4
 }
 
 // remove attribute after warning cycle and promoting warnings to errors
 #[rustc_error]
 fn main() { //~ ERROR: compilation successful
-    let e1 = Empty1;
-    let e2 = E::Empty2;
+    let e2 = Empty2;
+    let e4 = E::Empty4;
+    let xe2 = XEmpty2;
+    let xe4 = XE::XEmpty4;
 
     // Rejected by parser as yet
-    // match e1 {
-    //     Empty1() => () // ERROR `Empty1` does not name a tuple variant or a tuple struct
+    // match e2 {
+    //     Empty2() => () // ERROR `Empty2` does not name a tuple variant or a tuple struct
     // }
-    match e1 {
-        Empty1(..) => () //~ WARN `Empty1` does not name a tuple variant or a tuple struct
+    // match xe2 {
+    //     XEmpty2() => () // ERROR `XEmpty2` does not name a tuple variant or a tuple struct
+    // }
+    match e2 {
+        Empty2(..) => () //~ WARN `Empty2` does not name a tuple variant or a tuple struct
+            //~^ WARN hard error
+    }
+    match xe2 {
+        XEmpty2(..) => () //~ WARN `XEmpty2` does not name a tuple variant or a tuple struct
             //~^ WARN hard error
     }
     // Rejected by parser as yet
-    // match e2 {
-    //     E::Empty2() => () // ERROR `E::Empty2` does not name a tuple variant or a tuple struct
+    // match e4 {
+    //     E::Empty4() => () // ERROR `E::Empty4` does not name a tuple variant or a tuple struct
     // }
-    match e2 {
-        E::Empty2(..) => () //~ WARN `E::Empty2` does not name a tuple variant or a tuple struct
+    // match xe4 {
+    //     XE::XEmpty4() => (), // ERROR `XE::XEmpty4` does not name a tuple variant or a tuple
+    //     _ => {},
+    // }
+    match e4 {
+        E::Empty4(..) => () //~ WARN `E::Empty4` does not name a tuple variant or a tuple struct
+            //~^ WARN hard error
+    }
+    match xe4 {
+        XE::XEmpty4(..) => (), //~ WARN `XE::XEmpty4` does not name a tuple variant or a tuple
             //~^ WARN hard error
+        _ => {},
     }
 }
diff --git a/src/test/run-pass/empty-struct-braces.rs b/src/test/run-pass/empty-struct-braces.rs
index 80ea1bc3a0e..b4ce1b97a4c 100644
--- a/src/test/run-pass/empty-struct-braces.rs
+++ b/src/test/run-pass/empty-struct-braces.rs
@@ -11,8 +11,13 @@
 // Empty struct defined with braces add names into type namespace
 // Empty struct defined without braces add names into both type and value namespaces
 
+// aux-build:empty-struct.rs
+
 #![feature(braced_empty_structs)]
 
+extern crate empty_struct;
+use empty_struct::*;
+
 struct Empty1 {}
 struct Empty2;
 struct Empty3 {}
@@ -23,7 +28,7 @@ enum E {
     Empty5,
 }
 
-fn main() {
+fn local() {
     let e1: Empty1 = Empty1 {};
     let e2: Empty2 = Empty2 {};
     let e2: Empty2 = Empty2;
@@ -84,3 +89,59 @@ fn main() {
     let e22: Empty2 = Empty2 { ..e2 };
     let e33: Empty3 = Empty3 { ..e3 };
 }
+
+fn xcrate() {
+    let e1: XEmpty1 = XEmpty1 {};
+    let e2: XEmpty2 = XEmpty2 {};
+    let e2: XEmpty2 = XEmpty2;
+    let e3: XE = XE::XEmpty3 {};
+    // FIXME: Commented out tests are waiting for PR 30882 (fixes for variant namespaces)
+    // let e4: XE = XE::XEmpty4 {};
+    let e4: XE = XE::XEmpty4;
+
+    match e1 {
+        XEmpty1 {} => {}
+    }
+    match e2 {
+        XEmpty2 {} => {}
+    }
+    match e3 {
+        XE::XEmpty3 {} => {}
+        _ => {}
+    }
+    // match e4 {
+    //     XE::XEmpty4 {} => {}
+    //     _ => {}
+    // }
+
+    match e1 {
+        XEmpty1 { .. } => {}
+    }
+    match e2 {
+        XEmpty2 { .. } => {}
+    }
+    match e3 {
+        XE::XEmpty3 { .. } => {}
+        _ => {}
+    }
+    // match e4 {
+    //     XE::XEmpty4 { .. } => {}
+    //     _ => {}
+    // }
+
+    match e2 {
+        XEmpty2 => {}
+    }
+    // match e4 {
+    //     XE::XEmpty4 => {}
+    //     _ => {}
+    // }
+
+    let e11: XEmpty1 = XEmpty1 { ..e1 };
+    let e22: XEmpty2 = XEmpty2 { ..e2 };
+}
+
+fn main() {
+    local();
+    xcrate();
+}