Skip to content

Commit 700651c

Browse files
committed
Fixed issue rust-lang#56199.
1 parent 0a1b226 commit 700651c

File tree

5 files changed

+149
-54
lines changed

5 files changed

+149
-54
lines changed

src/librustc/ty/mod.rs

+52-32
Original file line numberDiff line numberDiff line change
@@ -1754,17 +1754,19 @@ bitflags! {
17541754
pub struct AdtFlags: u32 {
17551755
const NO_ADT_FLAGS = 0;
17561756
const IS_ENUM = 1 << 0;
1757-
const IS_PHANTOM_DATA = 1 << 1;
1758-
const IS_FUNDAMENTAL = 1 << 2;
1759-
const IS_UNION = 1 << 3;
1760-
const IS_BOX = 1 << 4;
1757+
const IS_UNION = 1 << 1;
1758+
const IS_STRUCT = 1 << 2;
1759+
const IS_TUPLE_STRUCT = 1 << 3;
1760+
const IS_PHANTOM_DATA = 1 << 4;
1761+
const IS_FUNDAMENTAL = 1 << 5;
1762+
const IS_BOX = 1 << 6;
17611763
/// Indicates whether the type is an `Arc`.
1762-
const IS_ARC = 1 << 5;
1764+
const IS_ARC = 1 << 7;
17631765
/// Indicates whether the type is an `Rc`.
1764-
const IS_RC = 1 << 6;
1766+
const IS_RC = 1 << 8;
17651767
/// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
17661768
/// (i.e., this flag is never set unless this ADT is an enum).
1767-
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 7;
1769+
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 9;
17681770
}
17691771
}
17701772

@@ -2079,31 +2081,43 @@ impl<'a, 'gcx, 'tcx> AdtDef {
20792081
repr: ReprOptions) -> Self {
20802082
debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
20812083
let mut flags = AdtFlags::NO_ADT_FLAGS;
2084+
2085+
if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
2086+
debug!("found non-exhaustive variant list for {:?}", did);
2087+
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
2088+
}
2089+
flags |= match kind {
2090+
AdtKind::Enum => AdtFlags::IS_ENUM,
2091+
AdtKind::Union => AdtFlags::IS_UNION,
2092+
AdtKind::Struct => AdtFlags::IS_STRUCT,
2093+
};
2094+
2095+
if let AdtKind::Struct = kind {
2096+
let variant_def = &variants[VariantIdx::new(0)];
2097+
let def_key = tcx.def_key(variant_def.did);
2098+
match def_key.disambiguated_data.data {
2099+
DefPathData::StructCtor => flags |= AdtFlags::IS_TUPLE_STRUCT,
2100+
_ => (),
2101+
}
2102+
}
2103+
20822104
let attrs = tcx.get_attrs(did);
20832105
if attr::contains_name(&attrs, "fundamental") {
2084-
flags = flags | AdtFlags::IS_FUNDAMENTAL;
2106+
flags |= AdtFlags::IS_FUNDAMENTAL;
20852107
}
20862108
if Some(did) == tcx.lang_items().phantom_data() {
2087-
flags = flags | AdtFlags::IS_PHANTOM_DATA;
2109+
flags |= AdtFlags::IS_PHANTOM_DATA;
20882110
}
20892111
if Some(did) == tcx.lang_items().owned_box() {
2090-
flags = flags | AdtFlags::IS_BOX;
2112+
flags |= AdtFlags::IS_BOX;
20912113
}
20922114
if Some(did) == tcx.lang_items().arc() {
2093-
flags = flags | AdtFlags::IS_ARC;
2115+
flags |= AdtFlags::IS_ARC;
20942116
}
20952117
if Some(did) == tcx.lang_items().rc() {
2096-
flags = flags | AdtFlags::IS_RC;
2097-
}
2098-
if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
2099-
debug!("found non-exhaustive variant list for {:?}", did);
2100-
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
2101-
}
2102-
match kind {
2103-
AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM,
2104-
AdtKind::Union => flags = flags | AdtFlags::IS_UNION,
2105-
AdtKind::Struct => {}
2118+
flags |= AdtFlags::IS_RC;
21062119
}
2120+
21072121
AdtDef {
21082122
did,
21092123
variants,
@@ -2114,25 +2128,31 @@ impl<'a, 'gcx, 'tcx> AdtDef {
21142128

21152129
#[inline]
21162130
pub fn is_struct(&self) -> bool {
2117-
!self.is_union() && !self.is_enum()
2131+
self.flags.contains(AdtFlags::IS_STRUCT)
2132+
}
2133+
2134+
/// If this function returns `true`, it implies that `is_struct` must return `true`.
2135+
#[inline]
2136+
pub fn is_tuple_struct(&self) -> bool {
2137+
self.flags.contains(AdtFlags::IS_TUPLE_STRUCT)
21182138
}
21192139

21202140
#[inline]
21212141
pub fn is_union(&self) -> bool {
2122-
self.flags.intersects(AdtFlags::IS_UNION)
2142+
self.flags.contains(AdtFlags::IS_UNION)
21232143
}
21242144

21252145
#[inline]
21262146
pub fn is_enum(&self) -> bool {
2127-
self.flags.intersects(AdtFlags::IS_ENUM)
2147+
self.flags.contains(AdtFlags::IS_ENUM)
21282148
}
21292149

21302150
#[inline]
21312151
pub fn is_variant_list_non_exhaustive(&self) -> bool {
2132-
self.flags.intersects(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
2152+
self.flags.contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
21332153
}
21342154

2135-
/// Returns the kind of the ADT - Struct or Enum.
2155+
/// Returns the kind of the ADT.
21362156
#[inline]
21372157
pub fn adt_kind(&self) -> AdtKind {
21382158
if self.is_enum() {
@@ -2161,33 +2181,33 @@ impl<'a, 'gcx, 'tcx> AdtDef {
21612181
}
21622182
}
21632183

2164-
/// Returns whether this type is #[fundamental] for the purposes
2184+
/// Returns whether this type is `#[fundamental]` for the purposes
21652185
/// of coherence checking.
21662186
#[inline]
21672187
pub fn is_fundamental(&self) -> bool {
2168-
self.flags.intersects(AdtFlags::IS_FUNDAMENTAL)
2188+
self.flags.contains(AdtFlags::IS_FUNDAMENTAL)
21692189
}
21702190

21712191
/// Returns `true` if this is PhantomData<T>.
21722192
#[inline]
21732193
pub fn is_phantom_data(&self) -> bool {
2174-
self.flags.intersects(AdtFlags::IS_PHANTOM_DATA)
2194+
self.flags.contains(AdtFlags::IS_PHANTOM_DATA)
21752195
}
21762196

21772197
/// Returns `true` if this is `Arc<T>`.
21782198
pub fn is_arc(&self) -> bool {
2179-
self.flags.intersects(AdtFlags::IS_ARC)
2199+
self.flags.contains(AdtFlags::IS_ARC)
21802200
}
21812201

21822202
/// Returns `true` if this is `Rc<T>`.
21832203
pub fn is_rc(&self) -> bool {
2184-
self.flags.intersects(AdtFlags::IS_RC)
2204+
self.flags.contains(AdtFlags::IS_RC)
21852205
}
21862206

21872207
/// Returns `true` if this is Box<T>.
21882208
#[inline]
21892209
pub fn is_box(&self) -> bool {
2190-
self.flags.intersects(AdtFlags::IS_BOX)
2210+
self.flags.contains(AdtFlags::IS_BOX)
21912211
}
21922212

21932213
/// Returns whether this type has a destructor.

src/librustc_typeck/check/callee.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
280280
Def::Local(id) | Def::Upvar(id, ..) => {
281281
Some(self.tcx.hir().span(id))
282282
}
283-
_ => self.tcx.hir().span_if_local(def.def_id())
283+
_ => def.opt_def_id().and_then(|did| self.tcx.hir().span_if_local(did)),
284284
};
285285
if let Some(span) = def_span {
286286
let label = match (unit_variant, inner_callee_path) {

src/librustc_typeck/check/mod.rs

+43-21
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ mod op;
9595

9696
use astconv::AstConv;
9797
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
98-
use rustc::hir::{self, GenericArg, Node, ItemKind, PatKind};
98+
use rustc::hir::{self, AdtKind, GenericArg, ItemKind, Node, PatKind};
9999
use rustc::hir::def::Def;
100100
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
101101
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
@@ -3217,8 +3217,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
32173217
return_expr_ty);
32183218
}
32193219

3220-
// A generic function for checking the then and else in an if
3221-
// or if-else.
3220+
// A generic function for checking the 'then' and 'else' clauses in an 'if'
3221+
// or 'if-else' expression.
32223222
fn check_then_else(&self,
32233223
cond_expr: &'gcx hir::Expr,
32243224
then_expr: &'gcx hir::Expr,
@@ -5156,26 +5156,48 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
51565156
}).unwrap_or(false);
51575157

51585158
let mut new_def = def;
5159-
let (def_id, ty) = if let Def::SelfCtor(impl_def_id) = def {
5160-
let ty = self.impl_self_ty(span, impl_def_id).ty;
5161-
5162-
match ty.ty_adt_def() {
5163-
Some(adt_def) if adt_def.is_struct() => {
5164-
let variant = adt_def.non_enum_variant();
5165-
new_def = Def::StructCtor(variant.did, variant.ctor_kind);
5166-
(variant.did, self.tcx.type_of(variant.did))
5167-
}
5168-
_ => {
5169-
(impl_def_id, self.tcx.types.err)
5170-
}
5159+
let (def_id, ty) = match def {
5160+
Def::SelfCtor(impl_def_id) => {
5161+
let ty = self.impl_self_ty(span, impl_def_id).ty;
5162+
let adt_def = ty.ty_adt_def();
5163+
5164+
match adt_def {
5165+
Some(adt_def) if adt_def.is_tuple_struct() => {
5166+
let variant = adt_def.non_enum_variant();
5167+
new_def = Def::StructCtor(variant.did, variant.ctor_kind);
5168+
(variant.did, self.tcx.type_of(variant.did))
5169+
}
5170+
_ => {
5171+
let mut err = self.tcx.sess.struct_span_err(span,
5172+
"the `Self` constructor can only be used with tuple or unit structs");
5173+
if let Some(adt_def) = adt_def {
5174+
match adt_def.adt_kind() {
5175+
AdtKind::Enum => {
5176+
err.note("did you mean to use one of the enum's variants?");
5177+
},
5178+
AdtKind::Union => {},
5179+
AdtKind::Struct => {
5180+
err.span_label(
5181+
span,
5182+
format!("did you mean `Self {{ /* fields */ }}`?"),
5183+
);
5184+
}
5185+
}
5186+
}
5187+
err.emit();
5188+
5189+
(impl_def_id, self.tcx.types.err)
5190+
}
5191+
};
51715192
}
5172-
} else {
5173-
let def_id = def.def_id();
5193+
_ => {
5194+
let def_id = def.def_id();
51745195

5175-
// The things we are substituting into the type should not contain
5176-
// escaping late-bound regions, and nor should the base type scheme.
5177-
let ty = self.tcx.type_of(def_id);
5178-
(def_id, ty)
5196+
// The things we are substituting into the type should not contain
5197+
// escaping late-bound regions, and nor should the base type scheme.
5198+
let ty = self.tcx.type_of(def_id);
5199+
(def_id, ty)
5200+
}
51795201
};
51805202

51815203
let substs = AstConv::create_substs_for_generic_args(

src/test/ui/issues/issue-56199.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
enum Foo {}
3+
struct Bar {}
4+
5+
impl Foo {
6+
fn foo() {
7+
let _ = Self;
8+
//~^ ERROR the `Self` constructor can only be used with tuple structs
9+
let _ = Self();
10+
//~^ ERROR the `Self` constructor can only be used with tuple structs
11+
}
12+
}
13+
14+
impl Bar {
15+
fn bar() {
16+
let _ = Self;
17+
//~^ ERROR the `Self` constructor can only be used with tuple structs
18+
let _ = Self();
19+
//~^ ERROR the `Self` constructor can only be used with tuple structs
20+
}
21+
}
22+
23+
fn main() {}

src/test/ui/issues/issue-56199.stderr

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error: the `Self` constructor can only be used with tuple structs
2+
--> $DIR/issue-56199.rs:7:17
3+
|
4+
LL | let _ = Self;
5+
| ^^^^
6+
|
7+
= note: did you mean to use one of the enum's variants?
8+
9+
error: the `Self` constructor can only be used with tuple structs
10+
--> $DIR/issue-56199.rs:9:17
11+
|
12+
LL | let _ = Self();
13+
| ^^^^
14+
|
15+
= note: did you mean to use one of the enum's variants?
16+
17+
error: the `Self` constructor can only be used with tuple structs
18+
--> $DIR/issue-56199.rs:16:17
19+
|
20+
LL | let _ = Self;
21+
| ^^^^ did you mean `Self { /* fields */ }`?
22+
23+
error: the `Self` constructor can only be used with tuple structs
24+
--> $DIR/issue-56199.rs:18:17
25+
|
26+
LL | let _ = Self();
27+
| ^^^^ did you mean `Self { /* fields */ }`?
28+
29+
error: aborting due to 4 previous errors
30+

0 commit comments

Comments
 (0)