diff options
| author | Caleb Zulawski <caleb.zulawski@gmail.com> | 2020-06-14 00:47:42 -0400 |
|---|---|---|
| committer | Caleb Zulawski <caleb.zulawski@gmail.com> | 2020-09-05 20:45:43 -0400 |
| commit | 4efe97a3d9a5f2d295bc2fa9bd2bb90edf1986d5 (patch) | |
| tree | ef7b2d81a2d2b0c2f467631d6585a038bd200e1c /compiler | |
| parent | de921ab3c3aa25d65b1476d77285da1ca99af397 (diff) | |
| download | rust-4efe97a3d9a5f2d295bc2fa9bd2bb90edf1986d5.tar.gz rust-4efe97a3d9a5f2d295bc2fa9bd2bb90edf1986d5.zip | |
Check placement of more attributes
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 111 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/collect.rs | 30 |
2 files changed, 116 insertions, 25 deletions
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 392070839dc..037a653e3e0 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -71,6 +71,16 @@ impl CheckAttrVisitor<'tcx> { self.check_track_caller(&attr.span, attrs, span, target) } else if self.tcx.sess.check_name(attr, sym::doc) { self.check_doc_alias(attr, hir_id, target) + } else if self.tcx.sess.check_name(attr, sym::cold) { + self.check_cold(&attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::link_name) { + self.check_link_name(&attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::no_link) { + self.check_no_link(&attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::export_name) { + self.check_export_name(&attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::link_section) { + self.check_link_section(&attr, span, target) } else { true }; @@ -277,6 +287,99 @@ impl CheckAttrVisitor<'tcx> { true } + /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid. + fn check_cold(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Fn | Target::Method(..) | Target::ForeignFn => true, + _ => { + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a function") + .span_label(*span, "not a function") + .emit(); + false + } + } + } + + /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. Returns `true` if valid. + fn check_link_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + if target == Target::ForeignFn || target == Target::ForeignStatic { + true + } else { + let mut err = self.tcx.sess.struct_span_err( + attr.span, + "attribute should be applied to a foreign function or static", + ); + err.span_label(*span, "not a foreign function or static"); + + // See issue #47725 + if target == Target::ForeignMod { + if let Some(value) = attr.value_str() { + err.span_help( + attr.span, + &format!(r#"try `#[link(name = "{}")]` instead"#, value), + ); + } else { + err.span_help(attr.span, r#"try `#[link(name = "...")]` instead"#); + } + } + + err.emit(); + false + } + } + + /// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid. + fn check_no_link(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + if target == Target::ExternCrate { + true + } else { + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to an `extern crate` item") + .span_label(*span, "not an `extern crate` item") + .emit(); + false + } + } + + /// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid. + fn check_export_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Static | Target::Fn | Target::Method(..) => true, + _ => { + self.tcx + .sess + .struct_span_err( + attr.span, + "attribute should be applied to a function or static", + ) + .span_label(*span, "not a function or static") + .emit(); + false + } + } + } + + /// Checks if `#[link_section]` is applied to a function or static. Returns `true` if valid. + fn check_link_section(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Static | Target::Fn | Target::Method(..) => true, + _ => { + self.tcx + .sess + .struct_span_err( + attr.span, + "attribute should be applied to a function or static", + ) + .span_label(*span, "not a function or static") + .emit(); + false + } + } + } + /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr( &self, @@ -421,10 +524,8 @@ impl CheckAttrVisitor<'tcx> { fn check_stmt_attributes(&self, stmt: &hir::Stmt<'_>) { // When checking statements ignore expressions, they will be checked later if let hir::StmtKind::Local(ref l) = stmt.kind { + self.check_attributes(l.hir_id, &l.attrs, &stmt.span, Target::Statement, None); for attr in l.attrs.iter() { - if self.tcx.sess.check_name(attr, sym::inline) { - self.check_inline(l.hir_id, attr, &stmt.span, Target::Statement); - } if self.tcx.sess.check_name(attr, sym::repr) { self.emit_repr_error( attr.span, @@ -442,10 +543,8 @@ impl CheckAttrVisitor<'tcx> { hir::ExprKind::Closure(..) => Target::Closure, _ => Target::Expression, }; + self.check_attributes(expr.hir_id, &expr.attrs, &expr.span, target, None); for attr in expr.attrs.iter() { - if self.tcx.sess.check_name(attr, sym::inline) { - self.check_inline(expr.hir_id, attr, &expr.span, target); - } if self.tcx.sess.check_name(attr, sym::repr) { self.emit_repr_error( attr.span, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 94555e588bd..b316f724349 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2490,10 +2490,17 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.export_name = Some(s); } } else if tcx.sess.check_name(attr, sym::target_feature) { - if !tcx.features().target_feature_11 { - check_target_feature_safe_fn(tcx, id, attr.span); - } else if let Some(local_id) = id.as_local() { - if tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { + if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { + if !tcx.features().target_feature_11 { + let mut err = feature_err( + &tcx.sess.parse_sess, + sym::target_feature_11, + attr.span, + "`#[target_feature(..)]` can only be applied to `unsafe` functions", + ); + err.span_label(tcx.def_span(id), "not an `unsafe` function"); + err.emit(); + } else if let Some(local_id) = id.as_local() { check_target_feature_trait_unsafe(tcx, local_id, attr.span); } } @@ -2750,21 +2757,6 @@ fn check_link_name_xor_ordinal( } } -/// Checks the function annotated with `#[target_feature]` is unsafe, -/// reporting an error if it isn't. -fn check_target_feature_safe_fn(tcx: TyCtxt<'_>, id: DefId, attr_span: Span) { - if tcx.is_closure(id) || tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { - let mut err = feature_err( - &tcx.sess.parse_sess, - sym::target_feature_11, - attr_span, - "`#[target_feature(..)]` can only be applied to `unsafe` functions", - ); - err.span_label(tcx.def_span(id), "not an `unsafe` function"); - err.emit(); - } -} - /// Checks the function annotated with `#[target_feature]` is not a safe /// trait method implementation, reporting an error if it is. fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) { |
