diff options
Diffstat (limited to 'lib/Frontend')
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 680 |
1 files changed, 680 insertions, 0 deletions
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 7b37db5535..c537507950 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -8,8 +8,24 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/CompilerInvocation.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/Version.h" +#include "clang/Driver/Arg.h" +#include "clang/Driver/ArgList.h" +#include "clang/Driver/CC1Options.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/OptTable.h" +#include "clang/Driver/Option.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/LangStandard.h" +#include "clang/Frontend/PCHReader.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/System/Host.h" +#include "llvm/System/Path.h" using namespace clang; static const char *getAnalysisName(Analyses Kind) { @@ -52,6 +68,10 @@ static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { } } +//===----------------------------------------------------------------------===// +// Serialization (to args) +//===----------------------------------------------------------------------===// + static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, std::vector<std::string> &Res) { for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i) @@ -580,3 +600,663 @@ void CompilerInvocation::toArgs(std::vector<std::string> &Res) { PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), Res); TargetOptsToArgs(getTargetOpts(), Res); } + +//===----------------------------------------------------------------------===// +// Deserialization (to args) +//===----------------------------------------------------------------------===// + +using namespace clang::driver; +using namespace clang::driver::cc1options; + +static llvm::StringRef getLastArgValue(ArgList &Args, cc1options::ID ID, + llvm::StringRef Default = "") { + if (Arg *A = Args.getLastArg(ID)) + return A->getValue(Args); + return Default; +} + +static int getLastArgIntValue(ArgList &Args, cc1options::ID ID, + int Default, Diagnostic &Diags) { + Arg *A = Args.getLastArg(ID); + if (!A) + return Default; + + int Res = Default; + if (llvm::StringRef(A->getValue(Args)).getAsInteger(10, Res)) + Diags.Report(diag::err_drv_invalid_int_value) + << A->getAsString(Args) << A->getValue(Args); + + return Res; +} + +static std::vector<std::string> +getAllArgValues(ArgList &Args, cc1options::ID ID) { + llvm::SmallVector<const char *, 16> Values; + Args.AddAllArgValues(Values, ID); + return std::vector<std::string>(Values.begin(), Values.end()); +} + +// + +static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, + Diagnostic &Diags) { + using namespace cc1options; + + Opts.AnalysisList.clear(); +#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) \ + if (Args.hasArg(OPT_analysis_##NAME)) Opts.AnalysisList.push_back(NAME); +#include "clang/Frontend/Analyses.def" + + if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { + llvm::StringRef Name = A->getValue(Args); + AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name) +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ + .Case(CMDFLAG, NAME##Model) +#include "clang/Frontend/Analyses.def" + .Default(NumStores); + // FIXME: Error handling. + if (Value == NumStores) + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Name; + else + Opts.AnalysisStoreOpt = Value; + } + + if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) { + llvm::StringRef Name = A->getValue(Args); + AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name) +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ + .Case(CMDFLAG, NAME##Model) +#include "clang/Frontend/Analyses.def" + .Default(NumConstraints); + // FIXME: Error handling. + if (Value == NumConstraints) + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Name; + else + Opts.AnalysisConstraintsOpt = Value; + } + + if (Arg *A = Args.getLastArg(OPT_analyzer_output)) { + llvm::StringRef Name = A->getValue(Args); + AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name) +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \ + .Case(CMDFLAG, PD_##NAME) +#include "clang/Frontend/Analyses.def" + .Default(NUM_ANALYSIS_DIAG_CLIENTS); + // FIXME: Error handling. + if (Value == NUM_ANALYSIS_DIAG_CLIENTS) + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Name; + else + Opts.AnalysisDiagOpt = Value; + } + + Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz); + Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); + Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers); + Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); + Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead); + Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); + Opts.AnalyzeSpecificFunction = getLastArgValue(Args, OPT_analyze_function); + Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks); + Opts.EnableExperimentalInternalChecks = + Args.hasArg(OPT_analyzer_experimental_internal_checks); + Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); +} + +static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, + Diagnostic &Diags) { + using namespace cc1options; + // -Os implies -O2 + if (Args.hasArg(OPT_Os)) + Opts.OptimizationLevel = 2; + else { + Opts.OptimizationLevel = getLastArgIntValue(Args, OPT_O, 0, Diags); + if (Opts.OptimizationLevel > 3) { + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel; + Opts.OptimizationLevel = 3; + } + } + + // We must always run at least the always inlining pass. + Opts.Inlining = (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining + : CodeGenOptions::OnlyAlwaysInlining; + + Opts.DebugInfo = Args.hasArg(OPT_g); + Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); + Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); + Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); + Opts.NoCommon = Args.hasArg(OPT_fno_common); + Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); + Opts.OptimizeSize = Args.hasArg(OPT_Os); + Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize); + + Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); + Opts.CodeModel = getLastArgValue(Args, OPT_mcode_model); + Opts.DebugPass = getLastArgValue(Args, OPT_mdebug_pass); + Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim); + Opts.FloatABI = getLastArgValue(Args, OPT_mfloat_abi); + Opts.LimitFloatPrecision = getLastArgValue(Args, OPT_mlimit_float_precision); + Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); + Opts.SoftFloat = Args.hasArg(OPT_msoft_float); + Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); + Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic"); + + Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name); + + // FIXME: Put elsewhere? +#ifdef NDEBUG + Opts.VerifyModule = 0; +#else + Opts.VerifyModule = 1; +#endif +} + +static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, + ArgList &Args) { + using namespace cc1options; + Opts.OutputFile = getLastArgValue(Args, OPT_dependency_file); + Opts.Targets = getAllArgValues(Args, OPT_MT); + Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps); + Opts.UsePhonyTargets = Args.hasArg(OPT_MP); +} + +static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, + Diagnostic &Diags) { + using namespace cc1options; + Opts.IgnoreWarnings = Args.hasArg(OPT_w); + Opts.NoRewriteMacros = Args.hasArg(OPT_Wno_rewrite_macros); + Opts.Pedantic = Args.hasArg(OPT_pedantic); + Opts.PedanticErrors = Args.hasArg(OPT_pedantic_errors); + Opts.ShowCarets = !Args.hasArg(OPT_fno_caret_diagnostics); + Opts.ShowColors = Args.hasArg(OPT_fcolor_diagnostics); + Opts.ShowColumn = !Args.hasArg(OPT_fno_show_column); + Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info); + Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location); + Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option); + Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); + Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); + Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags); + Opts.DumpBuildInformation = getLastArgValue(Args, OPT_dump_build_information); + Opts.Warnings = getAllArgValues(Args, OPT_W); +} + +static FrontendOptions::InputKind +ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { + using namespace cc1options; + Opts.ProgramAction = frontend::ParseSyntaxOnly; + if (const Arg *A = Args.getLastArg(OPT_Action_Group)) { + switch (A->getOption().getID()) { + default: + assert(0 && "Invalid option in group!"); + case OPT_ast_dump: + Opts.ProgramAction = frontend::ASTDump; break; + case OPT_ast_print: + Opts.ProgramAction = frontend::ASTPrint; break; + case OPT_ast_print_xml: + Opts.ProgramAction = frontend::ASTPrintXML; break; + case OPT_ast_view: + Opts.ProgramAction = frontend::ASTView; break; + case OPT_dump_raw_tokens: + Opts.ProgramAction = frontend::DumpRawTokens; break; + case OPT_dump_record_layouts: + Opts.ProgramAction = frontend::DumpRecordLayouts; break; + case OPT_dump_tokens: + Opts.ProgramAction = frontend::DumpTokens; break; + case OPT_S: + Opts.ProgramAction = frontend::EmitAssembly; break; + case OPT_emit_llvm_bc: + Opts.ProgramAction = frontend::EmitBC; break; + case OPT_emit_html: + Opts.ProgramAction = frontend::EmitHTML; break; + case OPT_emit_llvm: + Opts.ProgramAction = frontend::EmitLLVM; break; + case OPT_emit_llvm_only: + Opts.ProgramAction = frontend::EmitLLVMOnly; break; + case OPT_fixit: + Opts.ProgramAction = frontend::FixIt; break; + case OPT_emit_pch: + Opts.ProgramAction = frontend::GeneratePCH; break; + case OPT_emit_pth: + Opts.ProgramAction = frontend::GeneratePTH; break; + case OPT_parse_noop: + Opts.ProgramAction = frontend::ParseNoop; break; + case OPT_parse_print_callbacks: + Opts.ProgramAction = frontend::ParsePrintCallbacks; break; + case OPT_fsyntax_only: + Opts.ProgramAction = frontend::ParseSyntaxOnly; break; + case OPT_print_decl_contexts: + Opts.ProgramAction = frontend::PrintDeclContext; break; + case OPT_E: + Opts.ProgramAction = frontend::PrintPreprocessedInput; break; + case OPT_rewrite_blocks: + Opts.ProgramAction = frontend::RewriteBlocks; break; + case OPT_rewrite_macros: + Opts.ProgramAction = frontend::RewriteMacros; break; + case OPT_rewrite_objc: + Opts.ProgramAction = frontend::RewriteObjC; break; + case OPT_rewrite_test: + Opts.ProgramAction = frontend::RewriteTest; break; + case OPT_analyze: + Opts.ProgramAction = frontend::RunAnalysis; break; + case OPT_Eonly: + Opts.ProgramAction = frontend::RunPreprocessorOnly; break; + } + } + if (const Arg *A = Args.getLastArg(OPT_plugin)) { + Opts.ProgramAction = frontend::PluginAction; + Opts.ActionName = A->getValue(Args); + } + + if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) { + Opts.CodeCompletionAt = + ParsedSourceLocation::FromString(A->getValue(Args)); + if (Opts.CodeCompletionAt.FileName.empty()) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(Args); + } + Opts.DebugCodeCompletionPrinter = + !Args.hasArg(OPT_no_code_completion_debug_printer); + Opts.DisableFree = Args.hasArg(OPT_disable_free); + Opts.EmptyInputOnly = Args.hasArg(OPT_empty_input_only); + + Opts.FixItLocations.clear(); + for (arg_iterator it = Args.filtered_begin(OPT_fixit_at), + ie = Args.filtered_end(); it != ie; ++it) { + const char *Loc = it->getValue(Args); + ParsedSourceLocation PSL = ParsedSourceLocation::FromString(Loc); + + if (PSL.FileName.empty()) { + Diags.Report(diag::err_drv_invalid_value) << it->getAsString(Args) << Loc; + continue; + } + + Opts.FixItLocations.push_back(PSL); + } + + Opts.OutputFile = getLastArgValue(Args, OPT_o); + Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch); + Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); + Opts.ShowStats = Args.hasArg(OPT_print_stats); + Opts.ShowTimers = Args.hasArg(OPT_ftime_report); + Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view); + + FrontendOptions::InputKind DashX = FrontendOptions::IK_None; + if (const Arg *A = Args.getLastArg(OPT_x)) { + DashX = llvm::StringSwitch<FrontendOptions::InputKind>(A->getValue(Args)) + .Case("c", FrontendOptions::IK_C) + .Case("cl", FrontendOptions::IK_OpenCL) + .Case("c", FrontendOptions::IK_C) + .Case("cl", FrontendOptions::IK_OpenCL) + .Case("c++", FrontendOptions::IK_CXX) + .Case("objective-c", FrontendOptions::IK_ObjC) + .Case("objective-c++", FrontendOptions::IK_ObjCXX) + .Case("cpp-output", FrontendOptions::IK_PreprocessedC) + .Case("assembler-with-cpp", FrontendOptions::IK_Asm) + .Case("c++-cpp-output", FrontendOptions::IK_PreprocessedCXX) + .Case("objective-c-cpp-output", FrontendOptions::IK_PreprocessedObjC) + .Case("objective-c++-cpp-output", FrontendOptions::IK_PreprocessedObjCXX) + .Case("c-header", FrontendOptions::IK_C) + .Case("objective-c-header", FrontendOptions::IK_ObjC) + .Case("c++-header", FrontendOptions::IK_CXX) + .Case("objective-c++-header", FrontendOptions::IK_ObjCXX) + .Case("ast", FrontendOptions::IK_AST) + .Default(FrontendOptions::IK_None); + if (DashX == FrontendOptions::IK_None) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(Args); + } + + // '-' is the default input if none is given. + std::vector<std::string> Inputs = getAllArgValues(Args, OPT_INPUT); + Opts.Inputs.clear(); + if (Inputs.empty()) + Inputs.push_back("-"); + for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { + FrontendOptions::InputKind IK = DashX; + if (IK == FrontendOptions::IK_None) { + IK = FrontendOptions::getInputKindForExtension( + llvm::StringRef(Inputs[i]).rsplit('.').second); + // FIXME: Remove this hack. + if (i == 0) + DashX = IK; + } + Opts.Inputs.push_back(std::make_pair(IK, Inputs[i])); + } + + return DashX; +} + +static std::string GetBuiltinIncludePath(const char *Argv0, + void *MainAddr) { + llvm::sys::Path P = llvm::sys::Path::GetMainExecutable(Argv0, MainAddr); + + if (!P.isEmpty()) { + P.eraseComponent(); // Remove /clang from foo/bin/clang + P.eraseComponent(); // Remove /bin from foo/bin + + // Get foo/lib/clang/<version>/include + P.appendComponent("lib"); + P.appendComponent("clang"); + P.appendComponent(CLANG_VERSION_STRING); + P.appendComponent("include"); + } + + return P.str(); +} + +static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, + const char *Argv0, void *MainAddr) { + using namespace cc1options; + Opts.Sysroot = getLastArgValue(Args, OPT_isysroot, "/"); + Opts.Verbose = Args.hasArg(OPT_v); + Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc); + Opts.BuiltinIncludePath = ""; + // FIXME: Add an option for this, its a slow call. + if (!Args.hasArg(OPT_nobuiltininc)) + Opts.BuiltinIncludePath = GetBuiltinIncludePath(Argv0, MainAddr); + + // Add -I... and -F... options in order. + for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath(it->getValue(Args), frontend::Angled, true, + /*IsFramework=*/ it->getOption().matches(OPT_F)); + + // Add -iprefix/-iwith-prefix/-iwithprefixbefore options. + llvm::StringRef Prefix = ""; // FIXME: This isn't the correct default prefix. + for (arg_iterator it = Args.filtered_begin(OPT_iprefix, OPT_iwithprefix, + OPT_iwithprefixbefore), + ie = Args.filtered_end(); it != ie; ++it) { + if (it->getOption().matches(OPT_iprefix)) + Prefix = it->getValue(Args); + else if (it->getOption().matches(OPT_iwithprefix)) + Opts.AddPath(Prefix.str() + it->getValue(Args), + frontend::System, false, false); + else + Opts.AddPath(Prefix.str() + it->getValue(Args), + frontend::Angled, false, false); + } + + for (arg_iterator it = Args.filtered_begin(OPT_idirafter), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath(it->getValue(Args), frontend::After, true, false); + for (arg_iterator it = Args.filtered_begin(OPT_iquote), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath(it->getValue(Args), frontend::Quoted, true, false); + for (arg_iterator it = Args.filtered_begin(OPT_isystem), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath(it->getValue(Args), frontend::System, true, false); + + // FIXME: Need options for the various environment variables! +} + +static void ParseLangArgs(LangOptions &Opts, ArgList &Args, + FrontendOptions::InputKind IK, + Diagnostic &Diags) { + // FIXME: Cleanup per-file based stuff. + + // Set some properties which depend soley on the input kind; it would be nice + // to move these to the language standard, and have the driver resolve the + // input kind + language standard. + if (IK == FrontendOptions::IK_Asm) { + Opts.AsmPreprocessor = 1; + } else if (IK == FrontendOptions::IK_ObjC || + IK == FrontendOptions::IK_ObjCXX || + IK == FrontendOptions::IK_PreprocessedObjC || + IK == FrontendOptions::IK_PreprocessedObjCXX) { + Opts.ObjC1 = Opts.ObjC2 = 1; + } + + LangStandard::Kind LangStd = LangStandard::lang_unspecified; + if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { + LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args)) +#define LANGSTANDARD(id, name, desc, features) \ + .Case(name, LangStandard::lang_##id) +#include "clang/Frontend/LangStandards.def" + .Default(LangStandard::lang_unspecified); + if (LangStd == LangStandard::lang_unspecified) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(Args); + } + + if (LangStd == LangStandard::lang_unspecified) { + // Based on the base language, pick one. + switch (IK) { + case FrontendOptions::IK_None: + case FrontendOptions::IK_AST: + assert(0 && "Invalid input kind!"); + case FrontendOptions::IK_OpenCL: + LangStd = LangStandard::lang_opencl; + break; + case FrontendOptions::IK_Asm: + case FrontendOptions::IK_C: + case FrontendOptions::IK_PreprocessedC: + case FrontendOptions::IK_ObjC: + case FrontendOptions::IK_PreprocessedObjC: + LangStd = LangStandard::lang_gnu99; + break; + case FrontendOptions::IK_CXX: + case FrontendOptions::IK_PreprocessedCXX: + case FrontendOptions::IK_ObjCXX: + case FrontendOptions::IK_PreprocessedObjCXX: + LangStd = LangStandard::lang_gnucxx98; + break; + } + } + + const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); + Opts.BCPLComment = Std.hasBCPLComments(); + Opts.C99 = Std.isC99(); + Opts.CPlusPlus = Std.isCPlusPlus(); + Opts.CPlusPlus0x = Std.isCPlusPlus0x(); + Opts.Digraphs = Std.hasDigraphs(); + Opts.GNUMode = Std.isGNUMode(); + Opts.GNUInline = !Std.isC99(); + Opts.HexFloats = Std.hasHexFloats(); + Opts.ImplicitInt = Std.hasImplicitInt(); + + // OpenCL has some additional defaults. + if (LangStd == LangStandard::lang_opencl) { + Opts.OpenCL = 1; + Opts.AltiVec = 1; + Opts.CXXOperatorNames = 1; + Opts.LaxVectorConversions = 1; + } + + // OpenCL and C++ both have bool, true, false keywords. + Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; + + if (Opts.CPlusPlus) + Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names); + + if (Args.hasArg(OPT_fobjc_gc_only)) + Opts.setGCMode(LangOptions::GCOnly); + else if (Args.hasArg(OPT_fobjc_gc)) + Opts.setGCMode(LangOptions::HybridGC); + + if (Args.hasArg(OPT_print_ivar_layout)) + Opts.ObjCGCBitmapPrint = 1; + + if (Args.hasArg(OPT_faltivec)) + Opts.AltiVec = 1; + + if (Args.hasArg(OPT_pthread)) + Opts.POSIXThreads = 1; + + llvm::StringRef Vis = getLastArgValue(Args, OPT_fvisibility, + "default"); + if (Vis == "default") + Opts.setVisibilityMode(LangOptions::Default); + else if (Vis == "hidden") + Opts.setVisibilityMode(LangOptions::Hidden); + else if (Vis == "protected") + Opts.setVisibilityMode(LangOptions::Protected); + else + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis; + + Opts.OverflowChecking = Args.hasArg(OPT_ftrapv); + + // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs + // is specified, or -std is set to a conforming mode. + Opts.Trigraphs = !Opts.GNUMode; + if (Args.hasArg(OPT_trigraphs)) + Opts.Trigraphs = 1; + + Opts.DollarIdents = !Opts.AsmPreprocessor; + if (Args.hasArg(OPT_fdollars_in_identifiers)) + Opts.DollarIdents = 1; + + Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); + Opts.Microsoft = Args.hasArg(OPT_fms_extensions); + Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); + if (Args.hasArg(OPT_fno_lax_vector_conversions)) + Opts.LaxVectorConversions = 0; + Opts.Exceptions = Args.hasArg(OPT_fexceptions); + Opts.Rtti = !Args.hasArg(OPT_fno_rtti); + Opts.Blocks = Args.hasArg(OPT_fblocks); + Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); + Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); + Opts.Freestanding = Args.hasArg(OPT_ffreestanding); + Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; + Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); + Opts.AccessControl = Args.hasArg(OPT_faccess_control); + Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); + Opts.MathErrno = !Args.hasArg(OPT_fno_math_errno); + Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99, + Diags); + Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); + Opts.ObjCConstantStringClass = getLastArgValue(Args, + OPT_fconstant_string_class); + Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); + Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); + Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); + Opts.Static = Args.hasArg(OPT_static_define); + Opts.OptimizeSize = 0; + + // FIXME: Eliminate this dependency. + unsigned Opt = + Args.hasArg(OPT_Os) ? 2 : getLastArgIntValue(Args, OPT_O, 0, Diags); + Opts.Optimize = Opt != 0; + + // This is the __NO_INLINE__ define, which just depends on things like the + // optimization level and -fno-inline, not actually whether the backend has + // inlining enabled. + // + // FIXME: This is affected by other options (-fno-inline). + Opts.NoInline = !Opt; + + unsigned SSP = getLastArgIntValue(Args, OPT_stack_protector, 0, Diags); + switch (SSP) { + default: + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP; + break; + case 0: Opts.setStackProtectorMode(LangOptions::SSPOff); break; + case 1: Opts.setStackProtectorMode(LangOptions::SSPOn); break; + case 2: Opts.setStackProtectorMode(LangOptions::SSPReq); break; + } +} + +static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args) { + using namespace cc1options; + Opts.ImplicitPCHInclude = getLastArgValue(Args, OPT_include_pch); + Opts.ImplicitPTHInclude = getLastArgValue(Args, OPT_include_pth); + if (const Arg *A = Args.getLastArg(OPT_token_cache)) + Opts.TokenCache = A->getValue(Args); + else + Opts.TokenCache = Opts.ImplicitPTHInclude; + Opts.UsePredefines = !Args.hasArg(OPT_undef); + + // Add macros from the command line. + for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U), + ie = Args.filtered_end(); it != ie; ++it) { + if (it->getOption().matches(OPT_D)) + Opts.addMacroDef(it->getValue(Args)); + else + Opts.addMacroUndef(it->getValue(Args)); + } + + Opts.MacroIncludes = getAllArgValues(Args, OPT_imacros); + + // Add the ordered list of -includes. + for (arg_iterator it = Args.filtered_begin(OPT_include, OPT_include_pch, + OPT_include_pth), + ie = Args.filtered_end(); it != ie; ++it) { + // PCH is handled specially, we need to extra the original include path. + if (it->getOption().matches(OPT_include_pch)) { + std::string OriginalFile = + PCHReader::getOriginalSourceFile(it->getValue(Args)); + + // FIXME: Don't fail like this. + if (OriginalFile.empty()) + exit(1); + + Opts.Includes.push_back(OriginalFile); + } else + Opts.Includes.push_back(it->getValue(Args)); + } +} + +static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, + ArgList &Args) { + using namespace cc1options; + Opts.ShowCPP = !Args.hasArg(OPT_dM); + Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD); + Opts.ShowLineMarkers = !Args.hasArg(OPT_P); + Opts.ShowComments = Args.hasArg(OPT_C); + Opts.ShowMacroComments = Args.hasArg(OPT_CC); +} + +static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { + using namespace cc1options; + Opts.ABI = getLastArgValue(Args, OPT_target_abi); + Opts.CPU = getLastArgValue(Args, OPT_mcpu); + Opts.Triple = getLastArgValue(Args, OPT_triple); + Opts.Features = getAllArgValues(Args, OPT_target_feature); + + // Use the host triple if unspecified. + if (Opts.Triple.empty()) + Opts.Triple = llvm::sys::getHostTriple(); +} + +// + +void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, + const char **ArgBegin, + const char **ArgEnd, + const char *Argv0, + void *MainAddr, + Diagnostic &Diags) { + // Parse the arguments. + llvm::OwningPtr<OptTable> Opts(createCC1OptTable()); + unsigned MissingArgIndex, MissingArgCount; + llvm::OwningPtr<InputArgList> Args( + Opts->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount)); + + // Check for missing argument error. + if (MissingArgCount) + Diags.Report(diag::err_drv_missing_argument) + << Args->getArgString(MissingArgIndex) << MissingArgCount; + + // Issue errors on unknown arguments. + for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN), + ie = Args->filtered_end(); it != ie; ++it) + Diags.Report(diag::err_drv_unknown_argument) << it->getAsString(*Args); + + ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags); + ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, Diags); + ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args); + ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags); + FrontendOptions::InputKind DashX = + ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); + ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args, + Argv0, MainAddr); + if (DashX != FrontendOptions::IK_AST) + ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags); + ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args); + ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); + ParseTargetArgs(Res.getTargetOpts(), *Args); +} |