Auto merge of #125436 - matthiaskrgr:rollup-uijo2ga, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #122665 (Add some tests for public-private dependencies.) - #123623 (Fix OutsideLoop's error suggestion: adding label `'block` for `if` block.) - #125054 (Handle `ReVar` in `note_and_explain_region`) - #125156 (Expand `for_loops_over_fallibles` lint to lint on fallibles behind references.) - #125222 (Migrate `run-make/issue-46239` to `rmake`) - #125316 (Tweak `Spacing` use) - #125392 (Wrap Context.ext in AssertUnwindSafe) - #125417 (self-contained linker: retry linking without `-fuse-ld=lld` on CCs that don't support it) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
39d2f2affd
52 changed files with 931 additions and 158 deletions
|
@ -661,11 +661,11 @@ impl TokenStream {
|
||||||
if attr_style == AttrStyle::Inner {
|
if attr_style == AttrStyle::Inner {
|
||||||
vec![
|
vec![
|
||||||
TokenTree::token_joint(token::Pound, span),
|
TokenTree::token_joint(token::Pound, span),
|
||||||
TokenTree::token_alone(token::Not, span),
|
TokenTree::token_joint_hidden(token::Not, span),
|
||||||
body,
|
body,
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
vec![TokenTree::token_alone(token::Pound, span), body]
|
vec![TokenTree::token_joint_hidden(token::Pound, span), body]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -681,22 +681,40 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The easiest way to implement token stream pretty printing would be to
|
||||||
|
// print each token followed by a single space. But that would produce ugly
|
||||||
|
// output, so we go to some effort to do better.
|
||||||
|
//
|
||||||
|
// First, we track whether each token that appears in source code is
|
||||||
|
// followed by a space, with `Spacing`, and reproduce that in the output.
|
||||||
|
// This works well in a lot of cases. E.g. `stringify!(x + y)` produces
|
||||||
|
// "x + y" and `stringify!(x+y)` produces "x+y".
|
||||||
|
//
|
||||||
|
// But this doesn't work for code produced by proc macros (which have no
|
||||||
|
// original source text representation) nor for code produced by decl
|
||||||
|
// macros (which are tricky because the whitespace after tokens appearing
|
||||||
|
// in macro rules isn't always what you want in the produced output). For
|
||||||
|
// these we mostly use `Spacing::Alone`, which is the conservative choice.
|
||||||
|
//
|
||||||
|
// So we have a backup mechanism for when `Spacing::Alone` occurs between a
|
||||||
|
// pair of tokens: we check if that pair of tokens can obviously go
|
||||||
|
// together without a space between them. E.g. token `x` followed by token
|
||||||
|
// `,` is better printed as `x,` than `x ,`. (Even if the original source
|
||||||
|
// code was `x ,`.)
|
||||||
|
//
|
||||||
|
// Finally, we must be careful about changing the output. Token pretty
|
||||||
|
// printing is used by `stringify!` and `impl Display for
|
||||||
|
// proc_macro::TokenStream`, and some programs rely on the output having a
|
||||||
|
// particular form, even though they shouldn't. In particular, some proc
|
||||||
|
// macros do `format!({stream})` on a token stream and then "parse" the
|
||||||
|
// output with simple string matching that can't handle whitespace changes.
|
||||||
|
// E.g. we have seen cases where a proc macro can handle `a :: b` but not
|
||||||
|
// `a::b`. See #117433 for some examples.
|
||||||
fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
|
fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
|
||||||
let mut iter = tts.trees().peekable();
|
let mut iter = tts.trees().peekable();
|
||||||
while let Some(tt) = iter.next() {
|
while let Some(tt) = iter.next() {
|
||||||
let spacing = self.print_tt(tt, convert_dollar_crate);
|
let spacing = self.print_tt(tt, convert_dollar_crate);
|
||||||
if let Some(next) = iter.peek() {
|
if let Some(next) = iter.peek() {
|
||||||
// Should we print a space after `tt`? There are two guiding
|
|
||||||
// factors.
|
|
||||||
// - `spacing` is the more important and accurate one. Most
|
|
||||||
// tokens have good spacing information, and
|
|
||||||
// `Joint`/`JointHidden` get used a lot.
|
|
||||||
// - `space_between` is the backup. Code produced by proc
|
|
||||||
// macros has worse spacing information, with no
|
|
||||||
// `JointHidden` usage and too much `Alone` usage, which
|
|
||||||
// would result in over-spaced output such as
|
|
||||||
// `( x () , y . z )`. `space_between` avoids some of the
|
|
||||||
// excess whitespace.
|
|
||||||
if spacing == Spacing::Alone && space_between(tt, next) {
|
if spacing == Spacing::Alone && space_between(tt, next) {
|
||||||
self.space();
|
self.space();
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||||
fn build_panic(&self, expr_str: &str, panic_path: Path) -> P<Expr> {
|
fn build_panic(&self, expr_str: &str, panic_path: Path) -> P<Expr> {
|
||||||
let escaped_expr_str = escape_to_fmt(expr_str);
|
let escaped_expr_str = escape_to_fmt(expr_str);
|
||||||
let initial = [
|
let initial = [
|
||||||
TokenTree::token_joint_hidden(
|
TokenTree::token_joint(
|
||||||
token::Literal(token::Lit {
|
token::Literal(token::Lit {
|
||||||
kind: token::LitKind::Str,
|
kind: token::LitKind::Str,
|
||||||
symbol: Symbol::intern(&if self.fmt_string.is_empty() {
|
symbol: Symbol::intern(&if self.fmt_string.is_empty() {
|
||||||
|
@ -172,7 +172,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||||
];
|
];
|
||||||
let captures = self.capture_decls.iter().flat_map(|cap| {
|
let captures = self.capture_decls.iter().flat_map(|cap| {
|
||||||
[
|
[
|
||||||
TokenTree::token_joint_hidden(
|
TokenTree::token_joint(
|
||||||
token::Ident(cap.ident.name, IdentIsRaw::No),
|
token::Ident(cap.ident.name, IdentIsRaw::No),
|
||||||
cap.ident.span,
|
cap.ident.span,
|
||||||
),
|
),
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::deriving::generic::*;
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use core::ops::ControlFlow;
|
use core::ops::ControlFlow;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::visit::walk_list;
|
use rustc_ast::visit::visit_opt;
|
||||||
use rustc_ast::{attr, EnumDef, VariantData};
|
use rustc_ast::{attr, EnumDef, VariantData};
|
||||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
|
@ -224,7 +224,7 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, '
|
||||||
self.visit_ident(v.ident);
|
self.visit_ident(v.ident);
|
||||||
self.visit_vis(&v.vis);
|
self.visit_vis(&v.vis);
|
||||||
self.visit_variant_data(&v.data);
|
self.visit_variant_data(&v.data);
|
||||||
walk_list!(self, visit_anon_const, &v.disr_expr);
|
visit_opt!(self, visit_anon_const, &v.disr_expr);
|
||||||
for attr in &v.attrs {
|
for attr in &v.attrs {
|
||||||
rustc_ast::visit::walk_attribute(self, attr);
|
rustc_ast::visit::walk_attribute(self, attr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -799,6 +799,27 @@ fn link_natively(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if linking failed with an error message that indicates the driver didn't recognize
|
||||||
|
// the `-fuse-ld=lld` option. If so, re-perform the link step without it. This avoids having
|
||||||
|
// to spawn multiple instances on the happy path to do version checking, and ensures things
|
||||||
|
// keep working on the tier 1 baseline of GLIBC 2.17+. That is generally understood as GCCs
|
||||||
|
// circa RHEL/CentOS 7, 4.5 or so, whereas lld support was added in GCC 9.
|
||||||
|
if matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, Lld::Yes))
|
||||||
|
&& unknown_arg_regex.is_match(&out)
|
||||||
|
&& out.contains("-fuse-ld=lld")
|
||||||
|
&& cmd.get_args().iter().any(|e| e.to_string_lossy() == "-fuse-ld=lld")
|
||||||
|
{
|
||||||
|
info!("linker output: {:?}", out);
|
||||||
|
warn!("The linker driver does not support `-fuse-ld=lld`. Retrying without it.");
|
||||||
|
for arg in cmd.take_args() {
|
||||||
|
if arg.to_string_lossy() != "-fuse-ld=lld" {
|
||||||
|
cmd.arg(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!("{:?}", &cmd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Detect '-static-pie' used with an older version of gcc or clang not supporting it.
|
// Detect '-static-pie' used with an older version of gcc or clang not supporting it.
|
||||||
// Fallback from '-static-pie' to '-static' in that case.
|
// Fallback from '-static-pie' to '-static' in that case.
|
||||||
if matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
|
if matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
|
||||||
|
|
|
@ -68,12 +68,15 @@ pub(crate) enum KleeneOp {
|
||||||
/// `MetaVarExpr` are "first-class" token trees. Useful for parsing macros.
|
/// `MetaVarExpr` are "first-class" token trees. Useful for parsing macros.
|
||||||
#[derive(Debug, PartialEq, Encodable, Decodable)]
|
#[derive(Debug, PartialEq, Encodable, Decodable)]
|
||||||
enum TokenTree {
|
enum TokenTree {
|
||||||
|
/// A token. Unlike `tokenstream::TokenTree::Token` this lacks a `Spacing`.
|
||||||
|
/// See the comments about `Spacing` in the `transcribe` function.
|
||||||
Token(Token),
|
Token(Token),
|
||||||
/// A delimited sequence, e.g. `($e:expr)` (RHS) or `{ $e }` (LHS).
|
/// A delimited sequence, e.g. `($e:expr)` (RHS) or `{ $e }` (LHS).
|
||||||
Delimited(DelimSpan, DelimSpacing, Delimited),
|
Delimited(DelimSpan, DelimSpacing, Delimited),
|
||||||
/// A kleene-style repetition sequence, e.g. `$($e:expr)*` (RHS) or `$($e),*` (LHS).
|
/// A kleene-style repetition sequence, e.g. `$($e:expr)*` (RHS) or `$($e),*` (LHS).
|
||||||
Sequence(DelimSpan, SequenceRepetition),
|
Sequence(DelimSpan, SequenceRepetition),
|
||||||
/// e.g., `$var`.
|
/// e.g., `$var`. The span covers the leading dollar and the ident. (The span within the ident
|
||||||
|
/// only covers the ident, e.g. `var`.)
|
||||||
MetaVar(Span, Ident),
|
MetaVar(Span, Ident),
|
||||||
/// e.g., `$var:expr`. Only appears on the LHS.
|
/// e.g., `$var:expr`. Only appears on the LHS.
|
||||||
MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
|
MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
|
||||||
|
|
|
@ -62,7 +62,10 @@ pub(super) fn parse(
|
||||||
match tree {
|
match tree {
|
||||||
TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
|
TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
|
||||||
let span = match trees.next() {
|
let span = match trees.next() {
|
||||||
Some(&tokenstream::TokenTree::Token(Token { kind: token::Colon, span }, _)) => {
|
Some(&tokenstream::TokenTree::Token(
|
||||||
|
Token { kind: token::Colon, span: colon_span },
|
||||||
|
_,
|
||||||
|
)) => {
|
||||||
match trees.next() {
|
match trees.next() {
|
||||||
Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
|
Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
|
||||||
Some((fragment, _)) => {
|
Some((fragment, _)) => {
|
||||||
|
@ -126,10 +129,12 @@ pub(super) fn parse(
|
||||||
}
|
}
|
||||||
_ => token.span,
|
_ => token.span,
|
||||||
},
|
},
|
||||||
tree => tree.map_or(span, tokenstream::TokenTree::span),
|
Some(tree) => tree.span(),
|
||||||
|
None => colon_span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tree => tree.map_or(start_sp, tokenstream::TokenTree::span),
|
Some(tree) => tree.span(),
|
||||||
|
None => start_sp,
|
||||||
};
|
};
|
||||||
|
|
||||||
result.push(TokenTree::MetaVarDecl(span, ident, None));
|
result.push(TokenTree::MetaVarDecl(span, ident, None));
|
||||||
|
@ -176,7 +181,7 @@ fn parse_tree<'a>(
|
||||||
// Depending on what `tree` is, we could be parsing different parts of a macro
|
// Depending on what `tree` is, we could be parsing different parts of a macro
|
||||||
match tree {
|
match tree {
|
||||||
// `tree` is a `$` token. Look at the next token in `trees`
|
// `tree` is a `$` token. Look at the next token in `trees`
|
||||||
&tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }, _) => {
|
&tokenstream::TokenTree::Token(Token { kind: token::Dollar, span: dollar_span }, _) => {
|
||||||
// FIXME: Handle `Invisible`-delimited groups in a more systematic way
|
// FIXME: Handle `Invisible`-delimited groups in a more systematic way
|
||||||
// during parsing.
|
// during parsing.
|
||||||
let mut next = outer_trees.next();
|
let mut next = outer_trees.next();
|
||||||
|
@ -209,7 +214,7 @@ fn parse_tree<'a>(
|
||||||
err.emit();
|
err.emit();
|
||||||
// Returns early the same read `$` to avoid spanning
|
// Returns early the same read `$` to avoid spanning
|
||||||
// unrelated diagnostics that could be performed afterwards
|
// unrelated diagnostics that could be performed afterwards
|
||||||
return TokenTree::token(token::Dollar, span);
|
return TokenTree::token(token::Dollar, dollar_span);
|
||||||
}
|
}
|
||||||
Ok(elem) => {
|
Ok(elem) => {
|
||||||
maybe_emit_macro_metavar_expr_feature(
|
maybe_emit_macro_metavar_expr_feature(
|
||||||
|
@ -251,7 +256,7 @@ fn parse_tree<'a>(
|
||||||
// special metavariable that names the crate of the invocation.
|
// special metavariable that names the crate of the invocation.
|
||||||
Some(tokenstream::TokenTree::Token(token, _)) if token.is_ident() => {
|
Some(tokenstream::TokenTree::Token(token, _)) if token.is_ident() => {
|
||||||
let (ident, is_raw) = token.ident().unwrap();
|
let (ident, is_raw) = token.ident().unwrap();
|
||||||
let span = ident.span.with_lo(span.lo());
|
let span = ident.span.with_lo(dollar_span.lo());
|
||||||
if ident.name == kw::Crate && matches!(is_raw, IdentIsRaw::No) {
|
if ident.name == kw::Crate && matches!(is_raw, IdentIsRaw::No) {
|
||||||
TokenTree::token(token::Ident(kw::DollarCrate, is_raw), span)
|
TokenTree::token(token::Ident(kw::DollarCrate, is_raw), span)
|
||||||
} else {
|
} else {
|
||||||
|
@ -260,16 +265,19 @@ fn parse_tree<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// `tree` is followed by another `$`. This is an escaped `$`.
|
// `tree` is followed by another `$`. This is an escaped `$`.
|
||||||
Some(&tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }, _)) => {
|
Some(&tokenstream::TokenTree::Token(
|
||||||
|
Token { kind: token::Dollar, span: dollar_span2 },
|
||||||
|
_,
|
||||||
|
)) => {
|
||||||
if parsing_patterns {
|
if parsing_patterns {
|
||||||
span_dollar_dollar_or_metavar_in_the_lhs_err(
|
span_dollar_dollar_or_metavar_in_the_lhs_err(
|
||||||
sess,
|
sess,
|
||||||
&Token { kind: token::Dollar, span },
|
&Token { kind: token::Dollar, span: dollar_span2 },
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
maybe_emit_macro_metavar_expr_feature(features, sess, span);
|
maybe_emit_macro_metavar_expr_feature(features, sess, dollar_span2);
|
||||||
}
|
}
|
||||||
TokenTree::token(token::Dollar, span)
|
TokenTree::token(token::Dollar, dollar_span2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// `tree` is followed by some other token. This is an error.
|
// `tree` is followed by some other token. This is an error.
|
||||||
|
@ -281,7 +289,7 @@ fn parse_tree<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are no more tokens. Just return the `$` we already have.
|
// There are no more tokens. Just return the `$` we already have.
|
||||||
None => TokenTree::token(token::Dollar, span),
|
None => TokenTree::token(token::Dollar, dollar_span),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -253,8 +253,23 @@ pub(super) fn transcribe<'a>(
|
||||||
mbe::TokenTree::MetaVar(mut sp, mut original_ident) => {
|
mbe::TokenTree::MetaVar(mut sp, mut original_ident) => {
|
||||||
// Find the matched nonterminal from the macro invocation, and use it to replace
|
// Find the matched nonterminal from the macro invocation, and use it to replace
|
||||||
// the meta-var.
|
// the meta-var.
|
||||||
|
//
|
||||||
|
// We use `Spacing::Alone` everywhere here, because that's the conservative choice
|
||||||
|
// and spacing of declarative macros is tricky. E.g. in this macro:
|
||||||
|
// ```
|
||||||
|
// macro_rules! idents {
|
||||||
|
// ($($a:ident,)*) => { stringify!($($a)*) }
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
// `$a` has no whitespace after it and will be marked `JointHidden`. If you then
|
||||||
|
// call `idents!(x,y,z,)`, each of `x`, `y`, and `z` will be marked as `Joint`. So
|
||||||
|
// if you choose to use `$x`'s spacing or the identifier's spacing, you'll end up
|
||||||
|
// producing "xyz", which is bad because it effectively merges tokens.
|
||||||
|
// `Spacing::Alone` is the safer option. Fortunately, `space_between` will avoid
|
||||||
|
// some of the unnecessary whitespace.
|
||||||
let ident = MacroRulesNormalizedIdent::new(original_ident);
|
let ident = MacroRulesNormalizedIdent::new(original_ident);
|
||||||
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
|
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
|
||||||
|
// njn: explain the use of alone here
|
||||||
let tt = match cur_matched {
|
let tt = match cur_matched {
|
||||||
MatchedSingle(ParseNtResult::Tt(tt)) => {
|
MatchedSingle(ParseNtResult::Tt(tt)) => {
|
||||||
// `tt`s are emitted into the output stream directly as "raw tokens",
|
// `tt`s are emitted into the output stream directly as "raw tokens",
|
||||||
|
|
|
@ -309,10 +309,10 @@ impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>>
|
||||||
use rustc_ast::token::*;
|
use rustc_ast::token::*;
|
||||||
|
|
||||||
// The code below is conservative, using `token_alone`/`Spacing::Alone`
|
// The code below is conservative, using `token_alone`/`Spacing::Alone`
|
||||||
// in most places. When the resulting code is pretty-printed by
|
// in most places. It's hard in general to do better when working at
|
||||||
// `print_tts` it ends up with spaces between most tokens, which is
|
// the token level. When the resulting code is pretty-printed by
|
||||||
// safe but ugly. It's hard in general to do better when working at the
|
// `print_tts` the `space_between` function helps avoid a lot of
|
||||||
// token level.
|
// unnecessary whitespace, so the results aren't too bad.
|
||||||
let (tree, rustc) = self;
|
let (tree, rustc) = self;
|
||||||
match tree {
|
match tree {
|
||||||
TokenTree::Punct(Punct { ch, joint, span }) => {
|
TokenTree::Punct(Punct { ch, joint, span }) => {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//!
|
//!
|
||||||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
|
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
|
||||||
|
|
||||||
use rustc_ast::visit::walk_list;
|
use rustc_ast::visit::visit_opt;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
@ -168,7 +168,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
|
||||||
hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement),
|
hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
walk_list!(visitor, visit_expr, &blk.expr);
|
visit_opt!(visitor, visit_expr, &blk.expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitor.cx = prev_cx;
|
visitor.cx = prev_cx;
|
||||||
|
|
|
@ -173,7 +173,10 @@ pub(super) fn note_and_explain_region<'tcx>(
|
||||||
|
|
||||||
ty::ReError(_) => return,
|
ty::ReError(_) => return,
|
||||||
|
|
||||||
ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => {
|
// FIXME(#125431): `ReVar` shouldn't reach here.
|
||||||
|
ty::ReVar(_) => (format!("lifetime `{region}`"), alt_span),
|
||||||
|
|
||||||
|
ty::ReBound(..) | ty::ReErased => {
|
||||||
bug!("unexpected region for note_and_explain_region: {:?}", region);
|
bug!("unexpected region for note_and_explain_region: {:?}", region);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -263,7 +263,7 @@ lint_extern_without_abi = extern declarations without an explicit ABI are deprec
|
||||||
.help = the default ABI is {$default_abi}
|
.help = the default ABI is {$default_abi}
|
||||||
|
|
||||||
lint_for_loops_over_fallibles =
|
lint_for_loops_over_fallibles =
|
||||||
for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement
|
for loop over {$article} `{$ref_prefix}{$ty}`. This is more readably written as an `if let` statement
|
||||||
.suggestion = consider using `if let` to clear intent
|
.suggestion = consider using `if let` to clear intent
|
||||||
.remove_next = to iterate over `{$recv_snip}` remove the call to `next`
|
.remove_next = to iterate over `{$recv_snip}` remove the call to `next`
|
||||||
.use_while_let = to check pattern in a loop use `while let`
|
.use_while_let = to check pattern in a loop use `while let`
|
||||||
|
|
|
@ -52,14 +52,27 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
|
||||||
|
|
||||||
let ty = cx.typeck_results().expr_ty(arg);
|
let ty = cx.typeck_results().expr_ty(arg);
|
||||||
|
|
||||||
let &ty::Adt(adt, args) = ty.kind() else { return };
|
let (adt, args, ref_mutability) = match ty.kind() {
|
||||||
|
&ty::Adt(adt, args) => (adt, args, None),
|
||||||
|
&ty::Ref(_, ty, mutability) => match ty.kind() {
|
||||||
|
&ty::Adt(adt, args) => (adt, args, Some(mutability)),
|
||||||
|
_ => return,
|
||||||
|
},
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
let (article, ty, var) = match adt.did() {
|
let (article, ty, var) = match adt.did() {
|
||||||
|
did if cx.tcx.is_diagnostic_item(sym::Option, did) && ref_mutability.is_some() => ("a", "Option", "Some"),
|
||||||
did if cx.tcx.is_diagnostic_item(sym::Option, did) => ("an", "Option", "Some"),
|
did if cx.tcx.is_diagnostic_item(sym::Option, did) => ("an", "Option", "Some"),
|
||||||
did if cx.tcx.is_diagnostic_item(sym::Result, did) => ("a", "Result", "Ok"),
|
did if cx.tcx.is_diagnostic_item(sym::Result, did) => ("a", "Result", "Ok"),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let ref_prefix = match ref_mutability {
|
||||||
|
None => "",
|
||||||
|
Some(ref_mutability) => ref_mutability.ref_prefix_str(),
|
||||||
|
};
|
||||||
|
|
||||||
let sub = if let Some(recv) = extract_iterator_next_call(cx, arg)
|
let sub = if let Some(recv) = extract_iterator_next_call(cx, arg)
|
||||||
&& let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
|
&& let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
|
||||||
{
|
{
|
||||||
|
@ -85,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
|
||||||
cx.emit_span_lint(
|
cx.emit_span_lint(
|
||||||
FOR_LOOPS_OVER_FALLIBLES,
|
FOR_LOOPS_OVER_FALLIBLES,
|
||||||
arg.span,
|
arg.span,
|
||||||
ForLoopsOverFalliblesDiag { article, ty, sub, question_mark, suggestion },
|
ForLoopsOverFalliblesDiag { article, ref_prefix, ty, sub, question_mark, suggestion },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -620,6 +620,7 @@ pub enum PtrNullChecksDiag<'a> {
|
||||||
#[diag(lint_for_loops_over_fallibles)]
|
#[diag(lint_for_loops_over_fallibles)]
|
||||||
pub struct ForLoopsOverFalliblesDiag<'a> {
|
pub struct ForLoopsOverFalliblesDiag<'a> {
|
||||||
pub article: &'static str,
|
pub article: &'static str,
|
||||||
|
pub ref_prefix: &'static str,
|
||||||
pub ty: &'static str,
|
pub ty: &'static str,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub sub: ForLoopsOverFalliblesLoopSub<'a>,
|
pub sub: ForLoopsOverFalliblesLoopSub<'a>,
|
||||||
|
|
|
@ -925,7 +925,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
for subpattern in prefix.iter() {
|
for subpattern in prefix.iter() {
|
||||||
self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
|
self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
|
||||||
}
|
}
|
||||||
for subpattern in slice {
|
if let Some(subpattern) = slice {
|
||||||
self.visit_primary_bindings(
|
self.visit_primary_bindings(
|
||||||
subpattern,
|
subpattern,
|
||||||
pattern_user_ty.clone().subslice(from, to),
|
pattern_user_ty.clone().subslice(from, to),
|
||||||
|
|
|
@ -1100,7 +1100,7 @@ pub struct BreakInsideCoroutine<'a> {
|
||||||
pub struct OutsideLoop<'a> {
|
pub struct OutsideLoop<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label]
|
#[label]
|
||||||
pub span: Span,
|
pub spans: Vec<Span>,
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
pub is_break: bool,
|
pub is_break: bool,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
|
@ -1112,7 +1112,7 @@ pub struct OutsideLoopSuggestion {
|
||||||
#[suggestion_part(code = "'block: ")]
|
#[suggestion_part(code = "'block: ")]
|
||||||
pub block_span: Span,
|
pub block_span: Span,
|
||||||
#[suggestion_part(code = " 'block")]
|
#[suggestion_part(code = " 'block")]
|
||||||
pub break_span: Span,
|
pub break_spans: Vec<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::fmt;
|
||||||
use Context::*;
|
use Context::*;
|
||||||
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -25,22 +27,55 @@ enum Context {
|
||||||
Closure(Span),
|
Closure(Span),
|
||||||
Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource },
|
Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource },
|
||||||
UnlabeledBlock(Span),
|
UnlabeledBlock(Span),
|
||||||
|
UnlabeledIfBlock(Span),
|
||||||
LabeledBlock,
|
LabeledBlock,
|
||||||
Constant,
|
Constant,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Clone)]
|
||||||
|
struct BlockInfo {
|
||||||
|
name: String,
|
||||||
|
spans: Vec<Span>,
|
||||||
|
suggs: Vec<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
enum BreakContextKind {
|
||||||
|
Break,
|
||||||
|
Continue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BreakContextKind {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
BreakContextKind::Break => "break",
|
||||||
|
BreakContextKind::Continue => "continue",
|
||||||
|
}
|
||||||
|
.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct CheckLoopVisitor<'a, 'tcx> {
|
struct CheckLoopVisitor<'a, 'tcx> {
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
cx: Context,
|
// Keep track of a stack of contexts, so that suggestions
|
||||||
|
// are not made for contexts where it would be incorrect,
|
||||||
|
// such as adding a label for an `if`.
|
||||||
|
// e.g. `if 'foo: {}` would be incorrect.
|
||||||
|
cx_stack: Vec<Context>,
|
||||||
|
block_breaks: BTreeMap<Span, BlockInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
|
fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
|
||||||
tcx.hir().visit_item_likes_in_module(
|
let mut check = CheckLoopVisitor {
|
||||||
module_def_id,
|
sess: tcx.sess,
|
||||||
&mut CheckLoopVisitor { sess: tcx.sess, tcx, cx: Normal },
|
tcx,
|
||||||
);
|
cx_stack: vec![Normal],
|
||||||
|
block_breaks: Default::default(),
|
||||||
|
};
|
||||||
|
tcx.hir().visit_item_likes_in_module(module_def_id, &mut check);
|
||||||
|
check.report_outside_loop_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn provide(providers: &mut Providers) {
|
pub(crate) fn provide(providers: &mut Providers) {
|
||||||
|
@ -83,6 +118,45 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||||
|
|
||||||
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
||||||
match e.kind {
|
match e.kind {
|
||||||
|
hir::ExprKind::If(cond, then, else_opt) => {
|
||||||
|
self.visit_expr(cond);
|
||||||
|
|
||||||
|
let get_block = |ck_loop: &CheckLoopVisitor<'a, 'hir>,
|
||||||
|
expr: &hir::Expr<'hir>|
|
||||||
|
-> Option<&hir::Block<'hir>> {
|
||||||
|
if let hir::ExprKind::Block(b, None) = expr.kind
|
||||||
|
&& matches!(
|
||||||
|
ck_loop.cx_stack.last(),
|
||||||
|
Some(&Normal)
|
||||||
|
| Some(&Constant)
|
||||||
|
| Some(&UnlabeledBlock(_))
|
||||||
|
| Some(&UnlabeledIfBlock(_))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Some(b)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(b) = get_block(self, then) {
|
||||||
|
self.with_context(UnlabeledIfBlock(b.span.shrink_to_lo()), |v| {
|
||||||
|
v.visit_block(b)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.visit_expr(then);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(else_expr) = else_opt {
|
||||||
|
if let Some(b) = get_block(self, else_expr) {
|
||||||
|
self.with_context(UnlabeledIfBlock(b.span.shrink_to_lo()), |v| {
|
||||||
|
v.visit_block(b)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.visit_expr(else_expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
hir::ExprKind::Loop(ref b, _, source, _) => {
|
hir::ExprKind::Loop(ref b, _, source, _) => {
|
||||||
self.with_context(Loop(source), |v| v.visit_block(b));
|
self.with_context(Loop(source), |v| v.visit_block(b));
|
||||||
}
|
}
|
||||||
|
@ -101,11 +175,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||||
hir::ExprKind::Block(ref b, Some(_label)) => {
|
hir::ExprKind::Block(ref b, Some(_label)) => {
|
||||||
self.with_context(LabeledBlock, |v| v.visit_block(b));
|
self.with_context(LabeledBlock, |v| v.visit_block(b));
|
||||||
}
|
}
|
||||||
hir::ExprKind::Block(ref b, None) if matches!(self.cx, Fn) => {
|
hir::ExprKind::Block(ref b, None) if matches!(self.cx_stack.last(), Some(&Fn)) => {
|
||||||
self.with_context(Normal, |v| v.visit_block(b));
|
self.with_context(Normal, |v| v.visit_block(b));
|
||||||
}
|
}
|
||||||
hir::ExprKind::Block(ref b, None)
|
hir::ExprKind::Block(ref b, None)
|
||||||
if matches!(self.cx, Normal | Constant | UnlabeledBlock(_)) =>
|
if matches!(
|
||||||
|
self.cx_stack.last(),
|
||||||
|
Some(&Normal) | Some(&Constant) | Some(&UnlabeledBlock(_))
|
||||||
|
) =>
|
||||||
{
|
{
|
||||||
self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b));
|
self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b));
|
||||||
}
|
}
|
||||||
|
@ -178,7 +255,12 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||||
Some(label) => sp_lo.with_hi(label.ident.span.hi()),
|
Some(label) => sp_lo.with_hi(label.ident.span.hi()),
|
||||||
None => sp_lo.shrink_to_lo(),
|
None => sp_lo.shrink_to_lo(),
|
||||||
};
|
};
|
||||||
self.require_break_cx("break", e.span, label_sp);
|
self.require_break_cx(
|
||||||
|
BreakContextKind::Break,
|
||||||
|
e.span,
|
||||||
|
label_sp,
|
||||||
|
self.cx_stack.len() - 1,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
hir::ExprKind::Continue(destination) => {
|
hir::ExprKind::Continue(destination) => {
|
||||||
self.require_label_in_labeled_block(e.span, &destination, "continue");
|
self.require_label_in_labeled_block(e.span, &destination, "continue");
|
||||||
|
@ -200,7 +282,12 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||||
}
|
}
|
||||||
Err(_) => {}
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
self.require_break_cx("continue", e.span, e.span)
|
self.require_break_cx(
|
||||||
|
BreakContextKind::Continue,
|
||||||
|
e.span,
|
||||||
|
e.span,
|
||||||
|
self.cx_stack.len() - 1,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_ => intravisit::walk_expr(self, e),
|
_ => intravisit::walk_expr(self, e),
|
||||||
}
|
}
|
||||||
|
@ -212,18 +299,26 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut CheckLoopVisitor<'a, 'hir>),
|
F: FnOnce(&mut CheckLoopVisitor<'a, 'hir>),
|
||||||
{
|
{
|
||||||
let old_cx = self.cx;
|
self.cx_stack.push(cx);
|
||||||
self.cx = cx;
|
|
||||||
f(self);
|
f(self);
|
||||||
self.cx = old_cx;
|
self.cx_stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_break_cx(&self, name: &str, span: Span, break_span: Span) {
|
fn require_break_cx(
|
||||||
let is_break = name == "break";
|
&mut self,
|
||||||
match self.cx {
|
br_cx_kind: BreakContextKind,
|
||||||
|
span: Span,
|
||||||
|
break_span: Span,
|
||||||
|
cx_pos: usize,
|
||||||
|
) {
|
||||||
|
match self.cx_stack[cx_pos] {
|
||||||
LabeledBlock | Loop(_) => {}
|
LabeledBlock | Loop(_) => {}
|
||||||
Closure(closure_span) => {
|
Closure(closure_span) => {
|
||||||
self.sess.dcx().emit_err(BreakInsideClosure { span, closure_span, name });
|
self.sess.dcx().emit_err(BreakInsideClosure {
|
||||||
|
span,
|
||||||
|
closure_span,
|
||||||
|
name: &br_cx_kind.to_string(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Coroutine { coroutine_span, kind, source } => {
|
Coroutine { coroutine_span, kind, source } => {
|
||||||
let kind = match kind {
|
let kind = match kind {
|
||||||
|
@ -239,17 +334,32 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
||||||
self.sess.dcx().emit_err(BreakInsideCoroutine {
|
self.sess.dcx().emit_err(BreakInsideCoroutine {
|
||||||
span,
|
span,
|
||||||
coroutine_span,
|
coroutine_span,
|
||||||
name,
|
name: &br_cx_kind.to_string(),
|
||||||
kind,
|
kind,
|
||||||
source,
|
source,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => {
|
UnlabeledBlock(block_span)
|
||||||
let suggestion = Some(OutsideLoopSuggestion { block_span, break_span });
|
if br_cx_kind == BreakContextKind::Break && block_span.eq_ctxt(break_span) =>
|
||||||
self.sess.dcx().emit_err(OutsideLoop { span, name, is_break, suggestion });
|
{
|
||||||
|
let block = self.block_breaks.entry(block_span).or_insert_with(|| BlockInfo {
|
||||||
|
name: br_cx_kind.to_string(),
|
||||||
|
spans: vec![],
|
||||||
|
suggs: vec![],
|
||||||
|
});
|
||||||
|
block.spans.push(span);
|
||||||
|
block.suggs.push(break_span);
|
||||||
}
|
}
|
||||||
Normal | Constant | Fn | UnlabeledBlock(_) => {
|
UnlabeledIfBlock(_) if br_cx_kind == BreakContextKind::Break => {
|
||||||
self.sess.dcx().emit_err(OutsideLoop { span, name, is_break, suggestion: None });
|
self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1);
|
||||||
|
}
|
||||||
|
Normal | Constant | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) => {
|
||||||
|
self.sess.dcx().emit_err(OutsideLoop {
|
||||||
|
spans: vec![span],
|
||||||
|
name: &br_cx_kind.to_string(),
|
||||||
|
is_break: br_cx_kind == BreakContextKind::Break,
|
||||||
|
suggestion: None,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,7 +371,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
||||||
cf_type: &str,
|
cf_type: &str,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if !span.is_desugaring(DesugaringKind::QuestionMark)
|
if !span.is_desugaring(DesugaringKind::QuestionMark)
|
||||||
&& self.cx == LabeledBlock
|
&& self.cx_stack.last() == Some(&LabeledBlock)
|
||||||
&& label.label.is_none()
|
&& label.label.is_none()
|
||||||
{
|
{
|
||||||
self.sess.dcx().emit_err(UnlabeledInLabeledBlock { span, cf_type });
|
self.sess.dcx().emit_err(UnlabeledInLabeledBlock { span, cf_type });
|
||||||
|
@ -269,4 +379,18 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_outside_loop_error(&mut self) {
|
||||||
|
for (s, block) in &self.block_breaks {
|
||||||
|
self.sess.dcx().emit_err(OutsideLoop {
|
||||||
|
spans: block.spans.clone(),
|
||||||
|
name: &block.name,
|
||||||
|
is_break: true,
|
||||||
|
suggestion: Some(OutsideLoopSuggestion {
|
||||||
|
block_span: *s,
|
||||||
|
break_spans: block.suggs.clone(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
|
||||||
use crate::{ResolutionError, Resolver, Segment, UseError};
|
use crate::{ResolutionError, Resolver, Segment, UseError};
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
|
use rustc_ast::visit::{visit_opt, walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||||
use rustc_errors::{codes::*, Applicability, DiagArgValue, IntoDiagArg, StashKey};
|
use rustc_errors::{codes::*, Applicability, DiagArgValue, IntoDiagArg, StashKey};
|
||||||
|
@ -3280,7 +3280,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
fn resolve_local(&mut self, local: &'ast Local) {
|
fn resolve_local(&mut self, local: &'ast Local) {
|
||||||
debug!("resolving local ({:?})", local);
|
debug!("resolving local ({:?})", local);
|
||||||
// Resolve the type.
|
// Resolve the type.
|
||||||
walk_list!(self, visit_ty, &local.ty);
|
visit_opt!(self, visit_ty, &local.ty);
|
||||||
|
|
||||||
// Resolve the initializer.
|
// Resolve the initializer.
|
||||||
if let Some((init, els)) = local.kind.init_else_opt() {
|
if let Some((init, els)) = local.kind.init_else_opt() {
|
||||||
|
@ -3479,8 +3479,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
fn resolve_arm(&mut self, arm: &'ast Arm) {
|
fn resolve_arm(&mut self, arm: &'ast Arm) {
|
||||||
self.with_rib(ValueNS, RibKind::Normal, |this| {
|
self.with_rib(ValueNS, RibKind::Normal, |this| {
|
||||||
this.resolve_pattern_top(&arm.pat, PatternSource::Match);
|
this.resolve_pattern_top(&arm.pat, PatternSource::Match);
|
||||||
walk_list!(this, visit_expr, &arm.guard);
|
visit_opt!(this, visit_expr, &arm.guard);
|
||||||
walk_list!(this, visit_expr, &arm.body);
|
visit_opt!(this, visit_expr, &arm.body);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::mem::transmute;
|
||||||
use crate::any::Any;
|
use crate::any::Any;
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::marker::PhantomData;
|
use crate::marker::PhantomData;
|
||||||
|
use crate::panic::AssertUnwindSafe;
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
|
|
||||||
/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
|
/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
|
||||||
|
@ -236,7 +237,7 @@ enum ExtData<'a> {
|
||||||
pub struct Context<'a> {
|
pub struct Context<'a> {
|
||||||
waker: &'a Waker,
|
waker: &'a Waker,
|
||||||
local_waker: &'a LocalWaker,
|
local_waker: &'a LocalWaker,
|
||||||
ext: ExtData<'a>,
|
ext: AssertUnwindSafe<ExtData<'a>>,
|
||||||
// Ensure we future-proof against variance changes by forcing
|
// Ensure we future-proof against variance changes by forcing
|
||||||
// the lifetime to be invariant (argument-position lifetimes
|
// the lifetime to be invariant (argument-position lifetimes
|
||||||
// are contravariant while return-position lifetimes are
|
// are contravariant while return-position lifetimes are
|
||||||
|
@ -279,7 +280,9 @@ impl<'a> Context<'a> {
|
||||||
#[unstable(feature = "context_ext", issue = "123392")]
|
#[unstable(feature = "context_ext", issue = "123392")]
|
||||||
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||||
pub const fn ext(&mut self) -> &mut dyn Any {
|
pub const fn ext(&mut self) -> &mut dyn Any {
|
||||||
match &mut self.ext {
|
// FIXME: this field makes Context extra-weird about unwind safety
|
||||||
|
// can we justify AssertUnwindSafe if we stabilize this? do we care?
|
||||||
|
match &mut *self.ext {
|
||||||
ExtData::Some(data) => *data,
|
ExtData::Some(data) => *data,
|
||||||
ExtData::None(unit) => unit,
|
ExtData::None(unit) => unit,
|
||||||
}
|
}
|
||||||
|
@ -353,7 +356,7 @@ impl<'a> ContextBuilder<'a> {
|
||||||
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||||
#[unstable(feature = "context_ext", issue = "123392")]
|
#[unstable(feature = "context_ext", issue = "123392")]
|
||||||
pub const fn from(cx: &'a mut Context<'_>) -> Self {
|
pub const fn from(cx: &'a mut Context<'_>) -> Self {
|
||||||
let ext = match &mut cx.ext {
|
let ext = match &mut *cx.ext {
|
||||||
ExtData::Some(ext) => ExtData::Some(*ext),
|
ExtData::Some(ext) => ExtData::Some(*ext),
|
||||||
ExtData::None(()) => ExtData::None(()),
|
ExtData::None(()) => ExtData::None(()),
|
||||||
};
|
};
|
||||||
|
@ -396,7 +399,7 @@ impl<'a> ContextBuilder<'a> {
|
||||||
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||||
pub const fn build(self) -> Context<'a> {
|
pub const fn build(self) -> Context<'a> {
|
||||||
let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self;
|
let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self;
|
||||||
Context { waker, local_waker, ext, _marker, _marker2 }
|
Context { waker, local_waker, ext: AssertUnwindSafe(ext), _marker, _marker2 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,6 +170,7 @@ pub fn test_iter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(for_loops_over_fallibles)]
|
||||||
pub fn test_iter_mut() {
|
pub fn test_iter_mut() {
|
||||||
let mut ok: Result<isize, &'static str> = Ok(100);
|
let mut ok: Result<isize, &'static str> = Ok(100);
|
||||||
for loc in ok.iter_mut() {
|
for loc in ok.iter_mut() {
|
||||||
|
|
|
@ -282,7 +282,7 @@ fn push_expected_errors(
|
||||||
|
|
||||||
// Add notes for the backtrace
|
// Add notes for the backtrace
|
||||||
for span in primary_spans {
|
for span in primary_spans {
|
||||||
for frame in &span.expansion {
|
if let Some(frame) = &span.expansion {
|
||||||
push_backtrace(expected_errors, frame, file_name);
|
push_backtrace(expected_errors, frame, file_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,7 +315,7 @@ fn push_backtrace(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for previous_expansion in &expansion.span.expansion {
|
if let Some(previous_expansion) = &expansion.span.expansion {
|
||||||
push_backtrace(expected_errors, previous_expansion, file_name);
|
push_backtrace(expected_errors, previous_expansion, file_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,6 @@ run-make/issue-37839/Makefile
|
||||||
run-make/issue-37893/Makefile
|
run-make/issue-37893/Makefile
|
||||||
run-make/issue-38237/Makefile
|
run-make/issue-38237/Makefile
|
||||||
run-make/issue-40535/Makefile
|
run-make/issue-40535/Makefile
|
||||||
run-make/issue-46239/Makefile
|
|
||||||
run-make/issue-47384/Makefile
|
run-make/issue-47384/Makefile
|
||||||
run-make/issue-47551/Makefile
|
run-make/issue-47551/Makefile
|
||||||
run-make/issue-51671/Makefile
|
run-make/issue-51671/Makefile
|
||||||
|
|
21
tests/codegen/noalias-freeze.rs
Normal file
21
tests/codegen/noalias-freeze.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
//@ compile-flags: -Copt-level=1
|
||||||
|
|
||||||
|
// References returned by a Frozen pointer type
|
||||||
|
// could be marked as "noalias", which caused miscompilation errors.
|
||||||
|
// This test runs the most minimal possible code that can reproduce this bug,
|
||||||
|
// and checks that noalias does not appear.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/46239
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
fn project<T>(x: &(T,)) -> &T { &x.0 }
|
||||||
|
|
||||||
|
fn dummy() {}
|
||||||
|
|
||||||
|
// CHECK-LABEL: @foo(
|
||||||
|
// CHECK-NOT: noalias
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn foo() {
|
||||||
|
let f = (dummy as fn(),);
|
||||||
|
(*project(&f))();
|
||||||
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
# ignore-cross-compile
|
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(RUSTC) main.rs -C opt-level=1
|
|
||||||
$(call RUN,main)
|
|
|
@ -1,8 +0,0 @@
|
||||||
fn project<T>(x: &(T,)) -> &T { &x.0 }
|
|
||||||
|
|
||||||
fn dummy() {}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let f = (dummy as fn(),);
|
|
||||||
(*project(&f))();
|
|
||||||
}
|
|
|
@ -11,7 +11,6 @@ fn main() {
|
||||||
|
|
||||||
is_unwindsafe(async {
|
is_unwindsafe(async {
|
||||||
//~^ ERROR the type `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
//~^ ERROR the type `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
||||||
//~| ERROR the type `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
|
|
||||||
use std::ptr::null;
|
use std::ptr::null;
|
||||||
use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
||||||
let waker = unsafe {
|
let waker = unsafe {
|
||||||
|
|
|
@ -6,18 +6,19 @@ LL | is_unwindsafe(async {
|
||||||
| |_____|
|
| |_____|
|
||||||
| ||
|
| ||
|
||||||
LL | ||
|
LL | ||
|
||||||
LL | ||
|
|
||||||
LL | || use std::ptr::null;
|
LL | || use std::ptr::null;
|
||||||
|
LL | || use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
||||||
... ||
|
... ||
|
||||||
LL | || drop(cx_ref);
|
LL | || drop(cx_ref);
|
||||||
LL | || });
|
LL | || });
|
||||||
| ||_____-^ `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
| ||_____-^ `&mut Context<'_>` may not be safely transferred across an unwind boundary
|
||||||
| |_____|
|
| |_____|
|
||||||
| within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`
|
| within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`
|
||||||
|
|
|
|
||||||
= help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}: UnwindSafe`
|
= help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 29:6}: UnwindSafe`
|
||||||
|
= note: `UnwindSafe` is implemented for `&Context<'_>`, but not for `&mut Context<'_>`
|
||||||
note: future does not implement `UnwindSafe` as this value is used across an await
|
note: future does not implement `UnwindSafe` as this value is used across an await
|
||||||
--> $DIR/async-is-unwindsafe.rs:26:18
|
--> $DIR/async-is-unwindsafe.rs:25:18
|
||||||
|
|
|
|
||||||
LL | let cx_ref = &mut cx;
|
LL | let cx_ref = &mut cx;
|
||||||
| ------ has type `&mut Context<'_>` which does not implement `UnwindSafe`
|
| ------ has type `&mut Context<'_>` which does not implement `UnwindSafe`
|
||||||
|
@ -30,38 +31,6 @@ note: required by a bound in `is_unwindsafe`
|
||||||
LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
|
LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
|
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
|
||||||
|
|
||||||
error[E0277]: the type `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
|
error: aborting due to 1 previous error
|
||||||
--> $DIR/async-is-unwindsafe.rs:12:5
|
|
||||||
|
|
|
||||||
LL | is_unwindsafe(async {
|
|
||||||
| _____^_____________-
|
|
||||||
| |_____|
|
|
||||||
| ||
|
|
||||||
LL | ||
|
|
||||||
LL | ||
|
|
||||||
LL | || use std::ptr::null;
|
|
||||||
... ||
|
|
||||||
LL | || drop(cx_ref);
|
|
||||||
LL | || });
|
|
||||||
| ||_____-^ `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
|
|
||||||
| |_____|
|
|
||||||
| within this `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`
|
|
||||||
|
|
|
||||||
= help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}`, the trait `UnwindSafe` is not implemented for `&mut (dyn Any + 'static)`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 30:6}: UnwindSafe`
|
|
||||||
note: future does not implement `UnwindSafe` as this value is used across an await
|
|
||||||
--> $DIR/async-is-unwindsafe.rs:26:18
|
|
||||||
|
|
|
||||||
LL | let mut cx = Context::from_waker(&waker);
|
|
||||||
| ------ has type `Context<'_>` which does not implement `UnwindSafe`
|
|
||||||
...
|
|
||||||
LL | async {}.await; // this needs an inner await point
|
|
||||||
| ^^^^^ await occurs here, with `mut cx` maybe used later
|
|
||||||
note: required by a bound in `is_unwindsafe`
|
|
||||||
--> $DIR/async-is-unwindsafe.rs:3:26
|
|
||||||
|
|
|
||||||
LL | fn is_unwindsafe(_: impl std::panic::UnwindSafe) {}
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
|
14
tests/ui/async-await/context-is-sorta-unwindsafe.rs
Normal file
14
tests/ui/async-await/context-is-sorta-unwindsafe.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
//@ run-pass
|
||||||
|
// Tests against a regression surfaced by crater in https://github.com/rust-lang/rust/issues/125193
|
||||||
|
// Unwind Safety is not a very coherent concept, but we'd prefer no regressions until we kibosh it
|
||||||
|
// and this is an unstable feature anyways sooo...
|
||||||
|
|
||||||
|
use std::panic::UnwindSafe;
|
||||||
|
use std::task::Context;
|
||||||
|
|
||||||
|
fn unwind_safe<T: UnwindSafe>() {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
unwind_safe::<Context<'_>>(); // test UnwindSafe
|
||||||
|
unwind_safe::<&Context<'_>>(); // test RefUnwindSafe
|
||||||
|
}
|
8
tests/ui/inference/note-and-explain-ReVar-124973.rs
Normal file
8
tests/ui/inference/note-and-explain-ReVar-124973.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
//@ edition:2018
|
||||||
|
|
||||||
|
#![feature(c_variadic)]
|
||||||
|
|
||||||
|
async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, ...) {}
|
||||||
|
//~^ ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
|
||||||
|
|
||||||
|
fn main() {}
|
13
tests/ui/inference/note-and-explain-ReVar-124973.stderr
Normal file
13
tests/ui/inference/note-and-explain-ReVar-124973.stderr
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
|
||||||
|
--> $DIR/note-and-explain-ReVar-124973.rs:5:73
|
||||||
|
|
|
||||||
|
LL | async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, ...) {}
|
||||||
|
| ----------------------------------------------------------------------- ^^
|
||||||
|
| |
|
||||||
|
| opaque type defined here
|
||||||
|
|
|
||||||
|
= note: hidden type `{async fn body of multiple_named_lifetimes<'a, 'b>()}` captures lifetime `'_`
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0700`.
|
|
@ -41,3 +41,25 @@ fn _returns_result() -> Result<(), ()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _by_ref() {
|
||||||
|
// Shared refs
|
||||||
|
for _ in &Some(1) {}
|
||||||
|
//~^ WARN for loop over a `&Option`. This is more readably written as an `if let` statement
|
||||||
|
//~| HELP to check pattern in a loop use `while let`
|
||||||
|
//~| HELP consider using `if let` to clear intent
|
||||||
|
for _ in &Ok::<_, ()>(1) {}
|
||||||
|
//~^ WARN for loop over a `&Result`. This is more readably written as an `if let` statement
|
||||||
|
//~| HELP to check pattern in a loop use `while let`
|
||||||
|
//~| HELP consider using `if let` to clear intent
|
||||||
|
|
||||||
|
// Mutable refs
|
||||||
|
for _ in &mut Some(1) {}
|
||||||
|
//~^ WARN for loop over a `&mut Option`. This is more readably written as an `if let` statement
|
||||||
|
//~| HELP to check pattern in a loop use `while let`
|
||||||
|
//~| HELP consider using `if let` to clear intent
|
||||||
|
for _ in &mut Ok::<_, ()>(1) {}
|
||||||
|
//~^ WARN for loop over a `&mut Result`. This is more readably written as an `if let` statement
|
||||||
|
//~| HELP to check pattern in a loop use `while let`
|
||||||
|
//~| HELP consider using `if let` to clear intent
|
||||||
|
}
|
||||||
|
|
|
@ -97,5 +97,65 @@ help: consider using `if let` to clear intent
|
||||||
LL | if let Ok(_) = Ok::<_, ()>([0; 0]) {}
|
LL | if let Ok(_) = Ok::<_, ()>([0; 0]) {}
|
||||||
| ~~~~~~~~~~ ~~~
|
| ~~~~~~~~~~ ~~~
|
||||||
|
|
||||||
warning: 6 warnings emitted
|
warning: for loop over a `&Option`. This is more readably written as an `if let` statement
|
||||||
|
--> $DIR/for_loop_over_fallibles.rs:47:14
|
||||||
|
|
|
||||||
|
LL | for _ in &Some(1) {}
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
help: to check pattern in a loop use `while let`
|
||||||
|
|
|
||||||
|
LL | while let Some(_) = &Some(1) {}
|
||||||
|
| ~~~~~~~~~~~~~~~ ~~~
|
||||||
|
help: consider using `if let` to clear intent
|
||||||
|
|
|
||||||
|
LL | if let Some(_) = &Some(1) {}
|
||||||
|
| ~~~~~~~~~~~~ ~~~
|
||||||
|
|
||||||
|
warning: for loop over a `&Result`. This is more readably written as an `if let` statement
|
||||||
|
--> $DIR/for_loop_over_fallibles.rs:51:14
|
||||||
|
|
|
||||||
|
LL | for _ in &Ok::<_, ()>(1) {}
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: to check pattern in a loop use `while let`
|
||||||
|
|
|
||||||
|
LL | while let Ok(_) = &Ok::<_, ()>(1) {}
|
||||||
|
| ~~~~~~~~~~~~~ ~~~
|
||||||
|
help: consider using `if let` to clear intent
|
||||||
|
|
|
||||||
|
LL | if let Ok(_) = &Ok::<_, ()>(1) {}
|
||||||
|
| ~~~~~~~~~~ ~~~
|
||||||
|
|
||||||
|
warning: for loop over a `&mut Option`. This is more readably written as an `if let` statement
|
||||||
|
--> $DIR/for_loop_over_fallibles.rs:57:14
|
||||||
|
|
|
||||||
|
LL | for _ in &mut Some(1) {}
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: to check pattern in a loop use `while let`
|
||||||
|
|
|
||||||
|
LL | while let Some(_) = &mut Some(1) {}
|
||||||
|
| ~~~~~~~~~~~~~~~ ~~~
|
||||||
|
help: consider using `if let` to clear intent
|
||||||
|
|
|
||||||
|
LL | if let Some(_) = &mut Some(1) {}
|
||||||
|
| ~~~~~~~~~~~~ ~~~
|
||||||
|
|
||||||
|
warning: for loop over a `&mut Result`. This is more readably written as an `if let` statement
|
||||||
|
--> $DIR/for_loop_over_fallibles.rs:61:14
|
||||||
|
|
|
||||||
|
LL | for _ in &mut Ok::<_, ()>(1) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: to check pattern in a loop use `while let`
|
||||||
|
|
|
||||||
|
LL | while let Ok(_) = &mut Ok::<_, ()>(1) {}
|
||||||
|
| ~~~~~~~~~~~~~ ~~~
|
||||||
|
help: consider using `if let` to clear intent
|
||||||
|
|
|
||||||
|
LL | if let Ok(_) = &mut Ok::<_, ()>(1) {}
|
||||||
|
| ~~~~~~~~~~ ~~~
|
||||||
|
|
||||||
|
warning: 10 warnings emitted
|
||||||
|
|
||||||
|
|
31
tests/ui/loops/loop-if-else-break-issue-123261.fixed
Normal file
31
tests/ui/loops/loop-if-else-break-issue-123261.fixed
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
//@ run-rustfix
|
||||||
|
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let n = 1;
|
||||||
|
let m = 2;
|
||||||
|
let x = 'block: {
|
||||||
|
if n == 0 {
|
||||||
|
break 'block 1; //~ ERROR [E0268]
|
||||||
|
} else {
|
||||||
|
break 'block 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let y = 'block: {
|
||||||
|
if n == 0 {
|
||||||
|
break 'block 1; //~ ERROR [E0268]
|
||||||
|
}
|
||||||
|
break 'block 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
let z = 'block: {
|
||||||
|
if n == 0 {
|
||||||
|
if m > 1 {
|
||||||
|
break 'block 3; //~ ERROR [E0268]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break 'block 1;
|
||||||
|
};
|
||||||
|
}
|
31
tests/ui/loops/loop-if-else-break-issue-123261.rs
Normal file
31
tests/ui/loops/loop-if-else-break-issue-123261.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
//@ run-rustfix
|
||||||
|
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let n = 1;
|
||||||
|
let m = 2;
|
||||||
|
let x = {
|
||||||
|
if n == 0 {
|
||||||
|
break 1; //~ ERROR [E0268]
|
||||||
|
} else {
|
||||||
|
break 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let y = {
|
||||||
|
if n == 0 {
|
||||||
|
break 1; //~ ERROR [E0268]
|
||||||
|
}
|
||||||
|
break 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
let z = {
|
||||||
|
if n == 0 {
|
||||||
|
if m > 1 {
|
||||||
|
break 3; //~ ERROR [E0268]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break 1;
|
||||||
|
};
|
||||||
|
}
|
59
tests/ui/loops/loop-if-else-break-issue-123261.stderr
Normal file
59
tests/ui/loops/loop-if-else-break-issue-123261.stderr
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
error[E0268]: `break` outside of a loop or labeled block
|
||||||
|
--> $DIR/loop-if-else-break-issue-123261.rs:10:13
|
||||||
|
|
|
||||||
|
LL | break 1;
|
||||||
|
| ^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||||
|
LL | } else {
|
||||||
|
LL | break 2;
|
||||||
|
| ^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||||
|
|
|
||||||
|
help: consider labeling this block to be able to break within it
|
||||||
|
|
|
||||||
|
LL ~ let x = 'block: {
|
||||||
|
LL | if n == 0 {
|
||||||
|
LL ~ break 'block 1;
|
||||||
|
LL | } else {
|
||||||
|
LL ~ break 'block 2;
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0268]: `break` outside of a loop or labeled block
|
||||||
|
--> $DIR/loop-if-else-break-issue-123261.rs:18:13
|
||||||
|
|
|
||||||
|
LL | break 1;
|
||||||
|
| ^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||||
|
LL | }
|
||||||
|
LL | break 0;
|
||||||
|
| ^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||||
|
|
|
||||||
|
help: consider labeling this block to be able to break within it
|
||||||
|
|
|
||||||
|
LL ~ let y = 'block: {
|
||||||
|
LL | if n == 0 {
|
||||||
|
LL ~ break 'block 1;
|
||||||
|
LL | }
|
||||||
|
LL ~ break 'block 0;
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0268]: `break` outside of a loop or labeled block
|
||||||
|
--> $DIR/loop-if-else-break-issue-123261.rs:26:17
|
||||||
|
|
|
||||||
|
LL | break 3;
|
||||||
|
| ^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||||
|
...
|
||||||
|
LL | break 1;
|
||||||
|
| ^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||||
|
|
|
||||||
|
help: consider labeling this block to be able to break within it
|
||||||
|
|
|
||||||
|
LL ~ let z = 'block: {
|
||||||
|
LL | if n == 0 {
|
||||||
|
LL | if m > 1 {
|
||||||
|
LL ~ break 'block 3;
|
||||||
|
LL | }
|
||||||
|
LL | }
|
||||||
|
LL ~ break 'block 1;
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0268`.
|
|
@ -21,16 +21,21 @@ LL | foo!(());
|
||||||
= note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error[E0268]: `break` outside of a loop or labeled block
|
error[E0268]: `break` outside of a loop or labeled block
|
||||||
--> $DIR/break-in-unlabeled-block-in-macro.rs:27:19
|
--> $DIR/break-in-unlabeled-block-in-macro.rs:33:17
|
||||||
|
|
|
|
||||||
LL | foo!(stmt break ());
|
LL | foo!(=> break ());
|
||||||
| ^^^^^^^^ cannot `break` outside of a loop or labeled block
|
| ^^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||||
|
|
||||||
|
error[E0268]: `break` outside of a loop or labeled block
|
||||||
|
--> $DIR/break-in-unlabeled-block-in-macro.rs:38:17
|
||||||
|
|
|
|
||||||
help: consider labeling this block to be able to break within it
|
LL | break ()
|
||||||
|
|
| ^^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||||
LL ~ 'block: {
|
...
|
||||||
LL ~ foo!(stmt break 'block ());
|
LL | bar!()
|
||||||
|
| ------ in this macro invocation
|
||||||
|
|
|
|
||||||
|
= note: this error originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error[E0268]: `break` outside of a loop or labeled block
|
error[E0268]: `break` outside of a loop or labeled block
|
||||||
--> $DIR/break-in-unlabeled-block-in-macro.rs:12:11
|
--> $DIR/break-in-unlabeled-block-in-macro.rs:12:11
|
||||||
|
@ -48,21 +53,16 @@ LL | 'block: { break 'block $e; }
|
||||||
| +++++++ ++++++
|
| +++++++ ++++++
|
||||||
|
|
||||||
error[E0268]: `break` outside of a loop or labeled block
|
error[E0268]: `break` outside of a loop or labeled block
|
||||||
--> $DIR/break-in-unlabeled-block-in-macro.rs:33:17
|
--> $DIR/break-in-unlabeled-block-in-macro.rs:27:19
|
||||||
|
|
|
|
||||||
LL | foo!(=> break ());
|
LL | foo!(stmt break ());
|
||||||
| ^^^^^^^^ cannot `break` outside of a loop or labeled block
|
| ^^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||||
|
|
||||||
error[E0268]: `break` outside of a loop or labeled block
|
|
||||||
--> $DIR/break-in-unlabeled-block-in-macro.rs:38:17
|
|
||||||
|
|
|
|
||||||
LL | break ()
|
help: consider labeling this block to be able to break within it
|
||||||
| ^^^^^^^^ cannot `break` outside of a loop or labeled block
|
|
|
||||||
...
|
LL ~ 'block: {
|
||||||
LL | bar!()
|
LL ~ foo!(stmt break 'block ());
|
||||||
| ------ in this macro invocation
|
|
||||||
|
|
|
|
||||||
= note: this error originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info)
|
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
//@ aux-crate:shared=shared.rs
|
||||||
|
|
||||||
|
extern crate shared;
|
||||||
|
|
||||||
|
pub use shared::Shared;
|
||||||
|
|
||||||
|
pub struct SharedInType {
|
||||||
|
pub f: Shared
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
//@ aux-crate:shared=shared.rs
|
||||||
|
|
||||||
|
extern crate shared;
|
||||||
|
|
||||||
|
pub use shared::Shared;
|
||||||
|
|
||||||
|
pub struct SharedInType {
|
||||||
|
pub f: Shared
|
||||||
|
}
|
4
tests/ui/privacy/pub-priv-dep/auxiliary/indirect1.rs
Normal file
4
tests/ui/privacy/pub-priv-dep/auxiliary/indirect1.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
//@ aux-crate:priv:indirect2=indirect2.rs
|
||||||
|
//@ compile-flags: -Zunstable-options
|
||||||
|
|
||||||
|
extern crate indirect2;
|
4
tests/ui/privacy/pub-priv-dep/auxiliary/indirect2.rs
Normal file
4
tests/ui/privacy/pub-priv-dep/auxiliary/indirect2.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
//@ aux-crate:shared=shared.rs
|
||||||
|
|
||||||
|
// This is public.
|
||||||
|
extern crate shared;
|
22
tests/ui/privacy/pub-priv-dep/auxiliary/pm.rs
Normal file
22
tests/ui/privacy/pub-priv-dep/auxiliary/pm.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
//@ force-host
|
||||||
|
//@ no-prefer-dynamic
|
||||||
|
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn fn_like(input: TokenStream) -> TokenStream {
|
||||||
|
"".parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(PmDerive)]
|
||||||
|
pub fn pm_derive(item: TokenStream) -> TokenStream {
|
||||||
|
"".parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn pm_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
"".parse().unwrap()
|
||||||
|
}
|
|
@ -1,2 +1,11 @@
|
||||||
pub struct OtherType;
|
pub struct OtherType;
|
||||||
pub trait OtherTrait {}
|
pub trait OtherTrait {}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! m {
|
||||||
|
() => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum E {
|
||||||
|
V1
|
||||||
|
}
|
||||||
|
|
5
tests/ui/privacy/pub-priv-dep/auxiliary/reexport.rs
Normal file
5
tests/ui/privacy/pub-priv-dep/auxiliary/reexport.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
//@ aux-crate:shared=shared.rs
|
||||||
|
|
||||||
|
extern crate shared;
|
||||||
|
|
||||||
|
pub use shared::Shared;
|
1
tests/ui/privacy/pub-priv-dep/auxiliary/shared.rs
Normal file
1
tests/ui/privacy/pub-priv-dep/auxiliary/shared.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub struct Shared;
|
48
tests/ui/privacy/pub-priv-dep/diamond_deps.rs
Normal file
48
tests/ui/privacy/pub-priv-dep/diamond_deps.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
//@ aux-crate:priv:diamond_priv_dep=diamond_priv_dep.rs
|
||||||
|
//@ aux-crate:diamond_pub_dep=diamond_pub_dep.rs
|
||||||
|
//@ compile-flags: -Zunstable-options
|
||||||
|
|
||||||
|
// A diamond dependency:
|
||||||
|
//
|
||||||
|
// diamond_reepxort
|
||||||
|
// /\
|
||||||
|
// (public) / \ (PRIVATE)
|
||||||
|
// / \
|
||||||
|
// diamond_pub_dep diamond_priv_dep
|
||||||
|
// \ /
|
||||||
|
// (public) \ / (public)
|
||||||
|
// \/
|
||||||
|
// shared
|
||||||
|
//
|
||||||
|
// Where the pub and private crates reexport something from the shared crate.
|
||||||
|
//
|
||||||
|
// Checks the behavior when the same shared item appears in the public API,
|
||||||
|
// depending on whether it comes from the public side or the private side.
|
||||||
|
//
|
||||||
|
// NOTE: compiletest does not support deduplicating shared dependencies.
|
||||||
|
// However, it should work well enough for this test, the only downside is
|
||||||
|
// that diamond_shared gets built twice.
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![deny(exported_private_dependencies)]
|
||||||
|
|
||||||
|
extern crate diamond_priv_dep;
|
||||||
|
extern crate diamond_pub_dep;
|
||||||
|
|
||||||
|
// FIXME: This should trigger.
|
||||||
|
pub fn leaks_priv() -> diamond_priv_dep::Shared {
|
||||||
|
diamond_priv_dep::Shared
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn leaks_pub() -> diamond_pub_dep::Shared {
|
||||||
|
diamond_pub_dep::Shared
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PrivInStruct {
|
||||||
|
pub f: diamond_priv_dep::SharedInType
|
||||||
|
//~^ ERROR type `diamond_priv_dep::SharedInType` from private dependency 'diamond_priv_dep' in public interface
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PubInStruct {
|
||||||
|
pub f: diamond_pub_dep::SharedInType
|
||||||
|
}
|
14
tests/ui/privacy/pub-priv-dep/diamond_deps.stderr
Normal file
14
tests/ui/privacy/pub-priv-dep/diamond_deps.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error: type `diamond_priv_dep::SharedInType` from private dependency 'diamond_priv_dep' in public interface
|
||||||
|
--> $DIR/diamond_deps.rs:42:5
|
||||||
|
|
|
||||||
|
LL | pub f: diamond_priv_dep::SharedInType
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/diamond_deps.rs:27:9
|
||||||
|
|
|
||||||
|
LL | #![deny(exported_private_dependencies)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
//@ aux-crate:priv:priv_dep=priv_dep.rs
|
//@ aux-crate:priv:priv_dep=priv_dep.rs
|
||||||
//@ aux-build:pub_dep.rs
|
//@ aux-build:pub_dep.rs
|
||||||
|
//@ aux-crate:priv:pm=pm.rs
|
||||||
//@ compile-flags: -Zunstable-options
|
//@ compile-flags: -Zunstable-options
|
||||||
|
|
||||||
|
// Basic behavior check of exported_private_dependencies from either a public
|
||||||
|
// dependency or a private one.
|
||||||
|
|
||||||
#![deny(exported_private_dependencies)]
|
#![deny(exported_private_dependencies)]
|
||||||
|
|
||||||
// This crate is a private dependency
|
// This crate is a private dependency
|
||||||
extern crate priv_dep;
|
// FIXME: This should trigger.
|
||||||
|
pub extern crate priv_dep;
|
||||||
// This crate is a public dependency
|
// This crate is a public dependency
|
||||||
extern crate pub_dep;
|
extern crate pub_dep;
|
||||||
|
// This crate is a private dependency
|
||||||
|
extern crate pm;
|
||||||
|
|
||||||
use priv_dep::{OtherTrait, OtherType};
|
use priv_dep::{OtherTrait, OtherType};
|
||||||
use pub_dep::PubType;
|
use pub_dep::PubType;
|
||||||
|
@ -25,7 +33,10 @@ pub struct PublicType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PublicType {
|
impl PublicType {
|
||||||
pub fn pub_fn(param: OtherType) {}
|
pub fn pub_fn_param(param: OtherType) {}
|
||||||
|
//~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
|
||||||
|
pub fn pub_fn_return() -> OtherType { OtherType }
|
||||||
//~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface
|
//~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
|
||||||
fn priv_fn(param: OtherType) {}
|
fn priv_fn(param: OtherType) {}
|
||||||
|
@ -36,9 +47,61 @@ pub trait MyPubTrait {
|
||||||
}
|
}
|
||||||
//~^^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface
|
//~^^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface
|
||||||
|
|
||||||
|
pub trait WithSuperTrait: OtherTrait {}
|
||||||
|
//~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface
|
||||||
|
|
||||||
|
pub trait PubLocalTraitWithAssoc {
|
||||||
|
type X;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PrivateAssoc;
|
||||||
|
impl PubLocalTraitWithAssoc for PrivateAssoc {
|
||||||
|
type X = OtherType;
|
||||||
|
//~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn in_bounds<T: OtherTrait>(x: T) { unimplemented!() }
|
||||||
|
//~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface
|
||||||
|
|
||||||
|
pub fn private_in_generic() -> std::num::Saturating<OtherType> { unimplemented!() }
|
||||||
|
//~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
|
||||||
|
pub static STATIC: OtherType = OtherType;
|
||||||
|
//~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
|
||||||
|
pub const CONST: OtherType = OtherType;
|
||||||
|
//~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
|
||||||
|
pub type Alias = OtherType;
|
||||||
|
//~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
|
||||||
|
pub struct PublicWithPrivateImpl;
|
||||||
|
|
||||||
|
// FIXME: This should trigger.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/71043
|
||||||
|
impl OtherTrait for PublicWithPrivateImpl {}
|
||||||
|
|
||||||
|
pub trait PubTraitOnPrivate {}
|
||||||
|
|
||||||
|
// FIXME: This should trigger.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/71043
|
||||||
|
impl PubTraitOnPrivate for OtherType {}
|
||||||
|
|
||||||
pub struct AllowedPrivType {
|
pub struct AllowedPrivType {
|
||||||
#[allow(exported_private_dependencies)]
|
#[allow(exported_private_dependencies)]
|
||||||
pub allowed: OtherType,
|
pub allowed: OtherType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: This should trigger.
|
||||||
|
pub use priv_dep::m;
|
||||||
|
// FIXME: This should trigger.
|
||||||
|
pub use pm::fn_like;
|
||||||
|
// FIXME: This should trigger.
|
||||||
|
pub use pm::PmDerive;
|
||||||
|
// FIXME: This should trigger.
|
||||||
|
pub use pm::pm_attr;
|
||||||
|
|
||||||
|
// FIXME: This should trigger.
|
||||||
|
pub use priv_dep::E::V1;
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,26 +1,74 @@
|
||||||
error: type `OtherType` from private dependency 'priv_dep' in public interface
|
error: type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
--> $DIR/pub-priv1.rs:21:5
|
--> $DIR/pub-priv1.rs:29:5
|
||||||
|
|
|
|
||||||
LL | pub field: OtherType,
|
LL | pub field: OtherType,
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/pub-priv1.rs:4:9
|
--> $DIR/pub-priv1.rs:9:9
|
||||||
|
|
|
|
||||||
LL | #![deny(exported_private_dependencies)]
|
LL | #![deny(exported_private_dependencies)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: type `OtherType` from private dependency 'priv_dep' in public interface
|
error: type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
--> $DIR/pub-priv1.rs:28:5
|
--> $DIR/pub-priv1.rs:36:5
|
||||||
|
|
|
|
||||||
LL | pub fn pub_fn(param: OtherType) {}
|
LL | pub fn pub_fn_param(param: OtherType) {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
--> $DIR/pub-priv1.rs:39:5
|
||||||
|
|
|
||||||
|
LL | pub fn pub_fn_return() -> OtherType { OtherType }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: trait `OtherTrait` from private dependency 'priv_dep' in public interface
|
error: trait `OtherTrait` from private dependency 'priv_dep' in public interface
|
||||||
--> $DIR/pub-priv1.rs:35:5
|
--> $DIR/pub-priv1.rs:46:5
|
||||||
|
|
|
|
||||||
LL | type Foo: OtherTrait;
|
LL | type Foo: OtherTrait;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: trait `OtherTrait` from private dependency 'priv_dep' in public interface
|
||||||
|
--> $DIR/pub-priv1.rs:50:1
|
||||||
|
|
|
||||||
|
LL | pub trait WithSuperTrait: OtherTrait {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
--> $DIR/pub-priv1.rs:59:5
|
||||||
|
|
|
||||||
|
LL | type X = OtherType;
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: trait `OtherTrait` from private dependency 'priv_dep' in public interface
|
||||||
|
--> $DIR/pub-priv1.rs:63:1
|
||||||
|
|
|
||||||
|
LL | pub fn in_bounds<T: OtherTrait>(x: T) { unimplemented!() }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
--> $DIR/pub-priv1.rs:66:1
|
||||||
|
|
|
||||||
|
LL | pub fn private_in_generic() -> std::num::Saturating<OtherType> { unimplemented!() }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
--> $DIR/pub-priv1.rs:69:1
|
||||||
|
|
|
||||||
|
LL | pub static STATIC: OtherType = OtherType;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
--> $DIR/pub-priv1.rs:72:1
|
||||||
|
|
|
||||||
|
LL | pub const CONST: OtherType = OtherType;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: type `OtherType` from private dependency 'priv_dep' in public interface
|
||||||
|
--> $DIR/pub-priv1.rs:75:1
|
||||||
|
|
|
||||||
|
LL | pub type Alias = OtherType;
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 11 previous errors
|
||||||
|
|
||||||
|
|
15
tests/ui/privacy/pub-priv-dep/reexport_from_priv.rs
Normal file
15
tests/ui/privacy/pub-priv-dep/reexport_from_priv.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//@ aux-crate:priv:reexport=reexport.rs
|
||||||
|
//@ compile-flags: -Zunstable-options
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
// Checks the behavior of a reexported item from a private dependency.
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![deny(exported_private_dependencies)]
|
||||||
|
|
||||||
|
extern crate reexport;
|
||||||
|
|
||||||
|
// FIXME: This should trigger.
|
||||||
|
pub fn leaks_priv() -> reexport::Shared {
|
||||||
|
reexport::Shared
|
||||||
|
}
|
32
tests/ui/privacy/pub-priv-dep/shared_both_private.rs
Normal file
32
tests/ui/privacy/pub-priv-dep/shared_both_private.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
//@ aux-crate:priv:shared=shared.rs
|
||||||
|
//@ aux-crate:reexport=reexport.rs
|
||||||
|
//@ compile-flags: -Zunstable-options
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
// A shared dependency, where a private dependency reexports a public dependency.
|
||||||
|
//
|
||||||
|
// shared_both_private
|
||||||
|
// /\
|
||||||
|
// (PRIVATE) / | (PRIVATE)
|
||||||
|
// / |
|
||||||
|
// reexport |
|
||||||
|
// \ |
|
||||||
|
// (public) \ /
|
||||||
|
// \/
|
||||||
|
// shared
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![deny(exported_private_dependencies)]
|
||||||
|
|
||||||
|
extern crate shared;
|
||||||
|
extern crate reexport;
|
||||||
|
|
||||||
|
// FIXME: This should trigger.
|
||||||
|
pub fn leaks_priv() -> shared::Shared {
|
||||||
|
shared::Shared
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: This should trigger.
|
||||||
|
pub fn leaks_priv_reexport() -> reexport::Shared {
|
||||||
|
reexport::Shared
|
||||||
|
}
|
39
tests/ui/privacy/pub-priv-dep/shared_direct_private.rs
Normal file
39
tests/ui/privacy/pub-priv-dep/shared_direct_private.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
//@ aux-crate:priv:shared=shared.rs
|
||||||
|
//@ aux-crate:reexport=reexport.rs
|
||||||
|
//@ compile-flags: -Zunstable-options
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
// A shared dependency, where the public side reexports the same item as a
|
||||||
|
// direct private dependency.
|
||||||
|
//
|
||||||
|
// shared_direct_private
|
||||||
|
// /\
|
||||||
|
// (public) / | (PRIVATE)
|
||||||
|
// / |
|
||||||
|
// reexport |
|
||||||
|
// \ |
|
||||||
|
// (public) \ /
|
||||||
|
// \/
|
||||||
|
// shared
|
||||||
|
//
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![deny(exported_private_dependencies)]
|
||||||
|
|
||||||
|
extern crate shared;
|
||||||
|
extern crate reexport;
|
||||||
|
|
||||||
|
// FIXME: Should this trigger?
|
||||||
|
//
|
||||||
|
// One could make an argument that I said I want "reexport" to be public, and
|
||||||
|
// since "reexport" says "shared_direct_private" is public, then it should
|
||||||
|
// transitively be public for me. However, as written, this is explicitly
|
||||||
|
// referring to a dependency that is marked "private", which I think is
|
||||||
|
// confusing.
|
||||||
|
pub fn leaks_priv() -> shared::Shared {
|
||||||
|
shared::Shared
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn leaks_pub() -> reexport::Shared {
|
||||||
|
reexport::Shared
|
||||||
|
}
|
29
tests/ui/privacy/pub-priv-dep/shared_indirect.rs
Normal file
29
tests/ui/privacy/pub-priv-dep/shared_indirect.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//@ aux-crate:priv:shared=shared.rs
|
||||||
|
//@ aux-crate:priv:indirect1=indirect1.rs
|
||||||
|
//@ compile-flags: -Zunstable-options
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
// A shared dependency, where it is only indirectly public.
|
||||||
|
//
|
||||||
|
// shared_indirect
|
||||||
|
// /\
|
||||||
|
// (PRIVATE) / | (PRIVATE)
|
||||||
|
// / |
|
||||||
|
// indirect1 | |
|
||||||
|
// (PRIVATE) | |
|
||||||
|
// indirect2 | |
|
||||||
|
// \ |
|
||||||
|
// (public) \ /
|
||||||
|
// \/
|
||||||
|
// shared
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![deny(exported_private_dependencies)]
|
||||||
|
|
||||||
|
extern crate shared;
|
||||||
|
extern crate indirect1;
|
||||||
|
|
||||||
|
// FIXME: This should trigger.
|
||||||
|
pub fn leaks_priv() -> shared::Shared {
|
||||||
|
shared::Shared
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue