summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-12-14 16:03:44 +0000
committerbors <bors@rust-lang.org>2019-12-14 16:03:44 +0000
commitedff4c8b40c778ab40a74324e750217ff704113a (patch)
treec9f723e9e52b507528620e9edb07101e4accd9a4
parentb509d9b590b1082f01beae1259b3a667751585f3 (diff)
parentc403f6255c9628074a4d413e49ee58e5f3a31a02 (diff)
Auto merge of #67298 - Mark-Simulacrum:beta-backports, r=Mark-Simulacrum
[beta] Beta backports Backporting the following pull requests: * resolve: Always resolve visibilities on impl items #67236 * resolve: Resolve visibilities on fields with non-builtin attributes #67106 * E0023: handle expected != tuple pattern type #67044 * Fix `unused_parens` triggers on macro by example code #66983 * Fix some issues with attributes on unnamed fields #66669 * Ensure that we get a hard error on generic ZST constants if their bodies #67134 (via #67297) Some of these conflicted on merge, I resolved where possible, sometimes by cherry-picking a commit or two more from the relevant PRs. Since those changes are necessary though for backport to proceed (otherwise not even std/core compile), seems fine -- they're fairly minor cleanups anyway.
-rw-r--r--src/librustc/hir/map/def_collector.rs16
-rw-r--r--src/librustc/hir/map/definitions.rs11
-rw-r--r--src/librustc_codegen_ssa/mir/constant.rs5
-rw-r--r--src/librustc_lint/unused.rs4
-rw-r--r--src/librustc_mir/transform/simplify.rs11
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs182
-rw-r--r--src/librustc_resolve/diagnostics.rs40
-rw-r--r--src/librustc_resolve/lib.rs9
-rw-r--r--src/librustc_typeck/check/demand.rs16
-rw-r--r--src/librustc_typeck/check/pat.rs21
-rw-r--r--src/libsyntax_expand/expand.rs22
-rw-r--r--src/libsyntax_expand/placeholders.rs5
-rw-r--r--src/test/ui/attributes/field-attributes-vis-unresolved.rs25
-rw-r--r--src/test/ui/attributes/field-attributes-vis-unresolved.stderr15
-rw-r--r--src/test/ui/attributes/unnamed-field-attributes-dup.rs11
-rw-r--r--src/test/ui/attributes/unnamed-field-attributes-vis.rs11
-rw-r--r--src/test/ui/consts/assoc_const_generic_impl.rs19
-rw-r--r--src/test/ui/consts/assoc_const_generic_impl.stderr22
-rw-r--r--src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs21
-rw-r--r--src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr22
-rw-r--r--src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs3
-rw-r--r--src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr15
-rw-r--r--src/test/ui/lint/lint-unnecessary-parens.rs9
-rw-r--r--src/test/ui/lint/lint-unnecessary-parens.stderr22
-rw-r--r--src/test/ui/resolve/impl-items-vis-unresolved.rs25
-rw-r--r--src/test/ui/resolve/impl-items-vis-unresolved.stderr9
26 files changed, 416 insertions, 155 deletions
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index e9970e30bf9..70dc2248e0f 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -75,15 +75,16 @@ impl<'a> DefCollector<'a> {
}
fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) {
+ let index = |this: &Self| index.unwrap_or_else(|| {
+ let node_id = NodeId::placeholder_from_expn_id(this.expansion);
+ this.definitions.placeholder_field_index(node_id)
+ });
+
if field.is_placeholder {
+ self.definitions.set_placeholder_field_index(field.id, index(self));
self.visit_macro_invoc(field.id);
} else {
- let name = field.ident.map(|ident| ident.name)
- .or_else(|| index.map(sym::integer))
- .unwrap_or_else(|| {
- let node_id = NodeId::placeholder_from_expn_id(self.expansion);
- sym::integer(self.definitions.placeholder_field_indices[&node_id])
- });
+ let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
let def = self.create_def(field.id, DefPathData::ValueNs(name), field.span);
self.with_parent(def, |this| visit::walk_struct_field(this, field));
}
@@ -190,9 +191,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
// and every such attribute expands into a single field after it's resolved.
for (index, field) in data.fields().iter().enumerate() {
self.collect_field(field, Some(index));
- if field.is_placeholder && field.ident.is_none() {
- self.definitions.placeholder_field_indices.insert(field.id, index);
- }
}
}
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index be8d82173e4..450ab947172 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -105,7 +105,7 @@ pub struct Definitions {
/// we know what parent node that fragment should be attached to thanks to this table.
invocation_parents: FxHashMap<ExpnId, DefIndex>,
/// Indices of unnamed struct or variant fields with unresolved attributes.
- pub(super) placeholder_field_indices: NodeMap<usize>,
+ pub placeholder_field_indices: NodeMap<usize>,
}
/// A unique identifier that we can use to lookup a definition
@@ -544,6 +544,15 @@ impl Definitions {
let old_parent = self.invocation_parents.insert(invoc_id, parent);
assert!(old_parent.is_none(), "parent `DefIndex` is reset for an invocation");
}
+
+ pub fn placeholder_field_index(&self, node_id: ast::NodeId) -> usize {
+ self.placeholder_field_indices[&node_id]
+ }
+
+ pub fn set_placeholder_field_index(&mut self, node_id: ast::NodeId, index: usize) {
+ let old_index = self.placeholder_field_indices.insert(node_id, index);
+ assert!(old_index.is_none(), "placeholder field index is reset for a node ID");
+ }
}
impl DefPathData {
diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs
index d06359ab0ce..72d098eb311 100644
--- a/src/librustc_codegen_ssa/mir/constant.rs
+++ b/src/librustc_codegen_ssa/mir/constant.rs
@@ -23,7 +23,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
instance,
promoted: None,
};
- self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid))
+ self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid)).map_err(|err| {
+ self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
+ err
+ })
},
_ => Ok(self.monomorphize(&constant.literal)),
}
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index af43030d0f2..5b29cff9dac 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -374,7 +374,9 @@ impl UnusedParens {
match value.kind {
ast::ExprKind::Paren(ref inner) => {
if !Self::is_expr_parens_necessary(inner, followed_by_block) &&
- value.attrs.is_empty() {
+ value.attrs.is_empty() &&
+ !value.span.from_expansion()
+ {
let expr_text = if let Ok(snippet) = cx.sess().source_map()
.span_to_snippet(value.span) {
snippet
diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs
index 1b90ea78c64..385fc7ed2cd 100644
--- a/src/librustc_mir/transform/simplify.rs
+++ b/src/librustc_mir/transform/simplify.rs
@@ -363,9 +363,14 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> {
let stmt =
&self.body.basic_blocks()[location.block].statements[location.statement_index];
if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(c)))) = &stmt.kind {
- if p.as_local().is_some() {
- trace!("skipping store of const value {:?} to {:?}", c, local);
- return;
+ match c.literal.val {
+ // Keep assignments from unevaluated constants around, since the evaluation
+ // may report errors, even if the use of the constant is dead code.
+ interpret::ConstValue::Unevaluated(..) => {}
+ _ => if p.as_local().is_some() {
+ trace!("skipping store of const value {:?} to {:?}", c, p);
+ return;
+ },
}
}
}
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 648c5104b1a..0a966b252e2 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -11,7 +11,7 @@ use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleIm
use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
use crate::{ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
use crate::Namespace::{self, TypeNS, ValueNS, MacroNS};
-use crate::{ResolutionError, Determinacy, PathResult, CrateLint};
+use crate::{ResolutionError, VisResolutionError, Determinacy, PathResult, CrateLint};
use rustc::bug;
use rustc::hir::def::{self, *};
@@ -34,8 +34,7 @@ use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, Nod
use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind};
use syntax::feature_gate::is_builtin_attr;
use syntax::parse::token::{self, Token};
-use syntax::print::pprust;
-use syntax::{span_err, struct_span_err};
+use syntax::span_err;
use syntax::source_map::{respan, Spanned};
use syntax::symbol::{kw, sym};
use syntax::visit::{self, Visitor};
@@ -194,14 +193,25 @@ impl<'a> AsMut<Resolver<'a>> for BuildReducedGraphVisitor<'a, '_> {
impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
+ self.resolve_visibility_speculative(vis, false).unwrap_or_else(|err| {
+ self.r.report_vis_error(err);
+ ty::Visibility::Public
+ })
+ }
+
+ fn resolve_visibility_speculative<'ast>(
+ &mut self,
+ vis: &'ast ast::Visibility,
+ speculative: bool,
+ ) -> Result<ty::Visibility, VisResolutionError<'ast>> {
let parent_scope = &self.parent_scope;
match vis.node {
- ast::VisibilityKind::Public => ty::Visibility::Public,
+ ast::VisibilityKind::Public => Ok(ty::Visibility::Public),
ast::VisibilityKind::Crate(..) => {
- ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+ Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)))
}
ast::VisibilityKind::Inherited => {
- ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id)
+ Ok(ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id))
}
ast::VisibilityKind::Restricted { ref path, id, .. } => {
// For visibilities we are not ready to provide correct implementation of "uniform
@@ -211,86 +221,67 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
let ident = path.segments.get(0).expect("empty path in visibility").ident;
let crate_root = if ident.is_path_segment_keyword() {
None
- } else if ident.span.rust_2018() {
- let msg = "relative paths are not supported in visibilities on 2018 edition";
- self.r.session.struct_span_err(ident.span, msg)
- .span_suggestion(
- path.span,
- "try",
- format!("crate::{}", pprust::path_to_string(&path)),
- Applicability::MaybeIncorrect,
- )
- .emit();
- return ty::Visibility::Public;
- } else {
- let ctxt = ident.span.ctxt();
+ } else if ident.span.rust_2015() {
Some(Segment::from_ident(Ident::new(
- kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt)
+ kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ident.span.ctxt())
)))
+ } else {
+ return Err(VisResolutionError::Relative2018(ident.span, path));
};
let segments = crate_root.into_iter()
.chain(path.segments.iter().map(|seg| seg.into())).collect::<Vec<_>>();
- let expected_found_error = |this: &Self, res: Res| {
- let path_str = Segment::names_to_string(&segments);
- struct_span_err!(this.r.session, path.span, E0577,
- "expected module, found {} `{}`", res.descr(), path_str)
- .span_label(path.span, "not a module").emit();
- };
+ let expected_found_error = |res| Err(VisResolutionError::ExpectedFound(
+ path.span, Segment::names_to_string(&segments), res
+ ));
match self.r.resolve_path(
&segments,
Some(TypeNS),
parent_scope,
- true,
+ !speculative,
path.span,
CrateLint::SimplePath(id),
) {
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
let res = module.res().expect("visibility resolved to unnamed block");
- self.r.record_partial_res(id, PartialRes::new(res));
+ if !speculative {
+ self.r.record_partial_res(id, PartialRes::new(res));
+ }
if module.is_normal() {
if res == Res::Err {
- ty::Visibility::Public
+ Ok(ty::Visibility::Public)
} else {
let vis = ty::Visibility::Restricted(res.def_id());
if self.r.is_accessible_from(vis, parent_scope.module) {
- vis
+ Ok(vis)
} else {
- struct_span_err!(self.r.session, path.span, E0742,
- "visibilities can only be restricted to ancestor modules")
- .emit();
- ty::Visibility::Public
+ Err(VisResolutionError::AncestorOnly(path.span))
}
}
} else {
- expected_found_error(self, res);
- ty::Visibility::Public
+ expected_found_error(res)
}
}
- PathResult::Module(..) => {
- self.r.session.span_err(path.span, "visibility must resolve to a module");
- ty::Visibility::Public
- }
- PathResult::NonModule(partial_res) => {
- expected_found_error(self, partial_res.base_res());
- ty::Visibility::Public
- }
- PathResult::Failed { span, label, suggestion, .. } => {
- self.r.report_error(
- span, ResolutionError::FailedToResolve { label, suggestion }
- );
- ty::Visibility::Public
- }
- PathResult::Indeterminate => {
- span_err!(self.r.session, path.span, E0578,
- "cannot determine resolution for the visibility");
- ty::Visibility::Public
- }
+ PathResult::Module(..) =>
+ Err(VisResolutionError::ModuleOnly(path.span)),
+ PathResult::NonModule(partial_res) =>
+ expected_found_error(partial_res.base_res()),
+ PathResult::Failed { span, label, suggestion, .. } =>
+ Err(VisResolutionError::FailedToResolve(span, label, suggestion)),
+ PathResult::Indeterminate =>
+ Err(VisResolutionError::Indeterminate(path.span)),
}
}
}
}
+ fn insert_field_names_local(&mut self, def_id: DefId, vdata: &ast::VariantData) {
+ let field_names = vdata.fields().iter().map(|field| {
+ respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name))
+ }).collect();
+ self.insert_field_names(def_id, field_names);
+ }
+
fn insert_field_names(&mut self, def_id: DefId, field_names: Vec<Spanned<Name>>) {
if !field_names.is_empty() {
self.r.field_names.insert(def_id, field_names);
@@ -658,8 +649,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
self.r.define(parent, ident, TypeNS, imported_binding);
}
- ItemKind::GlobalAsm(..) => {}
-
ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root
ItemKind::Mod(..) => {
@@ -678,9 +667,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
self.parent_scope.module = module;
}
- // Handled in `rustc_metadata::{native_libs,link_args}`
- ItemKind::ForeignMod(..) => {}
-
// These items live in the value namespace.
ItemKind::Static(..) => {
let res = Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id));
@@ -729,62 +715,52 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
}
// These items live in both the type and value namespaces.
- ItemKind::Struct(ref struct_def, _) => {
+ ItemKind::Struct(ref vdata, _) => {
// Define a name in the type namespace.
let def_id = self.r.definitions.local_def_id(item.id);
let res = Res::Def(DefKind::Struct, def_id);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
- let mut ctor_vis = vis;
-
- let has_non_exhaustive = attr::contains_name(&item.attrs, sym::non_exhaustive);
-
- // If the structure is marked as non_exhaustive then lower the visibility
- // to within the crate.
- if has_non_exhaustive && vis == ty::Visibility::Public {
- ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
- }
-
// Record field names for error reporting.
- let field_names = struct_def.fields().iter().map(|field| {
- let field_vis = self.resolve_visibility(&field.vis);
- if ctor_vis.is_at_least(field_vis, &*self.r) {
- ctor_vis = field_vis;
- }
- respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name))
- }).collect();
- let item_def_id = self.r.definitions.local_def_id(item.id);
- self.insert_field_names(item_def_id, field_names);
+ self.insert_field_names_local(def_id, vdata);
// If this is a tuple or unit struct, define a name
// in the value namespace as well.
- if let Some(ctor_node_id) = struct_def.ctor_id() {
+ if let Some(ctor_node_id) = vdata.ctor_id() {
+ let mut ctor_vis = vis;
+ // If the structure is marked as non_exhaustive then lower the visibility
+ // to within the crate.
+ if vis == ty::Visibility::Public &&
+ attr::contains_name(&item.attrs, sym::non_exhaustive) {
+ ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
+ }
+ for field in vdata.fields() {
+ // NOTE: The field may be an expansion placeholder, but expansion sets
+ // correct visibilities for unnamed field placeholders specifically, so the
+ // constructor visibility should still be determined correctly.
+ if let Ok(field_vis) =
+ self.resolve_visibility_speculative(&field.vis, true) {
+ if ctor_vis.is_at_least(field_vis, &*self.r) {
+ ctor_vis = field_vis;
+ }
+ }
+ }
let ctor_res = Res::Def(
- DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(struct_def)),
+ DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(vdata)),
self.r.definitions.local_def_id(ctor_node_id),
);
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
- self.r.struct_constructors.insert(res.def_id(), (ctor_res, ctor_vis));
+ self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis));
}
}
ItemKind::Union(ref vdata, _) => {
- let res = Res::Def(DefKind::Union, self.r.definitions.local_def_id(item.id));
+ let def_id = self.r.definitions.local_def_id(item.id);
+ let res = Res::Def(DefKind::Union, def_id);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
// Record field names for error reporting.
- let field_names = vdata.fields().iter().map(|field| {
- self.resolve_visibility(&field.vis);
- respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name))
- }).collect();
- let item_def_id = self.r.definitions.local_def_id(item.id);
- self.insert_field_names(item_def_id, field_names);
- }
-
- ItemKind::Impl(.., ref impl_items) => {
- for impl_item in impl_items {
- self.resolve_visibility(&impl_item.vis);
- }
+ self.insert_field_names_local(def_id, vdata);
}
ItemKind::Trait(..) => {
@@ -801,6 +777,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
self.parent_scope.module = module;
}
+ // These items do not add names to modules.
+ ItemKind::Impl(..) | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
+
ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(),
}
}
@@ -1134,7 +1113,6 @@ macro_rules! method {
}
impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
- method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr);
method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat);
method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty);
@@ -1218,6 +1196,15 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
visit::walk_trait_item(self, item);
}
+ fn visit_impl_item(&mut self, item: &'b ast::ImplItem) {
+ if let ast::ImplItemKind::Macro(..) = item.kind {
+ self.visit_invoc(item.id);
+ } else {
+ self.resolve_visibility(&item.vis);
+ visit::walk_impl_item(self, item);
+ }
+ }
+
fn visit_token(&mut self, t: Token) {
if let token::Interpolated(nt) = t.kind {
if let token::NtExpr(ref expr) = *nt {
@@ -1279,6 +1266,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
if sf.is_placeholder {
self.visit_invoc(sf.id);
} else {
+ self.resolve_visibility(&sf.vis);
visit::walk_struct_field(self, sf);
}
}
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 3d68b72a655..6a8a678da04 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -11,6 +11,7 @@ use rustc::ty::{self, DefIdTree};
use rustc::util::nodemap::FxHashSet;
use syntax::ast::{self, Ident, Path};
use syntax::feature_gate::BUILTIN_ATTRIBUTES;
+use syntax::print::pprust;
use syntax::source_map::SourceMap;
use syntax::struct_span_err;
use syntax::symbol::{Symbol, kw};
@@ -22,6 +23,7 @@ use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportRes
use crate::{path_names_to_string, KNOWN_TOOLS};
use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment};
+use crate::VisResolutionError;
type Res = def::Res<ast::NodeId>;
@@ -355,6 +357,44 @@ impl<'a> Resolver<'a> {
}
}
+ crate fn report_vis_error(&self, vis_resolution_error: VisResolutionError<'_>) {
+ match vis_resolution_error {
+ VisResolutionError::Relative2018(span, path) => {
+ let mut err = self.session.struct_span_err(span,
+ "relative paths are not supported in visibilities on 2018 edition");
+ err.span_suggestion(
+ path.span,
+ "try",
+ format!("crate::{}", pprust::path_to_string(&path)),
+ Applicability::MaybeIncorrect,
+ );
+ err
+ }
+ VisResolutionError::AncestorOnly(span) => {
+ struct_span_err!(self.session, span, E0742,
+ "visibilities can only be restricted to ancestor modules")
+ }
+ VisResolutionError::FailedToResolve(span, label, suggestion) => {
+ self.into_struct_error(
+ span, ResolutionError::FailedToResolve { label, suggestion }
+ )
+ }
+ VisResolutionError::ExpectedFound(span, path_str, res) => {
+ let mut err = struct_span_err!(self.session, span, E0577,
+ "expected module, found {} `{}`", res.descr(), path_str);
+ err.span_label(span, "not a module");
+ err
+ }
+ VisResolutionError::Indeterminate(span) => {
+ struct_span_err!(self.session, span, E0578,
+ "cannot determine resolution for the visibility")
+ }
+ VisResolutionError::ModuleOnly(span) => {
+ self.session.struct_span_err(span, "visibility must resolve to a module")
+ }
+ }.emit()
+ }
+
/// Lookup typo candidate in scope for a macro or import.
fn early_lookup_typo_candidate(
&mut self,
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index b45eb356bdb..49685fe8077 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -218,6 +218,15 @@ enum ResolutionError<'a> {
SelfInTyParamDefault,
}
+enum VisResolutionError<'a> {
+ Relative2018(Span, &'a ast::Path),
+ AncestorOnly(Span),
+ FailedToResolve(Span, String, Option<Suggestion>),
+ ExpectedFound(Span, String, Res),
+ Indeterminate(Span),
+ ModuleOnly(Span),
+}
+
// A minimal representation of a path segment. We use this in resolve because
// we synthesize 'path segments' which don't have the rest of an AST or HIR
// `PathSegment`.
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index b4e07e4a0df..037531515c1 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -65,13 +65,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- pub fn demand_eqtype_pat(
+ pub fn demand_eqtype_pat_diag(
&self,
cause_span: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
match_expr_span: Option<Span>,
- ) {
+ ) -> Option<DiagnosticBuilder<'tcx>> {
let cause = if let Some(span) = match_expr_span {
self.cause(
cause_span,
@@ -80,9 +80,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
self.misc(cause_span)
};
- self.demand_eqtype_with_origin(&cause, expected, actual).map(|mut err| err.emit());
+ self.demand_eqtype_with_origin(&cause, expected, actual)
}
+ pub fn demand_eqtype_pat(
+ &self,
+ cause_span: Span,
+ expected: Ty<'tcx>,
+ actual: Ty<'tcx>,
+ match_expr_span: Option<Span>,
+ ) {
+ self.demand_eqtype_pat_diag(cause_span, expected, actual, match_expr_span)
+ .map(|mut err| err.emit());
+ }
pub fn demand_coerce(&self,
expr: &hir::Expr,
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index 950ae7c1d62..ca2ec1ea449 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -669,7 +669,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let pat_ty = pat_ty.fn_sig(tcx).output();
let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
- self.demand_eqtype_pat(pat.span, expected, pat_ty, match_arm_pat_span);
+ // Type-check the tuple struct pattern against the expected type.
+ let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, match_arm_pat_span);
+ let had_err = diag.is_some();
+ diag.map(|mut err| err.emit());
// Type-check subpatterns.
if subpats.len() == variant.fields.len()
@@ -687,7 +690,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
} else {
// Pattern has wrong number of fields.
- self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected);
+ self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err);
on_error();
return tcx.types.err;
}
@@ -700,8 +703,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
res: Res,
qpath: &hir::QPath,
subpats: &'tcx [P<Pat>],
- fields: &[ty::FieldDef],
- expected: Ty<'tcx>
+ fields: &'tcx [ty::FieldDef],
+ expected: Ty<'tcx>,
+ had_err: bool,
) {
let subpats_ending = pluralise!(subpats.len());
let fields_ending = pluralise!(fields.len());
@@ -729,9 +733,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// More generally, the expected type wants a tuple variant with one field of an
// N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
// with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
- let missing_parenthesis = match expected.kind {
- ty::Adt(_, substs) if fields.len() == 1 => {
- let field_ty = fields[0].ty(self.tcx, substs);
+ let missing_parenthesis = match (&expected.kind, fields, had_err) {
+ // #67037: only do this if we could sucessfully type-check the expected type against
+ // the tuple struct pattern. Otherwise the substs could get out of range on e.g.,
+ // `let P() = U;` where `P != U` with `struct P<T>(T);`.
+ (ty::Adt(_, substs), [field], false) => {
+ let field_ty = self.field_ty(pat_span, field, substs);
match field_ty.kind {
ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
_ => false,
diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs
index bdb50dbfb4f..c96b4a93dbd 100644
--- a/src/libsyntax_expand/expand.rs
+++ b/src/libsyntax_expand/expand.rs
@@ -85,7 +85,7 @@ macro_rules! ast_fragments {
// mention some macro variable from those arguments even if it's not used.
#[cfg_attr(bootstrap, allow(unused_macros))]
macro _repeating($flat_map_ast_elt) {}
- placeholder(AstFragmentKind::$Kind, *id).$make_ast()
+ placeholder(AstFragmentKind::$Kind, *id, None).$make_ast()
})),)?)*
_ => panic!("unexpected AST fragment kind")
}
@@ -274,6 +274,23 @@ pub enum InvocationKind {
},
}
+impl InvocationKind {
+ fn placeholder_visibility(&self) -> Option<ast::Visibility> {
+ // HACK: For unnamed fields placeholders should have the same visibility as the actual
+ // fields because for tuple structs/variants resolve determines visibilities of their
+ // constructor using these field visibilities before attributes on them are are expanded.
+ // The assumption is that the attribute expansion cannot change field visibilities,
+ // and it holds because only inert attributes are supported in this position.
+ match self {
+ InvocationKind::Attr { item: Annotatable::StructField(field), .. } |
+ InvocationKind::Derive { item: Annotatable::StructField(field), .. } |
+ InvocationKind::DeriveContainer { item: Annotatable::StructField(field), .. }
+ if field.ident.is_none() => Some(field.vis.clone()),
+ _ => None,
+ }
+ }
+}
+
impl Invocation {
pub fn span(&self) -> Span {
match &self.kind {
@@ -941,6 +958,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
_ => None,
};
let expn_id = ExpnId::fresh(expn_data);
+ let vis = kind.placeholder_visibility();
self.invocations.push(Invocation {
kind,
fragment_kind,
@@ -950,7 +968,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
..self.cx.current_expansion.clone()
},
});
- placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id))
+ placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis)
}
fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment {
diff --git a/src/libsyntax_expand/placeholders.rs b/src/libsyntax_expand/placeholders.rs
index e595888dae7..2d2c2cbc834 100644
--- a/src/libsyntax_expand/placeholders.rs
+++ b/src/libsyntax_expand/placeholders.rs
@@ -12,7 +12,8 @@ use smallvec::{smallvec, SmallVec};
use rustc_data_structures::fx::FxHashMap;
-pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
+pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId, vis: Option<ast::Visibility>)
+ -> AstFragment {
fn mac_placeholder() -> ast::Mac {
ast::Mac {
path: ast::Path { span: DUMMY_SP, segments: Vec::new() },
@@ -26,7 +27,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
let ident = ast::Ident::invalid();
let attrs = Vec::new();
let generics = ast::Generics::default();
- let vis = dummy_spanned(ast::VisibilityKind::Inherited);
+ let vis = vis.unwrap_or_else(|| dummy_spanned(ast::VisibilityKind::Inherited));
let span = DUMMY_SP;
let expr_placeholder = || P(ast::Expr {
id, span,
diff --git a/src/test/ui/attributes/field-attributes-vis-unresolved.rs b/src/test/ui/attributes/field-attributes-vis-unresolved.rs
new file mode 100644
index 00000000000..d1bd2a1e727
--- /dev/null
+++ b/src/test/ui/attributes/field-attributes-vis-unresolved.rs
@@ -0,0 +1,25 @@
+// Non-builtin attributes do not mess with field visibility resolution (issue #67006).
+
+mod internal {
+ struct S {
+ #[rustfmt::skip]
+ pub(in crate::internal) field: u8 // OK
+ }
+
+ struct Z(
+ #[rustfmt::skip]
+ pub(in crate::internal) u8 // OK
+ );
+}
+
+struct S {
+ #[rustfmt::skip]
+ pub(in nonexistent) field: u8 //~ ERROR failed to resolve
+}
+
+struct Z(
+ #[rustfmt::skip]
+ pub(in nonexistent) u8 //~ ERROR failed to resolve
+);
+
+fn main() {}
diff --git a/src/test/ui/attributes/field-attributes-vis-unresolved.stderr b/src/test/ui/attributes/field-attributes-vis-unresolved.stderr
new file mode 100644
index 00000000000..41c3cea3021
--- /dev/null
+++ b/src/test/ui/attributes/field-attributes-vis-unresolved.stderr
@@ -0,0 +1,15 @@
+error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
+ --> $DIR/field-attributes-vis-unresolved.rs:17:12
+ |
+LL | pub(in nonexistent) field: u8
+ | ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
+
+error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
+ --> $DIR/field-attributes-vis-unresolved.rs:22:12
+ |
+LL | pub(in nonexistent) u8
+ | ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/attributes/unnamed-field-attributes-dup.rs b/src/test/ui/attributes/unnamed-field-attributes-dup.rs
new file mode 100644
index 00000000000..7edfd033794
--- /dev/null
+++ b/src/test/ui/attributes/unnamed-field-attributes-dup.rs
@@ -0,0 +1,11 @@
+// Duplicate non-builtin attributes can be used on unnamed fields.
+
+// check-pass
+
+struct S (
+ #[rustfmt::skip]
+ #[rustfmt::skip]
+ u8
+);
+
+fn main() {}
diff --git a/src/test/ui/attributes/unnamed-field-attributes-vis.rs b/src/test/ui/attributes/unnamed-field-attributes-vis.rs
new file mode 100644
index 00000000000..d12155f6d81
--- /dev/null
+++ b/src/test/ui/attributes/unnamed-field-attributes-vis.rs
@@ -0,0 +1,11 @@
+// Unnamed fields don't lose their visibility due to non-builtin attributes on them.
+
+// check-pass
+
+mod m {
+ pub struct S(#[rustfmt::skip] pub u8);
+}
+
+fn main() {
+ m::S(0);
+}
diff --git a/src/test/ui/consts/assoc_const_generic_impl.rs b/src/test/ui/consts/assoc_const_generic_impl.rs
new file mode 100644
index 00000000000..62702a8ec5c
--- /dev/null
+++ b/src/test/ui/consts/assoc_const_generic_impl.rs
@@ -0,0 +1,19 @@
+#![warn(const_err)]
+
+trait ZeroSized: Sized {
+ const I_AM_ZERO_SIZED: ();
+ fn requires_zero_size(self);
+}
+
+impl<T: Sized> ZeroSized for T {
+ const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::<Self>()]; //~ WARN any use of this value
+ fn requires_zero_size(self) {
+ let () = Self::I_AM_ZERO_SIZED; //~ ERROR erroneous constant encountered
+ println!("requires_zero_size called");
+ }
+}
+
+fn main() {
+ ().requires_zero_size();
+ 42_u32.requires_zero_size();
+}
diff --git a/src/test/ui/consts/assoc_const_generic_impl.stderr b/src/test/ui/consts/assoc_const_generic_impl.stderr
new file mode 100644
index 00000000000..a114d5c6ccd
--- /dev/null
+++ b/src/test/ui/consts/assoc_const_generic_impl.stderr
@@ -0,0 +1,22 @@
+warning: any use of this value will cause an error
+ --> $DIR/assoc_const_generic_impl.rs:9:34
+ |
+LL | const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::<Self>()];
+ | -----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+ | |
+ | index out of bounds: the len is 1 but the index is 4
+ |
+note: lint level defined here
+ --> $DIR/assoc_const_generic_impl.rs:1:9
+ |
+LL | #![warn(const_err)]
+ | ^^^^^^^^^
+
+error: erroneous constant encountered
+ --> $DIR/assoc_const_generic_impl.rs:11:18
+ |
+LL | let () = Self::I_AM_ZERO_SIZED;
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
new file mode 100644
index 00000000000..44bd645598a
--- /dev/null
+++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
@@ -0,0 +1,21 @@
+// Regression test for #67037.
+//
+// In type checking patterns, E0023 occurs when the tuple pattern and the expected
+// tuple pattern have different number of fields. For example, as below, `P()`,
+// the tuple struct pattern, has 0 fields, but requires 1 field.
+//
+// In emitting E0023, we try to see if this is a case of e.g., `Some(a, b, c)` but where
+// the scrutinee was of type `Some((a, b, c))`, and suggest that parenthesis be added.
+//
+// However, we did not account for the expected type being different than the tuple pattern type.
+// This caused an issue when the tuple pattern type (`P<T>`) was generic.
+// Specifically, we tried deriving the 0th field's type using the `substs` of the expected type.
+// When attempting to substitute `T`, there was no such substitution, so "out of range" occured.
+
+struct U {} // 0 type parameters offered
+struct P<T>(T); // 1 type parameter wanted
+
+fn main() {
+ let P() = U {}; //~ ERROR mismatched types
+ //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 1 field
+}
diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
new file mode 100644
index 00000000000..36540820b25
--- /dev/null
+++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+ --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
+ |
+LL | let P() = U {};
+ | ^^^ expected struct `U`, found struct `P`
+ |
+ = note: expected type `U`
+ found type `P<_>`
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 1 field
+ --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
+ |
+LL | struct P<T>(T); // 1 type parameter wanted
+ | --------------- tuple struct defined here
+...
+LL | let P() = U {};
+ | ^^^ expected 1 field, found 0
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0023, E0308.
+For more information about an error, try `rustc --explain E0023`.
diff --git a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs
index 47063a7c267..e36a8468815 100644
--- a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs
+++ b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs
@@ -17,10 +17,7 @@ macro_rules! the_worship_the_heart_lifts_above {
macro_rules! and_the_heavens_reject_not {
() => {
- // ↓ But let's test that we still lint for unused parens around
- // function args inside of simple, one-deep macros.
#[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) }
- //~^ WARN unnecessary parentheses around function argument
}
}
diff --git a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr
deleted file mode 100644
index 57cdcd70e9d..00000000000
--- a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-warning: unnecessary parentheses around function argument
- --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:22:83
- |
-LL | #[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) }
- | ^^^ help: remove these parentheses
-...
-LL | and_the_heavens_reject_not!();
- | ------------------------------ in this macro invocation
- |
-note: lint level defined here
- --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:3:9
- |
-LL | #![warn(unused_parens)]
- | ^^^^^^^^^^^^^
-
diff --git a/src/test/ui/lint/lint-unnecessary-parens.rs b/src/test/ui/lint/lint-unnecessary-parens.rs
index 9f42b855a87..12ffb6d3c66 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.rs
+++ b/src/test/ui/lint/lint-unnecessary-parens.rs
@@ -25,6 +25,12 @@ fn passes_unused_parens_lint() -> &'static (dyn Trait) {
panic!()
}
+macro_rules! baz {
+ ($($foo:expr),+) => {
+ ($($foo),*)
+ }
+}
+
fn main() {
foo();
bar((true)); //~ ERROR unnecessary parentheses around function argument
@@ -55,4 +61,7 @@ fn main() {
let mut _a = (0); //~ ERROR unnecessary parentheses around assigned value
_a = (0); //~ ERROR unnecessary parentheses around assigned value
_a += (1); //~ ERROR unnecessary parentheses around assigned value
+
+ let _a = baz!(3, 4);
+ let _b = baz!(3);
}
diff --git a/src/test/ui/lint/lint-unnecessary-parens.stderr b/src/test/ui/lint/lint-unnecessary-parens.stderr
index adc1069b64d..541ae7aa4b5 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.stderr
+++ b/src/test/ui/lint/lint-unnecessary-parens.stderr
@@ -23,25 +23,25 @@ LL | fn unused_parens_around_return_type() -> (u32) {
| ^^^^^ help: remove these parentheses
error: unnecessary parentheses around function argument
- --> $DIR/lint-unnecessary-parens.rs:30:9
+ --> $DIR/lint-unnecessary-parens.rs:36:9
|
LL | bar((true));
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `if` condition
- --> $DIR/lint-unnecessary-parens.rs:32:8
+ --> $DIR/lint-unnecessary-parens.rs:38:8
|
LL | if (true) {}
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `while` condition
- --> $DIR/lint-unnecessary-parens.rs:33:11
+ --> $DIR/lint-unnecessary-parens.rs:39:11
|
LL | while (true) {}
| ^^^^^^ help: remove these parentheses
warning: denote infinite loops with `loop { ... }`
- --> $DIR/lint-unnecessary-parens.rs:33:5
+ --> $DIR/lint-unnecessary-parens.rs:39:5
|
LL | while (true) {}
| ^^^^^^^^^^^^ help: use `loop`
@@ -49,43 +49,43 @@ LL | while (true) {}
= note: `#[warn(while_true)]` on by default
error: unnecessary parentheses around `match` head expression
- --> $DIR/lint-unnecessary-parens.rs:35:11
+ --> $DIR/lint-unnecessary-parens.rs:41:11
|
LL | match (true) {
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `let` head expression
- --> $DIR/lint-unnecessary-parens.rs:38:16
+ --> $DIR/lint-unnecessary-parens.rs:44:16
|
LL | if let 1 = (1) {}
| ^^^ help: remove these parentheses
error: unnecessary parentheses around `let` head expression
- --> $DIR/lint-unnecessary-parens.rs:39:19
+ --> $DIR/lint-unnecessary-parens.rs:45:19
|
LL | while let 1 = (2) {}
| ^^^ help: remove these parentheses
error: unnecessary parentheses around method argument
- --> $DIR/lint-unnecessary-parens.rs:53:24
+ --> $DIR/lint-unnecessary-parens.rs:59:24
|
LL | X { y: false }.foo((true));
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:55:18
+ --> $DIR/lint-unnecessary-parens.rs:61:18
|
LL | let mut _a = (0);
| ^^^ help: remove these parentheses
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:56:10
+ --> $DIR/lint-unnecessary-parens.rs:62:10
|
LL | _a = (0);
| ^^^ help: remove these parentheses
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:57:11
+ --> $DIR/lint-unnecessary-parens.rs:63:11
|
LL | _a += (1);
| ^^^ help: remove these parentheses
diff --git a/src/test/ui/resolve/impl-items-vis-unresolved.rs b/src/test/ui/resolve/impl-items-vis-unresolved.rs
new file mode 100644
index 00000000000..9b4fe498239
--- /dev/null
+++ b/src/test/ui/resolve/impl-items-vis-unresolved.rs
@@ -0,0 +1,25 @@
+// Visibilities on impl items expanded from macros are resolved (issue #64705).
+
+macro_rules! perftools_inline {
+ ($($item:tt)*) => (
+ $($item)*
+ );
+}
+
+mod state {
+ pub struct RawFloatState;
+ impl RawFloatState {
+ perftools_inline! {
+ pub(super) fn new() {} // OK
+ }
+ }
+}
+
+pub struct RawFloatState;
+impl RawFloatState {
+ perftools_inline! {
+ pub(super) fn new() {} //~ ERROR failed to resolve: there are too many initial `super`s
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/impl-items-vis-unresolved.stderr b/src/test/ui/resolve/impl-items-vis-unresolved.stderr
new file mode 100644
index 00000000000..8e285e53124
--- /dev/null
+++ b/src/test/ui/resolve/impl-items-vis-unresolved.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: there are too many initial `super`s.
+ --> $DIR/impl-items-vis-unresolved.rs:21:13
+ |
+LL | pub(super) fn new() {}
+ | ^^^^^ there are too many initial `super`s.
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.