Auto merge of #109581 - matthiaskrgr:rollup-e8fi2vi, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #109355 (Fix bad suggestion for clone/is_some in field init shorthand) - #109484 (Bugfix: avoid panic on invalid json output from libtest) - #109539 (Refactor `find_*_stability` functions) - #109542 (rustdoc: clean up `storage.js`) - #109545 (Deeply check well-formedness of return-position `impl Trait` in trait) - #109568 (miri: fix raw pointer dyn receivers) - #109570 (Add GUI test for "Auto-hide item methods' documentation" setting) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
96bd50dd47
@ -226,315 +226,39 @@ pub fn to_opt_reason(&self) -> Option<Symbol> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collects stability info from all stability attributes in `attrs`.
|
/// Collects stability info from `stable`/`unstable`/`rustc_allowed_through_unstable_modules`
|
||||||
/// Returns `None` if no stability attributes are found.
|
/// attributes in `attrs`. Returns `None` if no stability attributes are found.
|
||||||
pub fn find_stability(
|
pub fn find_stability(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
attrs: &[Attribute],
|
attrs: &[Attribute],
|
||||||
item_sp: Span,
|
item_sp: Span,
|
||||||
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
|
) -> Option<(Stability, Span)> {
|
||||||
{
|
|
||||||
find_stability_generic(sess, attrs.iter(), item_sp)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_stability_generic<'a, I>(
|
|
||||||
sess: &Session,
|
|
||||||
attrs_iter: I,
|
|
||||||
item_sp: Span,
|
|
||||||
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
|
|
||||||
where
|
|
||||||
I: Iterator<Item = &'a Attribute>,
|
|
||||||
{
|
|
||||||
use StabilityLevel::*;
|
|
||||||
|
|
||||||
let mut stab: Option<(Stability, Span)> = None;
|
let mut stab: Option<(Stability, Span)> = None;
|
||||||
let mut const_stab: Option<(ConstStability, Span)> = None;
|
|
||||||
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
|
|
||||||
let mut promotable = false;
|
|
||||||
let mut allowed_through_unstable_modules = false;
|
let mut allowed_through_unstable_modules = false;
|
||||||
|
|
||||||
'outer: for attr in attrs_iter {
|
for attr in attrs {
|
||||||
if ![
|
match attr.name_or_empty() {
|
||||||
sym::rustc_const_unstable,
|
sym::rustc_allowed_through_unstable_modules => allowed_through_unstable_modules = true,
|
||||||
sym::rustc_const_stable,
|
sym::unstable => {
|
||||||
sym::unstable,
|
if stab.is_some() {
|
||||||
sym::stable,
|
handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels);
|
||||||
sym::rustc_promotable,
|
break;
|
||||||
sym::rustc_allowed_through_unstable_modules,
|
|
||||||
sym::rustc_default_body_unstable,
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
.any(|&s| attr.has_name(s))
|
|
||||||
{
|
|
||||||
continue; // not a stability level
|
|
||||||
}
|
|
||||||
|
|
||||||
let meta = attr.meta();
|
|
||||||
|
|
||||||
if attr.has_name(sym::rustc_promotable) {
|
|
||||||
promotable = true;
|
|
||||||
} else if attr.has_name(sym::rustc_allowed_through_unstable_modules) {
|
|
||||||
allowed_through_unstable_modules = true;
|
|
||||||
}
|
|
||||||
// attributes with data
|
|
||||||
else if let Some(meta @ MetaItem { kind: MetaItemKind::List(metas), .. }) = &meta {
|
|
||||||
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
|
|
||||||
if item.is_some() {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
meta.span,
|
|
||||||
AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if let Some(v) = meta.value_str() {
|
|
||||||
*item = Some(v);
|
if let Some((feature, level)) = parse_unstability(sess, attr) {
|
||||||
true
|
stab = Some((Stability { level, feature }, attr.span));
|
||||||
} else {
|
|
||||||
sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
let meta_name = meta.name_or_empty();
|
|
||||||
match meta_name {
|
|
||||||
sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => {
|
|
||||||
if meta_name == sym::unstable && stab.is_some() {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
attr.span,
|
|
||||||
AttrError::MultipleStabilityLevels,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
} else if meta_name == sym::rustc_const_unstable && const_stab.is_some() {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
attr.span,
|
|
||||||
AttrError::MultipleStabilityLevels,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
} else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
attr.span,
|
|
||||||
AttrError::MultipleStabilityLevels,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut feature = None;
|
|
||||||
let mut reason = None;
|
|
||||||
let mut issue = None;
|
|
||||||
let mut issue_num = None;
|
|
||||||
let mut is_soft = false;
|
|
||||||
let mut implied_by = None;
|
|
||||||
for meta in metas {
|
|
||||||
let Some(mi) = meta.meta_item() else {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
meta.span(),
|
|
||||||
AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
|
|
||||||
);
|
|
||||||
continue 'outer;
|
|
||||||
};
|
|
||||||
match mi.name_or_empty() {
|
|
||||||
sym::feature => {
|
|
||||||
if !get(mi, &mut feature) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sym::reason => {
|
|
||||||
if !get(mi, &mut reason) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sym::issue => {
|
|
||||||
if !get(mi, &mut issue) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// These unwraps are safe because `get` ensures the meta item
|
|
||||||
// is a name/value pair string literal.
|
|
||||||
issue_num = match issue.unwrap().as_str() {
|
|
||||||
"none" => None,
|
|
||||||
issue => match issue.parse::<NonZeroU32>() {
|
|
||||||
Ok(num) => Some(num),
|
|
||||||
Err(err) => {
|
|
||||||
sess.emit_err(
|
|
||||||
session_diagnostics::InvalidIssueString {
|
|
||||||
span: mi.span,
|
|
||||||
cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind(
|
|
||||||
mi.name_value_literal_span().unwrap(),
|
|
||||||
err.kind(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
sym::soft => {
|
|
||||||
if !mi.is_word() {
|
|
||||||
sess.emit_err(session_diagnostics::SoftNoArgs {
|
|
||||||
span: mi.span,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
is_soft = true;
|
|
||||||
}
|
|
||||||
sym::implied_by => {
|
|
||||||
if !get(mi, &mut implied_by) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
meta.span(),
|
|
||||||
AttrError::UnknownMetaItem(
|
|
||||||
pprust::path_to_string(&mi.path),
|
|
||||||
&["feature", "reason", "issue", "soft"],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match (feature, reason, issue) {
|
|
||||||
(Some(feature), reason, Some(_)) => {
|
|
||||||
if !rustc_lexer::is_ident(feature.as_str()) {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
attr.span,
|
|
||||||
AttrError::NonIdentFeature,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let level = Unstable {
|
|
||||||
reason: UnstableReason::from_opt_reason(reason),
|
|
||||||
issue: issue_num,
|
|
||||||
is_soft,
|
|
||||||
implied_by,
|
|
||||||
};
|
|
||||||
if sym::unstable == meta_name {
|
|
||||||
stab = Some((Stability { level, feature }, attr.span));
|
|
||||||
} else if sym::rustc_const_unstable == meta_name {
|
|
||||||
const_stab = Some((
|
|
||||||
ConstStability { level, feature, promotable: false },
|
|
||||||
attr.span,
|
|
||||||
));
|
|
||||||
} else if sym::rustc_default_body_unstable == meta_name {
|
|
||||||
body_stab =
|
|
||||||
Some((DefaultBodyStability { level, feature }, attr.span));
|
|
||||||
} else {
|
|
||||||
unreachable!("Unknown stability attribute {meta_name}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(None, _, _) => {
|
|
||||||
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
sess.emit_err(session_diagnostics::MissingIssue { span: attr.span });
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sym::rustc_const_stable | sym::stable => {
|
|
||||||
if meta_name == sym::stable && stab.is_some() {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
attr.span,
|
|
||||||
AttrError::MultipleStabilityLevels,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
} else if meta_name == sym::rustc_const_stable && const_stab.is_some() {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
attr.span,
|
|
||||||
AttrError::MultipleStabilityLevels,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut feature = None;
|
|
||||||
let mut since = None;
|
|
||||||
for meta in metas {
|
|
||||||
match meta {
|
|
||||||
NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() {
|
|
||||||
sym::feature => {
|
|
||||||
if !get(mi, &mut feature) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sym::since => {
|
|
||||||
if !get(mi, &mut since) {
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
meta.span(),
|
|
||||||
AttrError::UnknownMetaItem(
|
|
||||||
pprust::path_to_string(&mi.path),
|
|
||||||
&["feature", "since"],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NestedMetaItem::Lit(lit) => {
|
|
||||||
handle_errors(
|
|
||||||
&sess.parse_sess,
|
|
||||||
lit.span,
|
|
||||||
AttrError::UnsupportedLiteral(
|
|
||||||
UnsupportedLiteralReason::Generic,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
|
|
||||||
since = Some(rust_version_symbol());
|
|
||||||
}
|
|
||||||
|
|
||||||
match (feature, since) {
|
|
||||||
(Some(feature), Some(since)) => {
|
|
||||||
let level = Stable { since, allowed_through_unstable_modules: false };
|
|
||||||
if sym::stable == meta_name {
|
|
||||||
stab = Some((Stability { level, feature }, attr.span));
|
|
||||||
} else {
|
|
||||||
const_stab = Some((
|
|
||||||
ConstStability { level, feature, promotable: false },
|
|
||||||
attr.span,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(None, _) => {
|
|
||||||
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
sym::stable => {
|
||||||
}
|
if stab.is_some() {
|
||||||
|
handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels);
|
||||||
// Merge the const-unstable info into the stability info
|
break;
|
||||||
if promotable {
|
}
|
||||||
match &mut const_stab {
|
if let Some((feature, level)) = parse_stability(sess, attr) {
|
||||||
Some((stab, _)) => stab.promotable = promotable,
|
stab = Some((Stability { level, feature }, attr.span));
|
||||||
_ => _ = sess.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp }),
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,7 +277,286 @@ fn find_stability_generic<'a, I>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(stab, const_stab, body_stab)
|
stab
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
|
||||||
|
/// attributes in `attrs`. Returns `None` if no stability attributes are found.
|
||||||
|
pub fn find_const_stability(
|
||||||
|
sess: &Session,
|
||||||
|
attrs: &[Attribute],
|
||||||
|
item_sp: Span,
|
||||||
|
) -> Option<(ConstStability, Span)> {
|
||||||
|
let mut const_stab: Option<(ConstStability, Span)> = None;
|
||||||
|
let mut promotable = false;
|
||||||
|
|
||||||
|
for attr in attrs {
|
||||||
|
match attr.name_or_empty() {
|
||||||
|
sym::rustc_promotable => promotable = true,
|
||||||
|
sym::rustc_const_unstable => {
|
||||||
|
if const_stab.is_some() {
|
||||||
|
handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((feature, level)) = parse_unstability(sess, attr) {
|
||||||
|
const_stab =
|
||||||
|
Some((ConstStability { level, feature, promotable: false }, attr.span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sym::rustc_const_stable => {
|
||||||
|
if const_stab.is_some() {
|
||||||
|
handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some((feature, level)) = parse_stability(sess, attr) {
|
||||||
|
const_stab =
|
||||||
|
Some((ConstStability { level, feature, promotable: false }, attr.span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge the const-unstable info into the stability info
|
||||||
|
if promotable {
|
||||||
|
match &mut const_stab {
|
||||||
|
Some((stab, _)) => stab.promotable = promotable,
|
||||||
|
_ => _ = sess.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const_stab
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`.
|
||||||
|
/// Returns `None` if no stability attributes are found.
|
||||||
|
pub fn find_body_stability(
|
||||||
|
sess: &Session,
|
||||||
|
attrs: &[Attribute],
|
||||||
|
) -> Option<(DefaultBodyStability, Span)> {
|
||||||
|
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
|
||||||
|
|
||||||
|
for attr in attrs {
|
||||||
|
if attr.has_name(sym::rustc_default_body_unstable) {
|
||||||
|
if body_stab.is_some() {
|
||||||
|
handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((feature, level)) = parse_unstability(sess, attr) {
|
||||||
|
body_stab = Some((DefaultBodyStability { level, feature }, attr.span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body_stab
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and
|
||||||
|
/// its stability information.
|
||||||
|
fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> {
|
||||||
|
let meta = attr.meta()?;
|
||||||
|
let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None };
|
||||||
|
let insert_or_error = |meta: &MetaItem, item: &mut Option<Symbol>| {
|
||||||
|
if item.is_some() {
|
||||||
|
handle_errors(
|
||||||
|
&sess.parse_sess,
|
||||||
|
meta.span,
|
||||||
|
AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if let Some(v) = meta.value_str() {
|
||||||
|
*item = Some(v);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut feature = None;
|
||||||
|
let mut since = None;
|
||||||
|
for meta in metas {
|
||||||
|
let Some(mi) = meta.meta_item() else {
|
||||||
|
handle_errors(
|
||||||
|
&sess.parse_sess,
|
||||||
|
meta.span(),
|
||||||
|
AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
match mi.name_or_empty() {
|
||||||
|
sym::feature => {
|
||||||
|
if !insert_or_error(mi, &mut feature) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sym::since => {
|
||||||
|
if !insert_or_error(mi, &mut since) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
handle_errors(
|
||||||
|
&sess.parse_sess,
|
||||||
|
meta.span(),
|
||||||
|
AttrError::UnknownMetaItem(
|
||||||
|
pprust::path_to_string(&mi.path),
|
||||||
|
&["feature", "since"],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
|
||||||
|
since = Some(rust_version_symbol());
|
||||||
|
}
|
||||||
|
|
||||||
|
match (feature, since) {
|
||||||
|
(Some(feature), Some(since)) => {
|
||||||
|
let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false };
|
||||||
|
Some((feature, level))
|
||||||
|
}
|
||||||
|
(None, _) => {
|
||||||
|
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
|
||||||
|
/// attribute, and return the feature name and its stability information.
|
||||||
|
fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> {
|
||||||
|
let meta = attr.meta()?;
|
||||||
|
let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None };
|
||||||
|
let insert_or_error = |meta: &MetaItem, item: &mut Option<Symbol>| {
|
||||||
|
if item.is_some() {
|
||||||
|
handle_errors(
|
||||||
|
&sess.parse_sess,
|
||||||
|
meta.span,
|
||||||
|
AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if let Some(v) = meta.value_str() {
|
||||||
|
*item = Some(v);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut feature = None;
|
||||||
|
let mut reason = None;
|
||||||
|
let mut issue = None;
|
||||||
|
let mut issue_num = None;
|
||||||
|
let mut is_soft = false;
|
||||||
|
let mut implied_by = None;
|
||||||
|
for meta in metas {
|
||||||
|
let Some(mi) = meta.meta_item() else {
|
||||||
|
handle_errors(
|
||||||
|
&sess.parse_sess,
|
||||||
|
meta.span(),
|
||||||
|
AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
match mi.name_or_empty() {
|
||||||
|
sym::feature => {
|
||||||
|
if !insert_or_error(mi, &mut feature) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sym::reason => {
|
||||||
|
if !insert_or_error(mi, &mut reason) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sym::issue => {
|
||||||
|
if !insert_or_error(mi, &mut issue) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These unwraps are safe because `insert_or_error` ensures the meta item
|
||||||
|
// is a name/value pair string literal.
|
||||||
|
issue_num = match issue.unwrap().as_str() {
|
||||||
|
"none" => None,
|
||||||
|
issue => match issue.parse::<NonZeroU32>() {
|
||||||
|
Ok(num) => Some(num),
|
||||||
|
Err(err) => {
|
||||||
|
sess.emit_err(
|
||||||
|
session_diagnostics::InvalidIssueString {
|
||||||
|
span: mi.span,
|
||||||
|
cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind(
|
||||||
|
mi.name_value_literal_span().unwrap(),
|
||||||
|
err.kind(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
sym::soft => {
|
||||||
|
if !mi.is_word() {
|
||||||
|
sess.emit_err(session_diagnostics::SoftNoArgs { span: mi.span });
|
||||||
|
}
|
||||||
|
is_soft = true;
|
||||||
|
}
|
||||||
|
sym::implied_by => {
|
||||||
|
if !insert_or_error(mi, &mut implied_by) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
handle_errors(
|
||||||
|
&sess.parse_sess,
|
||||||
|
meta.span(),
|
||||||
|
AttrError::UnknownMetaItem(
|
||||||
|
pprust::path_to_string(&mi.path),
|
||||||
|
&["feature", "reason", "issue", "soft", "implied_by"],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match (feature, reason, issue) {
|
||||||
|
(Some(feature), reason, Some(_)) => {
|
||||||
|
if !rustc_lexer::is_ident(feature.as_str()) {
|
||||||
|
handle_errors(&sess.parse_sess, attr.span, AttrError::NonIdentFeature);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let level = StabilityLevel::Unstable {
|
||||||
|
reason: UnstableReason::from_opt_reason(reason),
|
||||||
|
issue: issue_num,
|
||||||
|
is_soft,
|
||||||
|
implied_by,
|
||||||
|
};
|
||||||
|
Some((feature, level))
|
||||||
|
}
|
||||||
|
(None, _, _) => {
|
||||||
|
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
sess.emit_err(session_diagnostics::MissingIssue { span: attr.span });
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
|
pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
|
||||||
|
@ -539,7 +539,15 @@ pub(crate) fn eval_fn_call(
|
|||||||
let mut receiver = args[0].clone();
|
let mut receiver = args[0].clone();
|
||||||
let receiver_place = loop {
|
let receiver_place = loop {
|
||||||
match receiver.layout.ty.kind() {
|
match receiver.layout.ty.kind() {
|
||||||
ty::Ref(..) | ty::RawPtr(..) => break self.deref_operand(&receiver)?,
|
ty::Ref(..) | ty::RawPtr(..) => {
|
||||||
|
// We do *not* use `deref_operand` here: we don't want to conceptually
|
||||||
|
// create a place that must be dereferenceable, since the receiver might
|
||||||
|
// be a raw pointer and (for `*const dyn Trait`) we don't need to
|
||||||
|
// actually access memory to resolve this method.
|
||||||
|
// Also see <https://github.com/rust-lang/miri/issues/2786>.
|
||||||
|
let val = self.read_immediate(&receiver)?;
|
||||||
|
break self.ref_to_mplace(&val)?;
|
||||||
|
}
|
||||||
ty::Dynamic(.., ty::Dyn) => break receiver.assert_mem_place(), // no immediate unsized values
|
ty::Dynamic(.., ty::Dyn) => break receiver.assert_mem_place(), // no immediate unsized values
|
||||||
ty::Dynamic(.., ty::DynStar) => {
|
ty::Dynamic(.., ty::DynStar) => {
|
||||||
// Not clear how to handle this, so far we assume the receiver is always a pointer.
|
// Not clear how to handle this, so far we assume the receiver is always a pointer.
|
||||||
|
@ -793,7 +793,9 @@ pub fn new(
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| (None, helper_attrs));
|
.unwrap_or_else(|| (None, helper_attrs));
|
||||||
let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span);
|
let stability = attr::find_stability(&sess, attrs, span);
|
||||||
|
let const_stability = attr::find_const_stability(&sess, attrs, span);
|
||||||
|
let body_stability = attr::find_body_stability(&sess, attrs);
|
||||||
if let Some((_, sp)) = const_stability {
|
if let Some((_, sp)) = const_stability {
|
||||||
sess.emit_err(errors::MacroConstStability {
|
sess.emit_err(errors::MacroConstStability {
|
||||||
span: sp,
|
span: sp,
|
||||||
|
@ -1544,42 +1544,81 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
|
|||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
let tcx = wfcx.tcx();
|
let tcx = wfcx.tcx();
|
||||||
if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id())
|
let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) else {
|
||||||
&& assoc_item.container == ty::AssocItemContainer::TraitContainer
|
return;
|
||||||
{
|
};
|
||||||
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering
|
if assoc_item.container != ty::AssocItemContainer::TraitContainer {
|
||||||
// strategy, we can't just call `check_associated_item` on the new RPITITs,
|
return;
|
||||||
// because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail.
|
}
|
||||||
// That's because we need to check that the bounds of the RPITIT hold using
|
fn_output.visit_with(&mut ImplTraitInTraitFinder {
|
||||||
// the special substs that we create during opaque type lowering, otherwise we're
|
wfcx,
|
||||||
// getting a bunch of early bound and free regions mixed up... Haven't looked too
|
fn_def_id,
|
||||||
// deep into this, though.
|
depth: ty::INNERMOST,
|
||||||
for arg in fn_output.walk() {
|
seen: FxHashSet::default(),
|
||||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
});
|
||||||
// RPITITs are always eagerly normalized into opaques, so always look for an
|
}
|
||||||
// opaque here.
|
|
||||||
&& let ty::Alias(ty::Opaque, opaque_ty) = ty.kind()
|
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering
|
||||||
&& let Some(opaque_def_id) = opaque_ty.def_id.as_local()
|
// strategy, we can't just call `check_associated_item` on the new RPITITs,
|
||||||
&& let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty()
|
// because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail.
|
||||||
&& let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin
|
// That's because we need to check that the bounds of the RPITIT hold using
|
||||||
&& source == fn_def_id
|
// the special substs that we create during opaque type lowering, otherwise we're
|
||||||
|
// getting a bunch of early bound and free regions mixed up... Haven't looked too
|
||||||
|
// deep into this, though.
|
||||||
|
struct ImplTraitInTraitFinder<'a, 'tcx> {
|
||||||
|
wfcx: &'a WfCheckingCtxt<'a, 'tcx>,
|
||||||
|
fn_def_id: LocalDefId,
|
||||||
|
depth: ty::DebruijnIndex,
|
||||||
|
seen: FxHashSet<DefId>,
|
||||||
|
}
|
||||||
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
|
||||||
|
type BreakTy = !;
|
||||||
|
|
||||||
|
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<!> {
|
||||||
|
let tcx = self.wfcx.tcx();
|
||||||
|
if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind()
|
||||||
|
&& self.seen.insert(unshifted_opaque_ty.def_id)
|
||||||
|
&& let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local()
|
||||||
|
&& let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty()
|
||||||
|
&& let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin
|
||||||
|
&& source == self.fn_def_id
|
||||||
|
{
|
||||||
|
let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, depth| {
|
||||||
|
if let ty::ReLateBound(index, bv) = re.kind() {
|
||||||
|
if depth != ty::INNERMOST {
|
||||||
|
return tcx.mk_re_error_with_message(
|
||||||
|
DUMMY_SP,
|
||||||
|
"we shouldn't walk non-predicate binders with `impl Trait`...",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv)
|
||||||
|
} else {
|
||||||
|
re
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (bound, bound_span) in tcx
|
||||||
|
.bound_explicit_item_bounds(opaque_ty.def_id)
|
||||||
|
.subst_iter_copied(tcx, opaque_ty.substs)
|
||||||
{
|
{
|
||||||
let span = tcx.def_span(opaque_ty.def_id);
|
let bound = self.wfcx.normalize(bound_span, None, bound);
|
||||||
let bounds = wfcx.tcx().explicit_item_bounds(opaque_ty.def_id);
|
self.wfcx.register_obligations(traits::wf::predicate_obligations(
|
||||||
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
|
self.wfcx.infcx,
|
||||||
let bound = ty::EarlyBinder(bound).subst(tcx, opaque_ty.substs);
|
self.wfcx.param_env,
|
||||||
let normalized_bound = wfcx.normalize(span, None, bound);
|
self.wfcx.body_def_id,
|
||||||
traits::wf::predicate_obligations(
|
bound,
|
||||||
wfcx.infcx,
|
bound_span,
|
||||||
wfcx.param_env,
|
));
|
||||||
wfcx.body_def_id,
|
// Set the debruijn index back to innermost here, since we already eagerly
|
||||||
normalized_bound,
|
// shifted the substs that we use to generate these bounds. This is unfortunately
|
||||||
bound_span,
|
// subtly different behavior than the `ImplTraitInTraitFinder` we use in `param_env`,
|
||||||
)
|
// but that function doesn't actually need to normalize the bound it's visiting
|
||||||
});
|
// (whereas we have to do so here)...
|
||||||
wfcx.register_obligations(wf_obligations);
|
let old_depth = std::mem::replace(&mut self.depth, ty::INNERMOST);
|
||||||
|
bound.visit_with(self);
|
||||||
|
self.depth = old_depth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ty.super_visit_with(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -983,13 +983,18 @@ pub(crate) fn suggest_clone_for_ref(
|
|||||||
)
|
)
|
||||||
.must_apply_modulo_regions()
|
.must_apply_modulo_regions()
|
||||||
{
|
{
|
||||||
diag.span_suggestion_verbose(
|
let suggestion = match self.maybe_get_struct_pattern_shorthand_field(expr) {
|
||||||
expr.span.shrink_to_hi(),
|
Some(ident) => format!(": {}.clone()", ident),
|
||||||
"consider using clone here",
|
None => ".clone()".to_string()
|
||||||
".clone()",
|
};
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
diag.span_suggestion_verbose(
|
||||||
return true;
|
expr.span.shrink_to_hi(),
|
||||||
|
"consider using clone here",
|
||||||
|
suggestion,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -1150,13 +1155,17 @@ pub(crate) fn suggest_option_to_bool(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
diag.span_suggestion(
|
let suggestion = match self.maybe_get_struct_pattern_shorthand_field(expr) {
|
||||||
|
Some(ident) => format!(": {}.is_some()", ident),
|
||||||
|
None => ".is_some()".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
diag.span_suggestion_verbose(
|
||||||
expr.span.shrink_to_hi(),
|
expr.span.shrink_to_hi(),
|
||||||
"use `Option::is_some` to test if the `Option` has a value",
|
"use `Option::is_some` to test if the `Option` has a value",
|
||||||
".is_some()",
|
suggestion,
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +159,9 @@ fn annotate<F>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (stab, const_stab, body_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
|
let stab = attr::find_stability(&self.tcx.sess, attrs, item_sp);
|
||||||
|
let const_stab = attr::find_const_stability(&self.tcx.sess, attrs, item_sp);
|
||||||
|
let body_stab = attr::find_body_stability(&self.tcx.sess, attrs);
|
||||||
let mut const_span = None;
|
let mut const_span = None;
|
||||||
|
|
||||||
let const_stab = const_stab.map(|(const_stab, const_span_node)| {
|
let const_stab = const_stab.map(|(const_stab, const_span_node)| {
|
||||||
@ -742,8 +744,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
|||||||
let features = self.tcx.features();
|
let features = self.tcx.features();
|
||||||
if features.staged_api {
|
if features.staged_api {
|
||||||
let attrs = self.tcx.hir().attrs(item.hir_id());
|
let attrs = self.tcx.hir().attrs(item.hir_id());
|
||||||
let (stab, const_stab, _) =
|
let stab = attr::find_stability(&self.tcx.sess, attrs, item.span);
|
||||||
attr::find_stability(&self.tcx.sess, attrs, item.span);
|
let const_stab = attr::find_const_stability(&self.tcx.sess, attrs, item.span);
|
||||||
|
|
||||||
// If this impl block has an #[unstable] attribute, give an
|
// If this impl block has an #[unstable] attribute, give an
|
||||||
// error if all involved types and traits are stable, because
|
// error if all involved types and traits are stable, because
|
||||||
|
@ -100,18 +100,13 @@ fn render_all(mut self) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let trimmed = line.trim();
|
match serde_json::from_str(&line) {
|
||||||
if trimmed.starts_with("{") && trimmed.ends_with("}") {
|
Ok(parsed) => self.render_message(parsed),
|
||||||
self.render_message(match serde_json::from_str(&trimmed) {
|
Err(_err) => {
|
||||||
Ok(parsed) => parsed,
|
// Handle non-JSON output, for example when --nocapture is passed.
|
||||||
Err(err) => {
|
print!("{line}");
|
||||||
panic!("failed to parse libtest json output; error: {err}, line: {line:?}");
|
let _ = std::io::stdout().flush();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Handle non-JSON output, for example when --nocapture is passed.
|
|
||||||
print!("{line}");
|
|
||||||
let _ = std::io::stdout().flush();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,21 +87,6 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This part handles the "default" theme being used depending on the system one. */
|
|
||||||
html {
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
@media (prefers-color-scheme: light) {
|
|
||||||
html {
|
|
||||||
content: "light";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
html {
|
|
||||||
content: "dark";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* General structure and fonts */
|
/* General structure and fonts */
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@ -1538,7 +1523,7 @@ However, it's not needed with smaller screen width because the doc/code block is
|
|||||||
/*
|
/*
|
||||||
WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
|
WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
|
||||||
If you update this line, then you also need to update the line with the same warning
|
If you update this line, then you also need to update the line with the same warning
|
||||||
in storage.js
|
in main.js
|
||||||
*/
|
*/
|
||||||
@media (max-width: 700px) {
|
@media (max-width: 700px) {
|
||||||
/* When linking to an item with an `id` (for instance, by clicking a link in the sidebar,
|
/* When linking to an item with an `id` (for instance, by clicking a link in the sidebar,
|
||||||
|
@ -4,6 +4,11 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
// WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
|
||||||
|
// If you update this line, then you also need to update the media query with the same
|
||||||
|
// warning in rustdoc.css
|
||||||
|
window.RUSTDOC_MOBILE_BREAKPOINT = 700;
|
||||||
|
|
||||||
// Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL
|
// Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL
|
||||||
// for a resource under the root-path, with the resource-suffix.
|
// for a resource under the root-path, with the resource-suffix.
|
||||||
function resourcePath(basename, extension) {
|
function resourcePath(basename, extension) {
|
||||||
|
@ -8,29 +8,14 @@
|
|||||||
const darkThemes = ["dark", "ayu"];
|
const darkThemes = ["dark", "ayu"];
|
||||||
window.currentTheme = document.getElementById("themeStyle");
|
window.currentTheme = document.getElementById("themeStyle");
|
||||||
|
|
||||||
// WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
|
|
||||||
// If you update this line, then you also need to update the media query with the same
|
|
||||||
// warning in rustdoc.css
|
|
||||||
window.RUSTDOC_MOBILE_BREAKPOINT = 700;
|
|
||||||
|
|
||||||
const settingsDataset = (function() {
|
const settingsDataset = (function() {
|
||||||
const settingsElement = document.getElementById("default-settings");
|
const settingsElement = document.getElementById("default-settings");
|
||||||
if (settingsElement === null) {
|
return settingsElement && settingsElement.dataset ? settingsElement.dataset : null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const dataset = settingsElement.dataset;
|
|
||||||
if (dataset === undefined) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return dataset;
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function getSettingValue(settingName) {
|
function getSettingValue(settingName) {
|
||||||
const current = getCurrentValue(settingName);
|
const current = getCurrentValue(settingName);
|
||||||
if (current !== null) {
|
if (current === null && settingsDataset !== null) {
|
||||||
return current;
|
|
||||||
}
|
|
||||||
if (settingsDataset !== null) {
|
|
||||||
// See the comment for `default_settings.into_iter()` etc. in
|
// See the comment for `default_settings.into_iter()` etc. in
|
||||||
// `Options::from_matches` in `librustdoc/config.rs`.
|
// `Options::from_matches` in `librustdoc/config.rs`.
|
||||||
const def = settingsDataset[settingName.replace(/-/g,"_")];
|
const def = settingsDataset[settingName.replace(/-/g,"_")];
|
||||||
@ -38,7 +23,7 @@ function getSettingValue(settingName) {
|
|||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
const localStoredTheme = getSettingValue("theme");
|
const localStoredTheme = getSettingValue("theme");
|
||||||
@ -49,18 +34,16 @@ function hasClass(elem, className) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addClass(elem, className) {
|
function addClass(elem, className) {
|
||||||
if (!elem || !elem.classList) {
|
if (elem && elem.classList) {
|
||||||
return;
|
elem.classList.add(className);
|
||||||
}
|
}
|
||||||
elem.classList.add(className);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function removeClass(elem, className) {
|
function removeClass(elem, className) {
|
||||||
if (!elem || !elem.classList) {
|
if (elem && elem.classList) {
|
||||||
return;
|
elem.classList.remove(className);
|
||||||
}
|
}
|
||||||
elem.classList.remove(className);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -127,11 +110,7 @@ function getCurrentValue(name) {
|
|||||||
// Rust to the JS. If there is no such element, return null.
|
// Rust to the JS. If there is no such element, return null.
|
||||||
const getVar = (function getVar(name) {
|
const getVar = (function getVar(name) {
|
||||||
const el = document.getElementById("rustdoc-vars");
|
const el = document.getElementById("rustdoc-vars");
|
||||||
if (el) {
|
return el ? el.attributes["data-" + name].value : null;
|
||||||
return el.attributes["data-" + name].value;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function switchTheme(newThemeName, saveTheme) {
|
function switchTheme(newThemeName, saveTheme) {
|
||||||
@ -158,6 +137,9 @@ function switchTheme(newThemeName, saveTheme) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const updateTheme = (function() {
|
const updateTheme = (function() {
|
||||||
|
// only listen to (prefers-color-scheme: dark) because light is the default
|
||||||
|
const mql = window.matchMedia("(prefers-color-scheme: dark)");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the current theme to match whatever the current combination of
|
* Update the current theme to match whatever the current combination of
|
||||||
* * the preference for using the system theme
|
* * the preference for using the system theme
|
||||||
@ -177,7 +159,7 @@ const updateTheme = (function() {
|
|||||||
const lightTheme = getSettingValue("preferred-light-theme") || "light";
|
const lightTheme = getSettingValue("preferred-light-theme") || "light";
|
||||||
const darkTheme = getSettingValue("preferred-dark-theme") || "dark";
|
const darkTheme = getSettingValue("preferred-dark-theme") || "dark";
|
||||||
|
|
||||||
if (isDarkMode()) {
|
if (mql.matches) {
|
||||||
use(darkTheme, true);
|
use(darkTheme, true);
|
||||||
} else {
|
} else {
|
||||||
// prefers a light theme, or has no preference
|
// prefers a light theme, or has no preference
|
||||||
@ -191,37 +173,7 @@ const updateTheme = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is always updated below to a function () => bool.
|
mql.addEventListener("change", updateTheme);
|
||||||
let isDarkMode;
|
|
||||||
|
|
||||||
// Determine the function for isDarkMode, and if we have
|
|
||||||
// `window.matchMedia`, set up an event listener on the preferred color
|
|
||||||
// scheme.
|
|
||||||
//
|
|
||||||
// Otherwise, fall back to the prefers-color-scheme value CSS captured in
|
|
||||||
// the "content" property.
|
|
||||||
if (window.matchMedia) {
|
|
||||||
// only listen to (prefers-color-scheme: dark) because light is the default
|
|
||||||
const mql = window.matchMedia("(prefers-color-scheme: dark)");
|
|
||||||
|
|
||||||
isDarkMode = () => mql.matches;
|
|
||||||
|
|
||||||
if (mql.addEventListener) {
|
|
||||||
mql.addEventListener("change", updateTheme);
|
|
||||||
} else {
|
|
||||||
// This is deprecated, see:
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/addListener
|
|
||||||
mql.addListener(updateTheme);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// fallback to the CSS computed value
|
|
||||||
const cssContent = getComputedStyle(document.documentElement)
|
|
||||||
.getPropertyValue("content");
|
|
||||||
// (Note: the double-quotes come from that this is a CSS value, which
|
|
||||||
// might be a length, string, etc.)
|
|
||||||
const cssColorScheme = cssContent || "\"light\"";
|
|
||||||
isDarkMode = () => (cssColorScheme === "\"dark\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateTheme;
|
return updateTheme;
|
||||||
})();
|
})();
|
||||||
|
@ -123,8 +123,35 @@ fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 {
|
|||||||
assert_eq!(wpw.wrapper_ptr_wrapper(), 7);
|
assert_eq!(wpw.wrapper_ptr_wrapper(), 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn raw_ptr_receiver() {
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
fn foo(self: *const Self) -> &'static str;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo for i32 {
|
||||||
|
fn foo(self: *const Self) -> &'static str {
|
||||||
|
"I'm an i32!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo for u32 {
|
||||||
|
fn foo(self: *const Self) -> &'static str {
|
||||||
|
"I'm a u32!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let null_i32 = ptr::null::<i32>() as *const dyn Foo;
|
||||||
|
let null_u32 = ptr::null::<u32>() as *const dyn Foo;
|
||||||
|
|
||||||
|
assert_eq!("I'm an i32!", null_i32.foo());
|
||||||
|
assert_eq!("I'm a u32!", null_u32.foo());
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
pin_box_dyn();
|
pin_box_dyn();
|
||||||
stdlib_pointers();
|
stdlib_pointers();
|
||||||
pointers_and_wrappers();
|
pointers_and_wrappers();
|
||||||
|
raw_ptr_receiver();
|
||||||
}
|
}
|
||||||
|
48
tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml
Normal file
48
tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// This test ensures that the "Auto-hide item methods' documentation" setting is working as
|
||||||
|
// expected.
|
||||||
|
|
||||||
|
define-function: (
|
||||||
|
"check-setting",
|
||||||
|
(storage_value, setting_attribute_value, toggle_attribute_value),
|
||||||
|
block {
|
||||||
|
assert-local-storage: {"rustdoc-auto-hide-method-docs": |storage_value|}
|
||||||
|
click: "#settings-menu"
|
||||||
|
wait-for: "#settings"
|
||||||
|
assert-property: ("#auto-hide-method-docs", {"checked": |setting_attribute_value|})
|
||||||
|
assert-attribute: (".toggle.method-toggle", {"open": |toggle_attribute_value|})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
goto: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html"
|
||||||
|
|
||||||
|
// We check that the setting is disabled by default.
|
||||||
|
call-function: ("check-setting", {
|
||||||
|
"storage_value": null,
|
||||||
|
"setting_attribute_value": "false",
|
||||||
|
"toggle_attribute_value": "",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Now we change its value.
|
||||||
|
click: "#auto-hide-method-docs"
|
||||||
|
assert-local-storage: {"rustdoc-auto-hide-method-docs": "true"}
|
||||||
|
|
||||||
|
// We check that the changes were applied as expected.
|
||||||
|
reload:
|
||||||
|
|
||||||
|
call-function: ("check-setting", {
|
||||||
|
"storage_value": "true",
|
||||||
|
"setting_attribute_value": "true",
|
||||||
|
"toggle_attribute_value": null,
|
||||||
|
})
|
||||||
|
|
||||||
|
// And now we re-disable the setting.
|
||||||
|
click: "#auto-hide-method-docs"
|
||||||
|
assert-local-storage: {"rustdoc-auto-hide-method-docs": "false"}
|
||||||
|
|
||||||
|
// And we check everything is back the way it was before.
|
||||||
|
reload:
|
||||||
|
call-function: ("check-setting", {
|
||||||
|
"storage_value": "false",
|
||||||
|
"setting_attribute_value": "false",
|
||||||
|
"toggle_attribute_value": "",
|
||||||
|
})
|
@ -1,5 +1,5 @@
|
|||||||
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
--> $DIR/wf-bounds.rs:11:22
|
--> $DIR/wf-bounds.rs:13:22
|
||||||
|
|
|
|
||||||
LL | fn nya() -> impl Wf<Vec<[u8]>>;
|
LL | fn nya() -> impl Wf<Vec<[u8]>>;
|
||||||
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
@ -9,7 +9,7 @@ note: required by a bound in `Vec`
|
|||||||
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||||
|
|
||||||
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
--> $DIR/wf-bounds.rs:14:23
|
--> $DIR/wf-bounds.rs:16:23
|
||||||
|
|
|
|
||||||
LL | fn nya2() -> impl Wf<[u8]>;
|
LL | fn nya2() -> impl Wf<[u8]>;
|
||||||
| ^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^ doesn't have a size known at compile-time
|
||||||
@ -18,13 +18,23 @@ LL | fn nya2() -> impl Wf<[u8]>;
|
|||||||
note: required by a bound in `Wf`
|
note: required by a bound in `Wf`
|
||||||
--> $DIR/wf-bounds.rs:8:10
|
--> $DIR/wf-bounds.rs:8:10
|
||||||
|
|
|
|
||||||
LL | trait Wf<T> {}
|
LL | trait Wf<T> {
|
||||||
| ^ required by this bound in `Wf`
|
| ^ required by this bound in `Wf`
|
||||||
help: consider relaxing the implicit `Sized` restriction
|
help: consider relaxing the implicit `Sized` restriction
|
||||||
|
|
|
|
||||||
LL | trait Wf<T: ?Sized> {}
|
LL | trait Wf<T: ?Sized> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
--> $DIR/wf-bounds.rs:19:44
|
||||||
|
|
|
||||||
|
LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>;
|
||||||
|
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `[u8]`
|
||||||
|
note: required by a bound in `Vec`
|
||||||
|
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
--> $DIR/wf-bounds.rs:11:22
|
--> $DIR/wf-bounds.rs:13:22
|
||||||
|
|
|
|
||||||
LL | fn nya() -> impl Wf<Vec<[u8]>>;
|
LL | fn nya() -> impl Wf<Vec<[u8]>>;
|
||||||
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
@ -9,7 +9,7 @@ note: required by a bound in `Vec`
|
|||||||
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||||
|
|
||||||
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
--> $DIR/wf-bounds.rs:14:23
|
--> $DIR/wf-bounds.rs:16:23
|
||||||
|
|
|
|
||||||
LL | fn nya2() -> impl Wf<[u8]>;
|
LL | fn nya2() -> impl Wf<[u8]>;
|
||||||
| ^^^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^^^ doesn't have a size known at compile-time
|
||||||
@ -18,13 +18,23 @@ LL | fn nya2() -> impl Wf<[u8]>;
|
|||||||
note: required by a bound in `Wf`
|
note: required by a bound in `Wf`
|
||||||
--> $DIR/wf-bounds.rs:8:10
|
--> $DIR/wf-bounds.rs:8:10
|
||||||
|
|
|
|
||||||
LL | trait Wf<T> {}
|
LL | trait Wf<T> {
|
||||||
| ^ required by this bound in `Wf`
|
| ^ required by this bound in `Wf`
|
||||||
help: consider relaxing the implicit `Sized` restriction
|
help: consider relaxing the implicit `Sized` restriction
|
||||||
|
|
|
|
||||||
LL | trait Wf<T: ?Sized> {}
|
LL | trait Wf<T: ?Sized> {
|
||||||
| ++++++++
|
| ++++++++
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
--> $DIR/wf-bounds.rs:19:44
|
||||||
|
|
|
||||||
|
LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>;
|
||||||
|
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `[u8]`
|
||||||
|
note: required by a bound in `Vec`
|
||||||
|
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
#![feature(return_position_impl_trait_in_trait)]
|
#![feature(return_position_impl_trait_in_trait)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
trait Wf<T> {}
|
trait Wf<T> {
|
||||||
|
type Output;
|
||||||
|
}
|
||||||
|
|
||||||
trait Uwu {
|
trait Uwu {
|
||||||
fn nya() -> impl Wf<Vec<[u8]>>;
|
fn nya() -> impl Wf<Vec<[u8]>>;
|
||||||
@ -13,6 +15,9 @@ trait Uwu {
|
|||||||
|
|
||||||
fn nya2() -> impl Wf<[u8]>;
|
fn nya2() -> impl Wf<[u8]>;
|
||||||
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
|
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
|
||||||
|
|
||||||
|
fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>;
|
||||||
|
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
29
tests/ui/suggestions/issue-108470.fixed
Normal file
29
tests/ui/suggestions/issue-108470.fixed
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// run-rustfix
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
t: Thing
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Thing;
|
||||||
|
|
||||||
|
fn test_clone() {
|
||||||
|
let t = &Thing;
|
||||||
|
let _f = Foo {
|
||||||
|
t: t.clone() //~ ERROR mismatched types
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bar {
|
||||||
|
t: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_is_some() {
|
||||||
|
let t = Option::<i32>::Some(1);
|
||||||
|
let _f = Bar {
|
||||||
|
t: t.is_some() //~ ERROR mismatched types
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
29
tests/ui/suggestions/issue-108470.rs
Normal file
29
tests/ui/suggestions/issue-108470.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// run-rustfix
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
t: Thing
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Thing;
|
||||||
|
|
||||||
|
fn test_clone() {
|
||||||
|
let t = &Thing;
|
||||||
|
let _f = Foo {
|
||||||
|
t //~ ERROR mismatched types
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bar {
|
||||||
|
t: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_is_some() {
|
||||||
|
let t = Option::<i32>::Some(1);
|
||||||
|
let _f = Bar {
|
||||||
|
t //~ ERROR mismatched types
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
27
tests/ui/suggestions/issue-108470.stderr
Normal file
27
tests/ui/suggestions/issue-108470.stderr
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-108470.rs:14:9
|
||||||
|
|
|
||||||
|
LL | t
|
||||||
|
| ^ expected `Thing`, found `&Thing`
|
||||||
|
|
|
||||||
|
help: consider using clone here
|
||||||
|
|
|
||||||
|
LL | t: t.clone()
|
||||||
|
| +++++++++++
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-108470.rs:25:9
|
||||||
|
|
|
||||||
|
LL | t
|
||||||
|
| ^ expected `bool`, found `Option<i32>`
|
||||||
|
|
|
||||||
|
= note: expected type `bool`
|
||||||
|
found enum `Option<i32>`
|
||||||
|
help: use `Option::is_some` to test if the `Option` has a value
|
||||||
|
|
|
||||||
|
LL | t: t.is_some()
|
||||||
|
| +++++++++++++
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in New Issue
Block a user