| 1 | use crate::target::TargetInfo; | 
| 2 | use crate::{Build, Error, ErrorKind, Tool, ToolFamily}; | 
|---|
| 3 | use std::borrow::Cow; | 
|---|
| 4 | use std::ffi::OsString; | 
|---|
| 5 |  | 
|---|
| 6 | #[ derive(Debug, PartialEq, Default)] | 
|---|
| 7 | pub(crate) struct RustcCodegenFlags<'a> { | 
|---|
| 8 | branch_protection: Option<&'a str>, | 
|---|
| 9 | code_model: Option<&'a str>, | 
|---|
| 10 | no_vectorize_loops: bool, | 
|---|
| 11 | no_vectorize_slp: bool, | 
|---|
| 12 | profile_generate: Option<&'a str>, | 
|---|
| 13 | profile_use: Option<&'a str>, | 
|---|
| 14 | control_flow_guard: Option<&'a str>, | 
|---|
| 15 | lto: Option<&'a str>, | 
|---|
| 16 | relocation_model: Option<&'a str>, | 
|---|
| 17 | embed_bitcode: Option<bool>, | 
|---|
| 18 | force_frame_pointers: Option<bool>, | 
|---|
| 19 | no_redzone: Option<bool>, | 
|---|
| 20 | soft_float: Option<bool>, | 
|---|
| 21 | dwarf_version: Option<u32>, | 
|---|
| 22 | } | 
|---|
| 23 |  | 
|---|
| 24 | impl<'this> RustcCodegenFlags<'this> { | 
|---|
| 25 | // Parse flags obtained from CARGO_ENCODED_RUSTFLAGS | 
|---|
| 26 | pub(crate) fn parse(rustflags_env: &'this str) -> Result<Self, Error> { | 
|---|
| 27 | fn is_flag_prefix(flag: &str) -> bool { | 
|---|
| 28 | [ | 
|---|
| 29 | "-Z", | 
|---|
| 30 | "-C", | 
|---|
| 31 | "--codegen", | 
|---|
| 32 | "-L", | 
|---|
| 33 | "-l", | 
|---|
| 34 | "-o", | 
|---|
| 35 | "-W", | 
|---|
| 36 | "--warn", | 
|---|
| 37 | "-A", | 
|---|
| 38 | "--allow", | 
|---|
| 39 | "-D", | 
|---|
| 40 | "--deny", | 
|---|
| 41 | "-F", | 
|---|
| 42 | "--forbid", | 
|---|
| 43 | ] | 
|---|
| 44 | .contains(&flag) | 
|---|
| 45 | } | 
|---|
| 46 |  | 
|---|
| 47 | fn handle_flag_prefix<'a>(prev: &'a str, curr: &'a str) -> (&'a str, &'a str) { | 
|---|
| 48 | match prev { | 
|---|
| 49 | "--codegen"| "-C"=> ( "-C", curr), | 
|---|
| 50 | // Handle flags passed like --codegen=code-model=small | 
|---|
| 51 | _ if curr.starts_with( "--codegen=") => ( "-C", &curr[10..]), | 
|---|
| 52 | "-Z"=> ( "-Z", curr), | 
|---|
| 53 | "-L"| "-l"| "-o"=> (prev, curr), | 
|---|
| 54 | // Handle lint flags | 
|---|
| 55 | "-W"| "--warn"=> ( "-W", curr), | 
|---|
| 56 | "-A"| "--allow"=> ( "-A", curr), | 
|---|
| 57 | "-D"| "--deny"=> ( "-D", curr), | 
|---|
| 58 | "-F"| "--forbid"=> ( "-F", curr), | 
|---|
| 59 | _ => ( "", curr), | 
|---|
| 60 | } | 
|---|
| 61 | } | 
|---|
| 62 |  | 
|---|
| 63 | let mut codegen_flags = Self::default(); | 
|---|
| 64 |  | 
|---|
| 65 | let mut prev_prefix = None; | 
|---|
| 66 | for curr in rustflags_env.split( "\u{1f} ") { | 
|---|
| 67 | let prev = prev_prefix.take().unwrap_or( ""); | 
|---|
| 68 | if prev.is_empty() && is_flag_prefix(curr) { | 
|---|
| 69 | prev_prefix = Some(curr); | 
|---|
| 70 | continue; | 
|---|
| 71 | } | 
|---|
| 72 |  | 
|---|
| 73 | let (prefix, rustc_flag) = handle_flag_prefix(prev, curr); | 
|---|
| 74 | codegen_flags.set_rustc_flag(prefix, rustc_flag)?; | 
|---|
| 75 | } | 
|---|
| 76 |  | 
|---|
| 77 | Ok(codegen_flags) | 
|---|
| 78 | } | 
|---|
| 79 |  | 
|---|
| 80 | fn set_rustc_flag(&mut self, prefix: &str, flag: &'this str) -> Result<(), Error> { | 
|---|
| 81 | // Convert a textual representation of a bool-like rustc flag argument into an actual bool | 
|---|
| 82 | fn arg_to_bool(arg: impl AsRef<str>) -> Option<bool> { | 
|---|
| 83 | match arg.as_ref() { | 
|---|
| 84 | "y"| "yes"| "on"| "true"=> Some(true), | 
|---|
| 85 | "n"| "no"| "off"| "false"=> Some(false), | 
|---|
| 86 | _ => None, | 
|---|
| 87 | } | 
|---|
| 88 | } | 
|---|
| 89 |  | 
|---|
| 90 | fn arg_to_u32(arg: impl AsRef<str>) -> Option<u32> { | 
|---|
| 91 | arg.as_ref().parse().ok() | 
|---|
| 92 | } | 
|---|
| 93 |  | 
|---|
| 94 | let (flag, value) = if let Some((flag, value)) = flag.split_once( '=') { | 
|---|
| 95 | (flag, Some(value)) | 
|---|
| 96 | } else { | 
|---|
| 97 | (flag, None) | 
|---|
| 98 | }; | 
|---|
| 99 | let flag = if prefix.is_empty() { | 
|---|
| 100 | Cow::Borrowed(flag) | 
|---|
| 101 | } else { | 
|---|
| 102 | Cow::Owned(format!( "{prefix}{flag} ")) | 
|---|
| 103 | }; | 
|---|
| 104 |  | 
|---|
| 105 | fn flag_ok_or<'flag>( | 
|---|
| 106 | flag: Option<&'flag str>, | 
|---|
| 107 | msg: &'static str, | 
|---|
| 108 | ) -> Result<&'flag str, Error> { | 
|---|
| 109 | flag.ok_or(Error::new(ErrorKind::InvalidFlag, msg)) | 
|---|
| 110 | } | 
|---|
| 111 |  | 
|---|
| 112 | match flag.as_ref() { | 
|---|
| 113 | // https://doc.rust-lang.org/rustc/codegen-options/index.html#code-model | 
|---|
| 114 | "-Ccode-model"=> { | 
|---|
| 115 | self.code_model = Some(flag_ok_or(value, "-Ccode-model must have a value")?); | 
|---|
| 116 | } | 
|---|
| 117 | // https://doc.rust-lang.org/rustc/codegen-options/index.html#no-vectorize-loops | 
|---|
| 118 | "-Cno-vectorize-loops"=> self.no_vectorize_loops = true, | 
|---|
| 119 | // https://doc.rust-lang.org/rustc/codegen-options/index.html#no-vectorize-slp | 
|---|
| 120 | "-Cno-vectorize-slp"=> self.no_vectorize_slp = true, | 
|---|
| 121 | // https://doc.rust-lang.org/rustc/codegen-options/index.html#profile-generate | 
|---|
| 122 | "-Cprofile-generate"=> { | 
|---|
| 123 | self.profile_generate = | 
|---|
| 124 | Some(flag_ok_or(value, "-Cprofile-generate must have a value")?); | 
|---|
| 125 | } | 
|---|
| 126 | // https://doc.rust-lang.org/rustc/codegen-options/index.html#profile-use | 
|---|
| 127 | "-Cprofile-use"=> { | 
|---|
| 128 | self.profile_use = Some(flag_ok_or(value, "-Cprofile-use must have a value")?); | 
|---|
| 129 | } | 
|---|
| 130 | // https://doc.rust-lang.org/rustc/codegen-options/index.html#control-flow-guard | 
|---|
| 131 | "-Ccontrol-flow-guard"=> self.control_flow_guard = value.or(Some( "true")), | 
|---|
| 132 | // https://doc.rust-lang.org/rustc/codegen-options/index.html#lto | 
|---|
| 133 | "-Clto"=> self.lto = value.or(Some( "true")), | 
|---|
| 134 | // https://doc.rust-lang.org/rustc/codegen-options/index.html#relocation-model | 
|---|
| 135 | "-Crelocation-model"=> { | 
|---|
| 136 | self.relocation_model = | 
|---|
| 137 | Some(flag_ok_or(value, "-Crelocation-model must have a value")?); | 
|---|
| 138 | } | 
|---|
| 139 | // https://doc.rust-lang.org/rustc/codegen-options/index.html#embed-bitcode | 
|---|
| 140 | "-Cembed-bitcode"=> self.embed_bitcode = value.map_or(Some(true), arg_to_bool), | 
|---|
| 141 | // https://doc.rust-lang.org/rustc/codegen-options/index.html#force-frame-pointers | 
|---|
| 142 | "-Cforce-frame-pointers"=> { | 
|---|
| 143 | self.force_frame_pointers = value.map_or(Some(true), arg_to_bool) | 
|---|
| 144 | } | 
|---|
| 145 | // https://doc.rust-lang.org/rustc/codegen-options/index.html#no-redzone | 
|---|
| 146 | "-Cno-redzone"=> self.no_redzone = value.map_or(Some(true), arg_to_bool), | 
|---|
| 147 | // https://doc.rust-lang.org/rustc/codegen-options/index.html#soft-float | 
|---|
| 148 | // Note: This flag is now deprecated in rustc. | 
|---|
| 149 | "-Csoft-float"=> self.soft_float = value.map_or(Some(true), arg_to_bool), | 
|---|
| 150 | // https://doc.rust-lang.org/beta/unstable-book/compiler-flags/branch-protection.html | 
|---|
| 151 | // FIXME: Drop the -Z variant and update the doc link once the option is stabilised | 
|---|
| 152 | "-Zbranch-protection"| "-Cbranch-protection"=> { | 
|---|
| 153 | self.branch_protection = | 
|---|
| 154 | Some(flag_ok_or(value, "-Zbranch-protection must have a value")?); | 
|---|
| 155 | } | 
|---|
| 156 | // https://doc.rust-lang.org/beta/unstable-book/compiler-flags/dwarf-version.html | 
|---|
| 157 | // FIXME: Drop the -Z variant and update the doc link once the option is stablized | 
|---|
| 158 | "-Zdwarf-version"| "-Cdwarf-version"=> { | 
|---|
| 159 | self.dwarf_version = Some(value.and_then(arg_to_u32).ok_or(Error::new( | 
|---|
| 160 | ErrorKind::InvalidFlag, | 
|---|
| 161 | "-Zdwarf-version must have a value", | 
|---|
| 162 | ))?); | 
|---|
| 163 | } | 
|---|
| 164 | _ => {} | 
|---|
| 165 | } | 
|---|
| 166 | Ok(()) | 
|---|
| 167 | } | 
|---|
| 168 |  | 
|---|
| 169 | // Rust and clang/cc don't agree on what equivalent flags should look like. | 
|---|
| 170 | pub(crate) fn cc_flags(&self, build: &Build, tool: &mut Tool, target: &TargetInfo<'_>) { | 
|---|
| 171 | let family = tool.family; | 
|---|
| 172 | // Push `flag` to `flags` if it is supported by the currently used CC | 
|---|
| 173 | let mut push_if_supported = |flag: OsString| { | 
|---|
| 174 | if build | 
|---|
| 175 | .is_flag_supported_inner(&flag, tool, target) | 
|---|
| 176 | .unwrap_or(false) | 
|---|
| 177 | { | 
|---|
| 178 | tool.args.push(flag); | 
|---|
| 179 | } else { | 
|---|
| 180 | build.cargo_output.print_warning(&format!( | 
|---|
| 181 | "Inherited flag {:?}  is not supported by the currently used CC", | 
|---|
| 182 | flag | 
|---|
| 183 | )); | 
|---|
| 184 | } | 
|---|
| 185 | }; | 
|---|
| 186 |  | 
|---|
| 187 | let clang_or_gnu = | 
|---|
| 188 | matches!(family, ToolFamily::Clang { .. }) || matches!(family, ToolFamily::Gnu { .. }); | 
|---|
| 189 |  | 
|---|
| 190 | // Flags shared between clang and gnu | 
|---|
| 191 | if clang_or_gnu { | 
|---|
| 192 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mbranch-protection | 
|---|
| 193 | // https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html#index-mbranch-protection (Aarch64) | 
|---|
| 194 | // https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html#index-mbranch-protection-1 (ARM) | 
|---|
| 195 | // https://developer.arm.com/documentation/101754/0619/armclang-Reference/armclang-Command-line-Options/-mbranch-protection | 
|---|
| 196 | if let Some(value) = self.branch_protection { | 
|---|
| 197 | push_if_supported( | 
|---|
| 198 | format!( "-mbranch-protection={} ", value.replace( ",", "+")).into(), | 
|---|
| 199 | ); | 
|---|
| 200 | } | 
|---|
| 201 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mcmodel | 
|---|
| 202 | // https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html (several archs, search for `-mcmodel=`). | 
|---|
| 203 | // FIXME(madsmtm): Parse the model, to make sure we pass the correct value (depending on arch). | 
|---|
| 204 | if let Some(value) = self.code_model { | 
|---|
| 205 | push_if_supported(format!( "-mcmodel={value} ").into()); | 
|---|
| 206 | } | 
|---|
| 207 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fno-vectorize | 
|---|
| 208 | // https://gcc.gnu.org/onlinedocs/gnat_ugn/Vectorization-of-loops.html | 
|---|
| 209 | if self.no_vectorize_loops { | 
|---|
| 210 | push_if_supported( "-fno-vectorize".into()); | 
|---|
| 211 | } | 
|---|
| 212 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fno-slp-vectorize | 
|---|
| 213 | // https://gcc.gnu.org/onlinedocs/gnat_ugn/Vectorization-of-loops.html | 
|---|
| 214 | if self.no_vectorize_slp { | 
|---|
| 215 | push_if_supported( "-fno-slp-vectorize".into()); | 
|---|
| 216 | } | 
|---|
| 217 | if let Some(value) = self.relocation_model { | 
|---|
| 218 | let cc_flag = match value { | 
|---|
| 219 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fPIC | 
|---|
| 220 | // https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fPIC | 
|---|
| 221 | "pic"=> Some( "-fPIC"), | 
|---|
| 222 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fPIE | 
|---|
| 223 | // https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fPIE | 
|---|
| 224 | "pie"=> Some( "-fPIE"), | 
|---|
| 225 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mdynamic-no-pic | 
|---|
| 226 | // https://gcc.gnu.org/onlinedocs/gcc/RS_002f6000-and-PowerPC-Options.html#index-mdynamic-no-pic | 
|---|
| 227 | "dynamic-no-pic"=> Some( "-mdynamic-no-pic"), | 
|---|
| 228 | _ => None, | 
|---|
| 229 | }; | 
|---|
| 230 | if let Some(cc_flag) = cc_flag { | 
|---|
| 231 | push_if_supported(cc_flag.into()); | 
|---|
| 232 | } | 
|---|
| 233 | } | 
|---|
| 234 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fno-omit-frame-pointer | 
|---|
| 235 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fomit-frame-pointer | 
|---|
| 236 | // https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-fomit-frame-pointer | 
|---|
| 237 | if let Some(value) = self.force_frame_pointers { | 
|---|
| 238 | let cc_flag = if value { | 
|---|
| 239 | "-fno-omit-frame-pointer" | 
|---|
| 240 | } else { | 
|---|
| 241 | "-fomit-frame-pointer" | 
|---|
| 242 | }; | 
|---|
| 243 | push_if_supported(cc_flag.into()); | 
|---|
| 244 | } | 
|---|
| 245 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mno-red-zone | 
|---|
| 246 | // https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mno-red-zone | 
|---|
| 247 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mred-zone | 
|---|
| 248 | // https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mred-zone | 
|---|
| 249 | if let Some(value) = self.no_redzone { | 
|---|
| 250 | let cc_flag = if value { "-mno-red-zone"} else { "-mred-zone"}; | 
|---|
| 251 | push_if_supported(cc_flag.into()); | 
|---|
| 252 | } | 
|---|
| 253 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-msoft-float | 
|---|
| 254 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mhard-float | 
|---|
| 255 | // https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html (several archs, search for `-msoft-float`). | 
|---|
| 256 | // https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html (several archs, search for `-mhard-float`). | 
|---|
| 257 | if let Some(value) = self.soft_float { | 
|---|
| 258 | let cc_flag = if value { | 
|---|
| 259 | "-msoft-float" | 
|---|
| 260 | } else { | 
|---|
| 261 | // Do not use -mno-soft-float, that's basically just an alias for -mno-implicit-float. | 
|---|
| 262 | "-mhard-float" | 
|---|
| 263 | }; | 
|---|
| 264 | push_if_supported(cc_flag.into()); | 
|---|
| 265 | } | 
|---|
| 266 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-gdwarf-2 | 
|---|
| 267 | // https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html#index-gdwarf | 
|---|
| 268 | if let Some(value) = self.dwarf_version { | 
|---|
| 269 | push_if_supported(format!( "-gdwarf-{value} ").into()); | 
|---|
| 270 | } | 
|---|
| 271 | } | 
|---|
| 272 |  | 
|---|
| 273 | // Compiler-exclusive flags | 
|---|
| 274 | match family { | 
|---|
| 275 | ToolFamily::Clang { .. } => { | 
|---|
| 276 | // GNU and Clang compilers both support the same PGO flags, but they use different libraries and | 
|---|
| 277 | // different formats for the profile files which are not compatible. | 
|---|
| 278 | // clang and rustc both internally use llvm, so we want to inherit the PGO flags only for clang. | 
|---|
| 279 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fprofile-generate | 
|---|
| 280 | if let Some(value) = self.profile_generate { | 
|---|
| 281 | push_if_supported(format!( "-fprofile-generate={value} ").into()); | 
|---|
| 282 | } | 
|---|
| 283 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fprofile-use | 
|---|
| 284 | if let Some(value) = self.profile_use { | 
|---|
| 285 | push_if_supported(format!( "-fprofile-use={value} ").into()); | 
|---|
| 286 | } | 
|---|
| 287 |  | 
|---|
| 288 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fembed-bitcode | 
|---|
| 289 | if let Some(value) = self.embed_bitcode { | 
|---|
| 290 | let cc_val = if value { "all"} else { "off"}; | 
|---|
| 291 | push_if_supported(format!( "-fembed-bitcode={cc_val} ").into()); | 
|---|
| 292 | } | 
|---|
| 293 |  | 
|---|
| 294 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-flto | 
|---|
| 295 | if let Some(value) = self.lto { | 
|---|
| 296 | let cc_val = match value { | 
|---|
| 297 | "y"| "yes"| "on"| "true"| "fat"=> Some( "full"), | 
|---|
| 298 | "thin"=> Some( "thin"), | 
|---|
| 299 | _ => None, | 
|---|
| 300 | }; | 
|---|
| 301 | if let Some(cc_val) = cc_val { | 
|---|
| 302 | push_if_supported(format!( "-flto={cc_val} ").into()); | 
|---|
| 303 | } | 
|---|
| 304 | } | 
|---|
| 305 | // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mguard | 
|---|
| 306 | if let Some(value) = self.control_flow_guard { | 
|---|
| 307 | let cc_val = match value { | 
|---|
| 308 | "y"| "yes"| "on"| "true"| "checks"=> Some( "cf"), | 
|---|
| 309 | "nochecks"=> Some( "cf-nochecks"), | 
|---|
| 310 | "n"| "no"| "off"| "false"=> Some( "none"), | 
|---|
| 311 | _ => None, | 
|---|
| 312 | }; | 
|---|
| 313 | if let Some(cc_val) = cc_val { | 
|---|
| 314 | push_if_supported(format!( "-mguard={cc_val} ").into()); | 
|---|
| 315 | } | 
|---|
| 316 | } | 
|---|
| 317 | } | 
|---|
| 318 | ToolFamily::Gnu { .. } => {} | 
|---|
| 319 | ToolFamily::Msvc { .. } => { | 
|---|
| 320 | // https://learn.microsoft.com/en-us/cpp/build/reference/guard-enable-control-flow-guard | 
|---|
| 321 | if let Some(value) = self.control_flow_guard { | 
|---|
| 322 | let cc_val = match value { | 
|---|
| 323 | "y"| "yes"| "on"| "true"| "checks"=> Some( "cf"), | 
|---|
| 324 | "n"| "no"| "off"| "false"=> Some( "cf-"), | 
|---|
| 325 | _ => None, | 
|---|
| 326 | }; | 
|---|
| 327 | if let Some(cc_val) = cc_val { | 
|---|
| 328 | push_if_supported(format!( "/guard:{cc_val} ").into()); | 
|---|
| 329 | } | 
|---|
| 330 | } | 
|---|
| 331 | // https://learn.microsoft.com/en-us/cpp/build/reference/oy-frame-pointer-omission | 
|---|
| 332 | if let Some(value) = self.force_frame_pointers { | 
|---|
| 333 | // Flag is unsupported on 64-bit arches | 
|---|
| 334 | if !target.arch.contains( "64") { | 
|---|
| 335 | let cc_flag = if value { "/Oy-"} else { "/Oy"}; | 
|---|
| 336 | push_if_supported(cc_flag.into()); | 
|---|
| 337 | } | 
|---|
| 338 | } | 
|---|
| 339 | } | 
|---|
| 340 | } | 
|---|
| 341 | } | 
|---|
| 342 | } | 
|---|
| 343 |  | 
|---|
| 344 | #[ cfg(test)] | 
|---|
| 345 | mod tests { | 
|---|
| 346 | use super::*; | 
|---|
| 347 |  | 
|---|
| 348 | #[ track_caller] | 
|---|
| 349 | fn check(env: &str, expected: &RustcCodegenFlags) { | 
|---|
| 350 | let actual = RustcCodegenFlags::parse(env).unwrap(); | 
|---|
| 351 | assert_eq!(actual, *expected); | 
|---|
| 352 | } | 
|---|
| 353 |  | 
|---|
| 354 | #[ test] | 
|---|
| 355 | fn codegen_type() { | 
|---|
| 356 | let expected = RustcCodegenFlags { | 
|---|
| 357 | code_model: Some( "tiny"), | 
|---|
| 358 | ..RustcCodegenFlags::default() | 
|---|
| 359 | }; | 
|---|
| 360 | check( "-Ccode-model=tiny", &expected); | 
|---|
| 361 | check( "-C\u{1f} code-model=tiny", &expected); | 
|---|
| 362 | check( "--codegen\u{1f} code-model=tiny", &expected); | 
|---|
| 363 | check( "--codegen=code-model=tiny", &expected); | 
|---|
| 364 | } | 
|---|
| 365 |  | 
|---|
| 366 | #[ test] | 
|---|
| 367 | fn precedence() { | 
|---|
| 368 | check( | 
|---|
| 369 | "-ccode-model=tiny\u{1f} -Ccode-model=small", | 
|---|
| 370 | &RustcCodegenFlags { | 
|---|
| 371 | code_model: Some( "small"), | 
|---|
| 372 | ..RustcCodegenFlags::default() | 
|---|
| 373 | }, | 
|---|
| 374 | ); | 
|---|
| 375 | } | 
|---|
| 376 |  | 
|---|
| 377 | #[ test] | 
|---|
| 378 | fn two_valid_prefixes() { | 
|---|
| 379 | let expected = RustcCodegenFlags::default(); | 
|---|
| 380 | check( "-L\u{1f} -Clto", &expected); | 
|---|
| 381 | } | 
|---|
| 382 |  | 
|---|
| 383 | #[ test] | 
|---|
| 384 | fn three_valid_prefixes() { | 
|---|
| 385 | let expected = RustcCodegenFlags { | 
|---|
| 386 | lto: Some( "true"), | 
|---|
| 387 | ..RustcCodegenFlags::default() | 
|---|
| 388 | }; | 
|---|
| 389 | check( "-L\u{1f} -L\u{1f} -Clto", &expected); | 
|---|
| 390 | } | 
|---|
| 391 |  | 
|---|
| 392 | #[ test] | 
|---|
| 393 | fn all_rustc_flags() { | 
|---|
| 394 | // Throw all possible flags at the parser to catch false positives | 
|---|
| 395 | let flags = [ | 
|---|
| 396 | // Set all the flags we recognise first | 
|---|
| 397 | "-Ccode-model=tiny", | 
|---|
| 398 | "-Ccontrol-flow-guard=yes", | 
|---|
| 399 | "-Cembed-bitcode=no", | 
|---|
| 400 | "-Cforce-frame-pointers=yes", | 
|---|
| 401 | "-Clto=false", | 
|---|
| 402 | "-Clink-dead-code=yes", | 
|---|
| 403 | "-Cno-redzone=yes", | 
|---|
| 404 | "-Cno-vectorize-loops", | 
|---|
| 405 | "-Cno-vectorize-slp", | 
|---|
| 406 | "-Cprofile-generate=fooprofile", | 
|---|
| 407 | "-Cprofile-use=fooprofile", | 
|---|
| 408 | "-Crelocation-model=pic", | 
|---|
| 409 | "-Csoft-float=yes", | 
|---|
| 410 | "-Zbranch-protection=bti,pac-ret,leaf", | 
|---|
| 411 | "-Zdwarf-version=5", | 
|---|
| 412 | // Set flags we don't recognise but rustc supports next | 
|---|
| 413 | // rustc flags | 
|---|
| 414 | "--cfg", | 
|---|
| 415 | "a", | 
|---|
| 416 | "--check-cfg 'cfg(verbose)", | 
|---|
| 417 | "-L", | 
|---|
| 418 | "/usr/lib/foo", | 
|---|
| 419 | "-l", | 
|---|
| 420 | "static:+whole-archive=mylib", | 
|---|
| 421 | "--crate-type=dylib", | 
|---|
| 422 | "--crate-name=foo", | 
|---|
| 423 | "--edition=2021", | 
|---|
| 424 | "--emit=asm", | 
|---|
| 425 | "--print=crate-name", | 
|---|
| 426 | "-g", | 
|---|
| 427 | "-O", | 
|---|
| 428 | "-o", | 
|---|
| 429 | "foooutput", | 
|---|
| 430 | "--out-dir", | 
|---|
| 431 | "foooutdir", | 
|---|
| 432 | "--target", | 
|---|
| 433 | "aarch64-unknown-linux-gnu", | 
|---|
| 434 | "-W", | 
|---|
| 435 | "missing-docs", | 
|---|
| 436 | "-D", | 
|---|
| 437 | "unused-variables", | 
|---|
| 438 | "--force-warn", | 
|---|
| 439 | "dead-code", | 
|---|
| 440 | "-A", | 
|---|
| 441 | "unused", | 
|---|
| 442 | "-F", | 
|---|
| 443 | "unused", | 
|---|
| 444 | "--cap-lints", | 
|---|
| 445 | "warn", | 
|---|
| 446 | "--version", | 
|---|
| 447 | "--verbose", | 
|---|
| 448 | "-v", | 
|---|
| 449 | "--extern", | 
|---|
| 450 | "foocrate", | 
|---|
| 451 | "--sysroot", | 
|---|
| 452 | "fooroot", | 
|---|
| 453 | "--error-format", | 
|---|
| 454 | "human", | 
|---|
| 455 | "--color", | 
|---|
| 456 | "auto", | 
|---|
| 457 | "--diagnostic-width", | 
|---|
| 458 | "80", | 
|---|
| 459 | "--remap-path-prefix", | 
|---|
| 460 | "foo=bar", | 
|---|
| 461 | "--json=artifact", | 
|---|
| 462 | // Codegen flags | 
|---|
| 463 | "-Car", | 
|---|
| 464 | "-Ccodegen-units=1", | 
|---|
| 465 | "-Ccollapse-macro-debuginfo=yes", | 
|---|
| 466 | "-Cdebug-assertions=yes", | 
|---|
| 467 | "-Cdebuginfo=1", | 
|---|
| 468 | "-Cdefault-linker-libraries=yes", | 
|---|
| 469 | "-Cdlltool=foo", | 
|---|
| 470 | "-Cextra-filename=foo", | 
|---|
| 471 | "-Cforce-unwind-tables=yes", | 
|---|
| 472 | "-Cincremental=foodir", | 
|---|
| 473 | "-Cinline-threshold=6", | 
|---|
| 474 | "-Cinstrument-coverage", | 
|---|
| 475 | "-Clink-arg=-foo", | 
|---|
| 476 | "-Clink-args=-foo", | 
|---|
| 477 | "-Clink-self-contained=yes", | 
|---|
| 478 | "-Clinker=lld", | 
|---|
| 479 | "-Clinker-flavor=ld.lld", | 
|---|
| 480 | "-Clinker-plugin-lto=yes", | 
|---|
| 481 | "-Cllvm-args=foo", | 
|---|
| 482 | "-Cmetadata=foo", | 
|---|
| 483 | "-Cno-prepopulate-passes", | 
|---|
| 484 | "-Cno-stack-check", | 
|---|
| 485 | "-Copt-level=3", | 
|---|
| 486 | "-Coverflow-checks=yes", | 
|---|
| 487 | "-Cpanic=abort", | 
|---|
| 488 | "-Cpasses=foopass", | 
|---|
| 489 | "-Cprefer-dynamic=yes", | 
|---|
| 490 | "-Crelro-level=partial", | 
|---|
| 491 | "-Cremark=all", | 
|---|
| 492 | "-Crpath=yes", | 
|---|
| 493 | "-Csave-temps=yes", | 
|---|
| 494 | "-Csplit-debuginfo=packed", | 
|---|
| 495 | "-Cstrip=symbols", | 
|---|
| 496 | "-Csymbol-mangling-version=v0", | 
|---|
| 497 | "-Ctarget-cpu=native", | 
|---|
| 498 | "-Ctarget-feature=+sve", | 
|---|
| 499 | // Unstable options | 
|---|
| 500 | "-Ztune-cpu=machine", | 
|---|
| 501 | ]; | 
|---|
| 502 | check( | 
|---|
| 503 | &flags.join( "\u{1f} "), | 
|---|
| 504 | &RustcCodegenFlags { | 
|---|
| 505 | code_model: Some( "tiny"), | 
|---|
| 506 | control_flow_guard: Some( "yes"), | 
|---|
| 507 | embed_bitcode: Some(false), | 
|---|
| 508 | force_frame_pointers: Some(true), | 
|---|
| 509 | lto: Some( "false"), | 
|---|
| 510 | no_redzone: Some(true), | 
|---|
| 511 | no_vectorize_loops: true, | 
|---|
| 512 | no_vectorize_slp: true, | 
|---|
| 513 | profile_generate: Some( "fooprofile"), | 
|---|
| 514 | profile_use: Some( "fooprofile"), | 
|---|
| 515 | relocation_model: Some( "pic"), | 
|---|
| 516 | soft_float: Some(true), | 
|---|
| 517 | branch_protection: Some( "bti,pac-ret,leaf"), | 
|---|
| 518 | dwarf_version: Some(5), | 
|---|
| 519 | }, | 
|---|
| 520 | ); | 
|---|
| 521 | } | 
|---|
| 522 | } | 
|---|
| 523 |  | 
|---|