1 //===- unittests/Serialization/VarDeclConstantInitTest.cpp - CI tests -----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/ASTMatchers/ASTMatchFinder.h" 10 #include "clang/ASTMatchers/ASTMatchers.h" 11 #include "clang/Basic/FileManager.h" 12 #include "clang/Frontend/CompilerInstance.h" 13 #include "clang/Frontend/CompilerInvocation.h" 14 #include "clang/Frontend/FrontendActions.h" 15 #include "clang/Frontend/Utils.h" 16 #include "clang/Lex/HeaderSearch.h" 17 #include "clang/Tooling/Tooling.h" 18 #include "llvm/ADT/SmallString.h" 19 #include "llvm/Support/FileSystem.h" 20 #include "llvm/Support/raw_ostream.h" 21 22 #include "gtest/gtest.h" 23 24 using namespace llvm; 25 using namespace clang; 26 27 namespace { 28 29 class VarDeclConstantInitTest : public ::testing::Test { 30 void SetUp() override { 31 ASSERT_FALSE(sys::fs::createUniqueDirectory("modules-test", TestDir)); 32 } 33 34 void TearDown() override { sys::fs::remove_directories(TestDir); } 35 36 public: 37 SmallString<256> TestDir; 38 39 void addFile(StringRef Path, StringRef Contents) { 40 ASSERT_FALSE(sys::path::is_absolute(Path)); 41 42 SmallString<256> AbsPath(TestDir); 43 sys::path::append(AbsPath, Path); 44 45 ASSERT_FALSE( 46 sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath))); 47 48 std::error_code EC; 49 llvm::raw_fd_ostream OS(AbsPath, EC); 50 ASSERT_FALSE(EC); 51 OS << Contents; 52 } 53 }; 54 55 TEST_F(VarDeclConstantInitTest, CachedConstantInit) { 56 addFile("Cached.cppm", R"cpp( 57 export module Fibonacci.Cache; 58 59 export namespace Fibonacci 60 { 61 constexpr unsigned long Recursive(unsigned long n) 62 { 63 if (n == 0) 64 return 0; 65 if (n == 1) 66 return 1; 67 return Recursive(n - 2) + Recursive(n - 1); 68 } 69 70 template<unsigned long N> 71 struct Number{}; 72 73 struct DefaultStrategy 74 { 75 constexpr unsigned long operator()(unsigned long n, auto... other) const 76 { 77 return (n + ... + other); 78 } 79 }; 80 81 constexpr unsigned long Compute(Number<10ul>, auto strategy) 82 { 83 return strategy(Recursive(10ul)); 84 } 85 86 template<unsigned long N, typename Strategy = DefaultStrategy> 87 constexpr unsigned long Cache = Compute(Number<N>{}, Strategy{}); 88 89 template constexpr unsigned long Cache<10ul>; 90 } 91 )cpp"); 92 93 CreateInvocationOptions CIOpts; 94 CIOpts.VFS = llvm::vfs::createPhysicalFileSystem(); 95 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 96 CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions()); 97 CIOpts.Diags = Diags; 98 99 const char *Args[] = {"clang++", "-std=c++20", 100 "--precompile", "-working-directory", 101 TestDir.c_str(), "Cached.cppm"}; 102 std::shared_ptr<CompilerInvocation> Invocation = 103 createInvocation(Args, CIOpts); 104 ASSERT_TRUE(Invocation); 105 Invocation->getFrontendOpts().DisableFree = false; 106 107 CompilerInstance Instance; 108 Instance.setDiagnostics(Diags.get()); 109 Instance.setInvocation(Invocation); 110 111 std::string CacheBMIPath = llvm::Twine(TestDir + "/Cached.pcm").str(); 112 Instance.getFrontendOpts().OutputFile = CacheBMIPath; 113 114 GenerateReducedModuleInterfaceAction Action; 115 ASSERT_TRUE(Instance.ExecuteAction(Action)); 116 ASSERT_FALSE(Diags->hasErrorOccurred()); 117 118 std::string DepArg = 119 llvm::Twine("-fmodule-file=Fibonacci.Cache=" + CacheBMIPath).str(); 120 std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCodeWithArgs( 121 R"cpp( 122 import Fibonacci.Cache; 123 )cpp", 124 /*Args=*/{"-std=c++20", DepArg.c_str()}); 125 126 using namespace clang::ast_matchers; 127 ASTContext &Ctx = AST->getASTContext(); 128 const auto *cached = selectFirst<VarDecl>( 129 "Cache", 130 match(varDecl(isTemplateInstantiation(), hasName("Cache")).bind("Cache"), 131 Ctx)); 132 EXPECT_TRUE(cached); 133 EXPECT_TRUE(cached->getEvaluatedStmt()); 134 EXPECT_TRUE(cached->getEvaluatedStmt()->WasEvaluated); 135 EXPECT_TRUE(cached->getEvaluatedValue()); 136 EXPECT_TRUE(cached->getEvaluatedValue()->isInt()); 137 EXPECT_EQ(cached->getEvaluatedValue()->getInt(), 55); 138 } 139 140 } // anonymous namespace 141