11c9a8004SChuanqi Xu //===- unittests/Serialization/VarDeclConstantInitTest.cpp - CI tests -----===// 21c9a8004SChuanqi Xu // 31c9a8004SChuanqi Xu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 41c9a8004SChuanqi Xu // See https://llvm.org/LICENSE.txt for license information. 51c9a8004SChuanqi Xu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 61c9a8004SChuanqi Xu // 71c9a8004SChuanqi Xu //===----------------------------------------------------------------------===// 81c9a8004SChuanqi Xu 91c9a8004SChuanqi Xu #include "clang/ASTMatchers/ASTMatchFinder.h" 101c9a8004SChuanqi Xu #include "clang/ASTMatchers/ASTMatchers.h" 111c9a8004SChuanqi Xu #include "clang/Basic/FileManager.h" 121c9a8004SChuanqi Xu #include "clang/Frontend/CompilerInstance.h" 131c9a8004SChuanqi Xu #include "clang/Frontend/CompilerInvocation.h" 141c9a8004SChuanqi Xu #include "clang/Frontend/FrontendActions.h" 151c9a8004SChuanqi Xu #include "clang/Frontend/Utils.h" 161c9a8004SChuanqi Xu #include "clang/Lex/HeaderSearch.h" 171c9a8004SChuanqi Xu #include "clang/Tooling/Tooling.h" 181c9a8004SChuanqi Xu #include "llvm/ADT/SmallString.h" 191c9a8004SChuanqi Xu #include "llvm/Support/FileSystem.h" 201c9a8004SChuanqi Xu #include "llvm/Support/raw_ostream.h" 211c9a8004SChuanqi Xu 221c9a8004SChuanqi Xu #include "gtest/gtest.h" 231c9a8004SChuanqi Xu 241c9a8004SChuanqi Xu using namespace llvm; 251c9a8004SChuanqi Xu using namespace clang; 261c9a8004SChuanqi Xu 271c9a8004SChuanqi Xu namespace { 281c9a8004SChuanqi Xu 291c9a8004SChuanqi Xu class VarDeclConstantInitTest : public ::testing::Test { 301c9a8004SChuanqi Xu void SetUp() override { 311c9a8004SChuanqi Xu ASSERT_FALSE(sys::fs::createUniqueDirectory("modules-test", TestDir)); 321c9a8004SChuanqi Xu } 331c9a8004SChuanqi Xu 341c9a8004SChuanqi Xu void TearDown() override { sys::fs::remove_directories(TestDir); } 351c9a8004SChuanqi Xu 361c9a8004SChuanqi Xu public: 371c9a8004SChuanqi Xu SmallString<256> TestDir; 381c9a8004SChuanqi Xu 391c9a8004SChuanqi Xu void addFile(StringRef Path, StringRef Contents) { 401c9a8004SChuanqi Xu ASSERT_FALSE(sys::path::is_absolute(Path)); 411c9a8004SChuanqi Xu 421c9a8004SChuanqi Xu SmallString<256> AbsPath(TestDir); 431c9a8004SChuanqi Xu sys::path::append(AbsPath, Path); 441c9a8004SChuanqi Xu 451c9a8004SChuanqi Xu ASSERT_FALSE( 461c9a8004SChuanqi Xu sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath))); 471c9a8004SChuanqi Xu 481c9a8004SChuanqi Xu std::error_code EC; 491c9a8004SChuanqi Xu llvm::raw_fd_ostream OS(AbsPath, EC); 501c9a8004SChuanqi Xu ASSERT_FALSE(EC); 511c9a8004SChuanqi Xu OS << Contents; 521c9a8004SChuanqi Xu } 531c9a8004SChuanqi Xu }; 541c9a8004SChuanqi Xu 551c9a8004SChuanqi Xu TEST_F(VarDeclConstantInitTest, CachedConstantInit) { 561c9a8004SChuanqi Xu addFile("Cached.cppm", R"cpp( 571c9a8004SChuanqi Xu export module Fibonacci.Cache; 581c9a8004SChuanqi Xu 591c9a8004SChuanqi Xu export namespace Fibonacci 601c9a8004SChuanqi Xu { 611c9a8004SChuanqi Xu constexpr unsigned long Recursive(unsigned long n) 621c9a8004SChuanqi Xu { 631c9a8004SChuanqi Xu if (n == 0) 641c9a8004SChuanqi Xu return 0; 651c9a8004SChuanqi Xu if (n == 1) 661c9a8004SChuanqi Xu return 1; 671c9a8004SChuanqi Xu return Recursive(n - 2) + Recursive(n - 1); 681c9a8004SChuanqi Xu } 691c9a8004SChuanqi Xu 701c9a8004SChuanqi Xu template<unsigned long N> 711c9a8004SChuanqi Xu struct Number{}; 721c9a8004SChuanqi Xu 731c9a8004SChuanqi Xu struct DefaultStrategy 741c9a8004SChuanqi Xu { 751c9a8004SChuanqi Xu constexpr unsigned long operator()(unsigned long n, auto... other) const 761c9a8004SChuanqi Xu { 771c9a8004SChuanqi Xu return (n + ... + other); 781c9a8004SChuanqi Xu } 791c9a8004SChuanqi Xu }; 801c9a8004SChuanqi Xu 811c9a8004SChuanqi Xu constexpr unsigned long Compute(Number<10ul>, auto strategy) 821c9a8004SChuanqi Xu { 831c9a8004SChuanqi Xu return strategy(Recursive(10ul)); 841c9a8004SChuanqi Xu } 851c9a8004SChuanqi Xu 861c9a8004SChuanqi Xu template<unsigned long N, typename Strategy = DefaultStrategy> 871c9a8004SChuanqi Xu constexpr unsigned long Cache = Compute(Number<N>{}, Strategy{}); 881c9a8004SChuanqi Xu 891c9a8004SChuanqi Xu template constexpr unsigned long Cache<10ul>; 901c9a8004SChuanqi Xu } 911c9a8004SChuanqi Xu )cpp"); 921c9a8004SChuanqi Xu 93a1153cd6SSylvestre Ledru CreateInvocationOptions CIOpts; 94a1153cd6SSylvestre Ledru CIOpts.VFS = llvm::vfs::createPhysicalFileSystem(); 95*df9a14d7SKadir Cetinkaya IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 96*df9a14d7SKadir Cetinkaya CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions()); 97*df9a14d7SKadir Cetinkaya CIOpts.Diags = Diags; 981c9a8004SChuanqi Xu 99da00c60dSChuanqi Xu const char *Args[] = {"clang++", "-std=c++20", 100da00c60dSChuanqi Xu "--precompile", "-working-directory", 101da00c60dSChuanqi Xu TestDir.c_str(), "Cached.cppm"}; 1021c9a8004SChuanqi Xu std::shared_ptr<CompilerInvocation> Invocation = 1031c9a8004SChuanqi Xu createInvocation(Args, CIOpts); 1041c9a8004SChuanqi Xu ASSERT_TRUE(Invocation); 105b2ebd8b8SKrasimir Georgiev Invocation->getFrontendOpts().DisableFree = false; 1061c9a8004SChuanqi Xu 1071c9a8004SChuanqi Xu CompilerInstance Instance; 1081c9a8004SChuanqi Xu Instance.setDiagnostics(Diags.get()); 1091c9a8004SChuanqi Xu Instance.setInvocation(Invocation); 110da00c60dSChuanqi Xu 111da00c60dSChuanqi Xu std::string CacheBMIPath = llvm::Twine(TestDir + "/Cached.pcm").str(); 112da00c60dSChuanqi Xu Instance.getFrontendOpts().OutputFile = CacheBMIPath; 113da00c60dSChuanqi Xu 114da00c60dSChuanqi Xu GenerateReducedModuleInterfaceAction Action; 1151c9a8004SChuanqi Xu ASSERT_TRUE(Instance.ExecuteAction(Action)); 1161c9a8004SChuanqi Xu ASSERT_FALSE(Diags->hasErrorOccurred()); 1171c9a8004SChuanqi Xu 1181c9a8004SChuanqi Xu std::string DepArg = 1191c9a8004SChuanqi Xu llvm::Twine("-fmodule-file=Fibonacci.Cache=" + CacheBMIPath).str(); 1201c9a8004SChuanqi Xu std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCodeWithArgs( 1211c9a8004SChuanqi Xu R"cpp( 1221c9a8004SChuanqi Xu import Fibonacci.Cache; 1231c9a8004SChuanqi Xu )cpp", 1241c9a8004SChuanqi Xu /*Args=*/{"-std=c++20", DepArg.c_str()}); 1251c9a8004SChuanqi Xu 1261c9a8004SChuanqi Xu using namespace clang::ast_matchers; 1271c9a8004SChuanqi Xu ASTContext &Ctx = AST->getASTContext(); 1281c9a8004SChuanqi Xu const auto *cached = selectFirst<VarDecl>( 1291c9a8004SChuanqi Xu "Cache", 1301c9a8004SChuanqi Xu match(varDecl(isTemplateInstantiation(), hasName("Cache")).bind("Cache"), 1311c9a8004SChuanqi Xu Ctx)); 1321c9a8004SChuanqi Xu EXPECT_TRUE(cached); 1331c9a8004SChuanqi Xu EXPECT_TRUE(cached->getEvaluatedStmt()); 1341c9a8004SChuanqi Xu EXPECT_TRUE(cached->getEvaluatedStmt()->WasEvaluated); 1351c9a8004SChuanqi Xu EXPECT_TRUE(cached->getEvaluatedValue()); 1361c9a8004SChuanqi Xu EXPECT_TRUE(cached->getEvaluatedValue()->isInt()); 1371c9a8004SChuanqi Xu EXPECT_EQ(cached->getEvaluatedValue()->getInt(), 55); 1381c9a8004SChuanqi Xu } 1391c9a8004SChuanqi Xu 1401c9a8004SChuanqi Xu } // anonymous namespace 141