From 00dcb665e7ede908ba11638e8230340f396674f8 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Mon, 11 May 2020 00:16:16 +0300
Subject: [PATCH] cmdline: Make target features individually overridable

---
 src/doc/rustc/src/codegen-options/index.md  | 10 +++++++++-
 src/librustc_session/options.rs             | 16 +++++++++++++++-
 src/test/codegen/target-feature-multiple.rs |  9 +++++++++
 3 files changed, 33 insertions(+), 2 deletions(-)
 create mode 100644 src/test/codegen/target-feature-multiple.rs

diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index dbe281be7df74..c638f88057a52 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -464,7 +464,15 @@ machine. Each target has a default base CPU.
 
 Individual targets will support different features; this flag lets you control
 enabling or disabling a feature. Each feature should be prefixed with a `+` to
-enable it or `-` to disable it. Separate multiple features with commas.
+enable it or `-` to disable it.
+
+Features from multiple `-C target-feature` options are combined. \
+Multiple features can be specified in a single option by separating them
+with commas - `-C target-feature=+x,-y`. \
+If some feature is specified more than once with both `+` and `-`,
+then values passed later override values passed earlier. \
+For example, `-C target-feature=+x,-y,+z -Ctarget-feature=-x,+y`
+is equivalent to `-C target-feature=-x,+y,+z`.
 
 To see the valid options and an example of use, run `rustc --print
 target-features`.
diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs
index 4eabb55e6dfe7..ed7b2b3d58a7b 100644
--- a/src/librustc_session/options.rs
+++ b/src/librustc_session/options.rs
@@ -270,6 +270,7 @@ macro_rules! options {
             "one of supported relocation models (`rustc --print relocation-models`)";
         pub const parse_tls_model: &str =
             "one of supported TLS models (`rustc --print tls-models`)";
+        pub const parse_target_feature: &str = parse_string;
     }
 
     #[allow(dead_code)]
@@ -636,6 +637,19 @@ macro_rules! options {
             }
             true
         }
+
+        fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
+            match v {
+                Some(s) => {
+                    if !slot.is_empty() {
+                        slot.push_str(",");
+                    }
+                    slot.push_str(s);
+                    true
+                }
+                None => false,
+            }
+        }
     }
 ) }
 
@@ -731,7 +745,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
         "use soft float ABI (*eabihf targets only) (default: no)"),
     target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
         "select target processor (`rustc --print target-cpus` for details)"),
-    target_feature: String = (String::new(), parse_string, [TRACKED],
+    target_feature: String = (String::new(), parse_target_feature, [TRACKED],
         "target specific attributes. (`rustc --print target-features` for details). \
         This feature is unsafe."),
 
diff --git a/src/test/codegen/target-feature-multiple.rs b/src/test/codegen/target-feature-multiple.rs
new file mode 100644
index 0000000000000..f71a9c3c58216
--- /dev/null
+++ b/src/test/codegen/target-feature-multiple.rs
@@ -0,0 +1,9 @@
+// only-x86_64
+// compile-flags: -C target-feature=+sse2,-avx,+avx2 -C target-feature=+avx,-avx2
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: attributes #0 = { {{.*}}"target-features"="+sse2,-avx,+avx2,+avx,-avx2"{{.*}} }
+}