Auto merge of #140399 - tiif:unstable_impl, r=lcnr,BoxyUwU
Implement unstable trait impl This PR allows marking impls of stable trait with stable type as unstable. ## Approach In std/core, an impl can be marked as unstable by annotating it with ``#[unstable_feature_bound(feat_name)]``. This will add a ``ClauseKind::Unstable_Feature(feat_name)`` to the list of predicates in ``predicates_of`` . When an unstable impl's function is called, we will first iterate through all the goals in ``param_env`` to check if there is any ``ClauseKind::UnstableFeature(feat_name)`` in ``param_env``. The existence of ``ClauseKind::Unstable_Feature(feat_name)`` in ``param_env`` means an``#[unstable_feature_bound(feat_name)]`` is present at the call site of the function, so we allow the check to succeed in this case. If ``ClauseKind::UnstableFeature(feat_name)`` does not exist in ``param_env``, we will still allow the check to succeed for either of the cases below: 1. The feature is enabled through ``#[feature(feat_name)]`` outside of std / core. 2. We are in codegen because we may be monomorphizing a body from an upstream crate which had an unstable feature enabled that the downstream crate do not. For the rest of the case, it will fail with ambiguity. ## Limitation In this PR, we do not support: 1. using items that need ``#[unstable_feature_bound]`` within stable APIs 2. annotate main function with ``#[unstable_feature_bound]`` 3. annotate ``#[unstable_feature_bound]`` on items other than free function and impl ## Acknowledgement The design and mentoring are done by `@BoxyUwU`
This commit is contained in:
commit
014bd8290f
82 changed files with 1064 additions and 13 deletions
|
|
@ -420,6 +420,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_unsafe_specialization_marker]`.
|
||||
UnsafeSpecializationMarker(Span),
|
||||
|
||||
/// Represents `#[unstable_feature_bound]`.
|
||||
UnstableFeatureBound(ThinVec<(Symbol, Span)>),
|
||||
|
||||
/// Represents `#[used]`
|
||||
Used { used_by: UsedBy, span: Span },
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ impl AttributeKind {
|
|||
TrackCaller(..) => Yes,
|
||||
TypeConst(..) => Yes,
|
||||
UnsafeSpecializationMarker(..) => No,
|
||||
UnstableFeatureBound(..) => No,
|
||||
Used { .. } => No,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,6 +136,9 @@ attr_parsing_unrecognized_repr_hint =
|
|||
attr_parsing_unstable_cfg_target_compact =
|
||||
compact `cfg(target(..))` is experimental and subject to change
|
||||
|
||||
attr_parsing_unstable_feature_bound_incompatible_stability = Item annotated with `#[unstable_feature_bound]` should not be stable
|
||||
.help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
|
||||
|
||||
attr_parsing_unsupported_literal_cfg_boolean =
|
||||
literal in `cfg` predicate value must be a boolean
|
||||
attr_parsing_unsupported_literal_cfg_string =
|
||||
|
|
|
|||
|
|
@ -27,6 +27,26 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct UnstableFeatureBoundParser;
|
||||
impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
|
||||
const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
|
||||
type Item = (Symbol, Span);
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
if !cx.features().staged_api() {
|
||||
cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span });
|
||||
}
|
||||
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
|
||||
.into_iter()
|
||||
.zip(iter::repeat(cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct AllowConstFnUnstableParser;
|
||||
impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
|
||||
|
|
|
|||
|
|
@ -98,6 +98,16 @@ impl<S: Stage> AttributeParser<S> for StabilityParser {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some((Stability { level: StabilityLevel::Stable { .. }, .. }, _)) = self.stability {
|
||||
for other_attr in cx.all_attrs {
|
||||
if other_attr.word_is(sym::unstable_feature_bound) {
|
||||
cx.emit_err(session_diagnostics::UnstableFeatureBoundIncompatibleStability {
|
||||
span: cx.target_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (stability, span) = self.stability?;
|
||||
|
||||
Some(AttributeKind::Stability { stability, span })
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirI
|
|||
use rustc_session::Session;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
|
||||
use crate::attributes::allow_unstable::{
|
||||
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
|
||||
};
|
||||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser,
|
||||
OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser,
|
||||
|
|
@ -133,6 +135,7 @@ attribute_parsers!(
|
|||
Combine<AllowInternalUnstableParser>,
|
||||
Combine<ReprParser>,
|
||||
Combine<TargetFeatureParser>,
|
||||
Combine<UnstableFeatureBoundParser>,
|
||||
// tidy-alphabetical-end
|
||||
|
||||
// tidy-alphabetical-start
|
||||
|
|
|
|||
|
|
@ -503,6 +503,14 @@ pub(crate) struct UnrecognizedReprHint {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_unstable_feature_bound_incompatible_stability)]
|
||||
#[help]
|
||||
pub(crate) struct UnstableFeatureBoundIncompatibleStability {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_naked_functions_incompatible_attribute, code = E0736)]
|
||||
pub(crate) struct NakedFunctionIncompatibleAttribute {
|
||||
|
|
|
|||
|
|
@ -683,6 +683,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk,
|
||||
EncodeCrossCrate::Yes
|
||||
),
|
||||
ungated!(
|
||||
unstable_feature_bound, Normal, template!(Word, List: "feat1, feat2, ..."),
|
||||
DuplicatesOk, EncodeCrossCrate::No,
|
||||
),
|
||||
ungated!(
|
||||
rustc_const_unstable, Normal, template!(List: r#"feature = "name""#),
|
||||
DuplicatesOk, EncodeCrossCrate::Yes
|
||||
|
|
|
|||
|
|
@ -2212,12 +2212,16 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
|||
let implied_obligations = traits::elaborate(tcx, predicates_with_span);
|
||||
|
||||
for (pred, obligation_span) in implied_obligations {
|
||||
// We lower empty bounds like `Vec<dyn Copy>:` as
|
||||
// `WellFormed(Vec<dyn Copy>)`, which will later get checked by
|
||||
// regular WF checking
|
||||
if let ty::ClauseKind::WellFormed(..) = pred.kind().skip_binder() {
|
||||
continue;
|
||||
match pred.kind().skip_binder() {
|
||||
// We lower empty bounds like `Vec<dyn Copy>:` as
|
||||
// `WellFormed(Vec<dyn Copy>)`, which will later get checked by
|
||||
// regular WF checking
|
||||
ty::ClauseKind::WellFormed(..)
|
||||
// Unstable feature goals cannot be proven in an empty environment so skip them
|
||||
| ty::ClauseKind::UnstableFeature(..) => continue,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Match the existing behavior.
|
||||
if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) {
|
||||
let pred = self.normalize(span, None, pred);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::assert_matches::assert_matches;
|
||||
|
||||
use hir::Node;
|
||||
use rustc_attr_data_structures::{AttributeKind, find_attr};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
|
|
@ -333,6 +334,19 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
predicates.extend(const_evaluatable_predicates_of(tcx, def_id, &predicates));
|
||||
}
|
||||
|
||||
let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
|
||||
// FIXME(staged_api): We might want to look at the normal stability attributes too but
|
||||
// first we would need a way to let std/core use APIs with unstable feature bounds from
|
||||
// within stable APIs.
|
||||
let allow_unstable_feature_attr =
|
||||
find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i)
|
||||
.map(|i| i.as_slice())
|
||||
.unwrap_or_default();
|
||||
|
||||
for (feat_name, span) in allow_unstable_feature_attr {
|
||||
predicates.insert((ty::ClauseKind::UnstableFeature(*feat_name).upcast(tcx), *span));
|
||||
}
|
||||
|
||||
let mut predicates: Vec<_> = predicates.into_iter().collect();
|
||||
|
||||
// Subtle: before we store the predicates into the tcx, we
|
||||
|
|
@ -764,6 +778,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>(
|
|||
ty::ClauseKind::RegionOutlives(_)
|
||||
| ty::ClauseKind::ConstArgHasType(_, _)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::UnstableFeature(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(_) => {
|
||||
bug!(
|
||||
"unexpected non-`Self` predicate when computing \
|
||||
|
|
@ -791,6 +806,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>(
|
|||
| ty::ClauseKind::ConstArgHasType(_, _)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(_)
|
||||
| ty::ClauseKind::UnstableFeature(_)
|
||||
| ty::ClauseKind::HostEffect(..) => {
|
||||
bug!(
|
||||
"unexpected non-`Self` predicate when computing \
|
||||
|
|
|
|||
|
|
@ -499,6 +499,7 @@ fn trait_specialization_kind<'tcx>(
|
|||
| ty::ClauseKind::ConstArgHasType(..)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(..)
|
||||
| ty::ClauseKind::UnstableFeature(_)
|
||||
| ty::ClauseKind::HostEffect(..) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
|||
| ty::ClauseKind::ConstArgHasType(_, _)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(_)
|
||||
| ty::ClauseKind::UnstableFeature(_)
|
||||
| ty::ClauseKind::HostEffect(..) => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
|
||||
| ty::PredicateKind::Ambiguous => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -921,6 +921,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
| ty::ClauseKind::ConstArgHasType(_, _)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(_)
|
||||
| ty::ClauseKind::UnstableFeature(_)
|
||||
| ty::ClauseKind::HostEffect(..) => None,
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1519,8 +1519,9 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
|
|||
ClauseKind::TypeOutlives(..) |
|
||||
ClauseKind::RegionOutlives(..) => "lifetime",
|
||||
|
||||
ClauseKind::UnstableFeature(_)
|
||||
// `ConstArgHasType` is never global as `ct` is always a param
|
||||
ClauseKind::ConstArgHasType(..)
|
||||
| ClauseKind::ConstArgHasType(..)
|
||||
// Ignore projections, as they can only be global
|
||||
// if the trait bound is global
|
||||
| ClauseKind::Projection(..)
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
type FnInputTys = &'tcx [Ty<'tcx>];
|
||||
type ParamTy = ParamTy;
|
||||
type BoundTy = ty::BoundTy;
|
||||
type Symbol = Symbol;
|
||||
|
||||
type PlaceholderTy = ty::PlaceholderType;
|
||||
type ErrorGuaranteed = ErrorGuaranteed;
|
||||
|
|
@ -833,6 +834,13 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu
|
|||
fn associated_const_equality(self) -> bool {
|
||||
self.associated_const_equality()
|
||||
}
|
||||
|
||||
fn feature_bound_holds_in_crate(self, symbol: Symbol) -> bool {
|
||||
// We don't consider feature bounds to hold in the crate when `staged_api` feature is
|
||||
// enabled, even if it is enabled through `#[feature]`.
|
||||
// This is to prevent accidentally leaking unstable APIs to stable.
|
||||
!self.staged_api() && self.enabled(symbol)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Span<TyCtxt<'tcx>> for Span {
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
| PredicateKind::Clause(ClauseKind::TypeOutlives(_))
|
||||
| PredicateKind::Clause(ClauseKind::Projection(_))
|
||||
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
|
||||
| PredicateKind::Clause(ClauseKind::UnstableFeature(_))
|
||||
| PredicateKind::DynCompatible(_)
|
||||
| PredicateKind::Subtype(_)
|
||||
| PredicateKind::Coerce(_)
|
||||
|
|
@ -649,6 +650,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
PredicateKind::Clause(ClauseKind::Projection(..))
|
||||
| PredicateKind::Clause(ClauseKind::HostEffect(..))
|
||||
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
|
||||
| PredicateKind::Clause(ClauseKind::UnstableFeature(_))
|
||||
| PredicateKind::NormalizesTo(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
|
|
@ -670,6 +672,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
PredicateKind::Clause(ClauseKind::Trait(..))
|
||||
| PredicateKind::Clause(ClauseKind::HostEffect(..))
|
||||
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
|
||||
| PredicateKind::Clause(ClauseKind::UnstableFeature(_))
|
||||
| PredicateKind::NormalizesTo(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
|
|
|
|||
|
|
@ -3237,6 +3237,7 @@ define_print! {
|
|||
ty::ClauseKind::ConstEvaluatable(ct) => {
|
||||
p!("the constant `", print(ct), "` can be evaluated")
|
||||
}
|
||||
ty::ClauseKind::UnstableFeature(symbol) => p!("unstable feature: ", write("`{}`", symbol)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use crate::delegate::SolverDelegate;
|
|||
use crate::placeholder::BoundVarReplacer;
|
||||
use crate::solve::inspect::{self, ProofTreeBuilder};
|
||||
use crate::solve::search_graph::SearchGraph;
|
||||
use crate::solve::ty::may_use_unstable_feature;
|
||||
use crate::solve::{
|
||||
CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalEvaluationKind,
|
||||
GoalSource, GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput,
|
||||
|
|
@ -550,6 +551,9 @@ where
|
|||
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
|
||||
self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) })
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
|
||||
self.compute_unstable_feature_goal(param_env, symbol)
|
||||
}
|
||||
ty::PredicateKind::Subtype(predicate) => {
|
||||
self.compute_subtype_goal(Goal { param_env, predicate })
|
||||
}
|
||||
|
|
@ -1177,6 +1181,14 @@ where
|
|||
) -> T {
|
||||
BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0
|
||||
}
|
||||
|
||||
pub(super) fn may_use_unstable_feature(
|
||||
&self,
|
||||
param_env: I::ParamEnv,
|
||||
symbol: I::Symbol,
|
||||
) -> bool {
|
||||
may_use_unstable_feature(&**self.delegate, param_env, symbol)
|
||||
}
|
||||
}
|
||||
|
||||
/// Eagerly replace aliases with inference variables, emitting `AliasRelate`
|
||||
|
|
|
|||
|
|
@ -148,6 +148,20 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_unstable_feature_goal(
|
||||
&mut self,
|
||||
param_env: <I as Interner>::ParamEnv,
|
||||
symbol: <I as Interner>::Symbol,
|
||||
) -> QueryResult<I> {
|
||||
if self.may_use_unstable_feature(param_env, symbol) {
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
} else {
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
|
||||
MaybeCause::Ambiguity,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn compute_const_evaluatable_goal(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -667,6 +667,10 @@ passes_rustc_std_internal_symbol =
|
|||
attribute should be applied to functions or statics
|
||||
.label = not a function or static
|
||||
|
||||
passes_rustc_unstable_feature_bound =
|
||||
attribute should be applied to `impl` or free function outside of any `impl` or trait
|
||||
.label = not an `impl` or free function
|
||||
|
||||
passes_should_be_applied_to_fn =
|
||||
attribute should be applied to a function definition
|
||||
.label = {$on_crate ->
|
||||
|
|
|
|||
|
|
@ -247,6 +247,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
&Attribute::Parsed(AttributeKind::FfiPure(attr_span)) => {
|
||||
self.check_ffi_pure(attr_span, attrs, target)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::UnstableFeatureBound(syms)) => {
|
||||
self.check_unstable_feature_bound(syms.first().unwrap().1, span, target)
|
||||
}
|
||||
Attribute::Parsed(
|
||||
AttributeKind::BodyStability { .. }
|
||||
| AttributeKind::ConstStabilityIndirect
|
||||
|
|
@ -2267,6 +2270,47 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_unstable_feature_bound(&self, attr_span: Span, span: Span, target: Target) {
|
||||
match target {
|
||||
// FIXME(staged_api): There's no reason we can't support more targets here. We're just
|
||||
// being conservative to begin with.
|
||||
Target::Fn | Target::Impl => {}
|
||||
Target::ExternCrate
|
||||
| Target::Use
|
||||
| Target::Static
|
||||
| Target::Const
|
||||
| Target::Closure
|
||||
| Target::Mod
|
||||
| Target::ForeignMod
|
||||
| Target::GlobalAsm
|
||||
| Target::TyAlias
|
||||
| Target::Enum
|
||||
| Target::Variant
|
||||
| Target::Struct
|
||||
| Target::Field
|
||||
| Target::Union
|
||||
| Target::Trait
|
||||
| Target::TraitAlias
|
||||
| Target::Expression
|
||||
| Target::Statement
|
||||
| Target::Arm
|
||||
| Target::AssocConst
|
||||
| Target::Method(_)
|
||||
| Target::AssocTy
|
||||
| Target::ForeignFn
|
||||
| Target::ForeignStatic
|
||||
| Target::ForeignTy
|
||||
| Target::GenericParam(_)
|
||||
| Target::MacroDef
|
||||
| Target::Param
|
||||
| Target::PatField
|
||||
| Target::ExprField
|
||||
| Target::WherePredicate => {
|
||||
self.tcx.dcx().emit_err(errors::RustcUnstableFeatureBound { attr_span, span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_rustc_std_internal_symbol(&self, attr_span: Span, span: Span, target: Target) {
|
||||
match target {
|
||||
Target::Fn | Target::Static | Target::ForeignFn | Target::ForeignStatic => {}
|
||||
|
|
|
|||
|
|
@ -686,6 +686,15 @@ pub(crate) struct RustcAllowConstFnUnstable {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_rustc_unstable_feature_bound)]
|
||||
pub(crate) struct RustcUnstableFeatureBound {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_rustc_std_internal_symbol)]
|
||||
pub(crate) struct RustcStdInternalSymbol {
|
||||
|
|
|
|||
|
|
@ -802,12 +802,28 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
// FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
|
||||
let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability);
|
||||
|
||||
let unstable_feature_stab =
|
||||
find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i)
|
||||
.map(|i| i.as_slice())
|
||||
.unwrap_or_default();
|
||||
|
||||
// If this impl block has an #[unstable] attribute, give an
|
||||
// error if all involved types and traits are stable, because
|
||||
// it will have no effect.
|
||||
// See: https://github.com/rust-lang/rust/issues/55436
|
||||
//
|
||||
// The exception is when there are both #[unstable_feature_bound(..)] and
|
||||
// #![unstable(feature = "..", issue = "..")] that have the same symbol because
|
||||
// that can effectively mark an impl as unstable.
|
||||
//
|
||||
// For example:
|
||||
// ```
|
||||
// #[unstable_feature_bound(feat_foo)]
|
||||
// #[unstable(feature = "feat_foo", issue = "none")]
|
||||
// impl Foo for Bar {}
|
||||
// ```
|
||||
if let Some((
|
||||
Stability { level: attrs::StabilityLevel::Unstable { .. }, .. },
|
||||
Stability { level: attrs::StabilityLevel::Unstable { .. }, feature },
|
||||
span,
|
||||
)) = stab
|
||||
{
|
||||
|
|
@ -815,9 +831,21 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
c.visit_ty_unambig(self_ty);
|
||||
c.visit_trait_ref(t);
|
||||
|
||||
// Skip the lint if the impl is marked as unstable using
|
||||
// #[unstable_feature_bound(..)]
|
||||
let mut unstable_feature_bound_in_effect = false;
|
||||
for (unstable_bound_feat_name, _) in unstable_feature_stab {
|
||||
if *unstable_bound_feat_name == feature {
|
||||
unstable_feature_bound_in_effect = true;
|
||||
}
|
||||
}
|
||||
|
||||
// do not lint when the trait isn't resolved, since resolution error should
|
||||
// be fixed first
|
||||
if t.path.res != Res::Err && c.fully_stable {
|
||||
if t.path.res != Res::Err
|
||||
&& c.fully_stable
|
||||
&& !unstable_feature_bound_in_effect
|
||||
{
|
||||
self.tcx.emit_node_span_lint(
|
||||
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
|
||||
item.hir_id(),
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ where
|
|||
}
|
||||
ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self),
|
||||
ty::ClauseKind::WellFormed(term) => term.visit_with(self),
|
||||
ty::ClauseKind::UnstableFeature(_) => V::Result::output(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -764,6 +764,9 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> {
|
|||
ClauseKind::HostEffect(..) => {
|
||||
todo!()
|
||||
}
|
||||
ClauseKind::UnstableFeature(_) => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,6 +205,46 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
|
|||
}
|
||||
}
|
||||
|
||||
/// This is only used by unstable_feature_bound as it does not have issue number information for now.
|
||||
/// This is basically the same as `feature_err_issue`
|
||||
/// but without the feature issue note. If we can do a lookup for issue number from feature name,
|
||||
/// then we should directly use `feature_err_issue` for ambiguity error of
|
||||
/// `#[unstable_feature_bound]`.
|
||||
#[track_caller]
|
||||
pub fn feature_err_unstable_feature_bound(
|
||||
sess: &Session,
|
||||
feature: Symbol,
|
||||
span: impl Into<MultiSpan>,
|
||||
explain: impl Into<DiagMessage>,
|
||||
) -> Diag<'_> {
|
||||
let span = span.into();
|
||||
|
||||
// Cancel an earlier warning for this same error, if it exists.
|
||||
if let Some(span) = span.primary_span() {
|
||||
if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) {
|
||||
err.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() });
|
||||
|
||||
// #23973: do not suggest `#![feature(...)]` if we are in beta/stable
|
||||
if sess.psess.unstable_features.is_nightly_build() {
|
||||
err.subdiagnostic(FeatureDiagnosticHelp { feature });
|
||||
|
||||
if feature == sym::rustc_attrs {
|
||||
// We're unlikely to stabilize something out of `rustc_attrs`
|
||||
// without at least renaming it, so pointing out how old
|
||||
// the compiler is will do little good.
|
||||
} else if sess.opts.unstable_opts.ui_testing {
|
||||
err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
|
||||
} else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
|
||||
err.subdiagnostic(suggestion);
|
||||
}
|
||||
}
|
||||
err
|
||||
}
|
||||
|
||||
/// Info about a parsing session.
|
||||
pub struct ParseSess {
|
||||
dcx: DiagCtxt,
|
||||
|
|
|
|||
|
|
@ -2284,6 +2284,7 @@ symbols! {
|
|||
unsized_locals,
|
||||
unsized_tuple_coercion,
|
||||
unstable,
|
||||
unstable_feature_bound,
|
||||
unstable_location_reason_default: "this crate is being loaded from the sysroot, an \
|
||||
unstable location; did you mean to load this crate \
|
||||
from crates.io via `Cargo.toml` instead?",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use rustc_infer::traits::{
|
|||
Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation,
|
||||
};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _};
|
||||
use rustc_session::parse::feature_err_unstable_feature_bound;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
|
|
@ -611,6 +612,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
)
|
||||
.with_span_label(span, format!("cannot normalize `{alias}`"))
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(sym)) => {
|
||||
if let Some(e) = self.tainted_by_errors() {
|
||||
return e;
|
||||
}
|
||||
|
||||
let mut err;
|
||||
|
||||
if self.tcx.features().staged_api() {
|
||||
err = self.dcx().struct_span_err(
|
||||
span,
|
||||
format!("unstable feature `{sym}` is used without being enabled."),
|
||||
);
|
||||
|
||||
err.help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`"));
|
||||
} else {
|
||||
err = feature_err_unstable_feature_bound(
|
||||
&self.tcx.sess,
|
||||
sym,
|
||||
span,
|
||||
format!("use of unstable library feature `{sym}`"),
|
||||
);
|
||||
}
|
||||
err
|
||||
}
|
||||
|
||||
_ => {
|
||||
if let Some(e) = self.tainted_by_errors() {
|
||||
|
|
|
|||
|
|
@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
| ty::PredicateKind::ConstEquate { .. }
|
||||
// Ambiguous predicates should never error
|
||||
| ty::PredicateKind::Ambiguous
|
||||
// We never return Err when proving UnstableFeature goal.
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature{ .. })
|
||||
| ty::PredicateKind::NormalizesTo { .. }
|
||||
| ty::PredicateKind::AliasRelate { .. }
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => {
|
||||
|
|
|
|||
|
|
@ -800,6 +800,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||
// FIXME(generic_const_exprs): you can absolutely add this as a where clauses
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {}
|
||||
ty::PredicateKind::Ambiguous => return false,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ fn predicate_references_self<'tcx>(
|
|||
// FIXME(generic_const_exprs): this can mention `Self`
|
||||
| ty::ClauseKind::ConstEvaluatable(..)
|
||||
| ty::ClauseKind::HostEffect(..)
|
||||
| ty::ClauseKind::UnstableFeature(_)
|
||||
=> None,
|
||||
}
|
||||
}
|
||||
|
|
@ -278,6 +279,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|||
| ty::ClauseKind::ConstArgHasType(_, _)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(_)
|
||||
| ty::ClauseKind::UnstableFeature(_)
|
||||
| ty::ClauseKind::HostEffect(..) => false,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ use rustc_infer::traits::{
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
|
||||
use rustc_middle::ty::{
|
||||
self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode, may_use_unstable_feature,
|
||||
};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
use tracing::{debug, debug_span, instrument};
|
||||
|
||||
|
|
@ -404,6 +406,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
ty::PredicateKind::AliasRelate(..) => {
|
||||
bug!("AliasRelate is only used by the new solver")
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) => {
|
||||
unreachable!("unexpected higher ranked `UnstableFeature` goal")
|
||||
}
|
||||
},
|
||||
Some(pred) => match pred {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
|
||||
|
|
@ -767,6 +772,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
|
||||
if may_use_unstable_feature(self.selcx.infcx, obligation.param_env, symbol) {
|
||||
ProcessResult::Changed(Default::default())
|
||||
} else {
|
||||
ProcessResult::Unchanged
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
|
|||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::NormalizesTo(..)
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
|
||||
| ty::PredicateKind::AliasRelate(..) => {}
|
||||
|
||||
// We need to search through *all* WellFormed predicates
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
|
|||
use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
|
||||
use rustc_middle::ty::{
|
||||
self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt,
|
||||
TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate,
|
||||
TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, may_use_unstable_feature,
|
||||
};
|
||||
use rustc_span::{Symbol, sym};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
|
@ -832,6 +832,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => {
|
||||
if may_use_unstable_feature(self.infcx, obligation.param_env, symbol) {
|
||||
Ok(EvaluatedToOk)
|
||||
} else {
|
||||
Ok(EvaluatedToAmbig)
|
||||
}
|
||||
}
|
||||
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
|
||||
match const_evaluatable::is_const_evaluatable(
|
||||
self.infcx,
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ pub fn expand_trait_aliases<'tcx>(
|
|||
| ty::ClauseKind::ConstArgHasType(_, _)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(_)
|
||||
| ty::ClauseKind::UnstableFeature(_)
|
||||
| ty::ClauseKind::HostEffect(..) => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ pub fn clause_obligations<'tcx>(
|
|||
ty::ClauseKind::ConstEvaluatable(ct) => {
|
||||
wf.add_wf_preds_for_term(ct.into());
|
||||
}
|
||||
ty::ClauseKind::UnstableFeature(_) => {}
|
||||
}
|
||||
|
||||
wf.normalize(infcx)
|
||||
|
|
@ -1095,6 +1096,7 @@ pub fn object_region_bounds<'tcx>(
|
|||
| ty::ClauseKind::Projection(_)
|
||||
| ty::ClauseKind::ConstArgHasType(_, _)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::UnstableFeature(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(_) => None,
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool {
|
|||
| ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
|
||||
| ty::PredicateKind::NormalizesTo(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
|
||||
|
|
|
|||
|
|
@ -234,6 +234,9 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
|
|||
ty::ClauseKind::ConstArgHasType(..) => {
|
||||
// Nothing to elaborate
|
||||
}
|
||||
ty::ClauseKind::UnstableFeature(_) => {
|
||||
// Nothing to elaborate
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -401,7 +401,6 @@ impl<I: Interner> FlagComputation<I> {
|
|||
self.add_const(expected);
|
||||
self.add_const(found);
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => {}
|
||||
ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
|
||||
self.add_alias_term(alias);
|
||||
self.add_term(term);
|
||||
|
|
@ -410,6 +409,8 @@ impl<I: Interner> FlagComputation<I> {
|
|||
self.add_term(t1);
|
||||
self.add_term(t2);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_sym)) => {}
|
||||
ty::PredicateKind::Ambiguous => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -285,3 +285,40 @@ pub trait InferCtxtLike: Sized {
|
|||
|
||||
fn reset_opaque_types(&self);
|
||||
}
|
||||
|
||||
pub fn may_use_unstable_feature<'a, I: Interner, Infcx>(
|
||||
infcx: &'a Infcx,
|
||||
param_env: I::ParamEnv,
|
||||
symbol: I::Symbol,
|
||||
) -> bool
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
{
|
||||
// Iterate through all goals in param_env to find the one that has the same symbol.
|
||||
for pred in param_env.caller_bounds().iter() {
|
||||
if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() {
|
||||
if sym == symbol {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// During codegen we must assume that all feature bounds hold as we may be
|
||||
// monomorphizing a body from an upstream crate which had an unstable feature
|
||||
// enabled that we do not.
|
||||
//
|
||||
// Coherence should already report overlap errors involving unstable impls
|
||||
// as the affected code would otherwise break when stabilizing this feature.
|
||||
// It is also easily possible to accidentally cause unsoundness this way as
|
||||
// we have to always enable unstable impls during codegen.
|
||||
//
|
||||
// Return ambiguity can also prevent people from writing code which depends on inference guidance
|
||||
// that might no longer work after the impl is stabilised,
|
||||
// tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs is one of the example.
|
||||
//
|
||||
// Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled
|
||||
// if we are in std/core even if there is a corresponding `feature` attribute on the crate.
|
||||
|
||||
(infcx.typing_mode() == TypingMode::PostAnalysis)
|
||||
|| infcx.cx().features().feature_bound_holds_in_crate(symbol)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -630,6 +630,8 @@ pub trait Features<I: Interner>: Copy {
|
|||
fn coroutine_clone(self) -> bool;
|
||||
|
||||
fn associated_const_equality(self) -> bool;
|
||||
|
||||
fn feature_bound_holds_in_crate(self, symbol: I::Symbol) -> bool;
|
||||
}
|
||||
|
||||
pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ pub trait Interner:
|
|||
type ParamTy: ParamLike;
|
||||
type BoundTy: BoundVarLike<Self>;
|
||||
type PlaceholderTy: PlaceholderLike<Self, Bound = Self::BoundTy>;
|
||||
type Symbol: Copy + Hash + PartialEq + Eq + Debug;
|
||||
|
||||
// Things stored inside of tys
|
||||
type ErrorGuaranteed: Copy + Debug + Hash + Eq;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,13 @@ pub enum ClauseKind<I: Interner> {
|
|||
/// corresponding trait clause; this just enforces the *constness* of that
|
||||
/// implementation.
|
||||
HostEffect(ty::HostEffectPredicate<I>),
|
||||
|
||||
/// Support marking impl as unstable.
|
||||
UnstableFeature(
|
||||
#[type_foldable(identity)]
|
||||
#[type_visitable(ignore)]
|
||||
I::Symbol,
|
||||
),
|
||||
}
|
||||
|
||||
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
|
||||
|
|
@ -134,6 +141,9 @@ impl<I: Interner> fmt::Debug for ClauseKind<I> {
|
|||
ClauseKind::ConstEvaluatable(ct) => {
|
||||
write!(f, "ConstEvaluatable({ct:?})")
|
||||
}
|
||||
ClauseKind::UnstableFeature(feature_name) => {
|
||||
write!(f, "UnstableFeature({feature_name:?})")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -390,7 +390,8 @@ pub(crate) fn clean_predicate<'tcx>(
|
|||
ty::ClauseKind::ConstEvaluatable(..)
|
||||
| ty::ClauseKind::WellFormed(..)
|
||||
| ty::ClauseKind::ConstArgHasType(..)
|
||||
// FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `[const]`.
|
||||
| ty::ClauseKind::UnstableFeature(..)
|
||||
// FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `~const`.
|
||||
| ty::ClauseKind::HostEffect(_) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![stable(feature = "a", since = "1.1.1" )]
|
||||
|
||||
#[stable(feature = "a", since = "1.1.1" )]
|
||||
pub trait Foo {
|
||||
#[stable(feature = "a", since = "1.1.1" )]
|
||||
fn foo();
|
||||
}
|
||||
#[stable(feature = "a", since = "1.1.1" )]
|
||||
pub struct Bar;
|
||||
#[stable(feature = "a", since = "1.1.1" )]
|
||||
pub struct Moo;
|
||||
|
||||
#[unstable_feature_bound(feat_bar)]
|
||||
#[unstable(feature = "feat_bar", issue = "none" )]
|
||||
impl Foo for Bar {
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
#[unstable_feature_bound(feat_moo)]
|
||||
#[unstable(feature = "feat_moo", issue = "none" )]
|
||||
impl Foo for Moo {
|
||||
fn foo() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![stable(feature = "a", since = "1.1.1" )]
|
||||
|
||||
/// Aux crate for unstable impl codegen test.
|
||||
|
||||
#[stable(feature = "a", since = "1.1.1" )]
|
||||
pub trait Trait {
|
||||
#[stable(feature = "a", since = "1.1.1" )]
|
||||
fn method(&self);
|
||||
}
|
||||
|
||||
#[unstable_feature_bound(foo)]
|
||||
#[unstable(feature = "foo", issue = "none" )]
|
||||
impl<T> Trait for T {
|
||||
fn method(&self) {
|
||||
println!("hi");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
//@ aux-build:unstable_impl_codegen_aux1.rs
|
||||
#![feature(foo)]
|
||||
|
||||
extern crate unstable_impl_codegen_aux1 as aux;
|
||||
use aux::Trait;
|
||||
|
||||
/// Upstream crate for unstable impl codegen test
|
||||
/// that depends on aux crate in
|
||||
/// unstable_impl_codegen_aux1.rs
|
||||
|
||||
pub fn foo<T>(a: T) {
|
||||
a.method();
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![allow(dead_code)]
|
||||
#![stable(feature = "a", since = "1.1.1" )]
|
||||
|
||||
#[stable(feature = "a", since = "1.1.1" )]
|
||||
pub trait Trait {}
|
||||
|
||||
#[unstable_feature_bound(foo)]
|
||||
#[unstable(feature = "foo", issue = "none" )]
|
||||
impl <T> Trait for T {}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![stable(feature = "a", since = "1.1.1" )]
|
||||
|
||||
#[stable(feature = "a", since = "1.1.1" )]
|
||||
pub trait Trait {
|
||||
#[stable(feature = "a", since = "1.1.1" )]
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
#[stable(feature = "a", since = "1.1.1" )]
|
||||
impl Trait for Vec<u32> {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
#[unstable_feature_bound(bar)]
|
||||
#[unstable(feature = "bar", issue = "none" )]
|
||||
impl Trait for Vec<u64> {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![allow(dead_code)]
|
||||
#![stable(feature = "a", since = "1.1.1" )]
|
||||
|
||||
/// If #[unstable(..)] and #[unstable_feature_name(..)] have the same feature name,
|
||||
/// the error should not be thrown as it can effectively mark an impl as unstable.
|
||||
///
|
||||
/// If the feature name in #[feature] does not exist in #[unstable_feature_bound(..)]
|
||||
/// an error should still be thrown because that feature will not be unstable.
|
||||
|
||||
#[stable(feature = "a", since = "1.1.1")]
|
||||
trait Moo {}
|
||||
#[stable(feature = "a", since = "1.1.1")]
|
||||
trait Foo {}
|
||||
#[stable(feature = "a", since = "1.1.1")]
|
||||
trait Boo {}
|
||||
#[stable(feature = "a", since = "1.1.1")]
|
||||
pub struct Bar;
|
||||
|
||||
|
||||
#[unstable(feature = "feat_moo", issue = "none")]
|
||||
#[unstable_feature_bound(feat_foo)] //~^ ERROR: an `#[unstable]` annotation here has no effect
|
||||
impl Moo for Bar {}
|
||||
|
||||
#[unstable(feature = "feat_foo", issue = "none")]
|
||||
#[unstable_feature_bound(feat_foo)]
|
||||
impl Foo for Bar {}
|
||||
|
||||
|
||||
#[unstable(feature = "feat_foo", issue = "none")]
|
||||
#[unstable_feature_bound(feat_foo, feat_bar)]
|
||||
impl Boo for Bar {}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
error: an `#[unstable]` annotation here has no effect
|
||||
--> $DIR/unstable-feature-bound-no-effect.rs:22:1
|
||||
|
|
||||
LL | #[unstable(feature = "feat_moo", issue = "none")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
|
||||
= note: `#[deny(ineffective_unstable_trait_impl)]` on by default
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
//@ aux-build:unstable_feature.rs
|
||||
extern crate unstable_feature;
|
||||
use unstable_feature::{Foo, Bar, Moo};
|
||||
|
||||
// FIXME: both `feat_bar` and `feat_moo` are needed to pass this test,
|
||||
// but the diagnostic only will point out `feat_bar`.
|
||||
|
||||
fn main() {
|
||||
Bar::foo();
|
||||
//~^ ERROR: use of unstable library feature `feat_bar` [E0658]
|
||||
Moo::foo();
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
error[E0658]: use of unstable library feature `feat_bar`
|
||||
--> $DIR/unstable-feature-bound-two-error.rs:9:5
|
||||
|
|
||||
LL | Bar::foo();
|
||||
| ^^^
|
||||
|
|
||||
= help: add `#![feature(feat_bar)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: required for `Bar` to implement `Foo`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
error[E0658]: use of unstable library feature `feat_moo`
|
||||
--> $DIR/unstable-feature-cross-crate-exact-symbol.rs:16:5
|
||||
|
|
||||
LL | Moo::foo();
|
||||
| ^^^
|
||||
|
|
||||
= help: add `#![feature(feat_moo)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: required for `Moo` to implement `Foo`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
//@ aux-build:unstable_feature.rs
|
||||
//@ revisions: pass fail
|
||||
//@[pass] check-pass
|
||||
|
||||
#![cfg_attr(pass, feature(feat_bar, feat_moo))]
|
||||
#![cfg_attr(fail, feature(feat_bar))]
|
||||
|
||||
extern crate unstable_feature;
|
||||
use unstable_feature::{Foo, Bar, Moo};
|
||||
|
||||
/// To use impls gated by both `feat_foo` and `feat_moo`,
|
||||
/// both features must be enabled.
|
||||
|
||||
fn main() {
|
||||
Bar::foo();
|
||||
Moo::foo();
|
||||
//[fail]~^ ERROR:use of unstable library feature `feat_moo` [E0658]
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
//@ aux-build:unstable_feature.rs
|
||||
//@ check-pass
|
||||
#![feature(feat_bar, feat_moo)]
|
||||
extern crate unstable_feature;
|
||||
use unstable_feature::{Foo, Bar};
|
||||
|
||||
/// Bar::foo() should still be usable even if we enable multiple feature.
|
||||
|
||||
fn main() {
|
||||
Bar::foo();
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
error[E0658]: use of unstable library feature `feat_bar`
|
||||
--> $DIR/unstable-feature-cross-crate-require-bound.rs:12:5
|
||||
|
|
||||
LL | Bar::foo();
|
||||
| ^^^
|
||||
|
|
||||
= help: add `#![feature(feat_bar)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: required for `Bar` to implement `Foo`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
//@ aux-build:unstable_feature.rs
|
||||
//@ revisions: pass fail
|
||||
//@[pass] check-pass
|
||||
|
||||
#![cfg_attr(pass, feature(feat_bar))]
|
||||
extern crate unstable_feature;
|
||||
use unstable_feature::{Foo, Bar};
|
||||
|
||||
/// #[feature(..)] is required to use unstable impl.
|
||||
|
||||
fn main() {
|
||||
Bar::foo();
|
||||
//[fail]~^ ERROR: use of unstable library feature `feat_bar` [E0658]
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
error: unstable feature `feat_moo` is used without being enabled.
|
||||
--> $DIR/unstable-feature-exact-symbol.rs:37:5
|
||||
|
|
||||
LL | Bar::moo();
|
||||
| ^^^
|
||||
|
|
||||
= help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_moo)]`
|
||||
note: required for `Bar` to implement `Moo`
|
||||
--> $DIR/unstable-feature-exact-symbol.rs:29:6
|
||||
|
|
||||
LL | #[unstable_feature_bound(feat_moo)]
|
||||
| ----------------------------------- unsatisfied trait bound introduced here
|
||||
LL | impl Moo for Bar {
|
||||
| ^^^ ^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
//@ revisions: pass fail
|
||||
//@[pass] check-pass
|
||||
|
||||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![allow(dead_code)]
|
||||
#![unstable(feature = "feat_foo", issue = "none" )]
|
||||
|
||||
/// In staged-api crate, impl that is marked as unstable with
|
||||
/// feature name `feat_moo` should not be accessible
|
||||
/// if only `feat_foo` is enabled.
|
||||
|
||||
pub trait Foo {
|
||||
fn foo();
|
||||
}
|
||||
|
||||
pub trait Moo {
|
||||
fn moo();
|
||||
}
|
||||
|
||||
pub struct Bar;
|
||||
|
||||
#[unstable_feature_bound(feat_foo)]
|
||||
impl Foo for Bar {
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
#[unstable_feature_bound(feat_moo)]
|
||||
impl Moo for Bar {
|
||||
fn moo() {}
|
||||
}
|
||||
|
||||
#[cfg_attr(fail, unstable_feature_bound(feat_foo))]
|
||||
#[cfg_attr(pass, unstable_feature_bound(feat_foo, feat_moo))]
|
||||
fn bar() {
|
||||
Bar::foo();
|
||||
Bar::moo();
|
||||
//[fail]~^ ERROR unstable feature `feat_moo` is used without being enabled.
|
||||
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
error: unstable feature `feat_foo` is used without being enabled.
|
||||
--> $DIR/unstable-impl-assoc-type.rs:23:16
|
||||
|
|
||||
LL | type Assoc = Self;
|
||||
| ^^^^
|
||||
|
|
||||
= help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_foo)]`
|
||||
note: required for `Foo` to implement `Bar`
|
||||
--> $DIR/unstable-impl-assoc-type.rs:19:6
|
||||
|
|
||||
LL | #[unstable_feature_bound(feat_foo)]
|
||||
| ----------------------------------- unsatisfied trait bound introduced here
|
||||
LL | impl Bar for Foo {}
|
||||
| ^^^ ^^^
|
||||
note: required by a bound in `Trait::Assoc`
|
||||
--> $DIR/unstable-impl-assoc-type.rs:13:17
|
||||
|
|
||||
LL | type Assoc: Bar;
|
||||
| ^^^ required by this bound in `Trait::Assoc`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
28
tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs
Normal file
28
tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//@ revisions: pass fail
|
||||
//@[pass] check-pass
|
||||
|
||||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![unstable(feature = "feat_foo", issue = "none" )]
|
||||
|
||||
/// Test that you can't leak unstable impls through item bounds on associated types.
|
||||
|
||||
trait Bar {}
|
||||
|
||||
trait Trait {
|
||||
type Assoc: Bar;
|
||||
}
|
||||
|
||||
struct Foo;
|
||||
|
||||
#[unstable_feature_bound(feat_foo)]
|
||||
impl Bar for Foo {}
|
||||
|
||||
#[cfg_attr(pass, unstable_feature_bound(feat_foo))]
|
||||
impl Trait for Foo {
|
||||
type Assoc = Self;
|
||||
//[fail]~^ ERROR: unstable feature `feat_foo` is used without being enabled.
|
||||
|
||||
}
|
||||
|
||||
fn main(){}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
error: unstable feature `feat_foo` is used without being enabled.
|
||||
--> $DIR/unstable-impl-cannot-use-feature.rs:26:5
|
||||
|
|
||||
LL | Bar::foo();
|
||||
| ^^^
|
||||
|
|
||||
= help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_foo)]`
|
||||
note: required for `Bar` to implement `Foo`
|
||||
--> $DIR/unstable-impl-cannot-use-feature.rs:20:6
|
||||
|
|
||||
LL | #[unstable_feature_bound(feat_foo)]
|
||||
| ----------------------------------- unsatisfied trait bound introduced here
|
||||
LL | impl Foo for Bar {
|
||||
| ^^^ ^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
//@ revisions: pass fail
|
||||
//@[pass] check-pass
|
||||
|
||||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![allow(dead_code)]
|
||||
#![unstable(feature = "feat_foo", issue = "none" )]
|
||||
|
||||
#![cfg_attr(fail, feature(feat_foo))]
|
||||
|
||||
/// In staged-api crate, using an unstable impl requires
|
||||
/// #[unstable_feature_bound(..)], not #[feature(..)].
|
||||
|
||||
pub trait Foo {
|
||||
fn foo();
|
||||
}
|
||||
pub struct Bar;
|
||||
|
||||
#[unstable_feature_bound(feat_foo)]
|
||||
impl Foo for Bar {
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
#[cfg_attr(pass, unstable_feature_bound(feat_foo))]
|
||||
fn bar() {
|
||||
Bar::foo();
|
||||
//[fail]~^ ERROR: unstable feature `feat_foo` is used without being enabled.
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
//@ check-pass
|
||||
|
||||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![allow(dead_code)]
|
||||
#![unstable(feature = "feat_foo", issue = "none" )]
|
||||
|
||||
/// In staged-api crate, if feat_foo is only needed to use an impl,
|
||||
/// having both `feat_foo` and `feat_bar` will still make it pass.
|
||||
|
||||
pub trait Foo {
|
||||
fn foo();
|
||||
}
|
||||
pub struct Bar;
|
||||
|
||||
// Annotate the impl as unstable.
|
||||
#[unstable_feature_bound(feat_foo)]
|
||||
impl Foo for Bar {
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
#[unstable_feature_bound(feat_foo, feat_bar)]
|
||||
fn bar() {
|
||||
Bar::foo();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
error: unstable feature `feat_bar` is used without being enabled.
|
||||
--> $DIR/unstable_feature_bound_free_fn.rs:36:5
|
||||
|
|
||||
LL | bar();
|
||||
| ^^^^^
|
||||
|
|
||||
= help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_bar)]`
|
||||
note: required by a bound in `bar`
|
||||
--> $DIR/unstable_feature_bound_free_fn.rs:29:1
|
||||
|
|
||||
LL | #[unstable_feature_bound(feat_bar)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `bar`
|
||||
LL | fn bar() {
|
||||
| --- required by a bound in this function
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
//@ revisions: pass fail
|
||||
//@[pass] check-pass
|
||||
|
||||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![allow(dead_code)]
|
||||
#![stable(feature = "a", since = "1.1.1" )]
|
||||
|
||||
/// When a free function with #[unstable_feature_bound(feat_bar)] is called by another
|
||||
/// free function, that function should be annotated with
|
||||
/// #[unstable_feature_bound(feat_bar)] too.
|
||||
|
||||
#[stable(feature = "a", since = "1.1.1")]
|
||||
trait Foo {
|
||||
#[stable(feature = "a", since = "1.1.1")]
|
||||
fn foo() {
|
||||
}
|
||||
}
|
||||
#[stable(feature = "a", since = "1.1.1")]
|
||||
pub struct Bar;
|
||||
|
||||
#[unstable_feature_bound(feat_bar)]
|
||||
#[unstable(feature = "feat_bar", issue = "none" )]
|
||||
impl Foo for Bar {
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
|
||||
#[unstable_feature_bound(feat_bar)]
|
||||
fn bar() {
|
||||
Bar::foo();
|
||||
}
|
||||
|
||||
#[cfg_attr(pass, unstable_feature_bound(feat_bar))]
|
||||
fn bar2() {
|
||||
bar();
|
||||
//[fail]~^ERROR unstable feature `feat_bar` is used without being enabled.
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![allow(dead_code)]
|
||||
#![stable(feature = "a", since = "1.1.1" )]
|
||||
|
||||
// Lint against the usage of both #[unstable_feature_bound] and #[stable] on the
|
||||
// same item.
|
||||
|
||||
#[stable(feature = "a", since = "1.1.1")]
|
||||
#[unstable_feature_bound(feat_bar)]
|
||||
fn bar() {}
|
||||
//~^ ERROR Item annotated with `#[unstable_feature_bound]` should not be stable
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
error: Item annotated with `#[unstable_feature_bound]` should not be stable
|
||||
--> $DIR/unstable_feature_bound_incompatible_stability.rs:11:1
|
||||
|
|
||||
LL | fn bar() {}
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![allow(dead_code)]
|
||||
#![unstable(feature = "feat_bar", issue = "none" )]
|
||||
|
||||
/// Test the behaviour of multiple unstable_feature_bound attribute.
|
||||
|
||||
trait Foo {
|
||||
fn foo();
|
||||
}
|
||||
struct Bar;
|
||||
|
||||
#[unstable_feature_bound(feat_bar, feat_koo)]
|
||||
#[unstable_feature_bound(feat_foo, feat_moo)]
|
||||
impl Foo for Bar {
|
||||
fn foo(){}
|
||||
}
|
||||
|
||||
#[unstable_feature_bound(feat_bar, feat_koo)]
|
||||
#[unstable_feature_bound(feat_foo, feat_moo)]
|
||||
fn moo() {
|
||||
Bar::foo();
|
||||
}
|
||||
|
||||
#[unstable_feature_bound(feat_bar, feat_koo, feat_foo, feat_moo)]
|
||||
fn koo() {
|
||||
Bar::foo();
|
||||
}
|
||||
|
||||
#[unstable_feature_bound(feat_koo, feat_foo, feat_moo)]
|
||||
fn boo() {
|
||||
Bar::foo();
|
||||
//~^ ERROR: unstable feature `feat_bar` is used without being enabled.
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
error: unstable feature `feat_bar` is used without being enabled.
|
||||
--> $DIR/unstable_feature_bound_multi_attr.rs:32:5
|
||||
|
|
||||
LL | Bar::foo();
|
||||
| ^^^
|
||||
|
|
||||
= help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_bar)]`
|
||||
note: required for `Bar` to implement `Foo`
|
||||
--> $DIR/unstable_feature_bound_multi_attr.rs:15:6
|
||||
|
|
||||
LL | #[unstable_feature_bound(feat_bar, feat_koo)]
|
||||
| --------------------------------------------- unsatisfied trait bound introduced here
|
||||
LL | #[unstable_feature_bound(feat_foo, feat_moo)]
|
||||
LL | impl Foo for Bar {
|
||||
| ^^^ ^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
/// Unstable feature bound can only be used only when
|
||||
/// #[feature(staged_api)] is enabled.
|
||||
|
||||
pub trait Foo {
|
||||
}
|
||||
pub struct Bar;
|
||||
|
||||
#[unstable_feature_bound(feat_bar)]
|
||||
//~^ ERROR: stability attributes may not be used outside of the standard library
|
||||
impl Foo for Bar {
|
||||
}
|
||||
|
||||
fn main(){}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
error[E0734]: stability attributes may not be used outside of the standard library
|
||||
--> $DIR/unstable_feature_bound_staged_api.rs:8:1
|
||||
|
|
||||
LL | #[unstable_feature_bound(feat_bar)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0734`.
|
||||
13
tests/ui/unstable-feature-bound/unstable_impl_codegen.rs
Normal file
13
tests/ui/unstable-feature-bound/unstable_impl_codegen.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
//@ aux-build:unstable_impl_codegen_aux2.rs
|
||||
//@ run-pass
|
||||
|
||||
/// Downstream crate for unstable impl codegen test
|
||||
/// that depends on upstream crate in
|
||||
/// unstable_impl_codegen_aux2.rs
|
||||
|
||||
extern crate unstable_impl_codegen_aux2 as aux;
|
||||
use aux::foo;
|
||||
|
||||
fn main() {
|
||||
foo(1_u8);
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
error[E0119]: conflicting implementations of trait `Trait` for type `LocalTy`
|
||||
--> $DIR/unstable_impl_coherence.rs:14:1
|
||||
|
|
||||
LL | impl aux::Trait for LocalTy {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: conflicting implementation in crate `unstable_impl_coherence_aux`:
|
||||
- impl<T> Trait for T
|
||||
where unstable feature: `foo`;
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
error[E0119]: conflicting implementations of trait `Trait` for type `LocalTy`
|
||||
--> $DIR/unstable_impl_coherence.rs:14:1
|
||||
|
|
||||
LL | impl aux::Trait for LocalTy {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: conflicting implementation in crate `unstable_impl_coherence_aux`:
|
||||
- impl<T> Trait for T
|
||||
where unstable feature: `foo`;
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
||||
17
tests/ui/unstable-feature-bound/unstable_impl_coherence.rs
Normal file
17
tests/ui/unstable-feature-bound/unstable_impl_coherence.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
//@ aux-build:unstable_impl_coherence_aux.rs
|
||||
//@ revisions: enabled disabled
|
||||
|
||||
#![cfg_attr(enabled, feature(foo))]
|
||||
extern crate unstable_impl_coherence_aux as aux;
|
||||
use aux::Trait;
|
||||
|
||||
/// Coherence test for unstable impl.
|
||||
/// No matter feature `foo` is enabled or not, the impl
|
||||
/// for aux::Trait will be rejected by coherence checking.
|
||||
|
||||
struct LocalTy;
|
||||
|
||||
impl aux::Trait for LocalTy {}
|
||||
//~^ ERROR: conflicting implementations of trait `Trait` for type `LocalTy`
|
||||
|
||||
fn main(){}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
//@ aux-build:unstable_impl_method_selection_aux.rs
|
||||
|
||||
extern crate unstable_impl_method_selection_aux as aux;
|
||||
use aux::Trait;
|
||||
|
||||
// The test below should not infer the type based on the fact
|
||||
// that `impl Trait for Vec<u64>` is unstable. This would cause breakage
|
||||
// in downstream crate once `impl Trait for Vec<u64>` is stabilised.
|
||||
|
||||
fn bar() {
|
||||
vec![].foo();
|
||||
//~^ ERROR type annotations needed
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
error[E0283]: type annotations needed
|
||||
--> $DIR/unstable_impl_method_selection.rs:11:12
|
||||
|
|
||||
LL | vec![].foo();
|
||||
| ^^^ cannot infer type for struct `Vec<_>`
|
||||
|
|
||||
= note: multiple `impl`s satisfying `Vec<_>: Trait` found in the `unstable_impl_method_selection_aux` crate:
|
||||
- impl Trait for Vec<u32>;
|
||||
- impl Trait for Vec<u64>
|
||||
where unstable feature: `bar`;
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
23
tests/ui/unstable-feature-bound/unstable_inherent_method.rs
Normal file
23
tests/ui/unstable-feature-bound/unstable_inherent_method.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(staged_api)]
|
||||
#![stable(feature = "a", since = "1.1.1" )]
|
||||
|
||||
/// FIXME(tiif): we haven't allowed marking trait and impl method as
|
||||
/// unstable yet, but it should be possible.
|
||||
|
||||
#[stable(feature = "a", since = "1.1.1" )]
|
||||
pub trait Trait {
|
||||
#[unstable(feature = "feat", issue = "none" )]
|
||||
#[unstable_feature_bound(foo)]
|
||||
//~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait
|
||||
fn foo();
|
||||
}
|
||||
|
||||
#[stable(feature = "a", since = "1.1.1" )]
|
||||
impl Trait for u8 {
|
||||
#[unstable_feature_bound(foo)]
|
||||
//~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
error: attribute should be applied to `impl` or free function outside of any `impl` or trait
|
||||
--> $DIR/unstable_inherent_method.rs:11:5
|
||||
|
|
||||
LL | #[unstable_feature_bound(foo)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | fn foo();
|
||||
| --------- not an `impl` or free function
|
||||
|
||||
error: attribute should be applied to `impl` or free function outside of any `impl` or trait
|
||||
--> $DIR/unstable_inherent_method.rs:18:5
|
||||
|
|
||||
LL | #[unstable_feature_bound(foo)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | fn foo() {}
|
||||
| ----------- not an `impl` or free function
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue