From 8fdb6dee2da0dee97d64fe12eda46fb318414de9 Mon Sep 17 00:00:00 2001 From: Dylan Noblesmith Date: Fri, 23 Dec 2011 03:05:38 +0000 Subject: [PATCH] Let CompilerInvocation initialization indicate failure This fixes the FIXMEs in ParseAnalyzeArgs. (Also a precursor to moving the analyzer into an AST plugin.) For consistency, do the same with AssemblerInvocation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147218 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Frontend/CompilerInvocation.h | 4 +- lib/Frontend/CompilerInvocation.cpp | 90 +++++++++++++------ .../CreateInvocationFromCommandLine.cpp | 9 +- tools/arcmt-test/arcmt-test.cpp | 8 +- tools/driver/cc1_main.cpp | 17 ++-- tools/driver/cc1as_main.cpp | 28 ++++-- 6 files changed, 104 insertions(+), 52 deletions(-) diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h index bbefdb662d..821336c32c 100644 --- a/include/clang/Frontend/CompilerInvocation.h +++ b/include/clang/Frontend/CompilerInvocation.h @@ -90,13 +90,13 @@ public: /// @{ /// CreateFromArgs - Create a compiler invocation from a list of input - /// options. + /// options. Returns true on success. /// /// \param Res [out] - The resulting invocation. /// \param ArgBegin - The first element in the argument vector. /// \param ArgEnd - The last element in the argument vector. /// \param Diags - The diagnostic engine to use for errors. - static void CreateFromArgs(CompilerInvocation &Res, + static bool CreateFromArgs(CompilerInvocation &Res, const char* const *ArgBegin, const char* const *ArgEnd, DiagnosticsEngine &Diags); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 3ad555bfe8..18b247c9b9 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -944,10 +944,10 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, Args.getLastArgIntValue(OPT_O, DefaultOpt, Diags); } -static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, +static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { using namespace cc1options; - + bool Success = true; if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { StringRef Name = A->getValue(Args); AnalysisStores Value = llvm::StringSwitch(Name) @@ -955,12 +955,13 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, .Case(CMDFLAG, NAME##Model) #include "clang/Frontend/Analyses.def" .Default(NumStores); - // FIXME: Error handling. - if (Value == NumStores) + if (Value == NumStores) { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; - else + Success = false; + } else { Opts.AnalysisStoreOpt = Value; + } } if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) { @@ -970,12 +971,13 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, .Case(CMDFLAG, NAME##Model) #include "clang/Frontend/Analyses.def" .Default(NumConstraints); - // FIXME: Error handling. - if (Value == NumConstraints) + if (Value == NumConstraints) { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; - else + Success = false; + } else { Opts.AnalysisConstraintsOpt = Value; + } } if (Arg *A = Args.getLastArg(OPT_analyzer_output)) { @@ -985,12 +987,13 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, .Case(CMDFLAG, PD_##NAME) #include "clang/Frontend/Analyses.def" .Default(NUM_ANALYSIS_DIAG_CLIENTS); - // FIXME: Error handling. - if (Value == NUM_ANALYSIS_DIAG_CLIENTS) + if (Value == NUM_ANALYSIS_DIAG_CLIENTS) { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; - else + Success = false; + } else { Opts.AnalysisDiagOpt = Value; + } } if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) { @@ -1000,12 +1003,13 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, .Case(CMDFLAG, NAME) #include "clang/Frontend/Analyses.def" .Default(NumPurgeModes); - // FIXME: Error handling. - if (Value == NumPurgeModes) + if (Value == NumPurgeModes) { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; - else + Success = false; + } else { Opts.AnalysisPurgeOpt = Value; + } } Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help); @@ -1041,17 +1045,21 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, for (unsigned i = 0, e = checkers.size(); i != e; ++i) Opts.CheckersControlList.push_back(std::make_pair(checkers[i], enable)); } + + return Success; } -static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, +static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { using namespace cc1options; + bool Success = true; Opts.OptimizationLevel = getOptimizationLevel(Args, IK, Diags); if (Opts.OptimizationLevel > 3) { Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel; Opts.OptimizationLevel = 3; + Success = false; } // We must always run at least the always inlining pass. @@ -1140,11 +1148,15 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, .Case("non-legacy", CodeGenOptions::NonLegacy) .Case("mixed", CodeGenOptions::Mixed) .Default(~0U); - if (Method == ~0U) + if (Method == ~0U) { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; - else + Success = false; + } else { Opts.ObjCDispatchMethod = Method; + } } + + return Success; } static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, @@ -1159,9 +1171,11 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, Opts.AddMissingHeaderDeps = Args.hasArg(OPT_MG); } -static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, +static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { using namespace cc1options; + bool Success = true; + Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file); Opts.DiagnosticSerializationFile = Args.getLastArgValue(OPT_diagnostic_serialized_file); @@ -1192,10 +1206,12 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.ShowOverloads = DiagnosticsEngine::Ovl_Best; else if (ShowOverloads == "all") Opts.ShowOverloads = DiagnosticsEngine::Ovl_All; - else + else { Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fshow_overloads_EQ)->getAsString(Args) << ShowOverloads; + Success = false; + } StringRef ShowCategory = Args.getLastArgValue(OPT_fdiagnostics_show_category, "none"); @@ -1205,23 +1221,27 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.ShowCategories = 1; else if (ShowCategory == "name") Opts.ShowCategories = 2; - else + else { Diags.Report(diag::err_drv_invalid_value) << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args) << ShowCategory; + Success = false; + } StringRef Format = Args.getLastArgValue(OPT_fdiagnostics_format, "clang"); if (Format == "clang") Opts.Format = DiagnosticOptions::Clang; - else if (Format == "msvc") + else if (Format == "msvc") Opts.Format = DiagnosticOptions::Msvc; - else if (Format == "vi") + else if (Format == "vi") Opts.Format = DiagnosticOptions::Vi; - else + else { 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); Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits); @@ -1248,6 +1268,8 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags); Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information); Opts.Warnings = Args.getAllArgValues(OPT_W); + + return Success; } static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) { @@ -1994,10 +2016,12 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { // -void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, +bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, const char *const *ArgBegin, const char *const *ArgEnd, DiagnosticsEngine &Diags) { + bool Success = true; + // Parse the arguments. llvm::OwningPtr Opts(createCC1OptTable()); unsigned MissingArgIndex, MissingArgCount; @@ -2005,22 +2029,28 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, Opts->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount)); // Check for missing argument error. - if (MissingArgCount) + if (MissingArgCount) { Diags.Report(diag::err_drv_missing_argument) << Args->getArgString(MissingArgIndex) << MissingArgCount; + Success = false; + } // Issue errors on unknown arguments. for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN), - ie = Args->filtered_end(); it != ie; ++it) + ie = Args->filtered_end(); it != ie; ++it) { Diags.Report(diag::err_drv_unknown_argument) << (*it)->getAsString(*Args); + Success = false; + } - ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags); + Success = ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags) && Success; ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args); - 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 InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); - ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags); + Success = ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags) + && Success; ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args); if (DashX != IK_AST && DashX != IK_LLVM_IR) { ParseLangArgs(*Res.getLangOpts(), *Args, DashX, Diags); @@ -2035,6 +2065,8 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags); ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); ParseTargetArgs(Res.getTargetOpts(), *Args); + + return Success; } namespace { diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp index e94b944f04..f7a296143f 100644 --- a/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -80,11 +80,12 @@ clang::createInvocationFromCommandLine(ArrayRef ArgList, } const driver::ArgStringList &CCArgs = Cmd->getArguments(); - CompilerInvocation *CI = new CompilerInvocation(); - CompilerInvocation::CreateFromArgs(*CI, + llvm::OwningPtr CI(new CompilerInvocation()); + if (!CompilerInvocation::CreateFromArgs(*CI, const_cast(CCArgs.data()), const_cast(CCArgs.data()) + CCArgs.size(), - *Diags); - return CI; + *Diags)) + return 0; + return CI.take(); } diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp index 3f91fcf124..3dc4c11667 100644 --- a/tools/arcmt-test/arcmt-test.cpp +++ b/tools/arcmt-test/arcmt-test.cpp @@ -118,7 +118,8 @@ static bool checkForMigration(StringRef resourcesPath, } CompilerInvocation CI; - CompilerInvocation::CreateFromArgs(CI, Args.begin(), Args.end(), *Diags); + if (!CompilerInvocation::CreateFromArgs(CI, Args.begin(), Args.end(), *Diags)) + return true; if (CI.getFrontendOpts().Inputs.empty()) { llvm::errs() << "error: no input files\n"; @@ -159,8 +160,9 @@ static bool performTransformations(StringRef resourcesPath, new DiagnosticsEngine(DiagID, DiagClient)); CompilerInvocation origCI; - CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(), - *TopDiags); + if (!CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(), + *TopDiags)) + return true; if (origCI.getFrontendOpts().Inputs.empty()) { llvm::errs() << "error: no input files\n"; diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index f1fb68d539..0a14fdd315 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -77,7 +77,8 @@ static int cc1_test(DiagnosticsEngine &Diags, // Create a compiler invocation. llvm::errs() << "cc1 creating invocation.\n"; CompilerInvocation Invocation; - CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags); + if (!CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags)) + return 1; // Convert the invocation back to argument strings. std::vector InvocationArgs; @@ -95,8 +96,9 @@ static int cc1_test(DiagnosticsEngine &Diags, // Convert those arguments to another invocation, and check that we got the // same thing. CompilerInvocation Invocation2; - CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(), - Invocation2Args.end(), Diags); + if (!CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(), + Invocation2Args.end(), Diags)) + return 1; // FIXME: Implement CompilerInvocation comparison. if (true) { @@ -135,8 +137,11 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, // well formed diagnostic object. TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; DiagnosticsEngine Diags(DiagID, DiagsBuffer); - CompilerInvocation::CreateFromArgs(Clang->getInvocation(), ArgBegin, ArgEnd, - Diags); + bool Success; + Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(), + ArgBegin, ArgEnd, Diags); + if (!Success) + return 1; // Infer the builtin include path if unspecified. if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && @@ -157,7 +162,7 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics()); // Execute the frontend actions. - bool Success = ExecuteCompilerInvocation(Clang.get()); + Success = ExecuteCompilerInvocation(Clang.get()); // If any timers were active but haven't been destroyed yet, print their // results now. This happens in -disable-free mode. diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp index 9959b0d296..4591a36873 100644 --- a/tools/driver/cc1as_main.cpp +++ b/tools/driver/cc1as_main.cpp @@ -122,17 +122,19 @@ public: NoExecStack = 0; } - static void CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin, + static bool CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin, const char **ArgEnd, DiagnosticsEngine &Diags); }; } -void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, +bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, const char **ArgBegin, const char **ArgEnd, DiagnosticsEngine &Diags) { using namespace clang::driver::cc1asoptions; + bool Success = true; + // Parse the arguments. OwningPtr OptTbl(createCC1AsOptTable()); unsigned MissingArgIndex, MissingArgCount; @@ -140,14 +142,18 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, OptTbl->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount)); // Check for missing argument error. - if (MissingArgCount) + if (MissingArgCount) { Diags.Report(diag::err_drv_missing_argument) << Args->getArgString(MissingArgIndex) << MissingArgCount; + Success = false; + } // Issue errors on unknown arguments. for (arg_iterator it = Args->filtered_begin(cc1asoptions::OPT_UNKNOWN), - ie = Args->filtered_end(); it != ie; ++it) + ie = Args->filtered_end(); it != ie; ++it) { Diags.Report(diag::err_drv_unknown_argument) << (*it) ->getAsString(*Args); + Success = false; + } // Construct the invocation. @@ -171,8 +177,10 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, const Arg *A = it; if (First) Opts.InputFile = A->getValue(*Args); - else + else { Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(*Args); + Success = false; + } } } Opts.LLVMArgs = Args->getAllArgValues(OPT_mllvm); @@ -186,10 +194,11 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, .Case("null", FT_Null) .Case("obj", FT_Obj) .Default(~0U); - if (OutputType == ~0U) + if (OutputType == ~0U) { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(*Args) << Name; - else + Success = false; + } else Opts.OutputType = FileType(OutputType); } Opts.ShowHelp = Args->hasArg(OPT_help); @@ -204,6 +213,8 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, // Assemble Options Opts.RelaxAll = Args->hasArg(OPT_relax_all); Opts.NoExecStack = Args->hasArg(OPT_no_exec_stack); + + return true; } static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts, @@ -374,7 +385,8 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd, // Parse the arguments. AssemblerInvocation Asm; - AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags); + if (!AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags)) + return 1; // Honor -help. if (Asm.ShowHelp) { -- 2.40.0