about summary refs log tree commit diff
diff options
context:
space:
mode:
authorclubby789 <jamie@hill-daniel.co.uk>2023-02-27 01:32:07 +0000
committerclubby789 <jamie@hill-daniel.co.uk>2023-03-02 02:42:19 +0000
commitd84576955713d223c0c4752dab9111085033c78b (patch)
treea3700bffff00a0eef54566e08082e29a7699b545
parentc4e0cd966062ca67daed20775f4e8a60c28e57df (diff)
downloadrust-d84576955713d223c0c4752dab9111085033c78b.tar.gz
rust-d84576955713d223c0c4752dab9111085033c78b.zip
Restrict `#[rustc_box]` to `Box::new` calls
-rw-r--r--compiler/rustc_ast_lowering/locales/en-US.ftl3
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs12
-rw-r--r--compiler/rustc_mir_build/locales/en-US.ftl6
-rw-r--r--compiler/rustc_mir_build/src/errors.rs19
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs32
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs13
-rw-r--r--tests/ui/attributes/rustc-box.rs18
-rw-r--r--tests/ui/attributes/rustc-box.stderr34
9 files changed, 115 insertions, 29 deletions
diff --git a/compiler/rustc_ast_lowering/locales/en-US.ftl b/compiler/rustc_ast_lowering/locales/en-US.ftl
index a2837deafde..3ccd84398ec 100644
--- a/compiler/rustc_ast_lowering/locales/en-US.ftl
+++ b/compiler/rustc_ast_lowering/locales/en-US.ftl
@@ -22,9 +22,6 @@ ast_lowering_misplaced_impl_trait =
 ast_lowering_misplaced_assoc_ty_binding =
     associated type bounds are only allowed in where clauses and function signatures, not in {$position}
 
-ast_lowering_rustc_box_attribute_error =
-    #[rustc_box] requires precisely one argument and no other attributes are allowed
-
 ast_lowering_underscore_expr_lhs_assign =
     in expressions, `_` can only be used on the left-hand side of an assignment
     .label = `_` not allowed here
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index def74c2adee..5e6b6050bc0 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -88,13 +88,6 @@ pub struct MisplacedAssocTyBinding<'a> {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[diag(ast_lowering_rustc_box_attribute_error)]
-pub struct RustcBoxAttributeError {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic, Clone, Copy)]
 #[diag(ast_lowering_underscore_expr_lhs_assign)]
 pub struct UnderscoreExprLhsAssign {
     #[primary_span]
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index d4fafe38638..ffb30b1b391 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -2,7 +2,7 @@ use super::errors::{
     AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
     BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt,
     GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure,
-    RustcBoxAttributeError, UnderscoreExprLhsAssign,
+    UnderscoreExprLhsAssign,
 };
 use super::ResolverAstLoweringExt;
 use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
@@ -83,15 +83,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 }
                 ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
                 ExprKind::Call(f, args) => {
-                    if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) {
-                        if let [inner] = &args[..] && e.attrs.len() == 1 {
-                            let kind = hir::ExprKind::Box(self.lower_expr(&inner));
-                            return hir::Expr { hir_id, kind, span: self.lower_span(e.span) };
-                        } else {
-                            let guar = self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span });
-                            hir::ExprKind::Err(guar)
-                        }
-                    } else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
+                    if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
                         self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)
                     } else {
                         let f = self.lower_expr(f);
diff --git a/compiler/rustc_mir_build/locales/en-US.ftl b/compiler/rustc_mir_build/locales/en-US.ftl
index f9bda721df3..93e7fb330e0 100644
--- a/compiler/rustc_mir_build/locales/en-US.ftl
+++ b/compiler/rustc_mir_build/locales/en-US.ftl
@@ -374,3 +374,9 @@ mir_build_suggest_let_else = you might want to use `let else` to handle the {$co
     } matched
 
 mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+
+
+mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
+    .attributes = no other attributes may be applied
+    .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call
+    .missing_box = `#[rustc_box]` requires the `owned_box` lang item
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index c1f6b8b59ce..dc4d2276e4a 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -888,3 +888,22 @@ pub enum MiscPatternSuggestion {
         start_span: Span,
     },
 }
+
+#[derive(Diagnostic)]
+#[diag(mir_build_rustc_box_attribute_error)]
+pub struct RustcBoxAttributeError {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub reason: RustcBoxAttrReason,
+}
+
+#[derive(Subdiagnostic)]
+pub enum RustcBoxAttrReason {
+    #[note(mir_build_attributes)]
+    Attributes,
+    #[note(mir_build_not_box)]
+    NotBoxNew,
+    #[note(mir_build_missing_box)]
+    MissingBox,
+}
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index ae203233bd5..f3fa0c37be9 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -1,3 +1,4 @@
+use crate::errors;
 use crate::thir::cx::region::Scope;
 use crate::thir::cx::Cx;
 use crate::thir::util::UserAnnotatedTyHelpers;
@@ -18,7 +19,7 @@ use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{
     self, AdtKind, InlineConstSubsts, InlineConstSubstsParts, ScalarInt, Ty, UpvarSubsts, UserType,
 };
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 use rustc_target::abi::VariantIdx;
 
 impl<'tcx> Cx<'tcx> {
@@ -262,6 +263,7 @@ impl<'tcx> Cx<'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
     fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
         let tcx = self.tcx;
         let expr_ty = self.typeck_results().expr_ty(expr);
@@ -322,6 +324,34 @@ impl<'tcx> Cx<'tcx> {
                         fn_span: expr.span,
                     }
                 } else {
+                    let attrs = tcx.hir().attrs(expr.hir_id);
+                    if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_box) {
+                        if attrs.len() != 1 {
+                            tcx.sess.emit_err(errors::RustcBoxAttributeError {
+                                span: attrs[0].span,
+                                reason: errors::RustcBoxAttrReason::Attributes,
+                            });
+                        } else if let Some(box_item) = tcx.lang_items().owned_box() {
+                            if let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, fn_path)) = fun.kind
+                                && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
+                                && path.res.opt_def_id().map_or(false, |did| did == box_item)
+                                && fn_path.ident.name == sym::new
+                                && let [value] = args
+                            {
+                                return Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind: ExprKind::Box { value: self.mirror_expr(value) } }
+                            } else {
+                                tcx.sess.emit_err(errors::RustcBoxAttributeError {
+                                    span: expr.span,
+                                    reason: errors::RustcBoxAttrReason::NotBoxNew
+                                });
+                            }
+                        } else {
+                            tcx.sess.emit_err(errors::RustcBoxAttributeError {
+                                span: attrs[0].span,
+                                reason: errors::RustcBoxAttrReason::MissingBox,
+                            });
+                        }
+                    }
                     let adt_data =
                         if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = fun.kind {
                             // Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 4604ae5c2c7..50bef370930 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -287,15 +287,12 @@ impl<'a> VecArgs<'a> {
                     Some(VecArgs::Repeat(&args[0], &args[1]))
                 } else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
                     // `vec![a, b, c]` case
-                    if_chain! {
-                        if let hir::ExprKind::Box(boxed) = args[0].kind;
-                        if let hir::ExprKind::Array(args) = boxed.kind;
-                        then {
-                            return Some(VecArgs::Vec(args));
-                        }
+                    if let hir::ExprKind::Call(_, [arg]) = &args[0].kind
+                        && let hir::ExprKind::Array(args) = arg.kind {
+                        Some(VecArgs::Vec(args))
+                    } else {
+                        None
                     }
-
-                    None
                 } else if match_def_path(cx, fun_def_id, &paths::VEC_NEW) && args.is_empty() {
                     Some(VecArgs::Vec(&[]))
                 } else {
diff --git a/tests/ui/attributes/rustc-box.rs b/tests/ui/attributes/rustc-box.rs
new file mode 100644
index 00000000000..b3726fb3867
--- /dev/null
+++ b/tests/ui/attributes/rustc-box.rs
@@ -0,0 +1,18 @@
+#![feature(rustc_attrs, stmt_expr_attributes)]
+
+fn foo(_: u32, _: u32) {}
+fn bar(_: u32) {}
+
+fn main() {
+    #[rustc_box]
+    Box::new(1); // OK
+    #[rustc_box]
+    Box::pin(1); //~ ERROR `#[rustc_box]` attribute used incorrectly
+    #[rustc_box]
+    foo(1, 1); //~ ERROR `#[rustc_box]` attribute used incorrectly
+    #[rustc_box]
+    bar(1); //~ ERROR `#[rustc_box]` attribute used incorrectly
+    #[rustc_box] //~ ERROR `#[rustc_box]` attribute used incorrectly
+    #[rustfmt::skip]
+    Box::new(1);
+}
diff --git a/tests/ui/attributes/rustc-box.stderr b/tests/ui/attributes/rustc-box.stderr
new file mode 100644
index 00000000000..073a18c7d58
--- /dev/null
+++ b/tests/ui/attributes/rustc-box.stderr
@@ -0,0 +1,34 @@
+error: `#[rustc_box]` attribute used incorrectly
+  --> $DIR/rustc-box.rs:10:5
+   |
+LL |     Box::pin(1);
+   |     ^^^^^^^^^^^
+   |
+   = note: `#[rustc_box]` may only be applied to a `Box::new()` call
+
+error: `#[rustc_box]` attribute used incorrectly
+  --> $DIR/rustc-box.rs:12:5
+   |
+LL |     foo(1, 1);
+   |     ^^^^^^^^^
+   |
+   = note: `#[rustc_box]` may only be applied to a `Box::new()` call
+
+error: `#[rustc_box]` attribute used incorrectly
+  --> $DIR/rustc-box.rs:14:5
+   |
+LL |     bar(1);
+   |     ^^^^^^
+   |
+   = note: `#[rustc_box]` may only be applied to a `Box::new()` call
+
+error: `#[rustc_box]` attribute used incorrectly
+  --> $DIR/rustc-box.rs:15:5
+   |
+LL |     #[rustc_box]
+   |     ^^^^^^^^^^^^
+   |
+   = note: no other attributes may be applied
+
+error: aborting due to 4 previous errors
+