Skip to content

Commit 34f4ee7

Browse files
committed
[C++20] [Modules] Merge codes to decide if we should generate decl
There are two piece of codes in ASTWriterDecl to decide whether or not we should generate a function or a variable in current module unit (or PCH with object file extension, which is rarely used). One is in Visit*Decl and One is in `CanElideDef`. Since they are similar it should be better to merge them. This was meant to be a NFC patch. But it seems it helped me to find an existing bug.
1 parent 1d1f2e8 commit 34f4ee7

File tree

2 files changed

+69
-52
lines changed

2 files changed

+69
-52
lines changed

clang/lib/Serialization/ASTWriterDecl.cpp

Lines changed: 68 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -330,28 +330,82 @@ namespace clang {
330330
};
331331
}
332332

333+
// When building a C++20 module interface unit or a partition unit, a
334+
// strong definition in the module interface is provided by the
335+
// compilation of that unit, not by its users. (Inline variables are still
336+
// emitted in module users.)
337+
static bool shouldVarGenerateHereOnly(const VarDecl *VD) {
338+
if (VD->getStorageDuration() != SD_Static)
339+
return false;
340+
341+
if (VD->getDescribedVarTemplate())
342+
return false;
343+
344+
Module *M = VD->getOwningModule();
345+
if (!M)
346+
return false;
347+
348+
M = M->getTopLevelModule();
349+
ASTContext &Ctx = VD->getASTContext();
350+
if (!M->isInterfaceOrPartition() &&
351+
(!VD->hasAttr<DLLExportAttr>() ||
352+
!Ctx.getLangOpts().BuildingPCHWithObjectFile))
353+
return false;
354+
355+
return Ctx.GetGVALinkageForVariable(VD) >= GVA_StrongExternal;
356+
}
357+
358+
static bool shouldFunctionGenerateHereOnly(const FunctionDecl *FD) {
359+
if (FD->isDependentContext())
360+
return false;
361+
362+
ASTContext &Ctx = FD->getASTContext();
363+
auto Linkage = Ctx.GetGVALinkageForFunction(FD);
364+
if (Ctx.getLangOpts().ModulesCodegen ||
365+
(FD->hasAttr<DLLExportAttr>() &&
366+
Ctx.getLangOpts().BuildingPCHWithObjectFile))
367+
// Under -fmodules-codegen, codegen is performed for all non-internal,
368+
// non-always_inline functions, unless they are available elsewhere.
369+
if (!FD->hasAttr<AlwaysInlineAttr>() && Linkage != GVA_Internal &&
370+
Linkage != GVA_AvailableExternally)
371+
return true;
372+
373+
Module *M = FD->getOwningModule();
374+
if (!M)
375+
return false;
376+
377+
M = M->getTopLevelModule();
378+
if (M->isInterfaceOrPartition())
379+
if (Linkage >= GVA_StrongExternal)
380+
return true;
381+
382+
return false;
383+
}
384+
333385
bool clang::CanElideDeclDef(const Decl *D) {
334386
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
335-
if (FD->isInlined() || FD->isConstexpr())
336-
return false;
337-
338-
if (FD->isDependentContext())
387+
if (FD->isInlined() || FD->isConstexpr() || FD->isConsteval())
339388
return false;
340389

341-
if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
390+
// If the function should be generated somewhere else, we shouldn't elide
391+
// it.
392+
if (!shouldFunctionGenerateHereOnly(FD))
342393
return false;
343394
}
344395

345396
if (auto *VD = dyn_cast<VarDecl>(D)) {
346-
if (!VD->getDeclContext()->getRedeclContext()->isFileContext() ||
347-
VD->isInline() || VD->isConstexpr() || isa<ParmVarDecl>(VD) ||
348-
// Constant initialized variable may not affect the ABI, but they
349-
// may be used in constant evaluation in the frontend, so we have
350-
// to remain them.
351-
VD->hasConstantInitialization())
397+
if (VD->getDeclContext()->isDependentContext())
352398
return false;
353399

354-
if (VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
400+
// Constant initialized variable may not affect the ABI, but they
401+
// may be used in constant evaluation in the frontend, so we have
402+
// to remain them.
403+
if (VD->hasConstantInitialization() || VD->isConstexpr())
404+
return false;
405+
406+
// If the variable should be generated somewhere else, we shouldn't elide
407+
// it.
408+
if (!shouldVarGenerateHereOnly(VD))
355409
return false;
356410
}
357411

@@ -1183,19 +1237,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
11831237
VarDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()),
11841238
/*BitWidth=*/3);
11851239

1186-
bool ModulesCodegen = false;
1187-
if (Writer.WritingModule && D->getStorageDuration() == SD_Static &&
1188-
!D->getDescribedVarTemplate()) {
1189-
// When building a C++20 module interface unit or a partition unit, a
1190-
// strong definition in the module interface is provided by the
1191-
// compilation of that unit, not by its users. (Inline variables are still
1192-
// emitted in module users.)
1193-
ModulesCodegen = (Writer.WritingModule->isInterfaceOrPartition() ||
1194-
(D->hasAttr<DLLExportAttr>() &&
1195-
Writer.getLangOpts().BuildingPCHWithObjectFile)) &&
1196-
Record.getASTContext().GetGVALinkageForVariable(D) >=
1197-
GVA_StrongExternal;
1198-
}
1240+
bool ModulesCodegen = shouldVarGenerateHereOnly(D);
11991241
VarDeclBits.addBit(ModulesCodegen);
12001242

12011243
VarDeclBits.addBits(D->getStorageClass(), /*BitWidth=*/3);
@@ -3012,32 +3054,7 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
30123054
Writer->ClearSwitchCaseIDs();
30133055

30143056
assert(FD->doesThisDeclarationHaveABody());
3015-
bool ModulesCodegen = false;
3016-
if (!FD->isDependentContext()) {
3017-
std::optional<GVALinkage> Linkage;
3018-
if (Writer->WritingModule &&
3019-
Writer->WritingModule->isInterfaceOrPartition()) {
3020-
// When building a C++20 module interface unit or a partition unit, a
3021-
// strong definition in the module interface is provided by the
3022-
// compilation of that unit, not by its users. (Inline functions are still
3023-
// emitted in module users.)
3024-
Linkage = getASTContext().GetGVALinkageForFunction(FD);
3025-
ModulesCodegen = *Linkage >= GVA_StrongExternal;
3026-
}
3027-
if (Writer->getLangOpts().ModulesCodegen ||
3028-
(FD->hasAttr<DLLExportAttr>() &&
3029-
Writer->getLangOpts().BuildingPCHWithObjectFile)) {
3030-
3031-
// Under -fmodules-codegen, codegen is performed for all non-internal,
3032-
// non-always_inline functions, unless they are available elsewhere.
3033-
if (!FD->hasAttr<AlwaysInlineAttr>()) {
3034-
if (!Linkage)
3035-
Linkage = getASTContext().GetGVALinkageForFunction(FD);
3036-
ModulesCodegen =
3037-
*Linkage != GVA_Internal && *Linkage != GVA_AvailableExternally;
3038-
}
3039-
}
3040-
}
3057+
bool ModulesCodegen = shouldFunctionGenerateHereOnly(FD);
30413058
Record->push_back(ModulesCodegen);
30423059
if (ModulesCodegen)
30433060
Writer->AddDeclRef(FD, Writer->ModularCodegenDecls);

clang/test/Modules/external-but-not-type-external.cppm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ void *use() {
2828
return a.external_but_not_type_external(nullptr);
2929
}
3030

31-
// CHECK-NOT: define {{.*}}@_ZNW1a1A30external_but_not_type_externalEPN12_GLOBAL__N_15LocalE
31+
// CHECK: define {{.*}}internal {{.*}}@_ZNW1a1A30external_but_not_type_externalEPN12_GLOBAL__N_15LocalE

0 commit comments

Comments
 (0)