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 {
|
||||
vec![
|
||||
TokenTree::token_joint(token::Pound, span),
|
||||
TokenTree::token_alone(token::Not, span),
|
||||
TokenTree::token_joint_hidden(token::Not, span),
|
||||
body,
|
||||
]
|
||||
} 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) {
|
||||
let mut iter = tts.trees().peekable();
|
||||
while let Some(tt) = iter.next() {
|
||||
let spacing = self.print_tt(tt, convert_dollar_crate);
|
||||
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) {
|
||||
self.space();
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
fn build_panic(&self, expr_str: &str, panic_path: Path) -> P<Expr> {
|
||||
let escaped_expr_str = escape_to_fmt(expr_str);
|
||||
let initial = [
|
||||
TokenTree::token_joint_hidden(
|
||||
TokenTree::token_joint(
|
||||
token::Literal(token::Lit {
|
||||
kind: token::LitKind::Str,
|
||||
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| {
|
||||
[
|
||||
TokenTree::token_joint_hidden(
|
||||
TokenTree::token_joint(
|
||||
token::Ident(cap.ident.name, IdentIsRaw::No),
|
||||
cap.ident.span,
|
||||
),
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::deriving::generic::*;
|
|||
use crate::errors;
|
||||
use core::ops::ControlFlow;
|
||||
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_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||
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_vis(&v.vis);
|
||||
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 {
|
||||
rustc_ast::visit::walk_attribute(self, attr);
|
||||
}
|
||||
|
|
|
@ -799,6 +799,27 @@ fn link_natively(
|
|||
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.
|
||||
// Fallback from '-static-pie' to '-static' in that case.
|
||||
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.
|
||||
#[derive(Debug, PartialEq, Encodable, Decodable)]
|
||||
enum TokenTree {
|
||||
/// A token. Unlike `tokenstream::TokenTree::Token` this lacks a `Spacing`.
|
||||
/// See the comments about `Spacing` in the `transcribe` function.
|
||||
Token(Token),
|
||||
/// A delimited sequence, e.g. `($e:expr)` (RHS) or `{ $e }` (LHS).
|
||||
Delimited(DelimSpan, DelimSpacing, Delimited),
|
||||
/// A kleene-style repetition sequence, e.g. `$($e:expr)*` (RHS) or `$($e),*` (LHS).
|
||||
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),
|
||||
/// e.g., `$var:expr`. Only appears on the LHS.
|
||||
MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
|
||||
|
|
|
@ -62,7 +62,10 @@ pub(super) fn parse(
|
|||
match tree {
|
||||
TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
|
||||
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() {
|
||||
Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
|
||||
Some((fragment, _)) => {
|
||||
|
@ -126,10 +129,12 @@ pub(super) fn parse(
|
|||
}
|
||||
_ => 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));
|
||||
|
@ -176,7 +181,7 @@ fn parse_tree<'a>(
|
|||
// Depending on what `tree` is, we could be parsing different parts of a macro
|
||||
match tree {
|
||||
// `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
|
||||
// during parsing.
|
||||
let mut next = outer_trees.next();
|
||||
|
@ -209,7 +214,7 @@ fn parse_tree<'a>(
|
|||
err.emit();
|
||||
// Returns early the same read `$` to avoid spanning
|
||||
// unrelated diagnostics that could be performed afterwards
|
||||
return TokenTree::token(token::Dollar, span);
|
||||
return TokenTree::token(token::Dollar, dollar_span);
|
||||
}
|
||||
Ok(elem) => {
|
||||
maybe_emit_macro_metavar_expr_feature(
|
||||
|
@ -251,7 +256,7 @@ fn parse_tree<'a>(
|
|||
// special metavariable that names the crate of the invocation.
|
||||
Some(tokenstream::TokenTree::Token(token, _)) if token.is_ident() => {
|
||||
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) {
|
||||
TokenTree::token(token::Ident(kw::DollarCrate, is_raw), span)
|
||||
} else {
|
||||
|
@ -260,16 +265,19 @@ fn parse_tree<'a>(
|
|||
}
|
||||
|
||||
// `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 {
|
||||
span_dollar_dollar_or_metavar_in_the_lhs_err(
|
||||
sess,
|
||||
&Token { kind: token::Dollar, span },
|
||||
&Token { kind: token::Dollar, span: dollar_span2 },
|
||||
);
|
||||
} 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.
|
||||
|
@ -281,7 +289,7 @@ fn parse_tree<'a>(
|
|||
}
|
||||
|
||||
// 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) => {
|
||||
// Find the matched nonterminal from the macro invocation, and use it to replace
|
||||
// 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);
|
||||
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
|
||||
// njn: explain the use of alone here
|
||||
let tt = match cur_matched {
|
||||
MatchedSingle(ParseNtResult::Tt(tt)) => {
|
||||
// `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::*;
|
||||
|
||||
// The code below is conservative, using `token_alone`/`Spacing::Alone`
|
||||
// in most places. When the resulting code is pretty-printed by
|
||||
// `print_tts` it ends up with spaces between most tokens, which is
|
||||
// safe but ugly. It's hard in general to do better when working at the
|
||||
// token level.
|
||||
// in most places. It's hard in general to do better when working at
|
||||
// the token level. When the resulting code is pretty-printed by
|
||||
// `print_tts` the `space_between` function helps avoid a lot of
|
||||
// unnecessary whitespace, so the results aren't too bad.
|
||||
let (tree, rustc) = self;
|
||||
match tree {
|
||||
TokenTree::Punct(Punct { ch, joint, span }) => {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//!
|
||||
//! [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_hir as hir;
|
||||
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),
|
||||
}
|
||||
}
|
||||
walk_list!(visitor, visit_expr, &blk.expr);
|
||||
visit_opt!(visitor, visit_expr, &blk.expr);
|
||||
}
|
||||
|
||||
visitor.cx = prev_cx;
|
||||
|
|
|
@ -173,7 +173,10 @@ pub(super) fn note_and_explain_region<'tcx>(
|
|||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -263,7 +263,7 @@ lint_extern_without_abi = extern declarations without an explicit ABI are deprec
|
|||
.help = the default ABI is {$default_abi}
|
||||
|
||||
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
|
||||
.remove_next = to iterate over `{$recv_snip}` remove the call to `next`
|
||||
.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::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() {
|
||||
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::Result, did) => ("a", "Result", "Ok"),
|
||||
_ => 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 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(
|
||||
FOR_LOOPS_OVER_FALLIBLES,
|
||||
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)]
|
||||
pub struct ForLoopsOverFalliblesDiag<'a> {
|
||||
pub article: &'static str,
|
||||
pub ref_prefix: &'static str,
|
||||
pub ty: &'static str,
|
||||
#[subdiagnostic]
|
||||
pub sub: ForLoopsOverFalliblesLoopSub<'a>,
|
||||
|
|
|
@ -925,7 +925,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
for subpattern in prefix.iter() {
|
||||
self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
|
||||
}
|
||||
for subpattern in slice {
|
||||
if let Some(subpattern) = slice {
|
||||
self.visit_primary_bindings(
|
||||
subpattern,
|
||||
pattern_user_ty.clone().subslice(from, to),
|
||||
|
|
|
@ -1100,7 +1100,7 @@ pub struct BreakInsideCoroutine<'a> {
|
|||
pub struct OutsideLoop<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub spans: Vec<Span>,
|
||||
pub name: &'a str,
|
||||
pub is_break: bool,
|
||||
#[subdiagnostic]
|
||||
|
@ -1112,7 +1112,7 @@ pub struct OutsideLoopSuggestion {
|
|||
#[suggestion_part(code = "'block: ")]
|
||||
pub block_span: Span,
|
||||
#[suggestion_part(code = " 'block")]
|
||||
pub break_span: Span,
|
||||
pub break_spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
use Context::*;
|
||||
|
||||
use rustc_hir as hir;
|
||||
|
@ -25,22 +27,55 @@ enum Context {
|
|||
Closure(Span),
|
||||
Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource },
|
||||
UnlabeledBlock(Span),
|
||||
UnlabeledIfBlock(Span),
|
||||
LabeledBlock,
|
||||
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> {
|
||||
sess: &'a Session,
|
||||
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) {
|
||||
tcx.hir().visit_item_likes_in_module(
|
||||
module_def_id,
|
||||
&mut CheckLoopVisitor { sess: tcx.sess, tcx, cx: Normal },
|
||||
);
|
||||
let mut check = CheckLoopVisitor {
|
||||
sess: tcx.sess,
|
||||
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) {
|
||||
|
@ -83,6 +118,45 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
|||
|
||||
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
||||
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, _) => {
|
||||
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)) => {
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
@ -178,7 +255,12 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
|||
Some(label) => sp_lo.with_hi(label.ident.span.hi()),
|
||||
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) => {
|
||||
self.require_label_in_labeled_block(e.span, &destination, "continue");
|
||||
|
@ -200,7 +282,12 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
|||
}
|
||||
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),
|
||||
}
|
||||
|
@ -212,18 +299,26 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
|||
where
|
||||
F: FnOnce(&mut CheckLoopVisitor<'a, 'hir>),
|
||||
{
|
||||
let old_cx = self.cx;
|
||||
self.cx = cx;
|
||||
self.cx_stack.push(cx);
|
||||
f(self);
|
||||
self.cx = old_cx;
|
||||
self.cx_stack.pop();
|
||||
}
|
||||
|
||||
fn require_break_cx(&self, name: &str, span: Span, break_span: Span) {
|
||||
let is_break = name == "break";
|
||||
match self.cx {
|
||||
fn require_break_cx(
|
||||
&mut self,
|
||||
br_cx_kind: BreakContextKind,
|
||||
span: Span,
|
||||
break_span: Span,
|
||||
cx_pos: usize,
|
||||
) {
|
||||
match self.cx_stack[cx_pos] {
|
||||
LabeledBlock | Loop(_) => {}
|
||||
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 } => {
|
||||
let kind = match kind {
|
||||
|
@ -239,17 +334,32 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
|||
self.sess.dcx().emit_err(BreakInsideCoroutine {
|
||||
span,
|
||||
coroutine_span,
|
||||
name,
|
||||
name: &br_cx_kind.to_string(),
|
||||
kind,
|
||||
source,
|
||||
});
|
||||
}
|
||||
UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => {
|
||||
let suggestion = Some(OutsideLoopSuggestion { block_span, break_span });
|
||||
self.sess.dcx().emit_err(OutsideLoop { span, name, is_break, suggestion });
|
||||
UnlabeledBlock(block_span)
|
||||
if br_cx_kind == BreakContextKind::Break && block_span.eq_ctxt(break_span) =>
|
||||
{
|
||||
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(_) => {
|
||||
self.sess.dcx().emit_err(OutsideLoop { span, name, is_break, suggestion: None });
|
||||
UnlabeledIfBlock(_) if br_cx_kind == BreakContextKind::Break => {
|
||||
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,
|
||||
) -> bool {
|
||||
if !span.is_desugaring(DesugaringKind::QuestionMark)
|
||||
&& self.cx == LabeledBlock
|
||||
&& self.cx_stack.last() == Some(&LabeledBlock)
|
||||
&& label.label.is_none()
|
||||
{
|
||||
self.sess.dcx().emit_err(UnlabeledInLabeledBlock { span, cf_type });
|
||||
|
@ -269,4 +379,18 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
|||
}
|
||||
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 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_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
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) {
|
||||
debug!("resolving local ({:?})", local);
|
||||
// Resolve the type.
|
||||
walk_list!(self, visit_ty, &local.ty);
|
||||
visit_opt!(self, visit_ty, &local.ty);
|
||||
|
||||
// Resolve the initializer.
|
||||
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) {
|
||||
self.with_rib(ValueNS, RibKind::Normal, |this| {
|
||||
this.resolve_pattern_top(&arm.pat, PatternSource::Match);
|
||||
walk_list!(this, visit_expr, &arm.guard);
|
||||
walk_list!(this, visit_expr, &arm.body);
|
||||
visit_opt!(this, visit_expr, &arm.guard);
|
||||
visit_opt!(this, visit_expr, &arm.body);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::mem::transmute;
|
|||
use crate::any::Any;
|
||||
use crate::fmt;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::panic::AssertUnwindSafe;
|
||||
use crate::ptr;
|
||||
|
||||
/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
|
||||
|
@ -236,7 +237,7 @@ enum ExtData<'a> {
|
|||
pub struct Context<'a> {
|
||||
waker: &'a Waker,
|
||||
local_waker: &'a LocalWaker,
|
||||
ext: ExtData<'a>,
|
||||
ext: AssertUnwindSafe<ExtData<'a>>,
|
||||
// Ensure we future-proof against variance changes by forcing
|
||||
// the lifetime to be invariant (argument-position lifetimes
|
||||
// are contravariant while return-position lifetimes are
|
||||
|
@ -279,7 +280,9 @@ impl<'a> Context<'a> {
|
|||
#[unstable(feature = "context_ext", issue = "123392")]
|
||||
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||
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::None(unit) => unit,
|
||||
}
|
||||
|
@ -353,7 +356,7 @@ impl<'a> ContextBuilder<'a> {
|
|||
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||
#[unstable(feature = "context_ext", issue = "123392")]
|
||||
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::None(()) => ExtData::None(()),
|
||||
};
|
||||
|
@ -396,7 +399,7 @@ impl<'a> ContextBuilder<'a> {
|
|||
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
|
||||
pub const fn build(self) -> Context<'a> {
|
||||
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]
|
||||
#[allow(for_loops_over_fallibles)]
|
||||
pub fn test_iter_mut() {
|
||||
let mut ok: Result<isize, &'static str> = Ok(100);
|
||||
for loc in ok.iter_mut() {
|
||||
|
|
|
@ -282,7 +282,7 @@ fn push_expected_errors(
|
|||
|
||||
// Add notes for the backtrace
|
||||
for span in primary_spans {
|
||||
for frame in &span.expansion {
|
||||
if let Some(frame) = &span.expansion {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,6 @@ run-make/issue-37839/Makefile
|
|||
run-make/issue-37893/Makefile
|
||||
run-make/issue-38237/Makefile
|
||||
run-make/issue-40535/Makefile
|
||||
run-make/issue-46239/Makefile
|
||||
run-make/issue-47384/Makefile
|
||||
run-make/issue-47551/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 {
|
||||
//~^ 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::task::{Context, RawWaker, RawWakerVTable, Waker};
|
||||
let waker = unsafe {
|
||||
|
|
|
@ -6,18 +6,19 @@ LL | is_unwindsafe(async {
|
|||
| |_____|
|
||||
| ||
|
||||
LL | ||
|
||||
LL | ||
|
||||
LL | || use std::ptr::null;
|
||||
LL | || use std::task::{Context, RawWaker, RawWakerVTable, Waker};
|
||||
... ||
|
||||
LL | || drop(cx_ref);
|
||||
LL | || });
|
||||
| ||_____-^ `&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
|
||||
--> $DIR/async-is-unwindsafe.rs:26:18
|
||||
--> $DIR/async-is-unwindsafe.rs:25:18
|
||||
|
|
||||
LL | let cx_ref = &mut cx;
|
||||
| ------ 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) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_unwindsafe`
|
||||
|
||||
error[E0277]: the type `&mut (dyn Any + 'static)` may not be safely transferred across an unwind boundary
|
||||
--> $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
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
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]) {}
|
||||
| ~~~~~~~~~~ ~~~
|
||||
|
||||
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)
|
||||
|
||||
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 ());
|
||||
| ^^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||
LL | foo!(=> break ());
|
||||
| ^^^^^^^^ 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 ~ 'block: {
|
||||
LL ~ foo!(stmt break 'block ());
|
||||
LL | break ()
|
||||
| ^^^^^^^^ cannot `break` outside of a loop or labeled 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
|
||||
--> $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
|
||||
--> $DIR/break-in-unlabeled-block-in-macro.rs:33:17
|
||||
--> $DIR/break-in-unlabeled-block-in-macro.rs:27:19
|
||||
|
|
||||
LL | foo!(=> break ());
|
||||
| ^^^^^^^^ 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 | foo!(stmt break ());
|
||||
| ^^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||
|
|
||||
LL | break ()
|
||||
| ^^^^^^^^ cannot `break` outside of a loop or labeled block
|
||||
...
|
||||
LL | bar!()
|
||||
| ------ in this macro invocation
|
||||
help: consider labeling this block to be able to break within it
|
||||
|
|
||||
LL ~ 'block: {
|
||||
LL ~ foo!(stmt break 'block ());
|
||||
|
|
||||
= 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
|
||||
|
||||
|
|
|
@ -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 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-build:pub_dep.rs
|
||||
//@ aux-crate:priv:pm=pm.rs
|
||||
//@ compile-flags: -Zunstable-options
|
||||
|
||||
// Basic behavior check of exported_private_dependencies from either a public
|
||||
// dependency or a private one.
|
||||
|
||||
#![deny(exported_private_dependencies)]
|
||||
|
||||
// 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
|
||||
extern crate pub_dep;
|
||||
// This crate is a private dependency
|
||||
extern crate pm;
|
||||
|
||||
use priv_dep::{OtherTrait, OtherType};
|
||||
use pub_dep::PubType;
|
||||
|
@ -25,7 +33,10 @@ pub struct 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
|
||||
|
||||
fn priv_fn(param: OtherType) {}
|
||||
|
@ -36,9 +47,61 @@ pub trait MyPubTrait {
|
|||
}
|
||||
//~^^ 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 {
|
||||
#[allow(exported_private_dependencies)]
|
||||
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() {}
|
||||
|
|
|
@ -1,26 +1,74 @@
|
|||
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,
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/pub-priv1.rs:4:9
|
||||
--> $DIR/pub-priv1.rs:9:9
|
||||
|
|
||||
LL | #![deny(exported_private_dependencies)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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
|
||||
--> $DIR/pub-priv1.rs:35:5
|
||||
--> $DIR/pub-priv1.rs:46:5
|
||||
|
|
||||
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