diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index b0fa7745667..9ecd95f424f 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -85,55 +85,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { } else if attr.has_name(sym::rustc_allocator) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR; } else if attr.has_name(sym::ffi_returns_twice) { - if tcx.is_foreign_item(did) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE; - } else { - // `#[ffi_returns_twice]` is only allowed `extern fn`s. - struct_span_err!( - tcx.sess, - attr.span, - E0724, - "`#[ffi_returns_twice]` may only be used on foreign functions" - ) - .emit(); - } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE; } else if attr.has_name(sym::ffi_pure) { - if tcx.is_foreign_item(did) { - if attrs.iter().any(|a| a.has_name(sym::ffi_const)) { - // `#[ffi_const]` functions cannot be `#[ffi_pure]` - struct_span_err!( - tcx.sess, - attr.span, - E0757, - "`#[ffi_const]` function cannot be `#[ffi_pure]`" - ) - .emit(); - } else { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE; - } - } else { - // `#[ffi_pure]` is only allowed on foreign functions - struct_span_err!( - tcx.sess, - attr.span, - E0755, - "`#[ffi_pure]` may only be used on foreign functions" - ) - .emit(); - } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE; } else if attr.has_name(sym::ffi_const) { - if tcx.is_foreign_item(did) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST; - } else { - // `#[ffi_const]` is only allowed on foreign functions - struct_span_err!( - tcx.sess, - attr.span, - E0756, - "`#[ffi_const]` may only be used on foreign functions" - ) - .emit(); - } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST; } else if attr.has_name(sym::rustc_nounwind) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; } else if attr.has_name(sym::rustc_reallocator) { diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 91857dd227d..adfe243430f 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -182,6 +182,18 @@ passes_has_incoherent_inherent_impl = `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. .label = only adts, extern types and traits are supported +passes_both_ffi_const_and_pure = + `#[ffi_const]` function cannot be `#[ffi_pure]` + +passes_ffi_pure_invalid_target = + `#[ffi_pure]` may only be used on foreign functions + +passes_ffi_const_invalid_target = + `#[ffi_const]` may only be used on foreign functions + +passes_ffi_returns_twice_invalid_target = + `#[ffi_returns_twice]` may only be used on foreign functions + passes_must_use_async = `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f9f9799d3e4..f38b9c5834d 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -150,6 +150,9 @@ impl CheckAttrVisitor<'_> { sym::rustc_has_incoherent_inherent_impls => { self.check_has_incoherent_inherent_impls(&attr, span, target) } + sym::ffi_pure => self.check_ffi_pure(hir_id, attr.span, attrs), + sym::ffi_const => self.check_ffi_const(hir_id, attr.span), + sym::ffi_returns_twice => self.check_ffi_returns_twice(hir_id, attr.span), sym::rustc_const_unstable | sym::rustc_const_stable | sym::unstable @@ -1171,6 +1174,38 @@ impl CheckAttrVisitor<'_> { } } + fn check_ffi_pure(&self, hir_id: HirId, attr_span: Span, attrs: &[Attribute]) -> bool { + if !self.tcx.is_foreign_item(self.tcx.hir().local_def_id(hir_id)) { + self.tcx.sess.emit_err(errors::FfiPureInvalidTarget { attr_span }); + return false; + } + if attrs.iter().any(|a| a.has_name(sym::ffi_const)) { + // `#[ffi_const]` functions cannot be `#[ffi_pure]` + self.tcx.sess.emit_err(errors::BothFfiConstAndPure { attr_span }); + false + } else { + true + } + } + + fn check_ffi_const(&self, hir_id: HirId, attr_span: Span) -> bool { + if self.tcx.is_foreign_item(self.tcx.hir().local_def_id(hir_id)) { + true + } else { + self.tcx.sess.emit_err(errors::FfiConstInvalidTarget { attr_span }); + false + } + } + + fn check_ffi_returns_twice(&self, hir_id: HirId, attr_span: Span) -> bool { + if self.tcx.is_foreign_item(self.tcx.hir().local_def_id(hir_id)) { + true + } else { + self.tcx.sess.emit_err(errors::FfiReturnsTwiceInvalidTarget { attr_span }); + false + } + } + /// Warns against some misuses of `#[must_use]` fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) -> bool { if !matches!( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 9c6519ea4bb..b746e543a98 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -347,6 +347,34 @@ pub struct HasIncoherentInherentImpl { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_both_ffi_const_and_pure, code = "E0757")] +pub struct BothFfiConstAndPure { + #[primary_span] + pub attr_span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_ffi_pure_invalid_target, code = "E0755")] +pub struct FfiPureInvalidTarget { + #[primary_span] + pub attr_span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_ffi_const_invalid_target, code = "E0756")] +pub struct FfiConstInvalidTarget { + #[primary_span] + pub attr_span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_ffi_returns_twice_invalid_target, code = "E0724")] +pub struct FfiReturnsTwiceInvalidTarget { + #[primary_span] + pub attr_span: Span, +} + #[derive(LintDiagnostic)] #[diag(passes_must_use_async)] pub struct MustUseAsync {