diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h index f9698048b2..3affb009fc 100644 --- a/include/clang/Driver/ArgList.h +++ b/include/clang/Driver/ArgList.h @@ -204,10 +204,18 @@ namespace driver { StringRef getLastArgValue(OptSpecifier Id, StringRef Default = "") const; + /// getLastArgValue - Return the value of the last argument as an integer, + /// or a default. If Diags is non-null, emits an error if the argument + /// is given, but non-integral. + int getLastArgIntValue(OptSpecifier Id, int Default, + DiagnosticsEngine *Diags = 0) const; + /// getLastArgValue - Return the value of the last argument as an integer, /// or a default. Emits an error if the argument is given, but non-integral. int getLastArgIntValue(OptSpecifier Id, int Default, - DiagnosticsEngine &Diags) const; + DiagnosticsEngine &Diags) const { + return getLastArgIntValue(Id, Default, &Diags); + } /// getAllArgValues - Get the values of all instances of the given argument /// as strings. diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h index 0099aae8dc..0d2260acbc 100644 --- a/include/clang/Frontend/CompilerInvocation.h +++ b/include/clang/Frontend/CompilerInvocation.h @@ -33,6 +33,17 @@ namespace clang { class CompilerInvocation; class DiagnosticsEngine; + +namespace driver { +class ArgList; +} + +/// CompilerInvocation - Fill out Opts based on the options given in Args. +/// Args must have been created from the OptTable returned by +/// createCC1OptTable(). When errors are encountered, return false and, +/// if Diags is non-null, report the error(s). +bool ParseDiagnosticArgs(DiagnosticOptions &Opts, driver::ArgList &Args, + DiagnosticsEngine *Diags = 0); class CompilerInvocationBase : public RefCountedBase { protected: diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp index d26da25b3e..55a0ddfd27 100644 --- a/lib/Driver/ArgList.cpp +++ b/lib/Driver/ArgList.cpp @@ -154,13 +154,15 @@ StringRef ArgList::getLastArgValue(OptSpecifier Id, } int ArgList::getLastArgIntValue(OptSpecifier Id, int Default, - clang::DiagnosticsEngine &Diags) const { + clang::DiagnosticsEngine *Diags) const { int Res = Default; if (Arg *A = getLastArg(Id)) { - if (StringRef(A->getValue(*this)).getAsInteger(10, Res)) - Diags.Report(diag::err_drv_invalid_int_value) - << A->getAsString(*this) << A->getValue(*this); + if (StringRef(A->getValue(*this)).getAsInteger(10, Res)) { + if (Diags) + Diags->Report(diag::err_drv_invalid_int_value) + << A->getAsString(*this) << A->getValue(*this); + } } return Res; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 7f7f35cc09..13a9897f07 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1277,8 +1277,8 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, Opts.DOTOutputFile = Args.getLastArgValue(OPT_dependency_dot); } -static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, - DiagnosticsEngine &Diags) { +bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, + DiagnosticsEngine *Diags) { using namespace cc1options; bool Success = true; @@ -1312,10 +1312,11 @@ static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, else if (ShowOverloads == "all") Opts.ShowOverloads = DiagnosticsEngine::Ovl_All; else { - Diags.Report(diag::err_drv_invalid_value) + Success = false; + if (Diags) + Diags->Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fshow_overloads_EQ)->getAsString(Args) << ShowOverloads; - Success = false; } StringRef ShowCategory = @@ -1327,10 +1328,11 @@ static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, else if (ShowCategory == "name") Opts.ShowCategories = 2; else { - Diags.Report(diag::err_drv_invalid_value) + Success = false; + if (Diags) + Diags->Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args) << ShowCategory; - Success = false; } StringRef Format = @@ -1342,10 +1344,11 @@ static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, else if (Format == "vi") Opts.Format = DiagnosticOptions::Vi; else { - Diags.Report(diag::err_drv_invalid_value) + Success = false; + if (Diags) + Diags->Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fdiagnostics_format)->getAsString(Args) << Format; - Success = false; } Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); @@ -1366,13 +1369,23 @@ static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.TabStop = Args.getLastArgIntValue(OPT_ftabstop, DiagnosticOptions::DefaultTabStop, Diags); if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { - Diags.Report(diag::warn_ignoring_ftabstop_value) - << Opts.TabStop << DiagnosticOptions::DefaultTabStop; Opts.TabStop = DiagnosticOptions::DefaultTabStop; + if (Diags) + Diags->Report(diag::warn_ignoring_ftabstop_value) + << Opts.TabStop << DiagnosticOptions::DefaultTabStop; } Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags); Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information); - Opts.Warnings = Args.getAllArgValues(OPT_W); + + for (arg_iterator it = Args.filtered_begin(OPT_W), + ie = Args.filtered_end(); it != ie; ++it) { + StringRef V = (*it)->getValue(Args); + // "-Wl," and such are not warnings options. + if (V.startswith("l,") || V.startswith("a,") || V.startswith("p,")) + continue; + + Opts.Warnings.push_back(V); + } return Success; } @@ -2174,7 +2187,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, Success = ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags) && Success; Success = ParseMigratorArgs(Res.getMigratorOpts(), *Args) && Success; ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args); - Success = ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags) + Success = ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, &Diags) && Success; ParseFileSystemArgs(Res.getFileSystemOpts(), *Args); // FIXME: We shouldn't have to pass the DashX option around here diff --git a/test/Driver/diagnostics.c b/test/Driver/diagnostics.c new file mode 100644 index 0000000000..1330041ae4 --- /dev/null +++ b/test/Driver/diagnostics.c @@ -0,0 +1,9 @@ +// Parse diagnostic arguments in the driver +// PR12181 + +// RUN: !%clang -target x86_64-apple-darwin10 \ +// RUN: -fsyntax-only -fzyzzybalubah \ +// RUN: -Werror=unused-command-line-argument %s + +// RUN: !%clang -target x86_64-apple-darwin10 \ +// RUN: -fsyntax-only -fzyzzybalubah -Werror %s diff --git a/test/Driver/no-objc-arr.m b/test/Driver/no-objc-arr.m index 15fbdc20ce..e44939337a 100644 --- a/test/Driver/no-objc-arr.m +++ b/test/Driver/no-objc-arr.m @@ -1,4 +1,4 @@ -// RUN: %clang -Werror -fobjc-arc -fsyntax-only -fno-objc-arc -verify %s +// RUN: %clang -Werror -fobjc-arc -fsyntax-only -fno-objc-arc -Xclang -verify %s // rdar://8949617 void * FOO() { diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index 9e666eb43f..8c05fff4de 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -12,11 +12,16 @@ // //===----------------------------------------------------------------------===// +#include "clang/Driver/ArgList.h" +#include "clang/Driver/CC1Options.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Option.h" +#include "clang/Driver/OptTable.h" +#include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Frontend/Utils.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" @@ -370,11 +375,27 @@ int main(int argc_, const char **argv_) { llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes); + DiagnosticOptions DiagOpts; + { + // Note that ParseDiagnosticArgs() uses the cc1 option table. + OwningPtr CC1Opts(createCC1OptTable()); + unsigned MissingArgIndex, MissingArgCount; + OwningPtr Args(CC1Opts->ParseArgs(argv.begin()+1, argv.end(), + MissingArgIndex, MissingArgCount)); + // We ignore MissingArgCount and the return value of ParseDiagnosticArgs. + // Any errors that would be diagnosed here will also be diagnosed later, + // when the DiagnosticsEngine actually exists. + (void) ParseDiagnosticArgs(DiagOpts, *Args); + } + // Now we can create the DiagnosticsEngine with a properly-filled-out + // DiagnosticOptions instance. TextDiagnosticPrinter *DiagClient - = new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions()); + = new TextDiagnosticPrinter(llvm::errs(), DiagOpts); DiagClient->setPrefix(llvm::sys::path::stem(Path.str())); IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + DiagnosticsEngine Diags(DiagID, DiagClient); + ProcessWarningOptions(Diags, DiagOpts); #ifdef CLANG_IS_PRODUCTION const bool IsProduction = true;