Skip to content

Commit abade67

Browse files
committed
Fixed issue rust-lang#56199.
1 parent a01e476 commit abade67

File tree

5 files changed

+152
-56
lines changed

5 files changed

+152
-56
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

+46-23
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ use rustc::mir::interpret::{ConstValue, GlobalId};
9898
use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
9999
UserSelfTy, UserSubsts};
100100
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
101-
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind};
101+
use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate,
102+
RegionKind};
102103
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
103104
use rustc::ty::fold::TypeFoldable;
104105
use rustc::ty::query::Providers;
@@ -3221,8 +3222,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
32213222
return_expr_ty);
32223223
}
32233224

3224-
// A generic function for checking the then and else in an if
3225-
// or if-else.
3225+
// A generic function for checking the 'then' and 'else' clauses in an 'if'
3226+
// or 'if-else' expression.
32263227
fn check_then_else(&self,
32273228
cond_expr: &'gcx hir::Expr,
32283229
then_expr: &'gcx hir::Expr,
@@ -3547,8 +3548,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
35473548

35483549
// we don't look at stability attributes on
35493550
// struct-like enums (yet...), but it's definitely not
3550-
// a bug to have construct one.
3551-
if adt_kind != ty::AdtKind::Enum {
3551+
// a bug to have constructed one.
3552+
if adt_kind != AdtKind::Enum {
35523553
tcx.check_stability(v_field.did, Some(expr_id), field.span);
35533554
}
35543555

@@ -5148,26 +5149,48 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
51485149
}).unwrap_or(false);
51495150

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

5167-
// The things we are substituting into the type should not contain
5168-
// escaping late-bound regions, and nor should the base type scheme.
5169-
let ty = self.tcx.type_of(def_id);
5170-
(def_id, ty)
5189+
// The things we are substituting into the type should not contain
5190+
// escaping late-bound regions, and nor should the base type scheme.
5191+
let ty = self.tcx.type_of(def_id);
5192+
(def_id, ty)
5193+
}
51715194
};
51725195

51735196
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)