Move FFI attribute validation to check_attr

This commit is contained in:
inquisitivecrystal 2023-01-24 02:19:04 -08:00
parent 3984bc5833
commit 05b7cc8370
4 changed files with 78 additions and 47 deletions

View File

@ -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) {

View File

@ -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`

View File

@ -150,6 +150,9 @@ fn check_attributes(
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 @@ fn check_has_incoherent_inherent_impls(
}
}
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!(

View File

@ -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 {