[C++20] [Modules] Don't generate unused variables in other module units

even if its initializer has side effects

Close https://github.com/llvm/llvm-project/issues/61892

The variables whose initializer has side effects will be emitted even if
it is not used. But it shouldn't be true after we introduced modules.
The variables in other modules shouldn't be emitted if it is not used
even if its initializer has size effects.

Also this patch rename `Decl::isInCurrentModuleUnit` to
`Decl::isInAnotherModuleUnit` to make it closer to the semantics.
This commit is contained in:
Chuanqi Xu
2023-05-06 17:32:39 +08:00
parent 7591a7b6ea
commit b6c7177145
7 changed files with 83 additions and 12 deletions

View File

@@ -645,7 +645,7 @@ public:
}
/// Whether this declaration comes from another module unit.
bool isInCurrentModuleUnit() const;
bool isInAnotherModuleUnit() const;
/// FIXME: Implement discarding declarations actually in global module
/// fragment. See [module.global.frag]p3,4 for details.

View File

@@ -11926,6 +11926,10 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
!isMSStaticDataMemberInlineDefinition(VD))
return false;
// Variables in other module units shouldn't be forced to be emitted.
if (VD->isInAnotherModuleUnit())
return false;
// Variables that can be needed in other TUs are required.
auto Linkage = GetGVALinkageForVariable(VD);
if (!isDiscardableGVALinkage(Linkage))

View File

@@ -1023,24 +1023,26 @@ bool Decl::isInExportDeclContext() const {
return DC && isa<ExportDecl>(DC);
}
bool Decl::isInCurrentModuleUnit() const {
bool Decl::isInAnotherModuleUnit() const {
auto *M = getOwningModule();
if (!M)
return true;
return false;
M = M->getTopLevelModule();
// FIXME: It is problematic if the header module lives in another module
// unit. Consider to fix this by techniques like
// ExternalASTSource::hasExternalDefinitions.
if (M->isHeaderLikeModule())
return true;
return false;
// A global module without parent implies that we're parsing the global
// module. So it can't be in another module unit.
if (M->isGlobalModule())
return true;
return false;
assert(M->isModulePurview() && "New module kind?");
return M == getASTContext().getCurrentNamedModule();
return M != getASTContext().getCurrentNamedModule();
}
static Decl::Kind getKind(const Decl *D) { return D->getKind(); }

View File

@@ -1909,7 +1909,7 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) {
if (DeclModule->isHeaderLikeModule())
return false;
if (D->isInCurrentModuleUnit())
if (!D->isInAnotherModuleUnit())
return true;
// [module.reach]/p3:
@@ -3889,7 +3889,7 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
"bad export context");
// .. are attached to a named module M, do not appear in the
// translation unit containing the point of the lookup..
if (!D->isInCurrentModuleUnit() &&
if (D->isInAnotherModuleUnit() &&
llvm::any_of(AssociatedClasses, [&](auto *E) {
// ... and have the same innermost enclosing non-inline
// namespace scope as a declaration of an associated entity

View File

@@ -6543,7 +6543,7 @@ void Sema::AddOverloadCandidate(
}
// Functions with internal linkage are only viable in the same module unit.
if (getLangOpts().CPlusPlusModules && !Function->isInCurrentModuleUnit()) {
if (getLangOpts().CPlusPlusModules && Function->isInAnotherModuleUnit()) {
/// FIXME: Currently, the semantics of linkage in clang is slightly
/// different from the semantics in C++ spec. In C++ spec, only names
/// have linkage. So that all entities of the same should share one

View File

@@ -2851,7 +2851,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc();
SawDefaultArgument = true;
if (OldTypeParm->isInCurrentModuleUnit())
if (!OldTypeParm->isInAnotherModuleUnit())
RedundantDefaultArg = true;
else if (!getASTContext().isSameDefaultTemplateArgument(OldTypeParm,
NewTypeParm)) {
@@ -2903,7 +2903,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc();
SawDefaultArgument = true;
if (OldNonTypeParm->isInCurrentModuleUnit())
if (!OldNonTypeParm->isInAnotherModuleUnit())
RedundantDefaultArg = true;
else if (!getASTContext().isSameDefaultTemplateArgument(
OldNonTypeParm, NewNonTypeParm)) {
@@ -2954,7 +2954,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation();
SawDefaultArgument = true;
if (OldTemplateParm->isInCurrentModuleUnit())
if (!OldTemplateParm->isInAnotherModuleUnit())
RedundantDefaultArg = true;
else if (!getASTContext().isSameDefaultTemplateArgument(
OldTemplateParm, NewTemplateParm)) {

View File

@@ -0,0 +1,65 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: split-file %s %t
//
// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple \
// RUN: -emit-module-interface %t/a.cppm -o %t/a.pcm
// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple \
// RUN: %t/b.cpp -fmodule-file=a=%t/a.pcm -disable-llvm-passes \
// RUN: -emit-llvm -o - | FileCheck %t/b.cpp
// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple \
// RUN: %t/c.cpp -fmodule-file=a=%t/a.pcm -disable-llvm-passes \
// RUN: -emit-llvm -o - | FileCheck %t/c.cpp
//--- a.cppm
export module a;
struct integer {
explicit operator int() const {
return 0;
}
};
export template<typename>
int a = static_cast<int>(integer());
struct s {
~s();
operator int() const;
};
export template<typename>
auto d = s();
int aa() {
return a<void> + d<void>;
}
int dynamic_func();
export inline int dynamic_var = dynamic_func();
//--- b.cpp
import a;
void b() {}
// CHECK-NOT: @_ZW1a1dIvE =
// CHECK-NOT: @_ZGVW1a1dIvE =
// CHECK-NOT: @_ZW1a11dynamic_var =
// CHECK-NOT: @_ZGVW1a11dynamic_var =
// CHECK-NOT: @_ZW1a1aIvE =
// CHECK-NOT: @_ZGVW1a1aIvE =
//--- c.cpp
import a;
int c() {
return a<void> + d<void> + dynamic_var;
}
// The used variables are generated normally
// CHECK-DAG: @_ZW1a1aIvE =
// CHECK-DAG: @_ZW1a1dIvE =
// CHECK-DAG: @_ZW1a11dynamic_var = linkonce_odr
// CHECK-DAG: @_ZGVW1a1aIvE =
// CHECk-DAG: @_ZGVW1a1dIvE =
// CHECK-DAG: @_ZGVW1a11dynamic_var = linkonce_odr