@@ -869,6 +869,7 @@ void ASTWriter::WriteBlockInfoBlock() {
869
869
RECORD (WEAK_UNDECLARED_IDENTIFIERS);
870
870
RECORD (PENDING_IMPLICIT_INSTANTIATIONS);
871
871
RECORD (UPDATE_VISIBLE);
872
+ RECORD (DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD);
872
873
RECORD (DECL_UPDATE_OFFSETS);
873
874
RECORD (DECL_UPDATES);
874
875
RECORD (CUDA_SPECIAL_DECL_REFS);
@@ -3026,10 +3027,12 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
3026
3027
Stream.EmitRecordWithBlob (ConfigMacroAbbrev, Record, CM);
3027
3028
}
3028
3029
3029
- // Emit the initializers, if any.
3030
+ // Emit the reachable initializers.
3031
+ // The initializer may only be unreachable in reduced BMI.
3030
3032
RecordData Inits;
3031
3033
for (Decl *D : Context->getModuleInitializers (Mod))
3032
- Inits.push_back (GetDeclRef (D));
3034
+ if (wasDeclEmitted (D))
3035
+ Inits.push_back (GetDeclRef (D));
3033
3036
if (!Inits.empty ())
3034
3037
Stream.EmitRecord (SUBMODULE_INITIALIZERS, Inits);
3035
3038
@@ -3208,6 +3211,9 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
3208
3211
uint64_t Offset = Stream.GetCurrentBitNo ();
3209
3212
SmallVector<uint32_t , 128 > KindDeclPairs;
3210
3213
for (const auto *D : DC->decls ()) {
3214
+ if (DoneWritingDeclsAndTypes && !wasDeclEmitted (D))
3215
+ continue ;
3216
+
3211
3217
KindDeclPairs.push_back (D->getKind ());
3212
3218
KindDeclPairs.push_back (GetDeclRef (D));
3213
3219
}
@@ -3862,8 +3868,14 @@ class ASTDeclContextNameLookupTrait {
3862
3868
data_type getData (const Coll &Decls) {
3863
3869
unsigned Start = DeclIDs.size ();
3864
3870
for (NamedDecl *D : Decls) {
3865
- DeclIDs.push_back (
3866
- Writer.GetDeclRef (getDeclForLocalLookup (Writer.getLangOpts (), D)));
3871
+ NamedDecl *DeclForLocalLookup =
3872
+ getDeclForLocalLookup (Writer.getLangOpts (), D);
3873
+
3874
+ if (Writer.getDoneWritingDeclsAndTypes () &&
3875
+ !Writer.wasDeclEmitted (DeclForLocalLookup))
3876
+ continue ;
3877
+
3878
+ DeclIDs.push_back (Writer.GetDeclRef (DeclForLocalLookup));
3867
3879
}
3868
3880
return std::make_pair (Start, DeclIDs.size ());
3869
3881
}
@@ -3972,11 +3984,20 @@ bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result,
3972
3984
DC->hasNeedToReconcileExternalVisibleStorage ();
3973
3985
}
3974
3986
3975
- bool ASTWriter::isLookupResultEntirelyExternal (StoredDeclsList &Result,
3976
- DeclContext *DC) {
3977
- for (auto *D : Result.getLookupResult ())
3978
- if (!getDeclForLocalLookup (getLangOpts (), D)->isFromASTFile ())
3979
- return false ;
3987
+ bool ASTWriter::isLookupResultEntirelyExternalOrUnreachable (
3988
+ StoredDeclsList &Result, DeclContext *DC) {
3989
+ for (auto *D : Result.getLookupResult ()) {
3990
+ auto *LocalD = getDeclForLocalLookup (getLangOpts (), D);
3991
+ if (LocalD->isFromASTFile ())
3992
+ continue ;
3993
+
3994
+ // We can only be sure whether the local declaration is reachable
3995
+ // after we done writing the declarations and types.
3996
+ if (DoneWritingDeclsAndTypes && !wasDeclEmitted (LocalD))
3997
+ continue ;
3998
+
3999
+ return false ;
4000
+ }
3980
4001
3981
4002
return true ;
3982
4003
}
@@ -4014,8 +4035,17 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,
4014
4035
// don't need to write an entry for the name at all. If we can't
4015
4036
// write out a lookup set without performing more deserialization,
4016
4037
// just skip this entry.
4017
- if (isLookupResultExternal (Result, DC) &&
4018
- isLookupResultEntirelyExternal (Result, DC))
4038
+ //
4039
+ // Also in reduced BMI, we'd like to avoid writing unreachable
4040
+ // declarations in GMF, so we need to avoid writing declarations
4041
+ // that entirely external or unreachable.
4042
+ //
4043
+ // FIMXE: It looks sufficient to test
4044
+ // isLookupResultEntirelyExternalOrUnreachable here. But due to bug we have
4045
+ // to test isLookupResultExternal here. See
4046
+ // https://github.com/llvm/llvm-project/issues/61065 for details.
4047
+ if ((GeneratingReducedBMI || isLookupResultExternal (Result, DC)) &&
4048
+ isLookupResultEntirelyExternalOrUnreachable (Result, DC))
4019
4049
continue ;
4020
4050
4021
4051
// We also skip empty results. If any of the results could be external and
@@ -4206,9 +4236,15 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
4206
4236
continue ;
4207
4237
}
4208
4238
4209
- for (NamedDecl *ND : Result)
4210
- if (!ND->isFromASTFile ())
4211
- GetDeclRef (ND);
4239
+ for (NamedDecl *ND : Result) {
4240
+ if (ND->isFromASTFile ())
4241
+ continue ;
4242
+
4243
+ if (DoneWritingDeclsAndTypes && !wasDeclEmitted (ND))
4244
+ continue ;
4245
+
4246
+ GetDeclRef (ND);
4247
+ }
4212
4248
}
4213
4249
4214
4250
return 0 ;
@@ -4976,9 +5012,18 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
4976
5012
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl ();
4977
5013
4978
5014
// Force all top level declarations to be emitted.
4979
- for (const auto *D : TU->noload_decls ())
4980
- if (!D->isFromASTFile ())
4981
- GetDeclRef (D);
5015
+ //
5016
+ // We start emitting top level declarations from the module purview to
5017
+ // implement the eliding unreachable declaration feature.
5018
+ for (const auto *D : TU->noload_decls ()) {
5019
+ if (D->isFromASTFile ())
5020
+ continue ;
5021
+
5022
+ if (GeneratingReducedBMI && D->isFromExplicitGlobalModule ())
5023
+ continue ;
5024
+
5025
+ GetDeclRef (D);
5026
+ }
4982
5027
4983
5028
// If the translation unit has an anonymous namespace, and we don't already
4984
5029
// have an update block for it, write it as an update block.
@@ -5288,24 +5333,59 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
5288
5333
WriteDecl (Context, DOT.getDecl ());
5289
5334
}
5290
5335
} while (!DeclUpdates.empty ());
5291
- Stream.ExitBlock ();
5292
5336
5293
5337
DoneWritingDeclsAndTypes = true ;
5294
5338
5339
+ // DelayedNamespace is only meaningful in reduced BMI.
5340
+ // See the comments of DelayedNamespace for details.
5341
+ assert (DelayedNamespace.empty () || GeneratingReducedBMI);
5342
+ RecordData DelayedNamespaceRecord;
5343
+ for (NamespaceDecl *NS : DelayedNamespace) {
5344
+ uint64_t LexicalOffset = WriteDeclContextLexicalBlock (Context, NS);
5345
+ uint64_t VisibleOffset = WriteDeclContextVisibleBlock (Context, NS);
5346
+
5347
+ // Write the offset relative to current block.
5348
+ if (LexicalOffset)
5349
+ LexicalOffset -= DeclTypesBlockStartOffset;
5350
+
5351
+ if (VisibleOffset)
5352
+ VisibleOffset -= DeclTypesBlockStartOffset;
5353
+
5354
+ DelayedNamespaceRecord.push_back (getDeclID (NS));
5355
+ DelayedNamespaceRecord.push_back (LexicalOffset);
5356
+ DelayedNamespaceRecord.push_back (VisibleOffset);
5357
+ }
5358
+
5359
+ // The process of writing lexical and visible block for delayed namespace
5360
+ // shouldn't introduce any new decls, types or update to emit.
5361
+ assert (DeclTypesToEmit.empty ());
5362
+ assert (DeclUpdates.empty ());
5363
+
5364
+ Stream.ExitBlock ();
5365
+
5295
5366
// These things can only be done once we've written out decls and types.
5296
5367
WriteTypeDeclOffsets ();
5297
5368
if (!DeclUpdatesOffsetsRecord.empty ())
5298
5369
Stream.EmitRecord (DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord);
5299
5370
5371
+ if (!DelayedNamespaceRecord.empty ())
5372
+ Stream.EmitRecord (DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD,
5373
+ DelayedNamespaceRecord);
5374
+
5300
5375
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl ();
5301
5376
// Create a lexical update block containing all of the declarations in the
5302
5377
// translation unit that do not come from other AST files.
5303
5378
SmallVector<uint32_t , 128 > NewGlobalKindDeclPairs;
5304
5379
for (const auto *D : TU->noload_decls ()) {
5305
- if (!D->isFromASTFile ()) {
5306
- NewGlobalKindDeclPairs.push_back (D->getKind ());
5307
- NewGlobalKindDeclPairs.push_back (GetDeclRef (D));
5308
- }
5380
+ if (D->isFromASTFile ())
5381
+ continue ;
5382
+
5383
+ // In reduced BMI, skip unreached declarations.
5384
+ if (!wasDeclEmitted (D))
5385
+ continue ;
5386
+
5387
+ NewGlobalKindDeclPairs.push_back (D->getKind ());
5388
+ NewGlobalKindDeclPairs.push_back (GetDeclRef (D));
5309
5389
}
5310
5390
5311
5391
auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
@@ -5814,6 +5894,21 @@ DeclID ASTWriter::getDeclID(const Decl *D) {
5814
5894
return DeclIDs[D];
5815
5895
}
5816
5896
5897
+ bool ASTWriter::wasDeclEmitted (const Decl *D) const {
5898
+ assert (D);
5899
+
5900
+ assert (DoneWritingDeclsAndTypes &&
5901
+ " wasDeclEmitted should only be called after writing declarations" );
5902
+
5903
+ if (D->isFromASTFile ())
5904
+ return true ;
5905
+
5906
+ bool Emitted = DeclIDs.contains (D);
5907
+ assert ((Emitted || GeneratingReducedBMI) &&
5908
+ " The declaration can only be omitted in reduced BMI." );
5909
+ return Emitted;
5910
+ }
5911
+
5817
5912
void ASTWriter::associateDeclWithFile (const Decl *D, DeclID ID) {
5818
5913
assert (ID);
5819
5914
assert (D);
0 commit comments