about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs4
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs40
-rw-r--r--compiler/rustc_passes/src/stability.rs68
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs11
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs2
-rw-r--r--src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs41
-rw-r--r--src/test/ui/stability-attribute/generics-default-stability.rs59
-rw-r--r--src/test/ui/stability-attribute/generics-default-stability.stderr27
8 files changed, 226 insertions, 26 deletions
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index eb091d86b82..9ef17a93423 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1756,6 +1756,9 @@ impl EncodeContext<'a, 'tcx> {
                         EntryKind::TypeParam,
                         default.is_some(),
                     );
+                    if default.is_some() {
+                        self.encode_stability(def_id.to_def_id());
+                    }
                 }
                 GenericParamKind::Const { .. } => {
                     self.encode_info_for_generic_param(
@@ -1763,6 +1766,7 @@ impl EncodeContext<'a, 'tcx> {
                         EntryKind::ConstParam,
                         true,
                     );
+                    // FIXME(const_generics:defaults)
                 }
             }
         }
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 27658d50d45..4c0e513e75c 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -293,9 +293,15 @@ impl<'tcx> TyCtxt<'tcx> {
     /// If `id` is `Some(_)`, this function will also check if the item at `def_id` has been
     /// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
     /// `id`.
-    pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> EvalResult {
+    pub fn eval_stability(
+        self,
+        def_id: DefId,
+        id: Option<HirId>,
+        span: Span,
+        check_deprecation: bool,
+    ) -> EvalResult {
         // Deprecated attributes apply in-crate and cross-crate.
-        if let Some(id) = id {
+        if let (Some(id), true) = (id, check_deprecation) {
             if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) {
                 let parent_def_id = self.hir().local_def_id(self.hir().get_parent_item(id));
                 let skip = self
@@ -395,21 +401,39 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Additionally, this function will also check if the item is deprecated. If so, and `id` is
     /// not `None`, a deprecated lint attached to `id` will be emitted.
     pub fn check_stability(self, def_id: DefId, id: Option<HirId>, span: Span) {
+        self.check_stability_internal(def_id, id, span, true, |span, def_id| {
+            // The API could be uncallable for other reasons, for example when a private module
+            // was referenced.
+            self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id));
+        })
+    }
+
+    /// Checks if an item is stable or error out.
+    ///
+    /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
+    /// exist, emits an error.
+    ///
+    /// Additionally when `inherit_dep` is `true`, this function will also check if the item is deprecated. If so, and `id` is
+    /// not `None`, a deprecated lint attached to `id` will be emitted.
+    pub fn check_stability_internal(
+        self,
+        def_id: DefId,
+        id: Option<HirId>,
+        span: Span,
+        check_deprecation: bool,
+        unmarked: impl FnOnce(Span, DefId) -> (),
+    ) {
         let soft_handler = |lint, span, msg: &_| {
             self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| {
                 lint.build(msg).emit()
             })
         };
-        match self.eval_stability(def_id, id, span) {
+        match self.eval_stability(def_id, id, span, check_deprecation) {
             EvalResult::Allow => {}
             EvalResult::Deny { feature, reason, issue, is_soft } => {
                 report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler)
             }
-            EvalResult::Unmarked => {
-                // The API could be uncallable for other reasons, for example when a private module
-                // was referenced.
-                self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id));
-            }
+            EvalResult::Unmarked => unmarked(span, def_id),
         }
     }
 
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 4ca52f405fb..d658a58aeab 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -56,6 +56,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         attrs: &[Attribute],
         item_sp: Span,
         kind: AnnotationKind,
+        inherit_deprecation: bool,
         visit_children: F,
     ) where
         F: FnOnce(&mut Self),
@@ -63,7 +64,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
         let mut did_error = false;
         if !self.tcx.features().staged_api {
-            did_error = self.forbid_staged_api_attrs(hir_id, attrs);
+            did_error = self.forbid_staged_api_attrs(hir_id, attrs, inherit_deprecation);
         }
 
         let depr =
@@ -80,9 +81,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             let depr_entry = DeprecationEntry::local(depr.clone(), hir_id);
             self.index.depr_map.insert(hir_id, depr_entry);
         } else if let Some(parent_depr) = self.parent_depr.clone() {
-            is_deprecated = true;
-            info!("tagging child {:?} as deprecated from parent", hir_id);
-            self.index.depr_map.insert(hir_id, parent_depr);
+            if inherit_deprecation {
+                is_deprecated = true;
+                info!("tagging child {:?} as deprecated from parent", hir_id);
+                self.index.depr_map.insert(hir_id, parent_depr);
+            }
         }
 
         if self.tcx.features().staged_api {
@@ -186,7 +189,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         if stab.is_none() {
             debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
             if let Some(stab) = self.parent_stab {
-                if stab.level.is_unstable() {
+                if inherit_deprecation && stab.level.is_unstable() {
                     self.index.stab_map.insert(hir_id, stab);
                 }
             }
@@ -237,7 +240,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
     }
 
     // returns true if an error occurred, used to suppress some spurious errors
-    fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> bool {
+    fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute], inherit_deprecation: bool) -> bool {
         // Emit errors for non-staged-api crates.
         let unstable_attrs = [
             sym::unstable,
@@ -265,7 +268,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         // Propagate unstability.  This can happen even for non-staged-api crates in case
         // -Zforce-unstable-if-unmarked is set.
         if let Some(stab) = self.parent_stab {
-            if stab.level.is_unstable() {
+            if inherit_deprecation && stab.level.is_unstable() {
                 self.index.stab_map.insert(hir_id, stab);
             }
         }
@@ -301,18 +304,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
             }
             hir::ItemKind::Struct(ref sd, _) => {
                 if let Some(ctor_hir_id) = sd.ctor_hir_id() {
-                    self.annotate(ctor_hir_id, &i.attrs, i.span, AnnotationKind::Required, |_| {})
+                    self.annotate(
+                        ctor_hir_id,
+                        &i.attrs,
+                        i.span,
+                        AnnotationKind::Required,
+                        true,
+                        |_| {},
+                    )
                 }
             }
             _ => {}
         }
 
-        self.annotate(i.hir_id, &i.attrs, i.span, kind, |v| intravisit::walk_item(v, i));
+        self.annotate(i.hir_id, &i.attrs, i.span, kind, true, |v| intravisit::walk_item(v, i));
         self.in_trait_impl = orig_in_trait_impl;
     }
 
     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
-        self.annotate(ti.hir_id, &ti.attrs, ti.span, AnnotationKind::Required, |v| {
+        self.annotate(ti.hir_id, &ti.attrs, ti.span, AnnotationKind::Required, true, |v| {
             intravisit::walk_trait_item(v, ti);
         });
     }
@@ -320,15 +330,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
         let kind =
             if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
-        self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, |v| {
+        self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, true, |v| {
             intravisit::walk_impl_item(v, ii);
         });
     }
 
     fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
-        self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required, |v| {
+        self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required, true, |v| {
             if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
-                v.annotate(ctor_hir_id, &var.attrs, var.span, AnnotationKind::Required, |_| {});
+                v.annotate(
+                    ctor_hir_id,
+                    &var.attrs,
+                    var.span,
+                    AnnotationKind::Required,
+                    true,
+                    |_| {},
+                );
             }
 
             intravisit::walk_variant(v, var, g, item_id)
@@ -336,19 +353,33 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     }
 
     fn visit_struct_field(&mut self, s: &'tcx StructField<'tcx>) {
-        self.annotate(s.hir_id, &s.attrs, s.span, AnnotationKind::Required, |v| {
+        self.annotate(s.hir_id, &s.attrs, s.span, AnnotationKind::Required, true, |v| {
             intravisit::walk_struct_field(v, s);
         });
     }
 
     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
-        self.annotate(i.hir_id, &i.attrs, i.span, AnnotationKind::Required, |v| {
+        self.annotate(i.hir_id, &i.attrs, i.span, AnnotationKind::Required, true, |v| {
             intravisit::walk_foreign_item(v, i);
         });
     }
 
     fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
-        self.annotate(md.hir_id, &md.attrs, md.span, AnnotationKind::Required, |_| {});
+        self.annotate(md.hir_id, &md.attrs, md.span, AnnotationKind::Required, true, |_| {});
+    }
+
+    fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
+        let kind = match &p.kind {
+            // FIXME(const_generics:defaults)
+            hir::GenericParamKind::Type { default, .. } if default.is_some() => {
+                AnnotationKind::Container
+            }
+            _ => AnnotationKind::Prohibited,
+        };
+
+        self.annotate(p.hir_id, &p.attrs, p.span, kind, false, |v| {
+            intravisit::walk_generic_param(v, p);
+        });
     }
 }
 
@@ -422,6 +453,10 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
     fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
         self.check_missing_stability(md.hir_id, md.span);
     }
+
+    // Note that we don't need to `check_missing_stability` for default generic parameters,
+    // as we assume that any default generic parameters without attributes are automatically
+    // stable (assuming they have not inherited instability from their parent).
 }
 
 fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
@@ -484,6 +519,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
             &krate.item.attrs,
             krate.item.span,
             AnnotationKind::Required,
+            true,
             |v| intravisit::walk_crate(v, krate),
         );
     }
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index a743dc1cd20..c4f1ee2e6f6 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -360,7 +360,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
                     self.ast_region_to_region(&lt, Some(param)).into()
                 }
-                (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
+                (GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
+                    if *has_default {
+                        tcx.check_stability_internal(
+                            param.def_id,
+                            Some(arg.id()),
+                            arg.span(),
+                            false,
+                            |_, _| (),
+                        )
+                    }
                     if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) {
                         inferred_params.push(ty.span);
                         tcx.ty_error().into()
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 8a62031ec88..07e75594195 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -1227,7 +1227,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         if let Some(uc) = unstable_candidates {
             applicable_candidates.retain(|&(p, _)| {
                 if let stability::EvalResult::Deny { feature, .. } =
-                    self.tcx.eval_stability(p.item.def_id, None, self.span)
+                    self.tcx.eval_stability(p.item.def_id, None, self.span, true)
                 {
                     uc.push((p, feature));
                     return false;
diff --git a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs
new file mode 100644
index 00000000000..7596fa07cba
--- /dev/null
+++ b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs
@@ -0,0 +1,41 @@
+#![crate_type = "lib"]
+#![feature(staged_api)]
+
+#![stable(feature = "stable_test_feature", since = "1.0.0")]
+
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+pub trait Trait1<#[unstable(feature = "unstable_default", issue = "none")] T = ()> {
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    fn foo() -> T;
+}
+
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+pub trait Trait2<#[unstable(feature = "unstable_default", issue = "none")] T = usize> {
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    fn foo() -> T;
+}
+
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+pub trait Trait3<T = ()> {
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    fn foo() -> T;
+}
+
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+pub struct Struct1<#[unstable(feature = "unstable_default", issue = "none")] T = usize> {
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    pub field: T,
+}
+
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+pub struct Struct2<T = usize> {
+    #[stable(feature = "stable_test_feature", since = "1.0.0")]
+    pub field: T,
+}
+
+
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+pub const STRUCT1: Struct1 = Struct1 { field: 1 };
+
+#[stable(feature = "stable_test_feature", since = "1.0.0")]
+pub const STRUCT2: Struct2 = Struct2 { field: 1 };
diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs
new file mode 100644
index 00000000000..b8d6ad63102
--- /dev/null
+++ b/src/test/ui/stability-attribute/generics-default-stability.rs
@@ -0,0 +1,59 @@
+// aux-build:unstable_generic_param.rs
+
+extern crate unstable_generic_param;
+
+use unstable_generic_param::*;
+
+struct R;
+
+impl Trait1 for S {
+    fn foo() -> () { () } // ok
+}
+
+struct S;
+
+impl Trait1<usize> for S { //~ ERROR use of unstable library feature 'unstable_default'
+    fn foo() -> usize { 0 }
+}
+
+impl Trait1<isize> for S { //~ ERROR use of unstable library feature 'unstable_default'
+    fn foo() -> isize { 0 }
+}
+
+impl Trait2<usize> for S { //~ ERROR use of unstable library feature 'unstable_default'
+    fn foo() -> usize { 0 }
+}
+
+impl Trait3<usize> for S {
+    fn foo() -> usize { 0 } // ok
+}
+
+fn main() {
+    // let _ = S;
+
+    // let _ = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default'
+    // let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default'
+    // let _: Struct1<isize> = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default'
+
+    // let _ = STRUCT1; // ok
+    // let _: Struct1 = STRUCT1; // ok
+    // let _: Struct1<usize> = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default'
+    // let _: Struct1<usize> = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default'
+    // let _ = STRUCT1.field; // ok
+    // let _: usize = STRUCT1.field; //~ ERROR use of unstable library feature 'unstable_default'
+    // let _ = STRUCT1.field + 1; //~ ERROR use of unstable library feature 'unstable_default'
+    // let _ = STRUCT1.field + 1usize; //~ ERROR use of unstable library feature 'unstable_default'
+
+    // let _ = Struct2 { field: 1 }; // ok
+    // let _: Struct2 = Struct2 { field: 1 }; // ok
+    // let _: Struct2<usize> = Struct2 { field: 1 }; // ok
+
+    // let _ = STRUCT2;
+    // let _: Struct2 = STRUCT2; // ok
+    // let _: Struct2<usize> = STRUCT2; // ok
+    // let _: Struct2<usize> = STRUCT2; // ok
+    // let _ = STRUCT2.field; // ok
+    // let _: usize = STRUCT2.field; // ok
+    // let _ = STRUCT2.field + 1; // ok
+    // let _ = STRUCT2.field + 1usize; // ok
+}
diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr
new file mode 100644
index 00000000000..1b7f4b85b59
--- /dev/null
+++ b/src/test/ui/stability-attribute/generics-default-stability.stderr
@@ -0,0 +1,27 @@
+error[E0658]: use of unstable library feature 'unstable_default'
+  --> $DIR/generics-default-stability.rs:15:13
+   |
+LL | impl Trait1<usize> for S {
+   |             ^^^^^
+   |
+   = help: add `#![feature(unstable_default)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'unstable_default'
+  --> $DIR/generics-default-stability.rs:19:13
+   |
+LL | impl Trait1<isize> for S {
+   |             ^^^^^
+   |
+   = help: add `#![feature(unstable_default)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'unstable_default'
+  --> $DIR/generics-default-stability.rs:23:13
+   |
+LL | impl Trait2<usize> for S {
+   |             ^^^^^
+   |
+   = help: add `#![feature(unstable_default)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.