Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit a7a2086

Browse files
Avi-D-coderJacob Hughes
authored andcommitted
Stability annotations on generic trait parameters
1 parent 6d3acf5 commit a7a2086

File tree

8 files changed

+226
-26
lines changed

8 files changed

+226
-26
lines changed

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,13 +1756,17 @@ impl EncodeContext<'a, 'tcx> {
17561756
EntryKind::TypeParam,
17571757
default.is_some(),
17581758
);
1759+
if default.is_some() {
1760+
self.encode_stability(def_id.to_def_id());
1761+
}
17591762
}
17601763
GenericParamKind::Const { .. } => {
17611764
self.encode_info_for_generic_param(
17621765
def_id.to_def_id(),
17631766
EntryKind::ConstParam,
17641767
true,
17651768
);
1769+
// FIXME(const_generics:defaults)
17661770
}
17671771
}
17681772
}

compiler/rustc_middle/src/middle/stability.rs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,15 @@ impl<'tcx> TyCtxt<'tcx> {
293293
/// If `id` is `Some(_)`, this function will also check if the item at `def_id` has been
294294
/// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
295295
/// `id`.
296-
pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> EvalResult {
296+
pub fn eval_stability(
297+
self,
298+
def_id: DefId,
299+
id: Option<HirId>,
300+
span: Span,
301+
check_deprecation: bool,
302+
) -> EvalResult {
297303
// Deprecated attributes apply in-crate and cross-crate.
298-
if let Some(id) = id {
304+
if let (Some(id), true) = (id, check_deprecation) {
299305
if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) {
300306
let parent_def_id = self.hir().local_def_id(self.hir().get_parent_item(id));
301307
let skip = self
@@ -395,21 +401,39 @@ impl<'tcx> TyCtxt<'tcx> {
395401
/// Additionally, this function will also check if the item is deprecated. If so, and `id` is
396402
/// not `None`, a deprecated lint attached to `id` will be emitted.
397403
pub fn check_stability(self, def_id: DefId, id: Option<HirId>, span: Span) {
404+
self.check_stability_internal(def_id, id, span, true, |span, def_id| {
405+
// The API could be uncallable for other reasons, for example when a private module
406+
// was referenced.
407+
self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id));
408+
})
409+
}
410+
411+
/// Checks if an item is stable or error out.
412+
///
413+
/// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
414+
/// exist, emits an error.
415+
///
416+
/// Additionally when `inherit_dep` is `true`, this function will also check if the item is deprecated. If so, and `id` is
417+
/// not `None`, a deprecated lint attached to `id` will be emitted.
418+
pub fn check_stability_internal(
419+
self,
420+
def_id: DefId,
421+
id: Option<HirId>,
422+
span: Span,
423+
check_deprecation: bool,
424+
unmarked: impl FnOnce(Span, DefId) -> (),
425+
) {
398426
let soft_handler = |lint, span, msg: &_| {
399427
self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| {
400428
lint.build(msg).emit()
401429
})
402430
};
403-
match self.eval_stability(def_id, id, span) {
431+
match self.eval_stability(def_id, id, span, check_deprecation) {
404432
EvalResult::Allow => {}
405433
EvalResult::Deny { feature, reason, issue, is_soft } => {
406434
report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler)
407435
}
408-
EvalResult::Unmarked => {
409-
// The API could be uncallable for other reasons, for example when a private module
410-
// was referenced.
411-
self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id));
412-
}
436+
EvalResult::Unmarked => unmarked(span, def_id),
413437
}
414438
}
415439

compiler/rustc_passes/src/stability.rs

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
5656
attrs: &[Attribute],
5757
item_sp: Span,
5858
kind: AnnotationKind,
59+
inherit_deprecation: bool,
5960
visit_children: F,
6061
) where
6162
F: FnOnce(&mut Self),
6263
{
6364
debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
6465
let mut did_error = false;
6566
if !self.tcx.features().staged_api {
66-
did_error = self.forbid_staged_api_attrs(hir_id, attrs);
67+
did_error = self.forbid_staged_api_attrs(hir_id, attrs, inherit_deprecation);
6768
}
6869

6970
let depr =
@@ -80,9 +81,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
8081
let depr_entry = DeprecationEntry::local(depr.clone(), hir_id);
8182
self.index.depr_map.insert(hir_id, depr_entry);
8283
} else if let Some(parent_depr) = self.parent_depr.clone() {
83-
is_deprecated = true;
84-
info!("tagging child {:?} as deprecated from parent", hir_id);
85-
self.index.depr_map.insert(hir_id, parent_depr);
84+
if inherit_deprecation {
85+
is_deprecated = true;
86+
info!("tagging child {:?} as deprecated from parent", hir_id);
87+
self.index.depr_map.insert(hir_id, parent_depr);
88+
}
8689
}
8790

8891
if self.tcx.features().staged_api {
@@ -186,7 +189,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
186189
if stab.is_none() {
187190
debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
188191
if let Some(stab) = self.parent_stab {
189-
if stab.level.is_unstable() {
192+
if inherit_deprecation && stab.level.is_unstable() {
190193
self.index.stab_map.insert(hir_id, stab);
191194
}
192195
}
@@ -237,7 +240,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
237240
}
238241

239242
// returns true if an error occurred, used to suppress some spurious errors
240-
fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> bool {
243+
fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute], inherit_deprecation: bool) -> bool {
241244
// Emit errors for non-staged-api crates.
242245
let unstable_attrs = [
243246
sym::unstable,
@@ -265,7 +268,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
265268
// Propagate unstability. This can happen even for non-staged-api crates in case
266269
// -Zforce-unstable-if-unmarked is set.
267270
if let Some(stab) = self.parent_stab {
268-
if stab.level.is_unstable() {
271+
if inherit_deprecation && stab.level.is_unstable() {
269272
self.index.stab_map.insert(hir_id, stab);
270273
}
271274
}
@@ -301,54 +304,82 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
301304
}
302305
hir::ItemKind::Struct(ref sd, _) => {
303306
if let Some(ctor_hir_id) = sd.ctor_hir_id() {
304-
self.annotate(ctor_hir_id, &i.attrs, i.span, AnnotationKind::Required, |_| {})
307+
self.annotate(
308+
ctor_hir_id,
309+
&i.attrs,
310+
i.span,
311+
AnnotationKind::Required,
312+
true,
313+
|_| {},
314+
)
305315
}
306316
}
307317
_ => {}
308318
}
309319

310-
self.annotate(i.hir_id, &i.attrs, i.span, kind, |v| intravisit::walk_item(v, i));
320+
self.annotate(i.hir_id, &i.attrs, i.span, kind, true, |v| intravisit::walk_item(v, i));
311321
self.in_trait_impl = orig_in_trait_impl;
312322
}
313323

314324
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
315-
self.annotate(ti.hir_id, &ti.attrs, ti.span, AnnotationKind::Required, |v| {
325+
self.annotate(ti.hir_id, &ti.attrs, ti.span, AnnotationKind::Required, true, |v| {
316326
intravisit::walk_trait_item(v, ti);
317327
});
318328
}
319329

320330
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
321331
let kind =
322332
if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
323-
self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, |v| {
333+
self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, true, |v| {
324334
intravisit::walk_impl_item(v, ii);
325335
});
326336
}
327337

328338
fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
329-
self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required, |v| {
339+
self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required, true, |v| {
330340
if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
331-
v.annotate(ctor_hir_id, &var.attrs, var.span, AnnotationKind::Required, |_| {});
341+
v.annotate(
342+
ctor_hir_id,
343+
&var.attrs,
344+
var.span,
345+
AnnotationKind::Required,
346+
true,
347+
|_| {},
348+
);
332349
}
333350

334351
intravisit::walk_variant(v, var, g, item_id)
335352
})
336353
}
337354

338355
fn visit_struct_field(&mut self, s: &'tcx StructField<'tcx>) {
339-
self.annotate(s.hir_id, &s.attrs, s.span, AnnotationKind::Required, |v| {
356+
self.annotate(s.hir_id, &s.attrs, s.span, AnnotationKind::Required, true, |v| {
340357
intravisit::walk_struct_field(v, s);
341358
});
342359
}
343360

344361
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
345-
self.annotate(i.hir_id, &i.attrs, i.span, AnnotationKind::Required, |v| {
362+
self.annotate(i.hir_id, &i.attrs, i.span, AnnotationKind::Required, true, |v| {
346363
intravisit::walk_foreign_item(v, i);
347364
});
348365
}
349366

350367
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
351-
self.annotate(md.hir_id, &md.attrs, md.span, AnnotationKind::Required, |_| {});
368+
self.annotate(md.hir_id, &md.attrs, md.span, AnnotationKind::Required, true, |_| {});
369+
}
370+
371+
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
372+
let kind = match &p.kind {
373+
// FIXME(const_generics:defaults)
374+
hir::GenericParamKind::Type { default, .. } if default.is_some() => {
375+
AnnotationKind::Container
376+
}
377+
_ => AnnotationKind::Prohibited,
378+
};
379+
380+
self.annotate(p.hir_id, &p.attrs, p.span, kind, false, |v| {
381+
intravisit::walk_generic_param(v, p);
382+
});
352383
}
353384
}
354385

@@ -422,6 +453,10 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
422453
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
423454
self.check_missing_stability(md.hir_id, md.span);
424455
}
456+
457+
// Note that we don't need to `check_missing_stability` for default generic parameters,
458+
// as we assume that any default generic parameters without attributes are automatically
459+
// stable (assuming they have not inherited instability from their parent).
425460
}
426461

427462
fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
@@ -484,6 +519,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
484519
&krate.item.attrs,
485520
krate.item.span,
486521
AnnotationKind::Required,
522+
true,
487523
|v| intravisit::walk_crate(v, krate),
488524
);
489525
}

compiler/rustc_typeck/src/astconv/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
360360
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
361361
self.ast_region_to_region(&lt, Some(param)).into()
362362
}
363-
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
363+
(GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
364+
if *has_default {
365+
tcx.check_stability_internal(
366+
param.def_id,
367+
Some(arg.id()),
368+
arg.span(),
369+
false,
370+
|_, _| (),
371+
)
372+
}
364373
if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) {
365374
inferred_params.push(ty.span);
366375
tcx.ty_error().into()

compiler/rustc_typeck/src/check/method/probe.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1227,7 +1227,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12271227
if let Some(uc) = unstable_candidates {
12281228
applicable_candidates.retain(|&(p, _)| {
12291229
if let stability::EvalResult::Deny { feature, .. } =
1230-
self.tcx.eval_stability(p.item.def_id, None, self.span)
1230+
self.tcx.eval_stability(p.item.def_id, None, self.span, true)
12311231
{
12321232
uc.push((p, feature));
12331233
return false;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#![crate_type = "lib"]
2+
#![feature(staged_api)]
3+
4+
#![stable(feature = "stable_test_feature", since = "1.0.0")]
5+
6+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
7+
pub trait Trait1<#[unstable(feature = "unstable_default", issue = "none")] T = ()> {
8+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
9+
fn foo() -> T;
10+
}
11+
12+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
13+
pub trait Trait2<#[unstable(feature = "unstable_default", issue = "none")] T = usize> {
14+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
15+
fn foo() -> T;
16+
}
17+
18+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
19+
pub trait Trait3<T = ()> {
20+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
21+
fn foo() -> T;
22+
}
23+
24+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
25+
pub struct Struct1<#[unstable(feature = "unstable_default", issue = "none")] T = usize> {
26+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
27+
pub field: T,
28+
}
29+
30+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
31+
pub struct Struct2<T = usize> {
32+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
33+
pub field: T,
34+
}
35+
36+
37+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
38+
pub const STRUCT1: Struct1 = Struct1 { field: 1 };
39+
40+
#[stable(feature = "stable_test_feature", since = "1.0.0")]
41+
pub const STRUCT2: Struct2 = Struct2 { field: 1 };
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// aux-build:unstable_generic_param.rs
2+
3+
extern crate unstable_generic_param;
4+
5+
use unstable_generic_param::*;
6+
7+
struct R;
8+
9+
impl Trait1 for S {
10+
fn foo() -> () { () } // ok
11+
}
12+
13+
struct S;
14+
15+
impl Trait1<usize> for S { //~ ERROR use of unstable library feature 'unstable_default'
16+
fn foo() -> usize { 0 }
17+
}
18+
19+
impl Trait1<isize> for S { //~ ERROR use of unstable library feature 'unstable_default'
20+
fn foo() -> isize { 0 }
21+
}
22+
23+
impl Trait2<usize> for S { //~ ERROR use of unstable library feature 'unstable_default'
24+
fn foo() -> usize { 0 }
25+
}
26+
27+
impl Trait3<usize> for S {
28+
fn foo() -> usize { 0 } // ok
29+
}
30+
31+
fn main() {
32+
// let _ = S;
33+
34+
// let _ = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default'
35+
// let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default'
36+
// let _: Struct1<isize> = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default'
37+
38+
// let _ = STRUCT1; // ok
39+
// let _: Struct1 = STRUCT1; // ok
40+
// let _: Struct1<usize> = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default'
41+
// let _: Struct1<usize> = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default'
42+
// let _ = STRUCT1.field; // ok
43+
// let _: usize = STRUCT1.field; //~ ERROR use of unstable library feature 'unstable_default'
44+
// let _ = STRUCT1.field + 1; //~ ERROR use of unstable library feature 'unstable_default'
45+
// let _ = STRUCT1.field + 1usize; //~ ERROR use of unstable library feature 'unstable_default'
46+
47+
// let _ = Struct2 { field: 1 }; // ok
48+
// let _: Struct2 = Struct2 { field: 1 }; // ok
49+
// let _: Struct2<usize> = Struct2 { field: 1 }; // ok
50+
51+
// let _ = STRUCT2;
52+
// let _: Struct2 = STRUCT2; // ok
53+
// let _: Struct2<usize> = STRUCT2; // ok
54+
// let _: Struct2<usize> = STRUCT2; // ok
55+
// let _ = STRUCT2.field; // ok
56+
// let _: usize = STRUCT2.field; // ok
57+
// let _ = STRUCT2.field + 1; // ok
58+
// let _ = STRUCT2.field + 1usize; // ok
59+
}

0 commit comments

Comments
 (0)