Skip to content

Everybody loops pprint; -Z unstable-options #19964

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

Merged
merged 4 commits into from
Dec 23, 2014
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
175 changes: 130 additions & 45 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ use syntax::parse::token::InternedString;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use getopts::{optopt, optmulti, optflag, optflagopt};
use getopts;
use std::cell::{RefCell};
use std::fmt;
Expand Down Expand Up @@ -278,7 +277,8 @@ debugging_opts! {
PRINT_REGION_GRAPH,
PARSE_ONLY,
NO_TRANS,
NO_ANALYSIS
NO_ANALYSIS,
UNSTABLE_OPTIONS
]
0
}
Expand Down Expand Up @@ -330,7 +330,8 @@ pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> {
("no-trans", "Run all passes except translation; no output", NO_TRANS),
("no-analysis", "Parse and expand the source, but run no analysis and",
NO_TRANS),
]
("unstable-options", "Adds unstable command line options to rustc interface",
UNSTABLE_OPTIONS)]
}

#[deriving(Clone)]
Expand Down Expand Up @@ -653,95 +654,179 @@ pub fn build_target_config(opts: &Options, sp: &SpanHandler) -> Config {
}
}

/// Returns the "short" subset of the stable rustc command line options.
pub fn short_optgroups() -> Vec<getopts::OptGroup> {
rustc_short_optgroups().into_iter()
.filter(|g|g.is_stable())
.map(|g|g.opt_group)
.collect()
}

/// Returns all of the stable rustc command line options.
pub fn optgroups() -> Vec<getopts::OptGroup> {
rustc_optgroups().into_iter()
.filter(|g|g.is_stable())
.map(|g|g.opt_group)
.collect()
}

#[deriving(Copy, Clone, PartialEq, Eq, Show)]
pub enum OptionStability { Stable, Unstable }

#[deriving(Clone, PartialEq, Eq)]
pub struct RustcOptGroup {
pub opt_group: getopts::OptGroup,
pub stability: OptionStability,
}

impl RustcOptGroup {
pub fn is_stable(&self) -> bool {
self.stability == OptionStability::Stable
}

fn stable(g: getopts::OptGroup) -> RustcOptGroup {
RustcOptGroup { opt_group: g, stability: OptionStability::Stable }
}

fn unstable(g: getopts::OptGroup) -> RustcOptGroup {
RustcOptGroup { opt_group: g, stability: OptionStability::Unstable }
}
}

// The `opt` local module holds wrappers around the `getopts` API that
// adds extra rustc-specific metadata to each option; such metadata
// is exposed by . The public
// functions below ending with `_u` are the functions that return
// *unstable* options, i.e. options that are only enabled when the
// user also passes the `-Z unstable-options` debugging flag.
mod opt {
// The `fn opt_u` etc below are written so that we can use them
// in the future; do not warn about them not being used right now.
#![allow(dead_code)]

use getopts;
use super::RustcOptGroup;

type R = RustcOptGroup;
type S<'a> = &'a str;

fn stable(g: getopts::OptGroup) -> R { RustcOptGroup::stable(g) }
fn unstable(g: getopts::OptGroup) -> R { RustcOptGroup::unstable(g) }

// FIXME (pnkfelix): We default to stable since the current set of
// options is defacto stable. However, it would be good to revise the
// code so that a stable option is the thing that takes extra effort
// to encode.

pub fn opt(a: S, b: S, c: S, d: S) -> R { stable(getopts::optopt(a, b, c, d)) }
pub fn multi(a: S, b: S, c: S, d: S) -> R { stable(getopts::optmulti(a, b, c, d)) }
pub fn flag(a: S, b: S, c: S) -> R { stable(getopts::optflag(a, b, c)) }
pub fn flagopt(a: S, b: S, c: S, d: S) -> R { stable(getopts::optflagopt(a, b, c, d)) }

pub fn opt_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optopt(a, b, c, d)) }
pub fn multi_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optmulti(a, b, c, d)) }
pub fn flag_u(a: S, b: S, c: S) -> R { unstable(getopts::optflag(a, b, c)) }
pub fn flagopt_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optflagopt(a, b, c, d)) }
}

/// Returns the "short" subset of the rustc command line options,
/// including metadata for each option, such as whether the option is
/// part of the stable long-term interface for rustc.
pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
vec![
optflag("h", "help", "Display this message"),
optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
optmulti("L", "", "Add a directory to the library search path", "PATH"),
optmulti("l", "", "Link the generated crate(s) to the specified native
opt::flag("h", "help", "Display this message"),
opt::multi("", "cfg", "Configure the compilation environment", "SPEC"),
opt::multi("L", "", "Add a directory to the library search path", "PATH"),
opt::multi("l", "", "Link the generated crate(s) to the specified native
library NAME. The optional KIND can be one of,
static, dylib, or framework. If omitted, dylib is
assumed.", "NAME[:KIND]"),
optmulti("", "crate-type", "Comma separated list of types of crates
opt::multi("", "crate-type", "Comma separated list of types of crates
for the compiler to emit",
"[bin|lib|rlib|dylib|staticlib|dep-info]"),
optopt("", "crate-name", "Specify the name of the crate being built",
opt::opt("", "crate-name", "Specify the name of the crate being built",
"NAME"),
optmulti("", "emit", "Comma separated list of types of output for \
opt::multi("", "emit", "Comma separated list of types of output for \
the compiler to emit",
"[asm|llvm-bc|llvm-ir|obj|link]"),
optmulti("", "print", "Comma separated list of compiler information to \
opt::multi("", "print", "Comma separated list of compiler information to \
print on stdout",
"[crate-name|output-file-names|sysroot]"),
optflag("g", "", "Equivalent to --debuginfo=2"),
optflag("O", "", "Equivalent to --opt-level=2"),
optopt("o", "", "Write output to <filename>", "FILENAME"),
optopt("", "out-dir", "Write output to compiler-chosen filename \
opt::flag("g", "", "Equivalent to --debuginfo=2"),
opt::flag("O", "", "Equivalent to --opt-level=2"),
opt::opt("o", "", "Write output to <filename>", "FILENAME"),
opt::opt("", "out-dir", "Write output to compiler-chosen filename \
in <dir>", "DIR"),
optopt("", "explain", "Provide a detailed explanation of an error \
opt::opt("", "explain", "Provide a detailed explanation of an error \
message", "OPT"),
optflag("", "test", "Build a test harness"),
optopt("", "target", "Target triple cpu-manufacturer-kernel[-os] \
opt::flag("", "test", "Build a test harness"),
opt::opt("", "target", "Target triple cpu-manufacturer-kernel[-os] \
to compile for (see chapter 3.4 of \
http://www.sourceware.org/autobook/
for details)",
"TRIPLE"),
optmulti("W", "warn", "Set lint warnings", "OPT"),
optmulti("A", "allow", "Set lint allowed", "OPT"),
optmulti("D", "deny", "Set lint denied", "OPT"),
optmulti("F", "forbid", "Set lint forbidden", "OPT"),
optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
optflag("V", "version", "Print version info and exit"),
optflag("v", "verbose", "Use verbose output"),
opt::multi("W", "warn", "Set lint warnings", "OPT"),
opt::multi("A", "allow", "Set lint allowed", "OPT"),
opt::multi("D", "deny", "Set lint denied", "OPT"),
opt::multi("F", "forbid", "Set lint forbidden", "OPT"),
opt::multi("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
opt::flag("V", "version", "Print version info and exit"),
opt::flag("v", "verbose", "Use verbose output"),
]
}

// rustc command line options
pub fn optgroups() -> Vec<getopts::OptGroup> {
let mut opts = short_optgroups();
/// Returns all rustc command line options, including metadata for
/// each option, such as whether the option is part of the stable
/// long-term interface for rustc.
pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
let mut opts = rustc_short_optgroups();
opts.push_all(&[
optmulti("", "extern", "Specify where an external rust library is \
opt::multi("", "extern", "Specify where an external rust library is \
located",
"NAME=PATH"),
optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
optopt("", "sysroot", "Override the system root", "PATH"),
optmulti("Z", "", "Set internal debugging options", "FLAG"),
optopt("", "color", "Configure coloring of output:
opt::opt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
opt::opt("", "sysroot", "Override the system root", "PATH"),
opt::multi("Z", "", "Set internal debugging options", "FLAG"),
opt::opt("", "color", "Configure coloring of output:
auto = colorize, if output goes to a tty (default);
always = always colorize output;
never = never colorize output", "auto|always|never"),

// DEPRECATED
optflag("", "print-crate-name", "Output the crate name and exit"),
optflag("", "print-file-name", "Output the file(s) that would be \
opt::flag("", "print-crate-name", "Output the crate name and exit"),
opt::flag("", "print-file-name", "Output the file(s) that would be \
written if compilation \
continued and exit"),
optopt("", "debuginfo", "Emit DWARF debug info to the objects created:
opt::opt("", "debuginfo", "Emit DWARF debug info to the objects created:
0 = no debug info,
1 = line-tables only (for stacktraces and breakpoints),
2 = full debug info with variable and type information \
(same as -g)", "LEVEL"),
optflag("", "no-trans", "Run all passes except translation; no output"),
optflag("", "no-analysis", "Parse and expand the source, but run no \
opt::flag("", "no-trans", "Run all passes except translation; no output"),
opt::flag("", "no-analysis", "Parse and expand the source, but run no \
analysis and produce no output"),
optflag("", "parse-only", "Parse only; do not compile, assemble, \
opt::flag("", "parse-only", "Parse only; do not compile, assemble, \
or link"),
optflagopt("", "pretty",
opt::flagopt("", "pretty",
"Pretty-print the input instead of compiling;
valid types are: `normal` (un-annotated source),
`expanded` (crates expanded),
`typed` (crates expanded, with type annotations),
`expanded,identified` (fully parenthesized, AST nodes with IDs), or
`flowgraph=<nodeid>` (graphviz formatted flowgraph for node)",
`typed` (crates expanded, with type annotations), or
`expanded,identified` (fully parenthesized, AST nodes with IDs).",
"TYPE"),
optflagopt("", "dep-info",
opt::flagopt_u("", "xpretty",
"Pretty-print the input instead of compiling, unstable variants;
valid types are any of the types for `--pretty`, as well as:
`flowgraph=<nodeid>` (graphviz formatted flowgraph for node), or
`everybody_loops` (all function bodies replaced with `loop {}`).",
"TYPE"),
opt::flagopt("", "dep-info",
"Output dependency info to <filename> after compiling, \
in a format suitable for use by Makefiles", "FILENAME"),
]);
opts
}


// Convert strings provided as --cfg [cfgspec] into a crate_cfg
pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
cfgspecs.into_iter().map(|s| {
Expand Down
56 changes: 48 additions & 8 deletions src/librustc_driver/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,19 @@ fn run_compiler(args: &[String]) {
}

let pretty = matches.opt_default("pretty", "normal").map(|a| {
pretty::parse_pretty(&sess, a.as_slice())
// stable pretty-print variants only
pretty::parse_pretty(&sess, a.as_slice(), false)
});
let pretty = if pretty.is_none() &&
sess.debugging_opt(config::UNSTABLE_OPTIONS) {
matches.opt_str("xpretty").map(|a| {
// extended with unstable pretty-print variants
pretty::parse_pretty(&sess, a.as_slice(), true)
})
} else {
pretty
};

match pretty.into_iter().next() {
Some((ppm, opt_uii)) => {
pretty::pretty_print_input(sess, cfg, &input, ppm, opt_uii, ofile);
Expand Down Expand Up @@ -196,12 +207,16 @@ pub fn version(binary: &str, matches: &getopts::Matches) {
}
}

fn usage(verbose: bool) {
fn usage(verbose: bool, include_unstable_options: bool) {
let groups = if verbose {
config::optgroups()
config::rustc_optgroups()
} else {
config::short_optgroups()
config::rustc_short_optgroups()
};
let groups : Vec<_> = groups.into_iter()
.filter(|x| include_unstable_options || x.is_stable())
.map(|x|x.opt_group)
.collect();
let message = format!("Usage: rustc [OPTIONS] INPUT");
let extra_help = if verbose {
""
Expand Down Expand Up @@ -362,20 +377,45 @@ pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> {
let _binary = args.remove(0).unwrap();

if args.is_empty() {
usage(false);
// user did not write `-v` nor `-Z unstable-options`, so do not
// include that extra information.
usage(false, false);
return None;
}

let matches =
match getopts::getopts(args.as_slice(), config::optgroups().as_slice()) {
Ok(m) => m,
Err(f) => {
early_error(f.to_string().as_slice());
Err(f_stable_attempt) => {
// redo option parsing, including unstable options this time,
// in anticipation that the mishandled option was one of the
// unstable ones.
let all_groups : Vec<getopts::OptGroup>
= config::rustc_optgroups().into_iter().map(|x|x.opt_group).collect();
match getopts::getopts(args.as_slice(), all_groups.as_slice()) {
Ok(m_unstable) => {
let r = m_unstable.opt_strs("Z");
let include_unstable_options = r.iter().any(|x| *x == "unstable-options");
if include_unstable_options {
m_unstable
} else {
early_error(f_stable_attempt.to_string().as_slice());
}
}
Err(_) => {
// ignore the error from the unstable attempt; just
// pass the error we got from the first try.
early_error(f_stable_attempt.to_string().as_slice());
}
}
}
};

let r = matches.opt_strs("Z");
let include_unstable_options = r.iter().any(|x| *x == "unstable-options");

if matches.opt_present("h") || matches.opt_present("help") {
usage(matches.opt_present("verbose"));
usage(matches.opt_present("verbose"), include_unstable_options);
return None;
}

Expand Down
Loading