Richer argument handling for compilers#277
Conversation
src/compiler/args.rs
Outdated
| type ArgResult<T> = StdResult<T, ArgError>; | ||
|
|
||
| #[derive(Debug, PartialEq)] | ||
| pub enum ArgError { |
There was a problem hiding this comment.
When we finish merging all of your work my first order of business is to switch from error-chain to failure. 😃
| UnknownFlag(OsString), | ||
| /// Known flag argument ; e.g. "-bar" | ||
| Flag(&'static str), | ||
| Flag(&'static str, T), |
There was a problem hiding this comment.
It took me a lot more code reading to figure out why Flag needed to store the additional value here. I think the comment above Argument<T> could stand an additional sentence or two explaining what the type parameter is used for.
src/compiler/args.rs
Outdated
|
|
||
| /// Helper macro used to define ArgInfo::Flag's. | ||
| /// Variant is an enum variant, e.g. enum ArgType { Variant(()) } | ||
| /// flag!("-foo") |
There was a problem hiding this comment.
You removed the single argument macro rule below, so the comment here should be removed as well.
| Coverage, | ||
| ArgData!{ pub | ||
| TooHardFlag(()), | ||
| TooHard(OsString), |
There was a problem hiding this comment.
This is a little awkward, but it's not really terrible.
src/compiler/gcc.rs
Outdated
| SplitDwarf(()), | ||
| ProfileGenerate(()), | ||
| TestCoverage(()), | ||
| Coverage(()), |
There was a problem hiding this comment.
I don't know if it's feasible, but it would be nicer if the macro could take $x:ident without a type and handle it as ().
There was a problem hiding this comment.
To answer my own question: I don't think it's possible with current stable Rust. RFC 2298 adds a ? repetition operator to macros which would make this feasible. This code works on Nightly (although I couldn't get it to work on the playground for some reason):
https://gist.github.com/luser/0284cecdec8f7a2f789e37ffc52f963e
There was a problem hiding this comment.
Oh, it needed Edition: 2018 to work on the playground. (My local nightly is a few months out of date.)
src/compiler/gcc.rs
Outdated
|
|
||
| for item in ArgsIter::new(it, arg_info) { | ||
| for arg in ArgsIter::new(it, arg_info) { | ||
| let arg = try_arg!(arg.map_err(|e| e.static_description())); |
There was a problem hiding this comment.
You seem to have this same map_err clause in all the places you use try_arg!, so why not just bake it into the macro?
| ArgData!{ | ||
| TooHardFlag(()), | ||
| TooHard(OsString), | ||
| TooHardPath(PathBuf), |
There was a problem hiding this comment.
Since we don't really need the argument for TooHardPath, can we just drop this and use TooHard(OsString) for those arguments?
Further musing has me wonder if we could combine them all into TooHard(Option<OsString>) and just impl the right traits for Option<OsString>.
| Ok(T), | ||
| /// Cannot cache this compilation. | ||
| CannotCache(&'static str), | ||
| CannotCache(&'static str, Option<String>), |
There was a problem hiding this comment.
Does this buy us a whole lot? Do we wind up with anything but "failed to parse argument value" in the second field? I have a WIP patch for #263 that saves counts of the CannotCache reasons in the server stats. I don't think this change will be a problem for it, but I'm not sure how I'd expose this new field.
There was a problem hiding this comment.
Ah, I think you're inverting the way you're looking at this - "argument parse" is the consistent value that always gets put in the first field (exactly because of the cannotcache reason counting), but it didn't seem ideal to just throw away all nuance of that. Specifically, take a look at ArgParseError - Display creates a description of what went wrong with what part of the argument, which isn't possible in the bounds of a static string. This nice description will get printed in the logs.
src/compiler/rust.rs
Outdated
| @@ -72,7 +72,7 @@ pub struct RustHasher { | |||
| #[derive(Debug, Clone, PartialEq)] | |||
| pub struct ParsedArguments { | |||
| /// The full commandline, with arguments and their values as pairs. | |||
There was a problem hiding this comment.
Change the comment here to match?
| let toolchain_creator = Box::new(RustCompilerPackager { sysroot: sysroot.clone() }); | ||
| let mut arguments = arguments; | ||
| // Always request color output, the client will strip colors if needed. | ||
| arguments.push(Argument::WithValue("--color", ArgData::Color("always".into()), ArgDisposition::Separated)); |
There was a problem hiding this comment.
Would it be simpler to move this into generate_compile_commands? I don't remember exactly why I put it here in the first place.
| let me = *self; | ||
| let RustHasher { executable, sysroot, compiler_shlibs_digests, parsed_args: ParsedArguments { arguments, output_dir, externs, staticlibs, crate_name, dep_info, color_mode: _ } } = me; | ||
| trace!("[{}]: generate_hash_key", crate_name); | ||
| // TODO: this doesn't produce correct arguments if they should be concatenated - should use iter_os_strings |
There was a problem hiding this comment.
Is this fixed in a followup? If not, will this cause problems in practice?
There was a problem hiding this comment.
I will observe that this behaviour has always been the case (it's just being flagged now) so I suspect in practice it does not cause issues :)
src/compiler/rust.rs
Outdated
| // If no kind is specified, the default is dylib. | ||
| (name, None) => ("dylib".to_owned(), name), | ||
| }; | ||
| Ok(ArgLinkLibrary { kind: kind, name: name }) |
There was a problem hiding this comment.
nit: this could just be { kind, name }.
| } | ||
|
|
||
| #[derive(Clone, Debug, PartialEq)] | ||
| struct ArgLinkLibrary { |
There was a problem hiding this comment.
All of these could stand to have a one-line descriptive comment, like "Represents -l [KIND=]PATH link arguments to rustc".
| // auto-added for target json discovery | ||
| return Ok(ArgTarget::Unsure(arg)) | ||
| } | ||
| // The file doesn't exist so it can't be a path, safe to assume it's a name |
There was a problem hiding this comment.
I wonder if we'd be better off running rustc --print=target-list in the initial compiler detection and matching against that?
| } | ||
| Some(LinkLibrary(ArgLinkLibrary { kind, name })) => { | ||
| if kind == "static" { | ||
| static_lib_names.push(name.to_owned()) |
There was a problem hiding this comment.
We could presumably push this logic down into hash generation now, since the arguments there will have enough context. (It's not a big deal, though.)
luser
left a comment
There was a problem hiding this comment.
I left a number of comments, but I don't think any of them need to block merging. Feel free to merge this once you rebase and merge the previous PR.
5583ead to
7127eaf
Compare
|
I suddenly felt motivated, so I implemented a better macro that allows enum variants without data. It was actually nowhere near as bad as I thought it was going to be (which was why I avoided it originally). |
7127eaf to
b72bccc
Compare
| PassThrough(OsString), | ||
| PassThroughPath(PathBuf), | ||
| PreprocessorArgumentFlag(()), | ||
| PreprocessorArgumentFlag, |
There was a problem hiding this comment.
That's much nicer! I fiddled with this for a bit but couldn't find a working solution except with the unstable ? macro repetition operator.
|
The AppVeyor failures look to be network failures, but the stable and beta builds were successful so I'm going to merge this anyway. |
|
Rebased locally and merged: 105ab91...080e1a7 |
Co-authored-by: Lucio Franco <luciofranco14@gmail.com>
This now correctly pulls apart arguments like
rustc -l static=ainto their constituent parts at parse time. There should be no functional changes in this PR.This is the majority of the major argument handling rework I mentioned, pulled out of the rust distributed work for ease of review. Each of the commits can be considered in isolation.
Should be reviewed after #274 (or just examine the commits after the scheduler auth one).