about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-04-06 00:53:43 +0200
committerGitHub <noreply@github.com>2020-04-06 00:53:43 +0200
commitaafbe07af3eb9b497c5c24db0a5c7253b2125bbf (patch)
tree7b3e41c22dd1e72db2296cbee22cc6f4bb5b7436
parentbe93b1cdc5fbc94d4ab0c58f4c1542c1e45da877 (diff)
parent13bd25e4722a02f7b38797c7d116bfb9d1667e72 (diff)
downloadrust-aafbe07af3eb9b497c5c24db0a5c7253b2125bbf.tar.gz
rust-aafbe07af3eb9b497c5c24db0a5c7253b2125bbf.zip
Rollup merge of #70665 - petrochenkov:linkargs, r=nagisa
Do not lose or reorder user-provided linker arguments

Linker arguments are potentially order-dependent, so the order in which `-C link-arg` and `-C link-args` options are passed to `rustc` should be preserved when they are passed further to the linker.

Also, multiple `-C link-args` options are now appended to each other rather than overwrite each other.

In other words, `-C link-arg=a -C link-args="b c" -C link-args="d e" -C link-arg=f` is now passed as `"a" "b" "c" "d" "e" "f"` and not as `"d" "e" "a" "f"`.

Addresses https://github.com/rust-lang/rust/pull/70505#issuecomment-606780163.
-rw-r--r--src/librustc_codegen_ssa/back/link.rs24
-rw-r--r--src/librustc_interface/tests.rs2
-rw-r--r--src/librustc_session/options.rs18
-rw-r--r--src/test/run-make-fulldeps/link-args-order/Makefile10
-rw-r--r--src/test/run-make-fulldeps/link-args-order/empty.rs6
5 files changed, 38 insertions, 22 deletions
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 1e780c5f867..49786bc3b06 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -505,10 +505,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
             cmd.args(args);
         }
     }
-    if let Some(ref args) = sess.opts.debugging_opts.pre_link_args {
-        cmd.args(args);
-    }
-    cmd.args(&sess.opts.debugging_opts.pre_link_arg);
+    cmd.args(&sess.opts.debugging_opts.pre_link_args);
 
     if sess.target.target.options.is_like_fuchsia {
         let prefix = match sess.opts.debugging_opts.sanitizer {
@@ -1302,18 +1299,17 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(
         cmd.gc_sections(keep_metadata);
     }
 
-    let used_link_args = &codegen_results.crate_info.link_args;
+    let attr_link_args = codegen_results.crate_info.link_args.iter();
+    let user_link_args: Vec<_> =
+        sess.opts.cg.link_args.iter().chain(attr_link_args).cloned().collect();
 
     if crate_type == config::CrateType::Executable {
         let mut position_independent_executable = false;
 
         if t.options.position_independent_executables {
-            let empty_vec = Vec::new();
-            let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
-            let more_args = &sess.opts.cg.link_arg;
-            let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());
-
-            if is_pic(sess) && !sess.crt_static(Some(crate_type)) && !args.any(|x| *x == "-static")
+            if is_pic(sess)
+                && !sess.crt_static(Some(crate_type))
+                && !user_link_args.iter().any(|x| x == "-static")
             {
                 position_independent_executable = true;
             }
@@ -1444,11 +1440,7 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(
 
     // Finally add all the linker arguments provided on the command line along
     // with any #[link_args] attributes found inside the crate
-    if let Some(ref args) = sess.opts.cg.link_args {
-        cmd.args(args);
-    }
-    cmd.args(&sess.opts.cg.link_arg);
-    cmd.args(&used_link_args);
+    cmd.args(&user_link_args);
 }
 
 // # Native library linking
diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs
index f58c5cc8eeb..b452ccfe33a 100644
--- a/src/librustc_interface/tests.rs
+++ b/src/librustc_interface/tests.rs
@@ -382,7 +382,7 @@ fn test_codegen_options_tracking_hash() {
     opts.cg.linker = Some(PathBuf::from("linker"));
     assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
 
-    opts.cg.link_args = Some(vec![String::from("abc"), String::from("def")]);
+    opts.cg.link_args = vec![String::from("abc"), String::from("def")];
     assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
 
     opts.cg.link_dead_code = true;
diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs
index 3962e30335d..8cd6ca86f46 100644
--- a/src/librustc_session/options.rs
+++ b/src/librustc_session/options.rs
@@ -296,9 +296,17 @@ macro_rules! options {
         use std::path::PathBuf;
         use std::str::FromStr;
 
+        // Sometimes different options need to build a common structure.
+        // That structure can kept in one of the options' fields, the others become dummy.
+        macro_rules! redirect_field {
+            ($cg:ident.link_arg) => { $cg.link_args };
+            ($cg:ident.pre_link_arg) => { $cg.pre_link_args };
+            ($cg:ident.$field:ident) => { $cg.$field };
+        }
+
         $(
             pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
-                $parse(&mut cg.$opt, v)
+                $parse(&mut redirect_field!(cg.$opt), v)
             }
         )*
 
@@ -643,9 +651,9 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
         "this option is deprecated and does nothing"),
     linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
         "system linker to link outputs with"),
-    link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
+    link_arg: (/* redirected to link_args */) = ((), parse_string_push, [UNTRACKED],
         "a single extra argument to append to the linker invocation (can be used several times)"),
-    link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
+    link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
         "extra arguments to append to the linker invocation (space separated)"),
     link_dead_code: bool = (false, parse_bool, [UNTRACKED],
         "don't let linker strip dead code (turning it on can be used for code coverage)"),
@@ -876,9 +884,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "make rustc print the total optimization fuel used by a crate"),
     force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
         "force all crates to be `rustc_private` unstable"),
-    pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
+    pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED],
         "a single extra argument to prepend the linker invocation (can be used several times)"),
-    pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
+    pre_link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
         "extra arguments to prepend to the linker invocation (space separated)"),
     profile: bool = (false, parse_bool, [TRACKED],
                      "insert profiling code"),
diff --git a/src/test/run-make-fulldeps/link-args-order/Makefile b/src/test/run-make-fulldeps/link-args-order/Makefile
new file mode 100644
index 00000000000..98c1e0eac3b
--- /dev/null
+++ b/src/test/run-make-fulldeps/link-args-order/Makefile
@@ -0,0 +1,10 @@
+# ignore-msvc
+
+-include ../tools.mk
+
+RUSTC_FLAGS = -C linker-flavor=ld -C link-arg=a -C link-args="b c" -C link-args="d e" -C link-arg=f
+RUSTC_FLAGS_PRE = -C linker-flavor=ld -Z pre-link-arg=a -Z pre-link-args="b c" -Z pre-link-args="d e" -Z pre-link-arg=f
+
+all:
+	$(RUSTC) $(RUSTC_FLAGS) empty.rs 2>&1 | $(CGREP) '"a" "b" "c" "d" "e" "f" "g"'
+	$(RUSTC) $(RUSTC_FLAGS_PRE) empty.rs 2>&1 | $(CGREP) '"a" "b" "c" "d" "e" "f"'
diff --git a/src/test/run-make-fulldeps/link-args-order/empty.rs b/src/test/run-make-fulldeps/link-args-order/empty.rs
new file mode 100644
index 00000000000..2439171004b
--- /dev/null
+++ b/src/test/run-make-fulldeps/link-args-order/empty.rs
@@ -0,0 +1,6 @@
+#![feature(link_args)]
+
+#[link_args = "g"]
+extern "C" {}
+
+fn main() {}