Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustc: Stricter checking for #[link] attributes #96885

Merged
merged 1 commit into from
May 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 0 additions & 31 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,37 +396,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}

// Check for unstable modifiers on `#[link(..)]` attribute
if attr.has_name(sym::link) {
for nested_meta in attr.meta_item_list().unwrap_or_default() {
if nested_meta.has_name(sym::modifiers) {
if let Some(modifiers) = nested_meta.value_str() {
for modifier in modifiers.as_str().split(',') {
if let Some(modifier) = modifier.strip_prefix(&['+', '-']) {
macro_rules! gate_modifier { ($($name:literal => $feature:ident)*) => {
$(if modifier == $name {
let msg = concat!("`#[link(modifiers=\"", $name, "\")]` is unstable");
gate_feature_post!(
self,
$feature,
nested_meta.name_value_literal_span().unwrap(),
msg
);
})*
}}

gate_modifier!(
"bundle" => native_link_modifiers_bundle
"verbatim" => native_link_modifiers_verbatim
"as-needed" => native_link_modifiers_as_needed
);
}
}
}
}
}
}

// Emit errors for non-staged-api crates.
if !self.features.staged_api {
if attr.has_name(sym::rustc_deprecated)
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0455.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Some linking kinds are target-specific and not supported on all platforms.

Linking with `kind=framework` is only supported when targeting macOS,
as frameworks are specific to that operating system.

Similarly, `kind=raw-dylib` is only supported when targeting Windows-like
platforms.

Erroneous code example:

```ignore (should-compile_fail-but-cannot-doctest-conditionally-without-macos)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_error_codes/src/error_codes/E0458.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ Please specify a valid "kind" value, from one of the following:
* static
* dylib
* framework
* raw-dylib
2 changes: 2 additions & 0 deletions compiler/rustc_metadata/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(drain_filter)]
#![feature(generators)]
#![feature(let_chains)]
#![feature(let_else)]
#![feature(nll)]
#![feature(once_cell)]
Expand Down
514 changes: 274 additions & 240 deletions compiler/rustc_metadata/src/native_libs.rs

Large diffs are not rendered by default.

34 changes: 20 additions & 14 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use rustc_session::lint::builtin::{
use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use std::collections::hash_map::Entry;

pub(crate) fn target_from_impl_item<'tcx>(
Expand Down Expand Up @@ -1317,22 +1318,27 @@ impl CheckAttrVisitor<'_> {

/// Checks if `#[link]` is applied to an item other than a foreign module.
fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
match target {
Target::ForeignMod => {}
_ => {
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
let mut diag = lint.build("attribute should be applied to an `extern` block");
diag.warn(
"this was previously accepted by the compiler but is \
being phased out; it will become a hard error in \
a future release!",
);
if target == Target::ForeignMod
&& let hir::Node::Item(item) = self.tcx.hir().get(hir_id)
&& let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
&& !matches!(abi, Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic)
{
return;
}

diag.span_label(span, "not an `extern` block");
diag.emit();
});
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
let mut diag =
lint.build("attribute should be applied to an `extern` block with non-Rust ABI");
diag.warn(
"this was previously accepted by the compiler but is \
being phased out; it will become a hard error in \
a future release!",
);
if target != Target::ForeignMod {
diag.span_label(span, "not an `extern` block");
}
}
diag.emit();
});
}

/// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
Expand Down
104 changes: 45 additions & 59 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1937,33 +1937,27 @@ fn parse_native_lib_kind(
};

let kind = match kind {
"dylib" => NativeLibKind::Dylib { as_needed: None },
"framework" => NativeLibKind::Framework { as_needed: None },
"static" => NativeLibKind::Static { bundle: None, whole_archive: None },
"static-nobundle" => {
early_warn(
error_format,
"library kind `static-nobundle` has been superseded by specifying \
`-bundle` on library kind `static`. Try `static:-bundle`",
modifier `-bundle` with library kind `static`. Try `static:-bundle`",
);
if modifiers.is_some() {
petrochenkov marked this conversation as resolved.
Show resolved Hide resolved
early_error(
error_format,
"linking modifier can't be used with library kind `static-nobundle`",
)
}
if !nightly_options::match_is_nightly_build(matches) {
early_error(
error_format,
"library kind `static-nobundle` are currently unstable and only accepted on \
the nightly compiler",
"library kind `static-nobundle` is unstable \
and only accepted on the nightly compiler",
);
}
NativeLibKind::Static { bundle: Some(false), whole_archive: None }
}
s => early_error(
"dylib" => NativeLibKind::Dylib { as_needed: None },
"framework" => NativeLibKind::Framework { as_needed: None },
_ => early_error(
error_format,
&format!("unknown library kind `{s}`, expected one of dylib, framework, or static"),
&format!("unknown library kind `{kind}`, expected one of: static, dylib, framework"),
petrochenkov marked this conversation as resolved.
Show resolved Hide resolved
),
};
match modifiers {
Expand All @@ -1978,94 +1972,83 @@ fn parse_native_lib_modifiers(
error_format: ErrorOutputType,
matches: &getopts::Matches,
) -> (NativeLibKind, Option<bool>) {
let report_unstable_modifier = |modifier| {
if !nightly_options::is_unstable_enabled(matches) {
let why = if nightly_options::match_is_nightly_build(matches) {
" and only accepted on the nightly compiler"
} else {
", the `-Z unstable-options` flag must also be passed to use it"
};
early_error(
error_format,
&format!("{modifier} linking modifier is currently unstable{why}"),
)
}
};

let mut has_duplicate_modifiers = false;
let mut verbatim = None;
for modifier in modifiers.split(',') {
let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
Some(m) => (m, modifier.starts_with('+')),
None => early_error(
error_format,
"invalid linking modifier syntax, expected '+' or '-' prefix \
before one of: bundle, verbatim, whole-archive, as-needed",
before one of: bundle, verbatim, whole-archive, as-needed",
),
};

let report_unstable_modifier = || {
if !nightly_options::is_unstable_enabled(matches) {
let why = if nightly_options::match_is_nightly_build(matches) {
" and only accepted on the nightly compiler"
} else {
", the `-Z unstable-options` flag must also be passed to use it"
};
early_error(
error_format,
&format!("linking modifier `{modifier}` is unstable{why}"),
)
}
};
let assign_modifier = |dst: &mut Option<bool>| {
if dst.is_some() {
let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
early_error(error_format, &msg)
} else {
*dst = Some(value);
}
};
match (modifier, &mut kind) {
("bundle", NativeLibKind::Static { bundle, .. }) => {
report_unstable_modifier(modifier);
if bundle.is_some() {
has_duplicate_modifiers = true;
}
*bundle = Some(value);
report_unstable_modifier();
assign_modifier(bundle)
}
("bundle", _) => early_error(
error_format,
"bundle linking modifier is only compatible with \
`static` linking kind",
"linking modifier `bundle` is only compatible with `static` linking kind",
),

("verbatim", _) => {
report_unstable_modifier(modifier);
if verbatim.is_some() {
has_duplicate_modifiers = true;
}
verbatim = Some(value);
report_unstable_modifier();
assign_modifier(&mut verbatim)
}

("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
if whole_archive.is_some() {
has_duplicate_modifiers = true;
}
*whole_archive = Some(value);
assign_modifier(whole_archive)
}
("whole-archive", _) => early_error(
error_format,
"whole-archive linking modifier is only compatible with \
`static` linking kind",
"linking modifier `whole-archive` is only compatible with `static` linking kind",
),

("as-needed", NativeLibKind::Dylib { as_needed })
| ("as-needed", NativeLibKind::Framework { as_needed }) => {
report_unstable_modifier(modifier);
if as_needed.is_some() {
has_duplicate_modifiers = true;
}
*as_needed = Some(value);
report_unstable_modifier();
assign_modifier(as_needed)
}
("as-needed", _) => early_error(
error_format,
"as-needed linking modifier is only compatible with \
`dylib` and `framework` linking kinds",
"linking modifier `as-needed` is only compatible with \
`dylib` and `framework` linking kinds",
),

// Note: this error also excludes the case with empty modifier
// string, like `modifiers = ""`.
_ => early_error(
error_format,
&format!(
"unrecognized linking modifier `{modifier}`, expected one \
of: bundle, verbatim, whole-archive, as-needed"
"unknown linking modifier `{modifier}`, expected one \
of: bundle, verbatim, whole-archive, as-needed"
),
),
}
}
if has_duplicate_modifiers {
report_unstable_modifier("duplicating")
}

(kind, verbatim)
}
Expand Down Expand Up @@ -2093,6 +2076,9 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
None => (name, None),
Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
};
if name.is_empty() {
early_error(error_format, "library name must not be empty");
}
NativeLib { name, new_name, kind, verbatim }
})
.collect()
Expand Down
3 changes: 2 additions & 1 deletion src/doc/rustc/src/command-line-arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ where `KIND` may be one of:
If the kind is specified, then linking modifiers can be attached to it.
Modifiers are specified as a comma-delimited string with each modifier prefixed with
either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively.
The last boolean value specified for a given modifier wins. \
Specifying multiple `modifiers` arguments in a single `link` attribute,
or multiple identical modifiers in the same `modifiers` argument is not currently supported. \
Example: `-l static:+whole-archive=mylib`.

The kind of library and the modifiers can also be specified in a [`#[link]`
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/empty/empty-linkname.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[link(name = "")] //~ ERROR: given with empty name
#[link(name = "")] //~ ERROR: link name must not be empty
extern "C" {}

fn main() {}
6 changes: 3 additions & 3 deletions src/test/ui/empty/empty-linkname.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0454]: `#[link(name = "")]` given with empty name
--> $DIR/empty-linkname.rs:1:1
error[E0454]: link name must not be empty
--> $DIR/empty-linkname.rs:1:15
|
LL | #[link(name = "")]
| ^^^^^^^^^^^^^^^^^^ empty name given
| ^^ empty link name

error: aborting due to previous error

Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/error-codes/E0454.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0454]: `#[link(name = "")]` given with empty name
--> $DIR/E0454.rs:1:1
error[E0454]: link name must not be empty
--> $DIR/E0454.rs:1:15
|
LL | #[link(name = "")] extern "C" {}
| ^^^^^^^^^^^^^^^^^^ empty name given
| ^^ empty link name

error: aborting due to previous error

Expand Down
10 changes: 4 additions & 6 deletions src/test/ui/error-codes/E0458.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
error[E0458]: unknown kind: `wonderful_unicorn`
--> $DIR/E0458.rs:1:8
error[E0458]: unknown link kind `wonderful_unicorn`, expected one of: static, dylib, framework, raw-dylib
--> $DIR/E0458.rs:1:15
|
LL | #[link(kind = "wonderful_unicorn")] extern "C" {}
| -------^^^^^^^^^^^^^^^^^^^^^^^^^^--
| |
| unknown kind
| ^^^^^^^^^^^^^^^^^^^ unknown link kind

error[E0459]: `#[link(...)]` specified without `name = "foo"`
error[E0459]: `#[link]` attribute requires a `name = "string"` argument
--> $DIR/E0458.rs:1:1
|
LL | #[link(kind = "wonderful_unicorn")] extern "C" {}
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/error-codes/E0459.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0459]: `#[link(...)]` specified without `name = "foo"`
error[E0459]: `#[link]` attribute requires a `name = "string"` argument
--> $DIR/E0459.rs:1:1
|
LL | #[link(kind = "dylib")] extern "C" {}
Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/feature-gates/feature-gate-link_cfg.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0658]: kind="link_cfg" is unstable
--> $DIR/feature-gate-link_cfg.rs:1:1
error[E0658]: link cfg is unstable
--> $DIR/feature-gate-link_cfg.rs:1:22
|
LL | #[link(name = "foo", cfg(foo))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^
|
= note: see issue #37406 <https://github.com/rust-lang/rust/issues/37406> for more information
= help: add `#![feature(link_cfg)]` to the crate attributes to enable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[link(name = "foo", modifiers = "+as-needed")]
//~^ ERROR: `#[link(modifiers="as-needed")]` is unstable
#[link(name = "foo", kind = "dylib", modifiers = "+as-needed")]
//~^ ERROR: linking modifier `as-needed` is unstable
extern "C" {}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0658]: `#[link(modifiers="as-needed")]` is unstable
--> $DIR/feature-gate-native_link_modifiers_as_needed.rs:1:34
error[E0658]: linking modifier `as-needed` is unstable
--> $DIR/feature-gate-native_link_modifiers_as_needed.rs:1:50
|
LL | #[link(name = "foo", modifiers = "+as-needed")]
| ^^^^^^^^^^^^
LL | #[link(name = "foo", kind = "dylib", modifiers = "+as-needed")]
| ^^^^^^^^^^^^
|
= note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
= help: add `#![feature(native_link_modifiers_as_needed)]` to the crate attributes to enable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
error: bundle linking modifier is currently unstable and only accepted on the nightly compiler
error: linking modifier `bundle` is unstable and only accepted on the nightly compiler

Loading