
Close https://github.com/llvm/llvm-project/issues/71034 See https://discourse.llvm.org/t/rfc-c-20-modules-introduce-thin-bmi-and-decls-hash/74755 This patch introduces reduced BMI, which doesn't contain the definitions of functions and variables if its definitions won't contribute to the ABI. Testing is a big part of the patch. We want to make sure the reduced BMI contains the same behavior with the existing and relatively stable fatBMI. This is pretty helpful for further reduction. The user interfaces part it left to following patches to ease the reviewing.
193 lines
5.5 KiB
C++
193 lines
5.5 KiB
C++
//== unittests/Sema/SemaNoloadLookupTest.cpp -------------------------========//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/AST/DeclLookups.h"
|
|
#include "clang/AST/DeclarationName.h"
|
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
|
#include "clang/ASTMatchers/ASTMatchers.h"
|
|
#include "clang/Frontend/CompilerInstance.h"
|
|
#include "clang/Frontend/FrontendAction.h"
|
|
#include "clang/Frontend/FrontendActions.h"
|
|
#include "clang/Parse/ParseAST.h"
|
|
#include "clang/Sema/Lookup.h"
|
|
#include "clang/Sema/Sema.h"
|
|
#include "clang/Sema/SemaConsumer.h"
|
|
#include "clang/Tooling/Tooling.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
using namespace clang;
|
|
using namespace clang::tooling;
|
|
|
|
namespace {
|
|
|
|
class NoloadLookupTest : public ::testing::Test {
|
|
void SetUp() override {
|
|
ASSERT_FALSE(
|
|
sys::fs::createUniqueDirectory("modules-no-comments-test", TestDir));
|
|
}
|
|
|
|
void TearDown() override { sys::fs::remove_directories(TestDir); }
|
|
|
|
public:
|
|
SmallString<256> TestDir;
|
|
|
|
void addFile(StringRef Path, StringRef Contents) {
|
|
ASSERT_FALSE(sys::path::is_absolute(Path));
|
|
|
|
SmallString<256> AbsPath(TestDir);
|
|
sys::path::append(AbsPath, Path);
|
|
|
|
ASSERT_FALSE(
|
|
sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath)));
|
|
|
|
std::error_code EC;
|
|
llvm::raw_fd_ostream OS(AbsPath, EC);
|
|
ASSERT_FALSE(EC);
|
|
OS << Contents;
|
|
}
|
|
|
|
std::string GenerateModuleInterface(StringRef ModuleName,
|
|
StringRef Contents) {
|
|
std::string FileName = llvm::Twine(ModuleName + ".cppm").str();
|
|
addFile(FileName, Contents);
|
|
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
|
|
CompilerInstance::createDiagnostics(new DiagnosticOptions());
|
|
CreateInvocationOptions CIOpts;
|
|
CIOpts.Diags = Diags;
|
|
CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
|
|
|
|
std::string CacheBMIPath =
|
|
llvm::Twine(TestDir + "/" + ModuleName + ".pcm").str();
|
|
std::string PrebuiltModulePath =
|
|
"-fprebuilt-module-path=" + TestDir.str().str();
|
|
const char *Args[] = {"clang++",
|
|
"-std=c++20",
|
|
"--precompile",
|
|
PrebuiltModulePath.c_str(),
|
|
"-working-directory",
|
|
TestDir.c_str(),
|
|
"-I",
|
|
TestDir.c_str(),
|
|
FileName.c_str()};
|
|
std::shared_ptr<CompilerInvocation> Invocation =
|
|
createInvocation(Args, CIOpts);
|
|
EXPECT_TRUE(Invocation);
|
|
|
|
CompilerInstance Instance;
|
|
Instance.setDiagnostics(Diags.get());
|
|
Instance.setInvocation(Invocation);
|
|
Instance.getFrontendOpts().OutputFile = CacheBMIPath;
|
|
GenerateReducedModuleInterfaceAction Action;
|
|
EXPECT_TRUE(Instance.ExecuteAction(Action));
|
|
EXPECT_FALSE(Diags->hasErrorOccurred());
|
|
|
|
return CacheBMIPath;
|
|
}
|
|
};
|
|
|
|
struct TrivialVisibleDeclConsumer : public VisibleDeclConsumer {
|
|
TrivialVisibleDeclConsumer() {}
|
|
void EnteredContext(DeclContext *Ctx) override {}
|
|
void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
|
|
bool InBaseClass) override {
|
|
FoundNum++;
|
|
}
|
|
|
|
int FoundNum = 0;
|
|
};
|
|
|
|
class NoloadLookupConsumer : public SemaConsumer {
|
|
public:
|
|
void InitializeSema(Sema &S) override { SemaPtr = &S; }
|
|
|
|
bool HandleTopLevelDecl(DeclGroupRef D) override {
|
|
if (!D.isSingleDecl())
|
|
return true;
|
|
|
|
Decl *TD = D.getSingleDecl();
|
|
|
|
auto *ID = dyn_cast<ImportDecl>(TD);
|
|
if (!ID)
|
|
return true;
|
|
|
|
clang::Module *M = ID->getImportedModule();
|
|
assert(M);
|
|
if (M->Name != "R")
|
|
return true;
|
|
|
|
auto *Std = SemaPtr->getStdNamespace();
|
|
EXPECT_TRUE(Std);
|
|
TrivialVisibleDeclConsumer Consumer;
|
|
SemaPtr->LookupVisibleDecls(Std, Sema::LookupNameKind::LookupOrdinaryName,
|
|
Consumer,
|
|
/*IncludeGlobalScope=*/true,
|
|
/*IncludeDependentBases=*/false,
|
|
/*LoadExternal=*/false);
|
|
EXPECT_EQ(Consumer.FoundNum, 1);
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
Sema *SemaPtr = nullptr;
|
|
};
|
|
|
|
class NoloadLookupAction : public ASTFrontendAction {
|
|
std::unique_ptr<ASTConsumer>
|
|
CreateASTConsumer(CompilerInstance &CI, StringRef /*Unused*/) override {
|
|
return std::make_unique<NoloadLookupConsumer>();
|
|
}
|
|
};
|
|
|
|
TEST_F(NoloadLookupTest, NonModulesTest) {
|
|
GenerateModuleInterface("M", R"cpp(
|
|
module;
|
|
namespace std {
|
|
int What();
|
|
|
|
void bar(int x = What()) {
|
|
}
|
|
}
|
|
export module M;
|
|
export using std::bar;
|
|
)cpp");
|
|
|
|
GenerateModuleInterface("R", R"cpp(
|
|
module;
|
|
namespace std {
|
|
class Another;
|
|
int What(Another);
|
|
int What();
|
|
}
|
|
export module R;
|
|
)cpp");
|
|
|
|
const char *test_file_contents = R"cpp(
|
|
import M;
|
|
namespace std {
|
|
void use() {
|
|
bar();
|
|
}
|
|
}
|
|
import R;
|
|
)cpp";
|
|
std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str();
|
|
EXPECT_TRUE(runToolOnCodeWithArgs(std::make_unique<NoloadLookupAction>(),
|
|
test_file_contents,
|
|
{
|
|
"-std=c++20",
|
|
DepArg.c_str(),
|
|
"-I",
|
|
TestDir.c_str(),
|
|
},
|
|
"test.cpp"));
|
|
}
|
|
|
|
} // namespace
|