Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add check for doc alias attribute at crate level #76329

Merged
merged 6 commits into from
Oct 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_hir/src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ use crate::{Item, ItemKind, TraitItem, TraitItemKind};

use std::fmt::{self, Display};

#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum MethodKind {
Trait { body: bool },
Inherent,
}

#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Target {
ExternCrate,
Use,
Expand Down
56 changes: 53 additions & 3 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ use rustc_errors::{pluralize, struct_span_err};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{self, FnSig, ForeignItem, ForeignItemKind, HirId, Item, ItemKind, TraitItem};
use rustc_hir::{
self, FnSig, ForeignItem, ForeignItemKind, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID,
};
use rustc_hir::{MethodKind, Target};
use rustc_session::lint::builtin::{CONFLICTING_REPR_HINTS, UNUSED_ATTRIBUTES};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{Span, DUMMY_SP};

pub(crate) fn target_from_impl_item<'tcx>(
tcx: TyCtxt<'tcx>,
Expand Down Expand Up @@ -333,6 +335,17 @@ impl CheckAttrVisitor<'tcx> {
.emit();
GuillaumeGomez marked this conversation as resolved.
Show resolved Hide resolved
return false;
}
if CRATE_HIR_ID == hir_id {
self.tcx
.sess
.struct_span_err(
meta.span(),
"`#![doc(alias = \"...\")]` isn't allowed as a crate \
level attribute",
)
.emit();
GuillaumeGomez marked this conversation as resolved.
Show resolved Hide resolved
return false;
}
}
}
}
Expand Down Expand Up @@ -808,9 +821,46 @@ fn is_c_like_enum(item: &Item<'_>) -> bool {
}
}

fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
const ATTRS_TO_CHECK: &[Symbol] = &[
sym::macro_export,
sym::repr,
sym::path,
sym::automatically_derived,
sym::start,
sym::main,
];

for attr in attrs {
for attr_to_check in ATTRS_TO_CHECK {
if tcx.sess.check_name(attr, *attr_to_check) {
tcx.sess
.struct_span_err(
attr.span,
&format!(
"`{}` attribute cannot be used at crate level",
attr_to_check.to_ident_string()
),
)
.emit();
}
}
}
}

fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir()
.visit_item_likes_in_module(module_def_id, &mut CheckAttrVisitor { tcx }.as_deep_visitor());
if module_def_id.is_top_level_module() {
CheckAttrVisitor { tcx }.check_attributes(
CRATE_HIR_ID,
tcx.hir().krate_attrs(),
&DUMMY_SP,
Target::Mod,
None,
);
check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
}
ollie27 marked this conversation as resolved.
Show resolved Hide resolved
}

pub(crate) fn provide(providers: &mut Providers) {
Expand Down
44 changes: 26 additions & 18 deletions compiler/rustc_passes/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,29 +78,38 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)
// Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
// (with `ast::Item`), so make sure to keep them in sync.
fn entry_point_type(sess: &Session, item: &Item<'_>, at_root: bool) -> EntryPointType {
match item.kind {
ItemKind::Fn(..) => {
if sess.contains_name(&item.attrs, sym::start) {
EntryPointType::Start
} else if sess.contains_name(&item.attrs, sym::main) {
EntryPointType::MainAttr
} else if item.ident.name == sym::main {
if at_root {
// This is a top-level function so can be `main`.
EntryPointType::MainNamed
} else {
EntryPointType::OtherMain
}
} else {
EntryPointType::None
}
if sess.contains_name(&item.attrs, sym::start) {
EntryPointType::Start
} else if sess.contains_name(&item.attrs, sym::main) {
EntryPointType::MainAttr
} else if item.ident.name == sym::main {
if at_root {
// This is a top-level function so can be `main`.
EntryPointType::MainNamed
} else {
EntryPointType::OtherMain
}
_ => EntryPointType::None,
} else {
EntryPointType::None
}
}

fn throw_attr_err(sess: &Session, span: Span, attr: &str) {
sess.struct_span_err(span, &format!("`{}` attribute can only be used on functions", attr))
.emit();
}

fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
match entry_point_type(&ctxt.session, item, at_root) {
EntryPointType::None => (),
_ if !matches!(item.kind, ItemKind::Fn(..)) => {
if let Some(attr) = ctxt.session.find_by_name(item.attrs, sym::start) {
throw_attr_err(&ctxt.session, attr.span, "start");
}
if let Some(attr) = ctxt.session.find_by_name(item.attrs, sym::main) {
throw_attr_err(&ctxt.session, attr.span, "main");
}
}
EntryPointType::MainNamed => {
if ctxt.main_fn.is_none() {
ctxt.main_fn = Some((item.hir_id, item.span));
Expand Down Expand Up @@ -137,7 +146,6 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
.emit();
}
}
EntryPointType::None => (),
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_session/src/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ declare_lint! {
/// ### Example
///
/// ```rust
/// #![macro_export]
/// #![ignore]
/// ```
///
/// {{produces}}
Expand Down
6 changes: 6 additions & 0 deletions src/test/rustdoc-ui/doc-alias-crate-level.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#![feature(doc_alias)]

#![doc(alias = "crate-level-not-working")] //~ ERROR

#[doc(alias = "shouldn't work!")] //~ ERROR
pub fn foo() {}
14 changes: 14 additions & 0 deletions src/test/rustdoc-ui/doc-alias-crate-level.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: '\'' character isn't allowed in `#[doc(alias = "...")]`
--> $DIR/doc-alias-crate-level.rs:5:7
|
LL | #[doc(alias = "shouldn't work!")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: `#![doc(alias = "...")]` isn't allowed as a crate level attribute
--> $DIR/doc-alias-crate-level.rs:3:8
|
LL | #![doc(alias = "crate-level-not-working")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

7 changes: 7 additions & 0 deletions src/test/ui/doc-alias-crate-level.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// compile-flags: -Zdeduplicate-diagnostics=no

#![feature(doc_alias)]

#![crate_type = "lib"]

#![doc(alias = "shouldn't work!")] //~ ERROR
8 changes: 8 additions & 0 deletions src/test/ui/doc-alias-crate-level.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: '\'' character isn't allowed in `#[doc(alias = "...")]`
--> $DIR/doc-alias-crate-level.rs:7:8
|
LL | #![doc(alias = "shouldn't work!")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//~ NOTE: not an `extern crate` item
//~^ NOTE: not a function or static
//~^^ NOTE: not a function or closure
// This is testing whether various builtin attributes signals an
// error or warning when put in "weird" places.
//
Expand All @@ -7,9 +10,25 @@

// ignore-tidy-linelength

// Crate-level is accepted, though it is almost certainly unused?
#![macro_export]
//~^ ERROR: `macro_export` attribute cannot be used at crate level
#![main]
//~^ ERROR: `main` attribute cannot be used at crate level
#![start]
//~^ ERROR: `start` attribute cannot be used at crate level
#![repr()]
//~^ ERROR: `repr` attribute cannot be used at crate level
#![path = "3800"]
//~^ ERROR: `path` attribute cannot be used at crate level
#![automatically_derived]
//~^ ERROR: `automatically_derived` attribute cannot be used at crate level
#![no_mangle]
#![no_link]
//~^ ERROR: attribute should be applied to an `extern crate` item
#![export_name = "2200"]
//~^ ERROR: attribute should be applied to a function or static
#![inline]
ollie27 marked this conversation as resolved.
Show resolved Hide resolved

//~^ ERROR: attribute should be applied to function or closure
#[inline]
//~^ ERROR attribute should be applied to function or closure
mod inline {
Expand Down Expand Up @@ -88,4 +107,40 @@ mod export_name {
//~| NOTE not a function or static
}

#[main]
//~^ ERROR: `main` attribute can only be used on functions
mod main {
mod inner { #![main] }
//~^ ERROR: `main` attribute can only be used on functions

// for `fn f()` case, see feature-gate-main.rs

#[main] struct S;
//~^ ERROR: `main` attribute can only be used on functions

#[main] type T = S;
//~^ ERROR: `main` attribute can only be used on functions

#[main] impl S { }
//~^ ERROR: `main` attribute can only be used on functions
}

#[start]
//~^ ERROR: `start` attribute can only be used on functions
mod start {
mod inner { #![start] }
//~^ ERROR: `start` attribute can only be used on functions

// for `fn f()` case, see feature-gate-start.rs

#[start] struct S;
//~^ ERROR: `start` attribute can only be used on functions

#[start] type T = S;
//~^ ERROR: `start` attribute can only be used on functions

#[start] impl S { }
//~^ ERROR: `start` attribute can only be used on functions
}

fn main() {}
Loading