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 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 94 CompilerInstance::createDiagnostics(new DiagnosticOptions()); 95 CreateInvocationOptions CIOpts; 96 CIOpts.Diags = Diags; 97 CIOpts.VFS = llvm::vfs::createPhysicalFileSystem(); 98 99 std::string CacheBMIPath = llvm::Twine(TestDir + "/Cached.pcm").str(); 100 const char *Args[] = { 101 "clang++", "-std=c++20", "--precompile", "-working-directory", 102 TestDir.c_str(), "Cached.cppm", "-o", CacheBMIPath.c_str()}; 103 std::shared_ptr<CompilerInvocation> Invocation = 104 createInvocation(Args, CIOpts); 105 ASSERT_TRUE(Invocation); 106 107 CompilerInstance Instance; 108 Instance.setDiagnostics(Diags.get()); 109 Instance.setInvocation(Invocation); 110 GenerateModuleInterfaceAction Action; 111 ASSERT_TRUE(Instance.ExecuteAction(Action)); 112 ASSERT_FALSE(Diags->hasErrorOccurred()); 113 114 std::string DepArg = 115 llvm::Twine("-fmodule-file=Fibonacci.Cache=" + CacheBMIPath).str(); 116 std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCodeWithArgs( 117 R"cpp( 118 import Fibonacci.Cache; 119 )cpp", 120 /*Args=*/{"-std=c++20", DepArg.c_str()}); 121 122 using namespace clang::ast_matchers; 123 ASTContext &Ctx = AST->getASTContext(); 124 const auto *cached = selectFirst<VarDecl>( 125 "Cache", 126 match(varDecl(isTemplateInstantiation(), hasName("Cache")).bind("Cache"), 127 Ctx)); 128 EXPECT_TRUE(cached); 129 EXPECT_TRUE(cached->getEvaluatedStmt()); 130 EXPECT_TRUE(cached->getEvaluatedStmt()->WasEvaluated); 131 EXPECT_TRUE(cached->getEvaluatedValue()); 132 EXPECT_TRUE(cached->getEvaluatedValue()->isInt()); 133 EXPECT_EQ(cached->getEvaluatedValue()->getInt(), 55); 134 } 135 136 } // anonymous namespace 137