diff --git a/clang/unittests/Frontend/CompilerInvocationTest.cpp b/clang/unittests/Frontend/CompilerInvocationTest.cpp --- a/clang/unittests/Frontend/CompilerInvocationTest.cpp +++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp @@ -8,6 +8,7 @@ #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" #include "llvm/Support/Host.h" #include "gmock/gmock.h" @@ -22,123 +23,253 @@ using ::testing::StrNe; namespace { -struct OptsPopulationTest : public ::testing::Test { - IntrusiveRefCntPtr Diags; - CompilerInvocation CInvok; - - OptsPopulationTest() - : Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions())) {} -}; - -class CC1CommandLineGenerationTest : public ::testing::Test { -public: +struct CommandLineTest : public ::testing::Test { IntrusiveRefCntPtr Diags; SmallVector GeneratedArgs; SmallVector GeneratedArgsStorage; + CompilerInvocation Invocation; const char *operator()(const Twine &Arg) { return GeneratedArgsStorage.emplace_back(Arg.str()).c_str(); } - CC1CommandLineGenerationTest() - : Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions())) {} + CommandLineTest() + : Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions(), + new TextDiagnosticBuffer())) { + } }; -TEST_F(OptsPopulationTest, OptIsInitializedWithCustomDefaultValue) { - const char *Args[] = {"clang", "-xc++"}; +// Boolean option with a keypath that defaults to true. +// The only flag with a negative spelling can set the keypath to false. + +TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagNotPresent) { + const char *Args[] = {""}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary); + + // TODO: Test argument generation. +} + +TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagPresent) { + const char *Args[] = {"-fno-temp-file"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_FALSE(Invocation.getFrontendOpts().UseTemporary); + + // TODO: Test argument generation. +} + +TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagUnknownPresent) { + const char *Args[] = {"-ftemp-file"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_TRUE(Diags->hasErrorOccurred()); // Driver-only flag. + ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary); +} + +// Boolean option with a keypath that defaults to true. +// The flag with negative spelling can set the keypath to false. +// The flag with positive spelling can reset the keypath to true. + +TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNone) { + const char *Args[] = {""}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink); + + // TODO: Test argument generation. +} + +TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNegChange) { + const char *Args[] = {"-fno-autolink"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_FALSE(Invocation.getCodeGenOpts().Autolink); + + // TODO: Test argument generation. +} + +TEST_F(CommandLineTest, BoolOptionDefaultTruePresentPosReset) { + const char *Args[] = {"-fautolink"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_TRUE(Diags->hasErrorOccurred()); // Driver-only flag. + ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink); +} + +// Boolean option with a keypath that defaults to false. +// The flag with negative spelling can set the keypath to true. +// The flag with positive spelling can reset the keypath to false. + +TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNone) { + const char *Args[] = {""}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables); + + // TODO: Test argument generation. +} + +TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegChange) { + const char *Args[] = {"-gno-inline-line-tables"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_TRUE(Invocation.getCodeGenOpts().NoInlineLineTables); + + // TODO: Test argument generation. +} + +TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosReset) { + const char *Args[] = {"-ginline-line-tables"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_TRUE(Diags->hasErrorOccurred()); // Driver-only flag. + ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink); +} + +// Boolean option with a keypath that defaults to false. +// The flag with positive spelling can set the keypath to true. +// The flag with negative spelling can reset the keypath to false. + +TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNoneX) { + const char *Args[] = {""}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash); + + // TODO: Test argument generation. +} + +TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosChange) { + const char *Args[] = {"-gcodeview-ghash"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_TRUE(Invocation.getCodeGenOpts().CodeViewGHash); + + // TODO: Test argument generation. +} - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); +TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegReset) { + const char *Args[] = {"-gno-codeview-ghash"}; - ASSERT_TRUE(CInvok.getFrontendOpts().UseTemporary); + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_TRUE(Diags->hasErrorOccurred()); // Driver-only flag. + ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash); } -TEST_F(OptsPopulationTest, OptOfNegativeFlagIsPopulatedWithFalse) { - const char *Args[] = {"clang", "-xc++", "-fno-temp-file"}; +// Boolean option with a keypath that defaults to an arbitrary expression. +// The flag with positive spelling can set the keypath to true. +// The flag with negative spelling can set the keypath to false. - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); +// NOTE: The following tests need to be updated when we start enabling the new +// pass manager by default. - ASSERT_FALSE(CInvok.getFrontendOpts().UseTemporary); +TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentNone) { + const char *Args = {""}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_EQ(Invocation.getCodeGenOpts().ExperimentalNewPassManager, false); + + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + ASSERT_THAT(GeneratedArgs, + Not(Contains(StrEq("-fexperimental-new-pass-manager")))); } -TEST_F(OptsPopulationTest, OptsOfImpliedPositiveFlagArePopulatedWithTrue) { - const char *Args[] = {"clang", "-xc++", "-cl-unsafe-math-optimizations"}; +TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentPos) { + const char *Args[] = {"-fexperimental-new-pass-manager"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_TRUE(Invocation.getCodeGenOpts().ExperimentalNewPassManager); - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + ASSERT_THAT(GeneratedArgs, + Contains(StrEq("-fexperimental-new-pass-manager"))); + ASSERT_THAT(GeneratedArgs, + Not(Contains(StrEq("-fno-experimental-new-pass-manager")))); +} - // Explicitly provided flag. - ASSERT_TRUE(CInvok.getLangOpts()->CLUnsafeMath); +TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentNeg) { + const char *Args[] = {"-fno-experimental-new-pass-manager"}; - // Flags directly implied by explicitly provided flag. - ASSERT_TRUE(CInvok.getCodeGenOpts().LessPreciseFPMAD); - ASSERT_TRUE(CInvok.getLangOpts()->UnsafeFPMath); + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_FALSE(Invocation.getCodeGenOpts().ExperimentalNewPassManager); - // Flag transitively implied by explicitly provided flag. - ASSERT_TRUE(CInvok.getLangOpts()->AllowRecip); + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + ASSERT_THAT(GeneratedArgs, + Contains(StrEq("-fno-experimental-new-pass-manager"))); + ASSERT_THAT(GeneratedArgs, + Not(Contains(StrEq("-fexperimental-new-pass-manager")))); } -TEST_F(CC1CommandLineGenerationTest, CanGenerateCC1CommandLineFlag) { +TEST_F(CommandLineTest, CanGenerateCC1CommandLineFlag) { const char *Args[] = {"clang", "-xc++", "-fmodules-strict-context-hash", "-"}; - CompilerInvocation CInvok; - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); - CInvok.generateCC1CommandLine(GeneratedArgs, *this); + Invocation.generateCC1CommandLine(GeneratedArgs, *this); ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fmodules-strict-context-hash"))); } -TEST_F(CC1CommandLineGenerationTest, CanGenerateCC1CommandLineSeparate) { +TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparate) { const char *TripleCStr = "i686-apple-darwin9"; const char *Args[] = {"clang", "-xc++", "-triple", TripleCStr, "-"}; - CompilerInvocation CInvok; - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); - CInvok.generateCC1CommandLine(GeneratedArgs, *this); + Invocation.generateCC1CommandLine(GeneratedArgs, *this); ASSERT_THAT(GeneratedArgs, Contains(StrEq(TripleCStr))); } -TEST_F(CC1CommandLineGenerationTest, - CanGenerateCC1CommandLineSeparateRequiredPresent) { +TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredPresent) { const std::string DefaultTriple = llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); const char *Args[] = {"clang", "-xc++", "-triple", DefaultTriple.c_str(), "-"}; - CompilerInvocation CInvok; - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); - CInvok.generateCC1CommandLine(GeneratedArgs, *this); + Invocation.generateCC1CommandLine(GeneratedArgs, *this); // Triple should always be emitted even if it is the default ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str()))); } -TEST_F(CC1CommandLineGenerationTest, - CanGenerateCC1CommandLineSeparateRequiredAbsent) { +TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredAbsent) { const std::string DefaultTriple = llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); const char *Args[] = {"clang", "-xc++", "-"}; - CompilerInvocation CInvok; - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); - CInvok.generateCC1CommandLine(GeneratedArgs, *this); + Invocation.generateCC1CommandLine(GeneratedArgs, *this); // Triple should always be emitted even if it is the default ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str()))); } -TEST_F(CC1CommandLineGenerationTest, CanGenerateCC1CommandLineSeparateEnum) { +TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateEnum) { const char *RelocationModelCStr = "static"; const char *Args[] = {"clang", "-xc++", "-mrelocation-model", RelocationModelCStr, "-"}; - CompilerInvocation CInvok; - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); - CInvok.generateCC1CommandLine(GeneratedArgs, *this); + Invocation.generateCC1CommandLine(GeneratedArgs, *this); // Non default relocation model ASSERT_THAT(GeneratedArgs, Contains(StrEq(RelocationModelCStr))); @@ -147,90 +278,98 @@ RelocationModelCStr = "pic"; Args[3] = RelocationModelCStr; - CompilerInvocation CInvok1; - CompilerInvocation::CreateFromArgs(CInvok1, Args, *Diags); + CompilerInvocation Invocation2; + CompilerInvocation::CreateFromArgs(Invocation2, Args, *Diags); - CInvok1.generateCC1CommandLine(GeneratedArgs, *this); + Invocation2.generateCC1CommandLine(GeneratedArgs, *this); ASSERT_THAT(GeneratedArgs, Each(StrNe(RelocationModelCStr))); } -TEST_F(CC1CommandLineGenerationTest, NotPresentNegativeFlagNotGenerated) { - const char *Args[] = {"clang", "-xc++"}; - - CompilerInvocation CInvok; - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); - - CInvok.generateCC1CommandLine(GeneratedArgs, *this); - - ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-temp-file")))); -} - -TEST_F(CC1CommandLineGenerationTest, PresentNegativeFlagGenerated) { - const char *Args[] = {"clang", "-xc++", "-fno-temp-file"}; - - CompilerInvocation CInvok; - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); - - CInvok.generateCC1CommandLine(GeneratedArgs, *this); - - ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-temp-file"))); -} - -TEST_F(CC1CommandLineGenerationTest, NotPresentAndNotImpliedNotGenerated) { - const char *Args[] = {"clang", "-xc++"}; - - CompilerInvocation CInvok; - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); - - CInvok.generateCC1CommandLine(GeneratedArgs, *this); - - // Missing options are not generated. +// Tree of boolean options that can be (directly or transitively) implied by +// their parent: +// +// * -cl-unsafe-math-optimizations +// * -cl-mad-enable +// * -menable-unsafe-fp-math +// * -freciprocal-math + +TEST_F(CommandLineTest, ImpliedBoolOptionsNoFlagPresent) { + const char *Args[] = {""}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath); + ASSERT_FALSE(Invocation.getCodeGenOpts().LessPreciseFPMAD); + ASSERT_FALSE(Invocation.getLangOpts()->UnsafeFPMath); + ASSERT_FALSE(Invocation.getLangOpts()->AllowRecip); + + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + // Missing option is not generated. ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-unsafe-math-optimizations")))); + // Options that were not implied are not generated. ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); + ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); } -TEST_F(CC1CommandLineGenerationTest, NotPresentAndImpliedNotGenerated) { - const char *Args[] = {"clang", "-xc++", "-cl-unsafe-math-optimizations"}; - - CompilerInvocation CInvok; - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); +TEST_F(CommandLineTest, ImpliedBoolOptionsParentRootFlagPresent) { + const char *Args[] = {"-cl-unsafe-math-optimizations"}; - CInvok.generateCC1CommandLine(GeneratedArgs, *this); + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + // Explicitly provided root flag. + ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath); + // Flags directly implied by explicitly provided root flag. + ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD); + ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath); + // Flag transitively implied by explicitly provided root flag. + ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip); + Invocation.generateCC1CommandLine(GeneratedArgs, *this); // Missing options that were implied are not generated. ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); + ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); } -TEST_F(CC1CommandLineGenerationTest, PresentAndImpliedNotGenerated) { - const char *Args[] = {"clang", "-xc++", "-cl-unsafe-math-optimizations", - "-cl-mad-enable", "-menable-unsafe-fp-math"}; +TEST_F(CommandLineTest, ImpliedBoolOptionsAllFlagsPresent) { + const char *Args[] = {"-cl-unsafe-math-optimizations", "-cl-mad-enable", + "-menable-unsafe-fp-math", "-freciprocal-math"}; - CompilerInvocation CInvok; - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath); + ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD); + ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath); + ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip); - CInvok.generateCC1CommandLine(GeneratedArgs, *this); - - // Present options that were also implied are not generated. + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + // Implied flags not present - can be deduced from the root flag. ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); + ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); } -TEST_F(CC1CommandLineGenerationTest, PresentAndNotImpliedGenerated) { - const char *Args[] = {"clang", "-xc++", "-cl-mad-enable", - "-menable-unsafe-fp-math"}; - - CompilerInvocation CInvok; - CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); +TEST_F(CommandLineTest, ImpliedBoolOptionsImpliedFlagsPresent) { + const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math", + "-freciprocal-math"}; - CInvok.generateCC1CommandLine(GeneratedArgs, *this); + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath); + ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD); + ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath); + ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip); - // Present options that were not implied are generated. + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + ASSERT_THAT(GeneratedArgs, + Not(Contains(StrEq("-cl-unsafe-math-optimizations")))); ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable"))); ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math"))); + // Implied flag not preset - can be deduced from the present parent. + ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); } } // anonymous namespace