diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 07713590ff2e9..b2efb7c5f6182 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -642,14 +642,13 @@ pub(crate) struct LinkageParser; impl SingleAttributeParser for LinkageParser { const PATH: &[Symbol] = &[sym::linkage]; const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[ - Allow(Target::Fn), + Allow(Target::Fn), // const fn denied in check_attr Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), Allow(Target::Static), - Allow(Target::ForeignStatic), + Allow(Target::ForeignStatic), // extern static mut denied in check_attr Allow(Target::ForeignFn), - Warn(Target::Method(MethodKind::Trait { body: false })), // Not inherited ]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: [ "available_externally", diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 691b13f03e965..0f9c3c8534785 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -198,16 +198,10 @@ fn process_builtin_attrs( codegen_fn_attrs.import_linkage = linkage; if tcx.is_mutable_static(did.into()) { - let mut diag = tcx.dcx().struct_span_err( + tcx.dcx().span_delayed_bug( *span, - "extern mutable statics are not allowed with `#[linkage]`", + "`extern { #[linkage] static mut ...` is checked in check_attr}", ); - diag.note( - "marking the extern static mutable would allow changing which \ - symbol the static references rather than make the target of the \ - symbol mutable", - ); - diag.emit(); } } else { codegen_fn_attrs.linkage = linkage; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f9b508476689e..013981a06b057 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -233,6 +233,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::OnTypeError { directive, .. } => { self.check_diagnostic_on_type_error(hir_id, directive.as_deref()) } + AttributeKind::Linkage(_linkage, span) => { + self.check_linkage(*span, hir_id, target, item) + } // All of the following attributes have no specific checks. // tidy-alphabetical-start @@ -268,7 +271,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::LinkName { .. } => (), AttributeKind::LinkOrdinal { .. } => (), AttributeKind::LinkSection { .. } => (), - AttributeKind::Linkage(..) => (), AttributeKind::LoopMatch(..) => {} AttributeKind::MacroEscape => (), AttributeKind::MacroUse { .. } => (), @@ -1627,6 +1629,31 @@ impl<'tcx> CheckAttrVisitor<'tcx> { .emit_err(diagnostics::BothOptimizeNoneAndInline { optimize_span, inline_span }); } } + + fn check_linkage( + &self, + span: Span, + hir_id: HirId, + target: Target, + item: Option<&'tcx Item<'tcx>>, + ) { + // FIXME(eii) Once eii is no longer so experimental, suggest doing + // linkage stuff with externally implementable items instead + match target { + Target::ForeignStatic + if self.tcx.is_mutable_static(hir_id.expect_owner().def_id.into()) => + { + self.tcx.dcx().emit_err(diagnostics::StaticMutLinkage { span }); + } + Target::Fn + if let Item { kind: ItemKind::Fn { sig, .. }, .. } = item.unwrap() + && matches!(sig.header.constness, Constness::Const { .. }) => + { + self.tcx.dcx().emit_err(diagnostics::ConstFnLinkage { span }); + } + _ => {} + } + } } impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index 34fa0b264319d..d7691b6e0ea73 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -1190,3 +1190,23 @@ pub(crate) struct OnTypeErrorMalformedFormatLiterals { pub(crate) struct OnTypeErrorNotExactlyOneGeneric { pub count: usize, } + +#[derive(Diagnostic)] +#[diag("extern mutable statics are incompatible with the `linkage` attribute")] +#[note( + "the `linkage` attribute on extern statics generates a symbol that contains the address of \ + another static. Making the extern static mutable would allow changing the address, rather \ + than the static the address is pointing to" +)] +pub(crate) struct StaticMutLinkage { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag("`const fn` are incompatible with the `linkage` attribute")] +#[note("`const fn` may be called at compile time, which happens before linking")] +pub(crate) struct ConstFnLinkage { + #[primary_span] + pub span: Span, +} diff --git a/tests/ui/attributes/codegen_attr_on_required_trait_method.rs b/tests/ui/attributes/codegen_attr_on_required_trait_method.rs index cd9987f1e6a38..737ebf7f2b144 100644 --- a/tests/ui/attributes/codegen_attr_on_required_trait_method.rs +++ b/tests/ui/attributes/codegen_attr_on_required_trait_method.rs @@ -12,8 +12,7 @@ trait Test { //~| WARN previously accepted fn method2(&self); #[linkage = "common"] - //~^ ERROR cannot be used on required trait methods [unused_attributes] - //~| WARN previously accepted + //~^ ERROR `linkage` attribute cannot be used on required trait methods fn method3(&self); #[track_caller] fn method4(&self); diff --git a/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr b/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr index 91772d0d7c154..b5452ba2882c0 100644 --- a/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr +++ b/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr @@ -1,3 +1,11 @@ +error: the `linkage` attribute cannot be used on required trait methods + --> $DIR/codegen_attr_on_required_trait_method.rs:14:7 + | +LL | #[linkage = "common"] + | ^^^^^^^ + | + = help: the `linkage` attribute can be applied to foreign functions, foreign statics, functions with a body, and statics + error: the `cold` attribute cannot be used on required trait methods --> $DIR/codegen_attr_on_required_trait_method.rs:6:7 | @@ -21,14 +29,5 @@ LL | #[link_section = "__TEXT,__text"] = help: the `link_section` attribute can be applied to functions with a body and statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -error: the `linkage` attribute cannot be used on required trait methods - --> $DIR/codegen_attr_on_required_trait_method.rs:14:7 - | -LL | #[linkage = "common"] - | ^^^^^^^ - | - = help: the `linkage` attribute can be applied to foreign functions, foreign statics, functions with a body, and statics - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - error: aborting due to 3 previous errors diff --git a/tests/ui/attributes/linkage.rs b/tests/ui/attributes/linkage.rs index 932bfa88fc5f0..19969edf69e13 100644 --- a/tests/ui/attributes/linkage.rs +++ b/tests/ui/attributes/linkage.rs @@ -1,3 +1,4 @@ +#![crate_type = "lib"] #![feature(linkage)] #![feature(stmt_expr_attributes)] #![deny(unused_attributes)] @@ -35,8 +36,12 @@ extern "C" { fn bar(); } -fn main() { +fn foo() { let _ = #[linkage = "weak"] (|| 1); //~^^ ERROR attribute cannot be used on } + +#[linkage = "weak"] +//~^ERROR `const fn` are incompatible with the `linkage` attribute +const fn linkage() {} diff --git a/tests/ui/attributes/linkage.stderr b/tests/ui/attributes/linkage.stderr index ca4eeda03a7b8..11a5e7fdfde83 100644 --- a/tests/ui/attributes/linkage.stderr +++ b/tests/ui/attributes/linkage.stderr @@ -1,5 +1,5 @@ error: the `linkage` attribute cannot be used on type aliases - --> $DIR/linkage.rs:6:3 + --> $DIR/linkage.rs:7:3 | LL | #[linkage = "weak"] | ^^^^^^^ @@ -7,7 +7,7 @@ LL | #[linkage = "weak"] = help: the `linkage` attribute can be applied to foreign statics, functions, and statics error: the `linkage` attribute cannot be used on modules - --> $DIR/linkage.rs:9:3 + --> $DIR/linkage.rs:10:3 | LL | #[linkage = "weak"] | ^^^^^^^ @@ -15,7 +15,7 @@ LL | #[linkage = "weak"] = help: the `linkage` attribute can be applied to foreign statics, functions, and statics error: the `linkage` attribute cannot be used on structs - --> $DIR/linkage.rs:12:3 + --> $DIR/linkage.rs:13:3 | LL | #[linkage = "weak"] | ^^^^^^^ @@ -23,7 +23,7 @@ LL | #[linkage = "weak"] = help: the `linkage` attribute can be applied to foreign statics, functions, and statics error: the `linkage` attribute cannot be used on inherent impl blocks - --> $DIR/linkage.rs:15:3 + --> $DIR/linkage.rs:16:3 | LL | #[linkage = "weak"] | ^^^^^^^ @@ -31,7 +31,7 @@ LL | #[linkage = "weak"] = help: the `linkage` attribute can be applied to foreign statics, functions, and statics error: the `linkage` attribute cannot be used on expressions - --> $DIR/linkage.rs:23:7 + --> $DIR/linkage.rs:24:7 | LL | #[linkage = "weak"] | ^^^^^^^ @@ -39,12 +39,20 @@ LL | #[linkage = "weak"] = help: the `linkage` attribute can be applied to foreign statics, functions, and statics error: the `linkage` attribute cannot be used on closures - --> $DIR/linkage.rs:39:15 + --> $DIR/linkage.rs:40:15 | LL | let _ = #[linkage = "weak"] | ^^^^^^^ | = help: the `linkage` attribute can be applied to foreign functions, foreign statics, functions, methods, and statics -error: aborting due to 6 previous errors +error: `const fn` are incompatible with the `linkage` attribute + --> $DIR/linkage.rs:45:1 + | +LL | #[linkage = "weak"] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `const fn` may be called at compile time, which happens before linking + +error: aborting due to 7 previous errors diff --git a/tests/ui/linkage-attr/linkage-attr-mutable-static.rs b/tests/ui/linkage-attr/linkage-attr-mutable-static.rs index 09f7d65f97e4d..4426a352798c8 100644 --- a/tests/ui/linkage-attr/linkage-attr-mutable-static.rs +++ b/tests/ui/linkage-attr/linkage-attr-mutable-static.rs @@ -8,7 +8,8 @@ fn main() { #[rustfmt::skip] extern "C" { - #[linkage = "extern_weak"] //~ ERROR extern mutable statics are not allowed with `#[linkage]` + #[linkage = "extern_weak"] + //~^ ERROR extern mutable statics are incompatible with the `linkage` attribute static mut EXTERN_WEAK: *const u8; } diff --git a/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr b/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr index 50d5d8121969f..38ff337e4fec1 100644 --- a/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr +++ b/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr @@ -1,10 +1,10 @@ -error: extern mutable statics are not allowed with `#[linkage]` +error: extern mutable statics are incompatible with the `linkage` attribute --> $DIR/linkage-attr-mutable-static.rs:11:9 | LL | #[linkage = "extern_weak"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: marking the extern static mutable would allow changing which symbol the static references rather than make the target of the symbol mutable + = note: the `linkage` attribute on extern statics generates a symbol that contains the address of another static. Making the extern static mutable would allow changing the address, rather than the static the address is pointing to error: aborting due to 1 previous error